1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2010 Thomas Martitz
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
24 import android
.media
.AudioFormat
;
25 import android
.media
.AudioManager
;
26 import android
.media
.AudioTrack
;
27 import android
.util
.Log
;
29 public class RockboxPCM
extends AudioTrack
33 private void LOG(CharSequence text
)
35 Log
.d("RockboxBootloader", (String
) text
);
40 super(AudioManager
.STREAM_MUSIC
,
42 /* should be CHANNEL_OUT_STEREO in 2.0 and above */
43 AudioFormat
.CHANNEL_CONFIGURATION_STEREO
,
44 AudioFormat
.ENCODING_PCM_16BIT
,
46 AudioTrack
.MODE_STREAM
);
49 raw_data
= new byte[buf_len
*2];
50 for(int i
= 0; i
< raw_data
.length
; i
++) raw_data
[i
] = (byte) 0x00;
51 /* fill with silence */
52 write(raw_data
, 0, raw_data
.length
);
53 if (getState() == AudioTrack
.STATE_INITIALIZED
)
55 if (setNotificationMarkerPosition(bytes2frames(buf_len
*2)/4) != AudioTrack
.SUCCESS
)
56 LOG("setNotificationMarkerPosition Error");
57 setPlaybackPositionUpdateListener(new PCMListener(buf_len
*2));
61 int bytes2frames(int bytes
) {
62 /* 1 sample is 2 bytes, 2 samples are 1 frame */
66 int frames2bytes(int frames
) {
67 /* 1 frame is 2 samples, 1 sample is 2 bytes */
71 @SuppressWarnings("unused")
72 private void play_pause(boolean pause
) {
78 if (getPlayState() == AudioTrack
.PLAYSTATE_STOPPED
)
80 for(int i
= 0; i
< raw_data
.length
; i
++) raw_data
[i
] = (byte) 0x00;
81 LOG("Writing silence");
82 /* fill with silence */
83 write(raw_data
, 0, raw_data
.length
);
84 RockboxService
.startForeground();
88 LOG("play_pause() return");
92 public void stop() throws IllegalStateException
95 RockboxService
.stopForeground();
98 @SuppressWarnings("unused")
99 private void set_volume(int volume
)
101 /* volume comes from 0..-990 from Rockbox */
102 /* TODO volume is in dB, but this code acts as if it were in %, convert? */
104 /* special case min and max volume to not suffer from floating point accuracy */
107 else if (volume
== -990)
110 fvolume
= (volume
+ 990)/990.0f
;
111 setStereoVolume(fvolume
, fvolume
);
114 public native void pcmSamplesToByteArray(byte[] dest
);
116 private class PCMListener
implements OnPlaybackPositionUpdateListener
{
119 public PCMListener(int len
) {
121 buf
= new byte[len
/2];
124 public void onMarkerReached(AudioTrack track
) {
125 // push new data to the hardware
127 pcmSamplesToByteArray(buf
);
128 //LOG("Trying to write " + buf.length + " bytes");
129 result
= track
.write(buf
, 0, buf
.length
);
132 //LOG(result + " bytes written");
133 track
.setPlaybackPositionUpdateListener(this);
134 track
.setNotificationMarkerPosition(bytes2frames(max_len
)/4);
135 switch(track
.getPlayState())
137 case AudioTrack
.PLAYSTATE_PLAYING
:
138 //LOG("State PLAYING");
140 case AudioTrack
.PLAYSTATE_PAUSED
:
143 case AudioTrack
.PLAYSTATE_STOPPED
:
144 LOG("State STOPPED");
150 LOG("Error in onMarkerReached");
156 public void onPeriodicNotification(AudioTrack track
) {
157 // TODO Auto-generated method stub