summaryrefslogtreecommitdiff
path: root/apps/playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playback.c')
-rw-r--r--apps/playback.c858
1 files changed, 110 insertions, 748 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 7b614cd0d0..b38ae7acf1 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -23,67 +23,67 @@
23/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can 23/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
24 * play whilst audio is paused */ 24 * play whilst audio is paused */
25 25
26#include <stdio.h> 26//#include <stdio.h>
27#include <string.h> 27//#include <string.h>
28#include <stdlib.h> 28//#include <ctype.h>
29#include <ctype.h> 29
30 30#include "playback.h"
31#include "system.h" 31#include "codec_thread.h"
32#include "thread.h" 32//#include "system.h"
33#include "file.h" 33//#include "thread.h"
34#include "panic.h" 34//#include "file.h"
35#include "memory.h" 35//#include "panic.h"
36#include "lcd.h" 36//#include "memory.h"
37#include "font.h" 37//#include "lcd.h"
38#include "button.h" 38//#include "font.h"
39//#include "button.h"
39#include "kernel.h" 40#include "kernel.h"
40#include "tree.h" 41//#include "tree.h"
41#include "debug.h" 42//#include "debug.h"
42#include "sprintf.h" 43//#include "sprintf.h"
43#include "settings.h" 44//#include "settings.h"
44#include "codecs.h" 45#include "codecs.h"
45#include "audio.h" 46//#include "audio.h"
46#include "buffering.h" 47#include "buffering.h"
47#include "appevents.h" 48//#include "appevents.h"
48#include "voice_thread.h" 49#include "voice_thread.h"
49#include "mp3_playback.h" 50//#include "mp3_playback.h"
50#include "usb.h" 51#include "usb.h"
51#include "storage.h" 52//#include "storage.h"
52#include "screens.h" 53//#include "screens.h"
53#include "playlist.h" 54#include "playlist.h"
54#include "playback.h"
55#include "pcmbuf.h" 55#include "pcmbuf.h"
56#include "buffer.h" 56#include "buffer.h"
57#include "dsp.h" 57//#include "dsp.h"
58#include "abrepeat.h" 58//#include "abrepeat.h"
59#include "cuesheet.h" 59#include "cuesheet.h"
60#ifdef HAVE_TAGCACHE 60#ifdef HAVE_TAGCACHE
61#include "tagcache.h" 61#include "tagcache.h"
62#endif 62#endif
63#ifdef HAVE_LCD_BITMAP 63#ifdef HAVE_LCD_BITMAP
64#include "icons.h" 64//#include "icons.h"
65#include "peakmeter.h" 65//#include "peakmeter.h"
66#include "action.h" 66//#include "action.h"
67#ifdef HAVE_ALBUMART 67#ifdef HAVE_ALBUMART
68#include "albumart.h" 68#include "albumart.h"
69#include "bmp.h" 69//#include "bmp.h"
70#endif 70#endif
71#endif 71#endif
72#include "lang.h" 72//#include "lang.h"
73#include "misc.h" 73//#include "misc.h"
74#include "sound.h" 74#include "sound.h"
75#include "metadata.h" 75#include "metadata.h"
76#include "splash.h" 76#include "splash.h"
77#include "talk.h" 77#include "talk.h"
78#include "ata_idle_notify.h" 78//#include "ata_idle_notify.h"
79 79
80#ifdef HAVE_RECORDING 80#ifdef HAVE_RECORDING
81#include "recording.h" 81//#include "recording.h"
82#include "pcm_record.h" 82#include "pcm_record.h"
83#endif 83#endif
84 84
85#ifdef IPOD_ACCESSORY_PROTOCOL 85#ifdef IPOD_ACCESSORY_PROTOCOL
86#include "iap.h" 86//#include "iap.h"
87#endif 87#endif
88 88
89#define PLAYBACK_VOICE 89#define PLAYBACK_VOICE
@@ -118,52 +118,13 @@
118#endif 118#endif
119 119
120 120
121/* Define one constant that includes recording related functionality */ 121static enum filling_state {
122#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
123#define AUDIO_HAVE_RECORDING
124#endif
125
126enum {
127 Q_NULL = 0,
128 Q_AUDIO_PLAY = 1,
129 Q_AUDIO_STOP,
130 Q_AUDIO_PAUSE,
131 Q_AUDIO_SKIP,
132 Q_AUDIO_PRE_FF_REWIND,
133 Q_AUDIO_FF_REWIND,
134 Q_AUDIO_CHECK_NEW_TRACK,
135 Q_AUDIO_FLUSH,
136 Q_AUDIO_TRACK_CHANGED,
137 Q_AUDIO_DIR_SKIP,
138 Q_AUDIO_POSTINIT,
139 Q_AUDIO_FILL_BUFFER,
140 Q_AUDIO_FINISH_LOAD,
141 Q_CODEC_REQUEST_COMPLETE,
142 Q_CODEC_REQUEST_FAILED,
143
144 Q_CODEC_LOAD,
145 Q_CODEC_LOAD_DISK,
146
147#ifdef AUDIO_HAVE_RECORDING
148 Q_ENCODER_LOAD_DISK,
149 Q_ENCODER_RECORD,
150#endif
151
152 Q_CODEC_DO_CALLBACK,
153};
154
155enum filling_state {
156 STATE_IDLE, /* audio is stopped: nothing to do */ 122 STATE_IDLE, /* audio is stopped: nothing to do */
157 STATE_FILLING, /* adding tracks to the buffer */ 123 STATE_FILLING, /* adding tracks to the buffer */
158 STATE_FULL, /* can't add any more tracks */ 124 STATE_FULL, /* can't add any more tracks */
159 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */ 125 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */
160 STATE_FINISHED, /* all remaining tracks are fully buffered */ 126 STATE_FINISHED, /* all remaining tracks are fully buffered */
161}; 127} filling;
162
163#define MAX_TRACK 128
164#define MAX_MULTIPLE_AA 2
165
166#define MAX_TRACK_MASK (MAX_TRACK-1)
167 128
168/* As defined in plugins/lib/xxx2wav.h */ 129/* As defined in plugins/lib/xxx2wav.h */
169#define GUARD_BUFSIZE (32*1024) 130#define GUARD_BUFSIZE (32*1024)
@@ -177,15 +138,13 @@ static bool audio_thread_ready SHAREDBSS_ATTR = false;
177/* TBD: Split out "audio" and "playback" (ie. calling) threads */ 138/* TBD: Split out "audio" and "playback" (ie. calling) threads */
178 139
179/* Main state control */ 140/* Main state control */
180static volatile bool audio_codec_loaded SHAREDBSS_ATTR = false; /* Codec loaded? (C/A-) */
181static volatile bool playing SHAREDBSS_ATTR = false; /* Is audio playing? (A) */ 141static volatile bool playing SHAREDBSS_ATTR = false; /* Is audio playing? (A) */
182static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */ 142static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */
183 143
184/* Ring buffer where compressed audio and codecs are loaded */ 144/* Ring buffer where compressed audio and codecs are loaded */
185static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */ 145static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
186static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */ 146static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */
187/* FIXME: make filebuflen static */ 147static size_t filebuflen = 0; /* Size of buffer (A/C-) */
188size_t filebuflen = 0; /* Size of buffer (A/C-) */
189/* FIXME: make buf_ridx (C/A-) */ 148/* FIXME: make buf_ridx (C/A-) */
190 149
191/* Possible arrangements of the buffer */ 150/* Possible arrangements of the buffer */
@@ -196,16 +155,32 @@ static int buffer_state = AUDIOBUF_STATE_TRASHED; /* Buffer state */
196 * by audio_current/next_track will be valid for the full duration of the 155 * by audio_current/next_track will be valid for the full duration of the
197 * currently playing track */ 156 * currently playing track */
198static struct mp3entry mp3entry_buf[2]; 157static struct mp3entry mp3entry_buf[2];
199static struct mp3entry *thistrack_id3, /* the currently playing track */ 158struct mp3entry *thistrack_id3, /* the currently playing track */
200 *othertrack_id3; /* prev track during track-change-transition, or end of playlist, 159 *othertrack_id3; /* prev track during track-change-transition, or end of playlist,
201 * next track otherwise */ 160 * next track otherwise */
202static struct mp3entry unbuffered_id3; /* the id3 for the first unbuffered track */ 161static struct mp3entry unbuffered_id3; /* the id3 for the first unbuffered track */
203 162
204/* for cuesheet support */ 163/* for cuesheet support */
205static struct cuesheet *curr_cue = NULL; 164static struct cuesheet *curr_cue = NULL;
206 165
166
167#define MAX_MULTIPLE_AA 2
168
169#ifdef HAVE_ALBUMART
170static struct albumart_slot {
171 struct dim dim; /* holds width, height of the albumart */
172 int used; /* counter, increments if something uses it */
173} albumart_slots[MAX_MULTIPLE_AA];
174
175#define FOREACH_ALBUMART(i) for(i = 0;i < MAX_MULTIPLE_AA; i++)
176#endif
177
178
179#define MAX_TRACK 128
180#define MAX_TRACK_MASK (MAX_TRACK-1)
181
207/* Track info structure about songs in the file buffer (A/C-) */ 182/* Track info structure about songs in the file buffer (A/C-) */
208struct track_info { 183static struct track_info {
209 int audio_hid; /* The ID for the track's buffer handle */ 184 int audio_hid; /* The ID for the track's buffer handle */
210 int id3_hid; /* The ID for the track's metadata handle */ 185 int id3_hid; /* The ID for the track's metadata handle */
211 int codec_hid; /* The ID for the track's codec handle */ 186 int codec_hid; /* The ID for the track's codec handle */
@@ -217,23 +192,13 @@ struct track_info {
217 size_t filesize; /* File total length */ 192 size_t filesize; /* File total length */
218 193
219 bool taginfo_ready; /* Is metadata read */ 194 bool taginfo_ready; /* Is metadata read */
220}; 195
221 196} tracks[MAX_TRACK];
222
223#ifdef HAVE_ALBUMART
224struct albumart_slot {
225 struct dim dim; /* holds width, height of the albumart */
226 int used; /* counter, increments if something uses it */
227} albumart_slots[MAX_MULTIPLE_AA];
228
229#define FOREACH_ALBUMART(i) for(i = 0;i < MAX_MULTIPLE_AA; i++)
230#endif
231 197
232static struct track_info tracks[MAX_TRACK];
233static volatile int track_ridx = 0; /* Track being decoded (A/C-) */ 198static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
234static int track_widx = 0; /* Track being buffered (A) */ 199static int track_widx = 0; /* Track being buffered (A) */
235
236#define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */ 200#define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
201
237static struct track_info *prev_ti = NULL; /* Pointer to the previously played 202static struct track_info *prev_ti = NULL; /* Pointer to the previously played
238 track */ 203 track */
239 204
@@ -244,10 +209,8 @@ static int last_peek_offset = 0;
244/* Scrobbler support */ 209/* Scrobbler support */
245static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/ 210static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
246 211
247static enum filling_state filling;
248
249/* Track change controls */ 212/* Track change controls */
250static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */ 213bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
251static bool dir_skip = false; /* Is a directory skip pending? (A) */ 214static bool dir_skip = false; /* Is a directory skip pending? (A) */
252static bool new_playlist = false; /* Are we starting a new playlist? (A) */ 215static bool new_playlist = false; /* Are we starting a new playlist? (A) */
253static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */ 216static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
@@ -262,21 +225,23 @@ static bool start_play_g = false; /* Used by audio_load_track to notify
262 */ 225 */
263static bool track_load_started = false; 226static bool track_load_started = false;
264 227
265/* Set to true if the codec thread should send an audio stop request
266 * (typically because the end of the playlist has been reached).
267 */
268static bool codec_requested_stop = false;
269
270#ifdef HAVE_DISK_STORAGE 228#ifdef HAVE_DISK_STORAGE
271static size_t buffer_margin = 5; /* Buffer margin aka anti-skip buffer (A/C-) */ 229static size_t buffer_margin = 5; /* Buffer margin aka anti-skip buffer (A/C-) */
272#endif 230#endif
273 231
232/* Event queues */
233struct event_queue audio_queue SHAREDBSS_ATTR;
234struct event_queue codec_queue SHAREDBSS_ATTR;
235struct event_queue pcmbuf_queue SHAREDBSS_ATTR;
236
237extern struct codec_api ci;
238extern unsigned int codec_thread_id;
239
274/* Multiple threads */ 240/* Multiple threads */
275/* Set the watermark to trigger buffer fill (A/C) */ 241/* Set the watermark to trigger buffer fill (A/C) */
276static void set_filebuf_watermark(void); 242static void set_filebuf_watermark(void);
277 243
278/* Audio thread */ 244/* Audio thread */
279static struct event_queue audio_queue SHAREDBSS_ATTR;
280static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR; 245static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR;
281static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; 246static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
282static const char audio_thread_name[] = "audio"; 247static const char audio_thread_name[] = "audio";
@@ -287,26 +252,8 @@ static bool audio_have_tracks(void);
287static void audio_reset_buffer(void); 252static void audio_reset_buffer(void);
288static void audio_stop_playback(void); 253static void audio_stop_playback(void);
289 254
290/* Codec thread */ 255
291extern struct codec_api ci; 256/**************************************/
292static struct event_queue codec_queue SHAREDBSS_ATTR;
293static struct queue_sender_list codec_queue_sender_list;
294static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
295IBSS_ATTR;
296static const char codec_thread_name[] = "codec";
297unsigned int codec_thread_id; /* For modifying thread priority later. */
298
299/* PCM buffer messaging */
300static struct event_queue pcmbuf_queue SHAREDBSS_ATTR;
301
302/* Function to be called by pcm buffer callbacks.
303 * Permissible Context(s): Audio interrupt
304 */
305static void pcmbuf_callback_queue_post(long id, intptr_t data)
306{
307 /* No lock since we're already in audio interrupt context */
308 queue_post(&pcmbuf_queue, id, data);
309}
310 257
311/* Scan the pcmbuf queue and return true if a message pulled. 258/* Scan the pcmbuf queue and return true if a message pulled.
312 * Permissible Context(s): Thread 259 * Permissible Context(s): Thread
@@ -850,6 +797,7 @@ int audio_status(void)
850 797
851#ifdef HAVE_RECORDING 798#ifdef HAVE_RECORDING
852 /* Do this here for constitency with mpeg.c version */ 799 /* Do this here for constitency with mpeg.c version */
800 /* FIXME: pcm_rec_status() is deprecated */
853 ret |= pcm_rec_status(); 801 ret |= pcm_rec_status();
854#endif 802#endif
855 803
@@ -947,600 +895,6 @@ static void set_filebuf_watermark(void)
947 logf("fwmark: %d", bytes); 895 logf("fwmark: %d", bytes);
948} 896}
949 897
950const char *get_codec_filename(int cod_spec)
951{
952 const char *fname;
953
954#ifdef HAVE_RECORDING
955 /* Can choose decoder or encoder if one available */
956 int type = cod_spec & CODEC_TYPE_MASK;
957 int afmt = cod_spec & CODEC_AFMT_MASK;
958
959 if ((unsigned)afmt >= AFMT_NUM_CODECS)
960 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
961
962 fname = (type == CODEC_TYPE_ENCODER) ?
963 audio_formats[afmt].codec_enc_root_fn :
964 audio_formats[afmt].codec_root_fn;
965
966 logf("%s: %d - %s",
967 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
968 afmt, fname ? fname : "<unknown>");
969#else /* !HAVE_RECORDING */
970 /* Always decoder */
971 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
972 cod_spec = AFMT_UNKNOWN;
973 fname = audio_formats[cod_spec].codec_root_fn;
974 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
975#endif /* HAVE_RECORDING */
976
977 return fname;
978} /* get_codec_filename */
979
980/* --- Codec thread --- */
981static bool codec_pcmbuf_insert_callback(
982 const void *ch1, const void *ch2, int count)
983{
984 const char *src[2] = { ch1, ch2 };
985
986 while (count > 0)
987 {
988 int out_count = dsp_output_count(ci.dsp, count);
989 int inp_count;
990 char *dest;
991
992 /* Prevent audio from a previous track from playing */
993 if (ci.new_track || ci.stop_codec)
994 return true;
995
996 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
997 {
998 cancel_cpu_boost();
999 sleep(1);
1000 if (ci.seek_time || ci.new_track || ci.stop_codec)
1001 return true;
1002 }
1003
1004 /* Get the real input_size for output_size bytes, guarding
1005 * against resampling buffer overflows. */
1006 inp_count = dsp_input_count(ci.dsp, out_count);
1007
1008 if (inp_count <= 0)
1009 return true;
1010
1011 /* Input size has grown, no error, just don't write more than length */
1012 if (inp_count > count)
1013 inp_count = count;
1014
1015 out_count = dsp_process(ci.dsp, dest, src, inp_count);
1016
1017 if (out_count <= 0)
1018 return true;
1019
1020 pcmbuf_write_complete(out_count);
1021
1022 count -= inp_count;
1023 }
1024
1025 return true;
1026} /* codec_pcmbuf_insert_callback */
1027
1028static void* codec_get_buffer(size_t *size)
1029{
1030 if (codec_size >= CODEC_SIZE)
1031 return NULL;
1032 *size = CODEC_SIZE - codec_size;
1033 return &codecbuf[codec_size];
1034}
1035
1036/* Between the codec and PCM track change, we need to keep updating the
1037 "elapsed" value of the previous (to the codec, but current to the
1038 user/PCM/WPS) track, so that the progressbar reaches the end.
1039 During that transition, the WPS will display prevtrack_id3. */
1040static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
1041static void codec_pcmbuf_position_callback(size_t size)
1042{
1043 /* This is called from an ISR, so be quick */
1044 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
1045 othertrack_id3->elapsed;
1046
1047 if (time >= othertrack_id3->length)
1048 {
1049 pcmbuf_set_position_callback(NULL);
1050 othertrack_id3->elapsed = othertrack_id3->length;
1051 }
1052 else
1053 othertrack_id3->elapsed = time;
1054}
1055
1056static void codec_set_elapsed_callback(unsigned int value)
1057{
1058 unsigned int latency;
1059 if (ci.seek_time)
1060 return;
1061
1062#ifdef AB_REPEAT_ENABLE
1063 ab_position_report(value);
1064#endif
1065
1066 latency = pcmbuf_get_latency();
1067 if (value < latency)
1068 thistrack_id3->elapsed = 0;
1069 else if (value - latency > thistrack_id3->elapsed ||
1070 value - latency < thistrack_id3->elapsed - 2)
1071 {
1072 thistrack_id3->elapsed = value - latency;
1073 }
1074}
1075
1076static void codec_set_offset_callback(size_t value)
1077{
1078 unsigned int latency;
1079
1080 if (ci.seek_time)
1081 return;
1082
1083 latency = pcmbuf_get_latency() * thistrack_id3->bitrate / 8;
1084 if (value < latency)
1085 thistrack_id3->offset = 0;
1086 else
1087 thistrack_id3->offset = value - latency;
1088}
1089
1090static void codec_advance_buffer_counters(size_t amount)
1091{
1092 bufadvance(CUR_TI->audio_hid, amount);
1093 ci.curpos += amount;
1094}
1095
1096/* copy up-to size bytes into ptr and return the actual size copied */
1097static size_t codec_filebuf_callback(void *ptr, size_t size)
1098{
1099 ssize_t copy_n;
1100
1101 if (ci.stop_codec || !playing)
1102 return 0;
1103
1104 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
1105
1106 /* Nothing requested OR nothing left */
1107 if (copy_n == 0)
1108 return 0;
1109
1110 /* Update read and other position pointers */
1111 codec_advance_buffer_counters(copy_n);
1112
1113 /* Return the actual amount of data copied to the buffer */
1114 return copy_n;
1115} /* codec_filebuf_callback */
1116
1117static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1118{
1119 size_t copy_n = reqsize;
1120 ssize_t ret;
1121 void *ptr;
1122
1123 if (!playing)
1124 {
1125 *realsize = 0;
1126 return NULL;
1127 }
1128
1129 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1130 if (ret >= 0)
1131 copy_n = MIN((size_t)ret, reqsize);
1132
1133 if (copy_n == 0)
1134 {
1135 *realsize = 0;
1136 return NULL;
1137 }
1138
1139 *realsize = copy_n;
1140
1141 return ptr;
1142} /* codec_request_buffer_callback */
1143
1144static int get_codec_base_type(int type)
1145{
1146 switch (type) {
1147 case AFMT_MPA_L1:
1148 case AFMT_MPA_L2:
1149 case AFMT_MPA_L3:
1150 return AFMT_MPA_L3;
1151 }
1152
1153 return type;
1154}
1155
1156static void codec_advance_buffer_callback(size_t amount)
1157{
1158 codec_advance_buffer_counters(amount);
1159 codec_set_offset_callback(ci.curpos);
1160}
1161
1162static void codec_advance_buffer_loc_callback(void *ptr)
1163{
1164 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1165 codec_advance_buffer_callback(amount);
1166}
1167
1168static void codec_seek_complete_callback(void)
1169{
1170 logf("seek_complete");
1171 /* If seeking-while-playing, pcm playback is actually paused (pcm_is_paused())
1172 * but the paused flag is not set. If seeking-while-paused, the (paused) flag is
1173 * set, but pcm playback may have actually stopped due to a previous buffer clear.
1174 * The buffer clear below occurs with either condition. A seemless seek skips
1175 * this section and no buffer clear occurs.
1176 */
1177 if (pcm_is_paused() || paused)
1178 {
1179 /* Clear the buffer */
1180 pcmbuf_play_stop();
1181 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1182
1183 /* If seeking-while-playing, resume pcm playback */
1184 if (!paused)
1185 pcmbuf_pause(false);
1186 }
1187 ci.seek_time = 0;
1188}
1189
1190static bool codec_seek_buffer_callback(size_t newpos)
1191{
1192 logf("codec_seek_buffer_callback");
1193
1194 int ret = bufseek(CUR_TI->audio_hid, newpos);
1195 if (ret == 0) {
1196 ci.curpos = newpos;
1197 return true;
1198 }
1199 else {
1200 return false;
1201 }
1202}
1203
1204static void codec_configure_callback(int setting, intptr_t value)
1205{
1206 switch (setting) {
1207 default:
1208 if (!dsp_configure(ci.dsp, setting, value))
1209 { logf("Illegal key:%d", setting); }
1210 }
1211}
1212
1213static void codec_track_changed(void)
1214{
1215 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1216 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1217}
1218
1219static void codec_pcmbuf_track_changed_callback(void)
1220{
1221 pcmbuf_set_position_callback(NULL);
1222 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED, 0);
1223}
1224
1225static void codec_discard_codec_callback(void)
1226{
1227 if (CUR_TI->codec_hid >= 0)
1228 {
1229 bufclose(CUR_TI->codec_hid);
1230 CUR_TI->codec_hid = -1;
1231 }
1232}
1233
1234static inline void codec_gapless_track_change(void)
1235{
1236 /* callback keeps the progress bar moving while the pcmbuf empties */
1237 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1238 /* set the pcmbuf callback for when the track really changes */
1239 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1240}
1241
1242static inline void codec_crossfade_track_change(void)
1243{
1244 /* Initiate automatic crossfade mode */
1245 pcmbuf_crossfade_init(false);
1246 /* Notify the wps that the track change starts now */
1247 codec_track_changed();
1248}
1249
1250static void codec_track_skip_done(bool was_manual)
1251{
1252 /* Manual track change (always crossfade or flush audio). */
1253 if (was_manual)
1254 {
1255 pcmbuf_crossfade_init(true);
1256 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1257 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1258 }
1259 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1260 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1261 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1262 {
1263 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1264 {
1265 if (global_settings.playlist_shuffle)
1266 /* shuffle mode is on, so crossfade: */
1267 codec_crossfade_track_change();
1268 else
1269 /* shuffle mode is off, so do a gapless track change */
1270 codec_gapless_track_change();
1271 }
1272 else
1273 /* normal crossfade: */
1274 codec_crossfade_track_change();
1275 }
1276 else
1277 /* normal gapless playback. */
1278 codec_gapless_track_change();
1279}
1280
1281static bool codec_load_next_track(void)
1282{
1283 intptr_t result = Q_CODEC_REQUEST_FAILED;
1284
1285 prev_track_elapsed = thistrack_id3->elapsed;
1286
1287#ifdef AB_REPEAT_ENABLE
1288 ab_end_of_track_report();
1289#endif
1290
1291 logf("Request new track");
1292
1293 if (ci.new_track == 0)
1294 {
1295 ci.new_track++;
1296 automatic_skip = true;
1297 }
1298
1299 if (!ci.stop_codec)
1300 {
1301 trigger_cpu_boost();
1302 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1303 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1304 }
1305
1306 switch (result)
1307 {
1308 case Q_CODEC_REQUEST_COMPLETE:
1309 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1310 codec_track_skip_done(!automatic_skip);
1311 return true;
1312
1313 case Q_CODEC_REQUEST_FAILED:
1314 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1315 ci.new_track = 0;
1316 ci.stop_codec = true;
1317 codec_requested_stop = true;
1318 return false;
1319
1320 default:
1321 LOGFQUEUE("codec |< default");
1322 ci.stop_codec = true;
1323 codec_requested_stop = true;
1324 return false;
1325 }
1326}
1327
1328static bool codec_request_next_track_callback(void)
1329{
1330 int prev_codectype;
1331
1332 if (ci.stop_codec || !playing)
1333 return false;
1334
1335 prev_codectype = get_codec_base_type(thistrack_id3->codectype);
1336 if (!codec_load_next_track())
1337 return false;
1338
1339 /* Seek to the beginning of the new track because if the struct
1340 mp3entry was buffered, "elapsed" might not be zero (if the track has
1341 been played already but not unbuffered) */
1342 codec_seek_buffer_callback(thistrack_id3->first_frame_offset);
1343 /* Check if the next codec is the same file. */
1344 if (prev_codectype == get_codec_base_type(thistrack_id3->codectype))
1345 {
1346 logf("New track loaded");
1347 codec_discard_codec_callback();
1348 return true;
1349 }
1350 else
1351 {
1352 logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype);
1353 return false;
1354 }
1355}
1356
1357static void codec_thread(void)
1358{
1359 struct queue_event ev;
1360 int status;
1361
1362 while (1) {
1363 status = 0;
1364
1365 if (!pcmbuf_is_crossfade_active()) {
1366 cancel_cpu_boost();
1367 }
1368
1369 queue_wait(&codec_queue, &ev);
1370 codec_requested_stop = false;
1371
1372 switch (ev.id) {
1373 case Q_CODEC_LOAD_DISK:
1374 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1375 queue_reply(&codec_queue, 1);
1376 audio_codec_loaded = true;
1377 ci.stop_codec = false;
1378 status = codec_load_file((const char *)ev.data, &ci);
1379 LOGFQUEUE("codec_load_file %s %d\n", (const char *)ev.data, status);
1380 break;
1381
1382 case Q_CODEC_LOAD:
1383 LOGFQUEUE("codec < Q_CODEC_LOAD");
1384 if (CUR_TI->codec_hid < 0) {
1385 logf("Codec slot is empty!");
1386 /* Wait for the pcm buffer to go empty */
1387 while (pcm_is_playing())
1388 yield();
1389 /* This must be set to prevent an infinite loop */
1390 ci.stop_codec = true;
1391 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1392 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1393 break;
1394 }
1395
1396 audio_codec_loaded = true;
1397 ci.stop_codec = false;
1398 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1399 LOGFQUEUE("codec_load_buf %d\n", status);
1400 break;
1401
1402 case Q_CODEC_DO_CALLBACK:
1403 LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK");
1404 queue_reply(&codec_queue, 1);
1405 if ((void*)ev.data != NULL)
1406 {
1407 cpucache_invalidate();
1408 ((void (*)(void))ev.data)();
1409 cpucache_flush();
1410 }
1411 break;
1412
1413#ifdef AUDIO_HAVE_RECORDING
1414 case Q_ENCODER_LOAD_DISK:
1415 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1416 audio_codec_loaded = false; /* Not audio codec! */
1417 logf("loading encoder");
1418 ci.stop_encoder = false;
1419 status = codec_load_file((const char *)ev.data, &ci);
1420 logf("encoder stopped");
1421 break;
1422#endif /* AUDIO_HAVE_RECORDING */
1423
1424 default:
1425 LOGFQUEUE("codec < default");
1426 }
1427
1428 if (audio_codec_loaded)
1429 {
1430 if (ci.stop_codec)
1431 {
1432 status = CODEC_OK;
1433 if (!playing)
1434 pcmbuf_play_stop();
1435
1436 }
1437 audio_codec_loaded = false;
1438 }
1439
1440 switch (ev.id) {
1441 case Q_CODEC_LOAD_DISK:
1442 case Q_CODEC_LOAD:
1443 LOGFQUEUE("codec < Q_CODEC_LOAD");
1444 if (playing)
1445 {
1446 if (ci.new_track || status != CODEC_OK)
1447 {
1448 if (!ci.new_track)
1449 {
1450 logf("Codec failure, %d %d", ci.new_track, status);
1451 splash(HZ*2, "Codec failure");
1452 }
1453
1454 if (!codec_load_next_track())
1455 {
1456 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1457 /* End of playlist */
1458 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1459 break;
1460 }
1461 }
1462 else
1463 {
1464 logf("Codec finished");
1465 if (ci.stop_codec)
1466 {
1467 /* Wait for the audio to stop playing before
1468 * triggering the WPS exit */
1469 while(pcm_is_playing())
1470 {
1471 /* There has been one too many struct pointer swaps by now
1472 * so even though it says othertrack_id3, its the correct one! */
1473 othertrack_id3->elapsed =
1474 othertrack_id3->length - pcmbuf_get_latency();
1475 sleep(1);
1476 }
1477
1478 if (codec_requested_stop)
1479 {
1480 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1481 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1482 }
1483 break;
1484 }
1485 }
1486
1487 if (CUR_TI->codec_hid >= 0)
1488 {
1489 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1490 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1491 }
1492 else
1493 {
1494 const char *codec_fn =
1495 get_codec_filename(thistrack_id3->codectype);
1496 if (codec_fn)
1497 {
1498 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1499 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1500 (intptr_t)codec_fn);
1501 }
1502 }
1503 }
1504 break;
1505
1506#ifdef AUDIO_HAVE_RECORDING
1507 case Q_ENCODER_LOAD_DISK:
1508 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1509
1510 if (status == CODEC_OK)
1511 break;
1512
1513 logf("Encoder failure");
1514 splash(HZ*2, "Encoder failure");
1515
1516 if (ci.enc_codec_loaded < 0)
1517 break;
1518
1519 logf("Encoder failed to load");
1520 ci.enc_codec_loaded = -1;
1521 break;
1522#endif /* AUDIO_HAVE_RECORDING */
1523
1524 default:
1525 LOGFQUEUE("codec < default");
1526
1527 } /* end switch */
1528 }
1529}
1530
1531/* Borrow the codec thread and return the ID */
1532void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
1533{
1534 /* Set id before telling thread to call something; it may be
1535 * needed before this function returns. */
1536 if (id != NULL)
1537 *id = codec_thread_id;
1538
1539 /* Codec thread will signal just before entering callback */
1540 LOGFQUEUE("codec >| Q_CODEC_DO_CALLBACK");
1541 queue_send(&codec_queue, Q_CODEC_DO_CALLBACK, (intptr_t)fn);
1542}
1543
1544/* --- Buffering callbacks --- */ 898/* --- Buffering callbacks --- */
1545 899
1546static void buffering_low_buffer_callback(void *data) 900static void buffering_low_buffer_callback(void *data)
@@ -1722,7 +1076,7 @@ static bool audio_loadcodec(bool start_play)
1722 if (id3 && prev_id3 && 1076 if (id3 && prev_id3 &&
1723 get_codec_base_type(id3->codectype) == 1077 get_codec_base_type(id3->codectype) ==
1724 get_codec_base_type(prev_id3->codectype) 1078 get_codec_base_type(prev_id3->codectype)
1725 && audio_codec_loaded) 1079 && codec_is_loaded())
1726 { 1080 {
1727 logf("Reusing prev. codec"); 1081 logf("Reusing prev. codec");
1728 return true; 1082 return true;
@@ -2269,12 +1623,17 @@ unsigned long audio_prev_elapsed(void)
2269 return prev_track_elapsed; 1623 return prev_track_elapsed;
2270} 1624}
2271 1625
1626void audio_set_prev_elapsed(unsigned long setting)
1627{
1628 prev_track_elapsed = setting;
1629}
1630
2272static void audio_stop_codec_flush(void) 1631static void audio_stop_codec_flush(void)
2273{ 1632{
2274 ci.stop_codec = true; 1633 ci.stop_codec = true;
2275 pcmbuf_pause(true); 1634 pcmbuf_pause(true);
2276 1635
2277 while (audio_codec_loaded) 1636 while (codec_is_loaded())
2278 yield(); 1637 yield();
2279 1638
2280 /* If the audio codec is not loaded any more, and the audio is still 1639 /* If the audio codec is not loaded any more, and the audio is still
@@ -2292,9 +1651,9 @@ static void audio_stop_playback(void)
2292{ 1651{
2293 if (playing) 1652 if (playing)
2294 { 1653 {
2295 /* If still actively playing here, play out the last samples in the track 1654 /* If still actively playing here, play out the last samples in the
2296 * before stopping. A manual stop is actually paused at this point, so 1655 * pcm buffer before stopping. If a manual stop has occurred, the
2297 * don't continue playback. 1656 * paused flag is set, so don't continue playback.
2298 */ 1657 */
2299 if (!paused) 1658 if (!paused)
2300 pcmbuf_play_remainder(); 1659 pcmbuf_play_remainder();
@@ -2686,23 +2045,8 @@ void audio_init(void)
2686 2045
2687 pcm_init(); 2046 pcm_init();
2688 2047
2689 /* Initialize codec api. */ 2048 codec_init_codec_api();
2690 ci.read_filebuf = codec_filebuf_callback; 2049
2691 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2692 ci.codec_get_buffer = codec_get_buffer;
2693 ci.request_buffer = codec_request_buffer_callback;
2694 ci.advance_buffer = codec_advance_buffer_callback;
2695 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2696 ci.request_next_track = codec_request_next_track_callback;
2697 ci.seek_buffer = codec_seek_buffer_callback;
2698 ci.seek_complete = codec_seek_complete_callback;
2699 ci.set_elapsed = codec_set_elapsed_callback;
2700 ci.set_offset = codec_set_offset_callback;
2701 ci.configure = codec_configure_callback;
2702 ci.discard_codec = codec_discard_codec_callback;
2703 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2704 CODEC_IDX_AUDIO);
2705
2706 thistrack_id3 = &mp3entry_buf[0]; 2050 thistrack_id3 = &mp3entry_buf[0];
2707 othertrack_id3 = &mp3entry_buf[1]; 2051 othertrack_id3 = &mp3entry_buf[1];
2708 2052
@@ -2717,14 +2061,7 @@ void audio_init(void)
2717 talk first */ 2061 talk first */
2718 talk_init(); 2062 talk_init();
2719 2063
2720 codec_thread_id = create_thread( 2064 make_codec_thread();
2721 codec_thread, codec_stack, sizeof(codec_stack),
2722 CREATE_THREAD_FROZEN,
2723 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2724 IF_COP(, CPU));
2725
2726 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list,
2727 codec_thread_id);
2728 2065
2729 audio_thread_id = create_thread(audio_thread, audio_stack, 2066 audio_thread_id = create_thread(audio_thread, audio_stack,
2730 sizeof(audio_stack), CREATE_THREAD_FROZEN, 2067 sizeof(audio_stack), CREATE_THREAD_FROZEN,
@@ -2790,3 +2127,28 @@ bool audio_is_thread_ready(void)
2790{ 2127{
2791 return audio_thread_ready; 2128 return audio_thread_ready;
2792} 2129}
2130
2131size_t audio_get_filebuflen(void)
2132{
2133 return filebuflen;
2134}
2135
2136int get_audio_hid()
2137{
2138 return CUR_TI->audio_hid;
2139}
2140
2141int *get_codec_hid()
2142{
2143 return &tracks[track_ridx].codec_hid;
2144}
2145
2146bool audio_is_playing(void)
2147{
2148 return playing;
2149}
2150
2151bool audio_is_paused(void)
2152{
2153 return paused;
2154}