blob: 0e20d97fb40a42cd15c8299bb715e736bafb1f7f [file] [log] [blame]
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Miika Pekkarinen
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdio.h>
20#include <string.h>
21#include <stdlib.h>
22#include <ctype.h>
23
24#include "system.h"
25#include "thread.h"
26#include "file.h"
27#include "lcd.h"
28#include "font.h"
29#include "backlight.h"
30#include "button.h"
31#include "kernel.h"
32#include "tree.h"
33#include "debug.h"
34#include "sprintf.h"
35#include "settings.h"
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000036#include "codecs.h"
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000037#include "wps.h"
38#include "wps-display.h"
39#include "audio.h"
40#include "logf.h"
41#include "mp3_playback.h"
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000042#include "usb.h"
43#include "status.h"
44#include "main_menu.h"
45#include "ata.h"
46#include "screens.h"
47#include "playlist.h"
48#include "playback.h"
Miika Pekkarinen20b38972005-07-13 12:48:22 +000049#include "pcmbuf.h"
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000050#include "pcm_playback.h"
51#include "buffer.h"
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000052#include "dsp.h"
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000053#ifdef HAVE_LCD_BITMAP
54#include "icons.h"
55#include "peakmeter.h"
56#include "action.h"
57#endif
58#include "lang.h"
59#include "bookmark.h"
60#include "misc.h"
61#include "sound.h"
Dave Chapman3ad485b2005-06-14 22:27:57 +000062#include "metadata.h"
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000063
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +000064static volatile bool codec_loaded;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000065static volatile bool playing;
66static volatile bool paused;
67
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000068#define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec";
69#define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec";
70#define CODEC_FLAC "/.rockbox/codecs/flac.codec";
71#define CODEC_WAV "/.rockbox/codecs/wav.codec";
72#define CODEC_A52 "/.rockbox/codecs/a52.codec";
73#define CODEC_MPC "/.rockbox/codecs/mpc.codec";
74#define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec";
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000075
Miika Pekkarinen431e8132005-06-19 18:41:53 +000076#define AUDIO_FILL_CYCLE (1024*256)
Miika Pekkarinende3b04e2005-06-29 14:46:27 +000077#define AUDIO_DEFAULT_WATERMARK (1024*512)
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +000078#define AUDIO_DEFAULT_FILECHUNK (1024*32)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000079
80#define AUDIO_PLAY 1
81#define AUDIO_STOP 2
82#define AUDIO_PAUSE 3
83#define AUDIO_RESUME 4
84#define AUDIO_NEXT 5
85#define AUDIO_PREV 6
86#define AUDIO_FF_REWIND 7
87#define AUDIO_FLUSH_RELOAD 8
88#define AUDIO_CODEC_DONE 9
Miika Pekkarinen58af47c2005-06-13 22:09:12 +000089#define AUDIO_FLUSH 10
Miika Pekkarinen431e8132005-06-19 18:41:53 +000090#define AUDIO_TRACK_CHANGED 11
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000091
92#define CODEC_LOAD 1
93#define CODEC_LOAD_DISK 2
94
95/* As defined in plugins/lib/xxx2wav.h */
96#define MALLOC_BUFSIZE (512*1024)
97#define GUARD_BUFSIZE (8*1024)
98
99/* TODO:
100 Handle playlist_peek in mpeg.c
101 Track changing
102*/
103
104extern bool audio_is_initialized;
105
106/* Buffer control thread. */
107static struct event_queue audio_queue;
108static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
109static const char audio_thread_name[] = "audio";
110
111/* Codec thread. */
112static struct event_queue codec_queue;
Jens Arnoldbb3ed3c2005-07-03 15:09:11 +0000113static long codec_stack[(DEFAULT_STACK_SIZE + 0x2500)/sizeof(long)] IDATA_ATTR;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000114static const char codec_thread_name[] = "codec";
115
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000116static struct mutex mutex_bufferfill;
117
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000118/* Is file buffer currently being refilled? */
119static volatile bool filling;
120
121/* Ring buffer where tracks and codecs are loaded. */
Linus Nielsen Feltzingecf2f7472005-06-22 02:47:54 +0000122static char *codecbuf;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000123
124/* Total size of the ring buffer. */
Linus Nielsen Feltzingb5a0f702005-06-22 14:03:04 +0000125int codecbuflen;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000126
127/* Bytes available in the buffer. */
Linus Nielsen Feltzingb5a0f702005-06-22 14:03:04 +0000128int codecbufused;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000129
130/* Ring buffer read and write indexes. */
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000131static volatile int buf_ridx;
132static volatile int buf_widx;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000133
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000134static int last_peek_offset;
135
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000136/* Track information (count in file buffer, read/write indexes for
137 track ring structure. */
Linus Nielsen Feltzing17098e12005-06-22 20:37:31 +0000138int track_count;
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000139static volatile int track_ridx;
140static volatile int track_widx;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000141static bool track_changed;
142
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000143/* Partially loaded song's file handle to continue buffering later. */
144static int current_fd;
145
146/* Information about how many bytes left on the buffer re-fill run. */
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000147static long fill_bytesleft;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000148
149/* Track info structure about songs in the file buffer. */
150static struct track_info tracks[MAX_TRACK];
151
152/* Pointer to track info structure about current song playing. */
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000153static struct track_info *cur_ti;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000154
155/* Codec API including function callbacks. */
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000156extern struct codec_api ci;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000157
158/* When we change a song and buffer is not in filling state, this
159 variable keeps information about whether to go a next/previous track. */
160static int new_track;
161
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000162/* Callback function to call when current track has really changed. */
163void (*track_changed_callback)(struct track_info *ti);
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000164void (*track_buffer_callback)(struct mp3entry *id3, bool last_track);
Miika Pekkarinen9bde0382005-07-03 18:36:24 +0000165void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track);
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000166
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000167/* Configuration */
168static int conf_bufferlimit;
169static int conf_watermark;
170static int conf_filechunk;
Miika Pekkarinen2326bea2005-06-10 13:43:12 +0000171
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +0000172static bool v1first = false;
173
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000174static void mp3_set_elapsed(struct mp3entry* id3);
175int mp3_get_file_pos(void);
176
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000177bool codec_pcmbuf_insert_callback(char *buf, long length)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000178{
179 char *dest;
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000180 long realsize;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000181 int factor;
182 int next_channel = 0;
183 int processed_length;
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000184 int mono = 0;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000185
186 /* If non-interleaved stereo mode. */
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000187 if (dsp_config.stereo_mode == STEREO_NONINTERLEAVED)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000188 next_channel = length / 2;
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000189 else if (dsp_config.stereo_mode == STEREO_MONO) {
190 length *= 2;
191 mono = 1;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000192 }
193
194 if (dsp_config.sample_depth > 16) {
195 length /= 2;
196 factor = 1;
197 } else {
198 factor = 0;
199 }
200
201 while (length > 0) {
202 /* Request a few extra bytes for resampling. */
203 /* FIXME: Required extra bytes SHOULD be calculated. */
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000204 while ((dest = pcmbuf_request_buffer(length+16384, &realsize)) == NULL)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000205 yield();
206
207 if (realsize < 16384) {
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000208 pcmbuf_flush_buffer(0);
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000209 continue ;
210 }
211
212 realsize -= 16384;
213
214 if (next_channel) {
215 processed_length = dsp_process(dest, buf, realsize / 4) * 2;
216 dsp_process(dest, buf + next_channel, realsize / 4);
217 } else {
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000218 processed_length = dsp_process(dest, buf, realsize >> (mono + 1));
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000219 }
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000220 pcmbuf_flush_buffer(processed_length);
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000221 length -= realsize;
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000222 buf += realsize << (factor + mono);
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000223 }
224
225 return true;
226}
227
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000228bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000229 long length)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000230{
231 char *dest;
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000232 long realsize;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000233 int factor;
234 int processed_length;
235
236 /* non-interleaved stereo mode. */
237 if (dsp_config.sample_depth > 16) {
238 factor = 0;
239 } else {
240 length /= 2;
241 factor = 1;
242 }
243
244 while (length > 0) {
245 /* Request a few extra bytes for resampling. */
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000246 while ((dest = pcmbuf_request_buffer(length+4096, &realsize)) == NULL)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000247 yield();
248
249 if (realsize < 4096) {
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000250 pcmbuf_flush_buffer(0);
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000251 continue ;
252 }
253
254 realsize -= 4096;
255
256 processed_length = dsp_process(dest, ch1, realsize / 4) * 2;
257 dsp_process(dest, ch2, realsize / 4);
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000258 pcmbuf_flush_buffer(processed_length);
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000259 length -= realsize;
260 ch1 += realsize >> factor;
261 ch2 += realsize >> factor;
262 }
263
264 return true;
265}
266
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000267void* get_codec_memory_callback(long *size)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000268{
269 *size = MALLOC_BUFSIZE;
270 return &audiobuf[0];
271}
272
273void codec_set_elapsed_callback(unsigned int value)
274{
275 unsigned int latency;
276
Miika Pekkarinencf18f962005-06-20 06:49:21 +0000277 if (ci.stop_codec)
278 return ;
279
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000280 latency = pcmbuf_get_latency();
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +0000281
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000282 if (value < latency) {
283 cur_ti->id3.elapsed = 0;
284 } else if (value - latency > cur_ti->id3.elapsed
285 || value - latency < cur_ti->id3.elapsed - 2) {
286 cur_ti->id3.elapsed = value - latency;
287 }
288}
289
Ryan Jacksond1917562005-07-12 16:45:38 +0000290void codec_set_offset_callback(unsigned int value)
291{
292 unsigned int latency;
293
294 if (ci.stop_codec)
295 return ;
296
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000297 /* The 1000 here is a hack. pcmbuf_get_latency() should
Ryan Jacksond1917562005-07-12 16:45:38 +0000298 * be more accurate
299 */
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000300 latency = (pcmbuf_get_latency() + 1000) * cur_ti->id3.bitrate / 8;
Ryan Jacksond1917562005-07-12 16:45:38 +0000301
302 if (value < latency) {
303 cur_ti->id3.offset = 0;
304 } else if (value - latency > (unsigned int)cur_ti->id3.offset ) {
305 cur_ti->id3.offset = value - latency;
306 }
307}
308
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000309long codec_filebuf_callback(void *ptr, long size)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000310{
311 char *buf = (char *)ptr;
312 int copy_n;
313 int part_n;
314
315 if (ci.stop_codec || !playing)
316 return 0;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000317
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000318 copy_n = MIN((off_t)size, (off_t)cur_ti->available + cur_ti->filerem);
319
320 while (copy_n > cur_ti->available) {
321 yield();
322 if (ci.stop_codec)
323 return 0;
324 }
325
326 if (copy_n == 0)
327 return 0;
328
329 part_n = MIN(copy_n, codecbuflen - buf_ridx);
330 memcpy(buf, &codecbuf[buf_ridx], part_n);
331 if (part_n < copy_n) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000332 memcpy(&buf[part_n], &codecbuf[0], copy_n - part_n);
333 }
334
335 buf_ridx += copy_n;
336 if (buf_ridx >= codecbuflen)
337 buf_ridx -= codecbuflen;
338 ci.curpos += copy_n;
339 cur_ti->available -= copy_n;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000340 codecbufused -= copy_n;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000341
342 return copy_n;
343}
344
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000345void* codec_request_buffer_callback(long *realsize, long reqsize)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000346{
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000347 long part_n;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000348
349 if (ci.stop_codec || !playing) {
350 *realsize = 0;
351 return NULL;
352 }
353
354 *realsize = MIN((off_t)reqsize, (off_t)cur_ti->available + cur_ti->filerem);
355 if (*realsize == 0) {
356 return NULL;
357 }
358
359 while ((int)*realsize > cur_ti->available) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000360 yield();
361 if (ci.stop_codec) {
Miika Pekkarinen9ff373c2005-06-10 20:29:35 +0000362 *realsize = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000363 return NULL;
364 }
365 }
366
367 part_n = MIN((int)*realsize, codecbuflen - buf_ridx);
368 if (part_n < *realsize) {
369 part_n += GUARD_BUFSIZE;
370 if (part_n < *realsize)
371 *realsize = part_n;
372 memcpy(&codecbuf[codecbuflen], &codecbuf[0], *realsize -
373 (codecbuflen - buf_ridx));
374 }
375
376 return (char *)&codecbuf[buf_ridx];
377}
378
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000379static bool rebuffer_and_seek(int newpos)
380{
381 int fd;
382
383 logf("Re-buffering song");
384 mutex_lock(&mutex_bufferfill);
385
386 /* (Re-)open current track's file handle. */
387 fd = open(playlist_peek(0), O_RDONLY);
388 if (fd < 0) {
389 logf("Open failed!");
390 mutex_unlock(&mutex_bufferfill);
391 return false;
392 }
393 if (current_fd >= 0)
394 close(current_fd);
395 current_fd = fd;
396
397 /* Clear codec buffer. */
398 audio_invalidate_tracks();
399 codecbufused = 0;
400 buf_ridx = buf_widx = 0;
401 cur_ti->filerem = cur_ti->filesize - newpos;
402 cur_ti->filepos = newpos;
403 cur_ti->start_pos = newpos;
404 ci.curpos = newpos;
405 cur_ti->available = 0;
406 lseek(current_fd, newpos, SEEK_SET);
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000407 pcmbuf_flush_audio();
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000408
409 mutex_unlock(&mutex_bufferfill);
410
Miika Pekkarinen2724d0b2005-07-01 21:00:02 +0000411 while (cur_ti->available == 0 && cur_ti->filerem > 0) {
412 yield();
413 if (ci.stop_codec)
414 return false;
415 }
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000416
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000417 return true;
418}
419
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000420void codec_advance_buffer_callback(long amount)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000421{
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000422 if (amount > cur_ti->available + cur_ti->filerem)
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000423 amount = cur_ti->available + cur_ti->filerem;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000424
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000425 if (amount > cur_ti->available) {
426 if (!rebuffer_and_seek(ci.curpos + amount))
427 ci.stop_codec = true;
428 return ;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000429 }
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000430
431 buf_ridx += amount;
432 if (buf_ridx >= codecbuflen)
433 buf_ridx -= codecbuflen;
434 cur_ti->available -= amount;
435 codecbufused -= amount;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000436 ci.curpos += amount;
Ryan Jacksond1917562005-07-12 16:45:38 +0000437 codec_set_offset_callback(ci.curpos);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000438}
439
440void codec_advance_buffer_loc_callback(void *ptr)
441{
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000442 long amount;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000443
444 amount = (int)ptr - (int)&codecbuf[buf_ridx];
445 codec_advance_buffer_callback(amount);
446}
447
448off_t codec_mp3_get_filepos_callback(int newtime)
449{
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000450 off_t newpos;
451
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000452 cur_ti->id3.elapsed = newtime;
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000453 newpos = mp3_get_file_pos();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000454
455 return newpos;
456}
457
458bool codec_seek_buffer_callback(off_t newpos)
459{
460 int difference;
461
462 if (newpos < 0)
463 newpos = 0;
464
465 if (newpos >= cur_ti->filesize)
466 newpos = cur_ti->filesize - 1;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000467
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000468 difference = newpos - ci.curpos;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000469 /* Seeking forward */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000470 if (difference >= 0) {
471 logf("seek: +%d", difference);
472 codec_advance_buffer_callback(difference);
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000473 if (!pcmbuf_is_crossfade_active())
474 pcmbuf_play_stop();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000475 return true;
476 }
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000477
478 /* Seeking backward */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000479 difference = -difference;
480 if (ci.curpos - difference < 0)
481 difference = ci.curpos;
482
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000483 /* We need to reload the song. */
484 if (newpos < cur_ti->start_pos)
485 return rebuffer_and_seek(newpos);
486
487 /* Seeking inside buffer space. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000488 logf("seek: -%d", difference);
489 codecbufused += difference;
490 cur_ti->available += difference;
491 buf_ridx -= difference;
492 if (buf_ridx < 0)
493 buf_ridx = codecbuflen + buf_ridx;
494 ci.curpos -= difference;
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000495 if (!pcmbuf_is_crossfade_active())
496 pcmbuf_play_stop();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000497
498 return true;
499}
500
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000501void codec_configure_callback(int setting, void *value)
502{
503 switch (setting) {
504 case CODEC_SET_FILEBUF_WATERMARK:
505 conf_watermark = (unsigned int)value;
506 break;
507
508 case CODEC_SET_FILEBUF_CHUNKSIZE:
509 conf_filechunk = (unsigned int)value;
510 break;
511
512 case CODEC_SET_FILEBUF_LIMIT:
513 conf_bufferlimit = (unsigned int)value;
514 break;
515
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000516 case CODEC_DSP_ENABLE:
517 if ((bool)value)
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000518 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000519 else
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000520 ci.pcmbuf_insert = pcmbuf_insert_buffer;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000521 break ;
522
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000523 default:
Miika Pekkarinen65b840d2005-06-26 20:01:33 +0000524 if (!dsp_configure(setting, value)) {
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000525 logf("Illegal key: %d", setting);
Miika Pekkarinen65b840d2005-06-26 20:01:33 +0000526 }
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000527 }
528}
529
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000530void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
531 bool last_track))
532{
533 track_buffer_callback = handler;
534}
535
536void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3,
Miika Pekkarinen9bde0382005-07-03 18:36:24 +0000537 bool last_track))
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000538{
539 track_unbuffer_callback = handler;
540}
541
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000542void audio_set_track_changed_event(void (*handler)(struct track_info *ti))
543{
544 track_changed_callback = handler;
545}
546
Miika Pekkarinenc3fed622005-06-15 18:59:04 +0000547void codec_track_changed(void)
548{
549 track_changed = true;
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000550 queue_post(&audio_queue, AUDIO_TRACK_CHANGED, 0);
Miika Pekkarinenc3fed622005-06-15 18:59:04 +0000551}
552
Miika Pekkarinen3e33a0f2005-07-05 15:51:59 +0000553/* Give codecs or file buffering the right amount of processing time
554 to prevent pcm audio buffer from going empty. */
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000555void yield_codecs(void)
556{
Miika Pekkarinen61716dd2005-06-07 18:03:33 +0000557 yield();
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000558 if (!pcm_is_playing())
559 sleep(5);
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000560 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
Miika Pekkarinen3e33a0f2005-07-05 15:51:59 +0000561 && !ci.stop_codec && playing && queue_empty(&audio_queue)
562 && codecbufused > (128*1024))
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000563 yield();
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000564}
565
Linus Nielsen Feltzingdf807982005-07-07 09:53:02 +0000566/* FIXME: This code should be made more generic and move to metadata.c */
567void strip_id3v1_tag(void)
568{
569 int i;
570 static const unsigned char tag[] = "TAG";
571 int tagptr;
572 bool found = true;
573
574 if (codecbufused >= 128)
575 {
576 tagptr = buf_widx - 128;
577 if (tagptr < 0)
578 tagptr += codecbuflen;
579
580 for(i = 0;i < 3;i++)
581 {
582 if(tagptr >= codecbuflen)
583 tagptr -= codecbuflen;
584
585 if(codecbuf[tagptr] != tag[i])
586 {
587 found = false;
588 break;
589 }
590
591 tagptr++;
592 }
593
594 if(found)
595 {
596 /* Skip id3v1 tag */
597 logf("Skipping ID3v1 tag\n");
598 buf_widx -= 128;
599 tracks[track_widx].available -= 128;
600 codecbufused -= 128;
601 }
602 }
603}
604
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000605void audio_fill_file_buffer(void)
606{
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000607 long i, size;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000608 int rc;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000609
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000610 if (current_fd < 0)
611 return ;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000612
613 /* Throw away buffered codec. */
614 if (tracks[track_widx].start_pos != 0)
615 tracks[track_widx].codecsize = 0;
616
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000617 i = 0;
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000618 size = MIN(tracks[track_widx].filerem, AUDIO_FILL_CYCLE);
619 while (i < size) {
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000620 /* Give codecs some processing time. */
621 yield_codecs();
622
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000623 if (fill_bytesleft == 0)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000624 break ;
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000625 rc = MIN(conf_filechunk, codecbuflen - buf_widx);
Miika Pekkarinen3e33f852005-07-10 06:58:02 +0000626 rc = MIN(rc, fill_bytesleft);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000627 rc = read(current_fd, &codecbuf[buf_widx], rc);
628 if (rc <= 0) {
629 tracks[track_widx].filerem = 0;
Linus Nielsen Feltzingdf807982005-07-07 09:53:02 +0000630 strip_id3v1_tag();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000631 break ;
632 }
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000633
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000634 buf_widx += rc;
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000635 if (buf_widx >= codecbuflen)
636 buf_widx -= codecbuflen;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000637 i += rc;
638 tracks[track_widx].available += rc;
Miika Pekkarinen3eb962d2005-07-07 07:15:05 +0000639 tracks[track_widx].filerem -= rc;
640 tracks[track_widx].filepos += rc;
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000641 codecbufused += rc;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000642 fill_bytesleft -= rc;
643 }
644
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000645 /*logf("Filled:%d/%d", tracks[track_widx].available,
646 tracks[track_widx].filerem);*/
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000647}
648
649bool loadcodec(const char *trackname, bool start_play)
650{
651 char msgbuf[80];
652 off_t size;
653 int filetype;
654 int fd;
655 int i, rc;
656 const char *codec_path;
657 int copy_n;
658 int prev_track;
659
660 filetype = probe_file_format(trackname);
661 switch (filetype) {
662 case AFMT_OGG_VORBIS:
663 logf("Codec: Vorbis");
664 codec_path = CODEC_VORBIS;
665 break;
Jens Arnolde2cd5812005-06-18 09:51:10 +0000666 case AFMT_MPA_L1:
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000667 case AFMT_MPA_L2:
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000668 case AFMT_MPA_L3:
Jens Arnolde2cd5812005-06-18 09:51:10 +0000669 logf("Codec: MPA L1/L2/L3");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000670 codec_path = CODEC_MPA_L3;
671 break;
672 case AFMT_PCM_WAV:
673 logf("Codec: PCM WAV");
674 codec_path = CODEC_WAV;
675 break;
676 case AFMT_FLAC:
677 logf("Codec: FLAC");
678 codec_path = CODEC_FLAC;
679 break;
Dave Chapman55ed7d72005-06-11 10:08:17 +0000680 case AFMT_A52:
681 logf("Codec: A52");
682 codec_path = CODEC_A52;
683 break;
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000684 case AFMT_MPC:
685 logf("Codec: Musepack");
686 codec_path = CODEC_MPC;
687 break;
Dave Bryant57c6f6e2005-06-13 06:00:35 +0000688 case AFMT_WAVPACK:
689 logf("Codec: WAVPACK");
690 codec_path = CODEC_WAVPACK;
691 break;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000692 default:
693 logf("Codec: Unsupported");
694 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
695 splash(HZ*2, true, msgbuf);
696 codec_path = NULL;
697 }
698
Dave Chapman961c9a32005-06-18 16:24:27 +0000699 tracks[track_widx].id3.codectype = filetype;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000700 tracks[track_widx].codecsize = 0;
701 if (codec_path == NULL)
702 return false;
703
704 if (!start_play) {
705 prev_track = track_widx - 1;
706 if (prev_track < 0)
707 prev_track = MAX_TRACK-1;
Dave Chapman961c9a32005-06-18 16:24:27 +0000708 if (track_count > 0 && filetype == tracks[prev_track].id3.codectype) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000709 logf("Reusing prev. codec");
710 return true;
711 }
712 } else {
713 /* Load the codec directly from disk and save some memory. */
714 cur_ti = &tracks[track_widx];
715 ci.filesize = cur_ti->filesize;
716 ci.id3 = (struct mp3entry *)&cur_ti->id3;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000717 ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready;
718 ci.curpos = 0;
719 playing = true;
720 logf("Starting codec");
721 queue_post(&codec_queue, CODEC_LOAD_DISK, (void *)codec_path);
722 return true;
723 }
724
725 fd = open(codec_path, O_RDONLY);
726 if (fd < 0) {
727 logf("Codec doesn't exist!");
728 snprintf(msgbuf, sizeof(msgbuf)-1, "Couldn't load codec: %s", codec_path);
729 splash(HZ*2, true, msgbuf);
730 return false;
731 }
732
733 size = filesize(fd);
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000734 if ((off_t)fill_bytesleft < size + conf_watermark) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000735 logf("Not enough space");
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000736 fill_bytesleft = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000737 close(fd);
738 return false;
739 }
740
741 i = 0;
742 while (i < size) {
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000743 yield_codecs();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000744
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000745 copy_n = MIN(conf_filechunk, codecbuflen - buf_widx);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000746 rc = read(fd, &codecbuf[buf_widx], copy_n);
747 if (rc < 0)
748 return false;
749 buf_widx += rc;
Miika Pekkarinen3e33f852005-07-10 06:58:02 +0000750 codecbufused += rc;
751 fill_bytesleft -= rc;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000752 if (buf_widx >= codecbuflen)
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000753 buf_widx -= codecbuflen;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000754 i += rc;
755 }
756 close(fd);
757 logf("Done: %dB", i);
758
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000759 tracks[track_widx].codecsize = size;
760
761 return true;
762}
763
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000764bool read_next_metadata(void)
765{
766 int fd;
767 char *trackname;
768 int next_track;
769 int status;
770
Miika Pekkarinen527ce402005-07-10 08:46:12 +0000771 next_track = track_widx;
772 if (tracks[track_widx].taginfo_ready)
773 next_track++;
774
775 if (next_track >= MAX_TRACK)
776 next_track -= MAX_TRACK;
777
778 if (tracks[next_track].taginfo_ready)
779 return true;
780
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000781 trackname = playlist_peek(last_peek_offset);
782 if (!trackname)
783 return false;
784
785 fd = open(trackname, O_RDONLY);
786 if (fd < 0)
787 return false;
Miika Pekkarinen527ce402005-07-10 08:46:12 +0000788
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000789 /* Start buffer refilling also because we need to spin-up the disk. */
790 filling = true;
791 status = get_metadata(&tracks[next_track],fd,trackname,v1first);
Miika Pekkarinen8ad60cc2005-07-04 06:06:30 +0000792 track_changed = true;
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000793 close(fd);
794
795 return status;
796}
797
Miika Pekkarinena9ac3d12005-06-08 10:45:40 +0000798bool audio_load_track(int offset, bool start_play, int peek_offset)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000799{
800 char *trackname;
801 int fd;
802 off_t size;
803 int rc, i;
804 int copy_n;
Miika Pekkarinende3b04e2005-06-29 14:46:27 +0000805
Miika Pekkarinenb288dda2005-07-10 08:38:16 +0000806 /* Stop buffer filling if there is no free track entries.
807 Don't fill up the last track entry (we wan't to store next track
808 metadata there). */
809 if (track_count >= MAX_TRACK - 1) {
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000810 fill_bytesleft = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000811 return false;
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000812 }
813
814 /* Don't start loading track if the current write position already
815 contains a BUFFERED track. The entry may contain the metadata
816 which is ok. */
817 if (tracks[track_widx].filesize != 0)
818 return false;
819
820 /* Get track name from current playlist read position. */
Miika Pekkarinende3b04e2005-06-29 14:46:27 +0000821 logf("Buffering track:%d/%d", track_widx, track_ridx);
Miika Pekkarinena9ac3d12005-06-08 10:45:40 +0000822 trackname = playlist_peek(peek_offset);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000823 if (!trackname) {
Miika Pekkarinenc3fed622005-06-15 18:59:04 +0000824 logf("End-of-playlist");
825 conf_watermark = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000826 return false;
827 }
828
829 fd = open(trackname, O_RDONLY);
Miika Pekkarinende3b04e2005-06-29 14:46:27 +0000830 if (fd < 0) {
831 logf("Open failed");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000832 return false;
Miika Pekkarinende3b04e2005-06-29 14:46:27 +0000833 }
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000834
835 /* Initialize track entry. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000836 size = filesize(fd);
837 tracks[track_widx].filerem = size;
838 tracks[track_widx].filesize = size;
839 tracks[track_widx].filepos = 0;
840 tracks[track_widx].available = 0;
841 tracks[track_widx].taginfo_ready = false;
842 tracks[track_widx].playlist_offset = offset;
843
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000844 if (buf_widx >= codecbuflen)
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000845 buf_widx -= codecbuflen;
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000846
847 /* Set default values */
848 if (start_play) {
849 conf_bufferlimit = 0;
850 conf_watermark = AUDIO_DEFAULT_WATERMARK;
851 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000852 dsp_configure(DSP_RESET, 0);
853 ci.configure(CODEC_DSP_ENABLE, false);
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000854 }
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000855
856 /* Load the codec. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000857 tracks[track_widx].codecbuf = &codecbuf[buf_widx];
858 if (!loadcodec(trackname, start_play)) {
859 close(fd);
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000860 /* Stop buffer filling if codec load failed. */
861 fill_bytesleft = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000862 return false;
863 }
Miika Pekkarinend94cba62005-06-13 15:26:53 +0000864 // tracks[track_widx].filebuf = &codecbuf[buf_widx];
865 tracks[track_widx].start_pos = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000866
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000867 /* Get track metadata if we don't already have it. */
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000868 if (!tracks[track_widx].taginfo_ready) {
869 if (!get_metadata(&tracks[track_widx],fd,trackname,v1first)) {
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +0000870 logf("Metadata error!");
871 tracks[track_widx].filesize = 0;
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000872 close(fd);
873 return false;
874 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000875 }
Miika Pekkarinenaa30f042005-07-05 07:25:55 +0000876 tracks[track_widx].id3.elapsed = 0;
Dave Chapman3ad485b2005-06-14 22:27:57 +0000877
878 /* Starting playback from an offset is only support in MPA at the moment */
879 if (offset > 0) {
Miika Pekkarinen3eb962d2005-07-07 07:15:05 +0000880 switch (tracks[track_widx].id3.codectype) {
881 case AFMT_MPA_L2:
882 case AFMT_MPA_L3:
883 lseek(fd, offset, SEEK_SET);
884 tracks[track_widx].id3.offset = offset;
885 mp3_set_elapsed(&tracks[track_widx].id3);
886 tracks[track_widx].filepos = offset;
887 tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
888 ci.curpos = offset;
889 tracks[track_widx].start_pos = offset;
890 break;
891
892 case AFMT_WAVPACK:
893 lseek(fd, offset, SEEK_SET);
894 tracks[track_widx].id3.offset = offset;
895 tracks[track_widx].id3.elapsed = tracks[track_widx].id3.length / 2;
896 tracks[track_widx].filepos = offset;
897 tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
898 ci.curpos = offset;
899 tracks[track_widx].start_pos = offset;
900 break;
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000901 case AFMT_OGG_VORBIS:
902 tracks[track_widx].id3.offset = offset;
903 break;
Miika Pekkarinen3eb962d2005-07-07 07:15:05 +0000904 }
905 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000906
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000907 if (start_play) {
908 track_count++;
Miika Pekkarinen3e33f852005-07-10 06:58:02 +0000909 codec_track_changed();
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000910 }
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000911
912 /* Do some initial file buffering. */
Miika Pekkarinend94cba62005-06-13 15:26:53 +0000913 i = tracks[track_widx].start_pos;
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000914 size = MIN(size, AUDIO_FILL_CYCLE);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000915 while (i < size) {
916 /* Give codecs some processing time to prevent glitches. */
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000917 yield_codecs();
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000918
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000919 if (fill_bytesleft == 0)
920 break ;
921
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000922 copy_n = MIN(conf_filechunk, codecbuflen - buf_widx);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000923 copy_n = MIN(size - i, copy_n);
924 copy_n = MIN((int)fill_bytesleft, copy_n);
925 rc = read(fd, &codecbuf[buf_widx], copy_n);
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +0000926 if (rc < copy_n) {
Miika Pekkarinenfe468b12005-06-09 19:31:35 +0000927 logf("File error!");
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +0000928 tracks[track_widx].filesize = 0;
929 tracks[track_widx].filerem = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000930 close(fd);
931 return false;
932 }
933 buf_widx += rc;
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000934 if (buf_widx >= codecbuflen)
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000935 buf_widx -= codecbuflen;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000936 i += rc;
937 tracks[track_widx].available += rc;
938 tracks[track_widx].filerem -= rc;
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000939 codecbufused += rc;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000940 fill_bytesleft -= rc;
941 }
942
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000943 if (!start_play)
944 track_count++;
945
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000946 tracks[track_widx].filepos = i;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000947
Miika Pekkarinenef72f992005-06-14 14:36:46 +0000948 if (current_fd >= 0) {
949 close(current_fd);
950 current_fd = -1;
951 }
952
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000953 /* Leave the file handle open for faster buffer refill. */
954 if (tracks[track_widx].filerem != 0) {
955 current_fd = fd;
956 logf("Partially buf:%d", tracks[track_widx].available);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000957 } else {
958 logf("Completely buf.");
959 close(fd);
Linus Nielsen Feltzingdf807982005-07-07 09:53:02 +0000960
961 strip_id3v1_tag();
962
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000963 if (++track_widx >= MAX_TRACK) {
964 track_widx = 0;
965 }
966 tracks[track_widx].filerem = 0;
967 }
968
969 return true;
970}
971
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000972void audio_play_start(int offset)
973{
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000974 if (current_fd >= 0) {
975 close(current_fd);
976 current_fd = -1;
977 }
Miika Pekkarinen0d63cbb2005-07-10 20:37:36 +0000978
Miika Pekkarinenfe468b12005-06-09 19:31:35 +0000979 memset(&tracks, 0, sizeof(struct track_info) * MAX_TRACK);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000980 sound_set(SOUND_VOLUME, global_settings.volume);
981 track_count = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000982 track_widx = 0;
983 track_ridx = 0;
984 buf_ridx = 0;
985 buf_widx = 0;
986 codecbufused = 0;
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000987 pcmbuf_set_boost_mode(true);
Miika Pekkarinencf18f962005-06-20 06:49:21 +0000988
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000989 fill_bytesleft = codecbuflen;
990 filling = true;
991 last_peek_offset = 0;
992 if (audio_load_track(offset, true, 0)) {
993 last_peek_offset++;
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000994 if (track_buffer_callback) {
995 cur_ti->event_sent = true;
996 track_buffer_callback(&cur_ti->id3, true);
997 }
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000998 } else {
999 logf("Failure");
1000 }
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001001
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001002 pcmbuf_set_boost_mode(false);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001003}
1004
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001005void audio_clear_track_entries(void)
1006{
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001007 int cur_idx, event_count;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001008 int i;
1009
1010 cur_idx = track_widx;
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001011 event_count = 0;
1012 for (i = 0; i < MAX_TRACK - track_count; i++) {
1013 if (++cur_idx >= MAX_TRACK)
1014 cur_idx = 0;
1015
1016 if (tracks[cur_idx].event_sent)
1017 event_count++;
1018
1019 if (!track_unbuffer_callback)
1020 memset(&tracks[cur_idx], 0, sizeof(struct track_info));
1021 }
1022
1023 if (!track_unbuffer_callback)
1024 return ;
1025
1026 cur_idx = track_widx;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001027 for (i = 0; i < MAX_TRACK - track_count; i++) {
1028 if (++cur_idx >= MAX_TRACK)
1029 cur_idx = 0;
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001030
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001031 /* Send an event to notify that track has finished. */
1032 if (tracks[cur_idx].event_sent) {
1033 tracks[cur_idx].event_sent = true;
1034 event_count--;
1035 track_unbuffer_callback(&tracks[cur_idx].id3, event_count == 0);
1036 }
1037
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001038 memset(&tracks[cur_idx], 0, sizeof(struct track_info));
1039 }
1040}
1041
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001042/* Send callback events to notify about new tracks. */
1043static void generate_postbuffer_events(void)
1044{
1045 int i;
1046 int cur_ridx, event_count;
1047
1048 if (!track_buffer_callback)
1049 return ;
1050
1051 /* At first determine how many unsent events we have. */
1052 cur_ridx = track_ridx;
1053 event_count = 0;
1054 for (i = 0; i < track_count; i++) {
1055 if (!tracks[cur_ridx].event_sent)
1056 event_count++;
1057 if (++cur_ridx >= MAX_TRACK)
1058 cur_ridx -= MAX_TRACK;
1059 }
1060
1061 /* Now sent these events. */
1062 cur_ridx = track_ridx;
1063 for (i = 0; i < track_count; i++) {
1064 if (!tracks[cur_ridx].event_sent) {
1065 tracks[cur_ridx].event_sent = true;
1066 event_count--;
1067 track_buffer_callback(&tracks[cur_ridx].id3, event_count == 0);
1068 }
1069 if (++cur_ridx >= MAX_TRACK)
1070 cur_ridx -= MAX_TRACK;
1071 }
1072}
1073
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001074void initialize_buffer_fill(void)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001075{
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001076 int cur_idx, i;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001077
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001078
1079 fill_bytesleft = codecbuflen - codecbufused;
Miika Pekkarinenc520d692005-07-01 18:38:10 +00001080 cur_ti->start_pos = ci.curpos;
Miika Pekkarinende3b04e2005-06-29 14:46:27 +00001081
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001082 pcmbuf_set_boost_mode(true);
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001083
Miika Pekkarinende3b04e2005-06-29 14:46:27 +00001084 if (filling)
1085 return ;
1086
1087 filling = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001088
1089 /* Calculate real track count after throwing away old tracks. */
1090 cur_idx = track_ridx;
1091 for (i = 0; i < track_count; i++) {
1092 if (cur_idx == track_widx)
1093 break ;
1094
1095 if (++cur_idx >= MAX_TRACK)
1096 cur_idx = 0;
1097 }
1098
1099 track_count = i;
Miika Pekkarinen8d5822d2005-06-14 18:59:34 +00001100 if (tracks[track_widx].filesize != 0)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001101 track_count++;
1102
1103 /* Mark all other entries null. */
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001104 audio_clear_track_entries();
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001105}
1106
1107void audio_check_buffer(void)
1108{
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001109 /* Start buffer filling as necessary. */
1110 if ((codecbufused > conf_watermark || !queue_empty(&audio_queue)
1111 || !playing || ci.stop_codec || ci.reload_codec) && !filling)
1112 return ;
1113
Miika Pekkarinende3b04e2005-06-29 14:46:27 +00001114 initialize_buffer_fill();
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001115
1116 /* Limit buffering size at first run. */
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001117 if (conf_bufferlimit && fill_bytesleft > conf_bufferlimit
1118 - codecbufused) {
1119 fill_bytesleft = MAX(0, conf_bufferlimit - codecbufused);
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001120 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001121
1122 /* Try to load remainings of the file. */
1123 if (tracks[track_widx].filerem > 0)
1124 audio_fill_file_buffer();
1125
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001126 /* Increase track write index as necessary. */
1127 if (tracks[track_widx].filerem == 0 && tracks[track_widx].filesize != 0) {
1128 if (++track_widx == MAX_TRACK)
1129 track_widx = 0;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001130 }
1131
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001132 /* Load new files to fill the entire buffer. */
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001133 if (audio_load_track(0, false, last_peek_offset)) {
1134 last_peek_offset++;
1135 } else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) {
Miika Pekkarinen527ce402005-07-10 08:46:12 +00001136 /* Read next unbuffered track's metadata as necessary. */
1137 read_next_metadata();
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +00001138
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001139 generate_postbuffer_events();
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001140 filling = false;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001141 conf_bufferlimit = 0;
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001142 pcmbuf_set_boost_mode(false);
1143
1144#ifndef SIMULATOR
Miika Pekkarinenb288dda2005-07-10 08:38:16 +00001145 if (playing)
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001146 ata_sleep();
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001147#endif
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001148 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001149}
1150
1151void audio_update_trackinfo(void)
1152{
1153 if (new_track >= 0) {
1154 buf_ridx += cur_ti->available;
1155 codecbufused -= cur_ti->available;
1156
1157 cur_ti = &tracks[track_ridx];
1158 buf_ridx += cur_ti->codecsize;
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +00001159 codecbufused -= cur_ti->codecsize;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001160 if (buf_ridx >= codecbuflen)
1161 buf_ridx -= codecbuflen;
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +00001162
Miika Pekkarinenb4bc1062005-06-09 07:19:16 +00001163 if (!filling)
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001164 pcmbuf_set_boost_mode(false);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001165 } else {
Miika Pekkarinen1c5b3922005-06-11 13:47:01 +00001166 buf_ridx -= ci.curpos + cur_ti->codecsize;
1167 codecbufused += ci.curpos + cur_ti->codecsize;
Miika Pekkarinenf4724102005-06-07 21:51:29 +00001168 cur_ti->available = cur_ti->filesize;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001169
1170 cur_ti = &tracks[track_ridx];
Miika Pekkarinen1c5b3922005-06-11 13:47:01 +00001171 buf_ridx -= cur_ti->filesize;
1172 codecbufused += cur_ti->filesize;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001173 cur_ti->available = cur_ti->filesize;
1174 if (buf_ridx < 0)
1175 buf_ridx = codecbuflen + buf_ridx;
1176 }
Miika Pekkarinenaa30f042005-07-05 07:25:55 +00001177
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001178 ci.filesize = cur_ti->filesize;
Miika Pekkarinena380d902005-06-11 18:05:16 +00001179 cur_ti->id3.elapsed = 0;
1180 cur_ti->id3.offset = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001181 ci.id3 = (struct mp3entry *)&cur_ti->id3;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001182 ci.curpos = 0;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +00001183 cur_ti->start_pos = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001184 ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready;
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001185 if (!pcmbuf_crossfade_init())
1186 pcmbuf_add_event(codec_track_changed);
Miika Pekkarinenb469e732005-07-02 17:45:12 +00001187 else
1188 codec_track_changed();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001189}
1190
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001191static void audio_stop_playback(void)
1192{
1193 paused = false;
1194 playing = false;
1195 ci.stop_codec = true;
1196 if (current_fd >= 0) {
1197 close(current_fd);
1198 current_fd = -1;
1199 }
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001200 pcmbuf_play_stop();
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001201 pcm_play_pause(true);
1202 track_count = 0;
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001203 audio_clear_track_entries();
1204 filling = false;
1205}
1206
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001207/* Request the next track with new codec. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001208void audio_change_track(void)
1209{
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001210 logf("change track");
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001211
1212 /* Wait for new track data. */
Miika Pekkarinen22960c32005-07-06 15:44:59 +00001213 while (track_count <= 1 && filling)
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001214 yield();
1215
1216 /* If we are not filling, then it must be end-of-playlist. */
Miika Pekkarinen22960c32005-07-06 15:44:59 +00001217 if (track_count <= 1) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001218 logf("No more tracks");
Miika Pekkarinenc3fed622005-06-15 18:59:04 +00001219 while (pcm_is_playing())
1220 yield();
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001221 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001222 return ;
1223 }
1224
1225 if (++track_ridx >= MAX_TRACK)
1226 track_ridx = 0;
1227
1228 audio_update_trackinfo();
1229 queue_post(&codec_queue, CODEC_LOAD, 0);
1230}
1231
Miika Pekkarinen645a2e12005-07-10 16:33:03 +00001232static int get_codec_base_type(int type)
1233{
1234 switch (type) {
1235 case AFMT_MPA_L1:
1236 case AFMT_MPA_L2:
1237 case AFMT_MPA_L3:
1238 return AFMT_MPA_L3;
1239 }
1240
1241 return type;
1242}
1243
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001244bool codec_request_next_track_callback(void)
1245{
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001246 if (ci.stop_codec || !playing)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001247 return false;
1248
1249 logf("Request new track");
1250
1251 /* Advance to next track. */
1252 if (ci.reload_codec && new_track > 0) {
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001253 if (!playlist_check(new_track))
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001254 return false;
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001255 last_peek_offset--;
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001256 playlist_next(new_track);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001257 if (++track_ridx == MAX_TRACK)
1258 track_ridx = 0;
Miika Pekkarinend6e79422005-07-05 15:19:22 +00001259
1260 /* Wait for new track data (codectype 0 is invalid). When a correct
1261 codectype is set, we can assume that the filesize is correct. */
1262 while (tracks[track_ridx].id3.codectype == 0 && filling
1263 && !ci.stop_codec)
1264 yield();
1265
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001266 if (tracks[track_ridx].filesize == 0) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001267 logf("Loading from disk...");
1268 new_track = 0;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +00001269 queue_post(&audio_queue, AUDIO_PLAY, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001270 return false;
1271 }
1272 }
1273
1274 /* Advance to previous track. */
1275 else if (ci.reload_codec && new_track < 0) {
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001276 if (!playlist_check(new_track))
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001277 return false;
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001278 last_peek_offset++;
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001279 playlist_next(new_track);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001280 if (--track_ridx < 0)
1281 track_ridx = MAX_TRACK-1;
1282 if (tracks[track_ridx].filesize == 0 ||
1283 codecbufused+ci.curpos+tracks[track_ridx].filesize
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001284 /*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001285 logf("Loading from disk...");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001286 new_track = 0;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +00001287 queue_post(&audio_queue, AUDIO_PLAY, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001288 return false;
1289 }
1290 }
1291
1292 /* Codec requested track change (next track). */
1293 else {
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001294 if (!playlist_check(1))
1295 return false;
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001296 last_peek_offset--;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +00001297 playlist_next(1);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001298 if (++track_ridx >= MAX_TRACK)
1299 track_ridx = 0;
1300
Miika Pekkarinend6e79422005-07-05 15:19:22 +00001301 /* Wait for new track data (codectype 0 is invalid). When a correct
1302 codectype is set, we can assume that the filesize is correct. */
1303 while (tracks[track_ridx].id3.codectype == 0 && filling
1304 && !ci.stop_codec)
1305 yield();
1306
1307 if (tracks[track_ridx].filesize == 0) {
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001308 logf("No more tracks [2]");
1309 ci.stop_codec = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001310 new_track = 0;
Miika Pekkarinen0d63cbb2005-07-10 20:37:36 +00001311 queue_post(&audio_queue, AUDIO_PLAY, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001312 return false;
1313 }
1314 }
1315
1316 ci.reload_codec = false;
1317
Miika Pekkarinen645a2e12005-07-10 16:33:03 +00001318 /* Check if the next codec is the same file. */
1319 if (get_codec_base_type(cur_ti->id3.codectype) !=
1320 get_codec_base_type(tracks[track_ridx].id3.codectype)) {
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001321 logf("New codec:%d/%d", cur_ti->id3.codectype,
1322 tracks[track_ridx].id3.codectype);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001323 if (--track_ridx < 0)
1324 track_ridx = MAX_TRACK-1;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001325 new_track = 0;
1326 return false;
1327 }
1328
1329 logf("On-the-fly change");
1330 audio_update_trackinfo();
1331 new_track = 0;
1332
1333 return true;
1334}
1335
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001336/* Invalidates all but currently playing track. */
1337void audio_invalidate_tracks(void)
1338{
1339 if (track_count == 0) {
1340 queue_post(&audio_queue, AUDIO_PLAY, 0);
1341 return ;
1342 }
1343
1344 track_count = 1;
Miika Pekkarinende3b04e2005-06-29 14:46:27 +00001345 last_peek_offset = 1;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001346 track_widx = track_ridx;
1347 audio_clear_track_entries();
1348 codecbufused = cur_ti->available;
1349 buf_widx = buf_ridx + cur_ti->available;
1350 if (buf_widx >= codecbuflen)
1351 buf_widx -= codecbuflen;
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +00001352 read_next_metadata();
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001353}
1354
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001355static void initiate_track_change(int peek_index)
1356{
1357 if (!playlist_check(peek_index))
1358 return ;
1359
1360 new_track = peek_index;
1361 ci.reload_codec = true;
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001362
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001363 /* Detect if disk is spinning.. */
1364 if (filling) {
1365 ci.stop_codec = true;
1366 playlist_next(peek_index);
1367 queue_post(&audio_queue, AUDIO_PLAY, 0);
1368 }
1369
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001370 else if (!pcmbuf_crossfade_init())
1371 pcmbuf_flush_audio();
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001372
1373 codec_track_changed();
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001374}
1375
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001376void audio_thread(void)
1377{
1378 struct event ev;
1379
1380 while (1) {
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001381 yield_codecs();
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +00001382
1383 mutex_lock(&mutex_bufferfill);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001384 audio_check_buffer();
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +00001385 mutex_unlock(&mutex_bufferfill);
1386
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001387 queue_wait_w_tmo(&audio_queue, &ev, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001388 switch (ev.id) {
1389 case AUDIO_PLAY:
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001390 logf("starting...");
Miika Pekkarinen3b907072005-06-30 16:28:40 +00001391 playing = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001392 ci.stop_codec = true;
1393 ci.reload_codec = false;
1394 ci.seek_time = 0;
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001395 if (!pcmbuf_crossfade_init() && !pcmbuf_is_crossfade_active())
1396 pcmbuf_flush_audio();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001397 audio_play_start((int)ev.data);
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001398 playlist_update_resume_info(audio_current_track());
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001399 break ;
1400
1401 case AUDIO_STOP:
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001402 if (playing)
1403 playlist_update_resume_info(audio_current_track());
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001404 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001405 break ;
1406
1407 case AUDIO_PAUSE:
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001408 logf("audio_pause");
1409 pcm_play_pause(false);
1410 paused = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001411 break ;
1412
1413 case AUDIO_RESUME:
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001414 logf("audio_resume");
1415 pcm_play_pause(true);
1416 paused = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001417 break ;
1418
1419 case AUDIO_NEXT:
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001420 logf("audio_next");
1421 initiate_track_change(1);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001422 break ;
1423
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001424 case AUDIO_PREV:
1425 logf("audio_prev");
1426 initiate_track_change(-1);
1427 break;
1428
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001429 case AUDIO_FLUSH:
1430 audio_invalidate_tracks();
1431 break ;
1432
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001433 case AUDIO_TRACK_CHANGED:
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +00001434 if (track_changed_callback)
1435 track_changed_callback(cur_ti);
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001436 playlist_update_resume_info(audio_current_track());
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001437 break ;
1438
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001439 case AUDIO_CODEC_DONE:
1440 //if (playing)
1441 // audio_change_track();
1442 break ;
1443
1444#ifndef SIMULATOR
1445 case SYS_USB_CONNECTED:
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001446 logf("USB Connection");
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001447 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001448 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1449 usb_wait_for_disconnect(&audio_queue);
1450 break ;
1451#endif
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001452 case SYS_TIMEOUT:
1453 if (playing)
1454 playlist_update_resume_info(audio_current_track());
1455 break;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001456 }
1457 }
1458}
1459
1460void codec_thread(void)
1461{
1462 struct event ev;
Miika Pekkarinen85f49732005-06-27 19:29:49 +00001463 long codecsize;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001464 int status;
1465 int wrap;
1466
1467 while (1) {
1468 status = 0;
1469 queue_wait(&codec_queue, &ev);
1470 switch (ev.id) {
1471 case CODEC_LOAD_DISK:
1472 ci.stop_codec = false;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001473 codec_loaded = true;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +00001474 status = codec_load_file((char *)ev.data);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001475 break ;
1476
1477 case CODEC_LOAD:
1478 logf("Codec start");
1479 codecsize = cur_ti->codecsize;
1480 if (codecsize == 0) {
1481 logf("Codec slot is empty!");
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001482 /* Wait for the pcm buffer to go empty */
1483 while (pcm_is_playing())
1484 yield();
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001485 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001486 break ;
1487 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001488
1489 ci.stop_codec = false;
1490 wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001491 codec_loaded = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001492 status = codec_load_ram(cur_ti->codecbuf, codecsize,
Daniel Stenberg1dd672f2005-06-22 19:41:30 +00001493 &codecbuf[0], wrap);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001494 break ;
1495
1496#ifndef SIMULATOR
1497 case SYS_USB_CONNECTED:
1498 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1499 usb_wait_for_disconnect(&codec_queue);
1500 break ;
1501#endif
1502 }
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001503
1504 codec_loaded = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001505
1506 switch (ev.id) {
1507 case CODEC_LOAD_DISK:
1508 case CODEC_LOAD:
Daniel Stenberg1dd672f2005-06-22 19:41:30 +00001509 if (status != CODEC_OK) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001510 logf("Codec failure");
Miika Pekkarinene0037ad2005-06-12 18:16:35 +00001511 splash(HZ*2, true, "Codec failure");
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001512 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001513 } else {
1514 logf("Codec finished");
1515 }
1516
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001517 if (playing && !ci.stop_codec && !ci.reload_codec) {
1518 audio_change_track();
Miika Pekkarinenfe468b12005-06-09 19:31:35 +00001519 continue ;
1520 } else if (ci.stop_codec) {
1521 //playing = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001522 }
Miika Pekkarinenfe468b12005-06-09 19:31:35 +00001523 //queue_post(&audio_queue, AUDIO_CODEC_DONE, (void *)status);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001524 }
1525 }
1526}
1527
1528struct mp3entry* audio_current_track(void)
1529{
Miika Pekkarinenaa30f042005-07-05 07:25:55 +00001530 // logf("audio_current_track");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001531
1532 if (track_count > 0 && cur_ti->taginfo_ready)
1533 return (struct mp3entry *)&cur_ti->id3;
1534 else
1535 return NULL;
1536}
1537
1538struct mp3entry* audio_next_track(void)
1539{
1540 int next_idx = track_ridx + 1;
1541
1542 if (track_count == 0)
1543 return NULL;
1544
1545 if (next_idx >= MAX_TRACK)
1546 next_idx = 0;
1547
1548 if (!tracks[next_idx].taginfo_ready)
1549 return NULL;
1550
1551 //logf("audio_next_track");
1552
1553 return &tracks[next_idx].id3;
1554}
1555
1556bool audio_has_changed_track(void)
1557{
Miika Pekkarinend8cb7032005-06-26 19:41:29 +00001558 if (track_changed && track_count > 0 && playing) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001559 if (!cur_ti->taginfo_ready)
1560 return false;
1561 track_changed = false;
1562 return true;
1563 }
1564
1565 return false;
1566}
1567
1568void audio_play(int offset)
1569{
1570 logf("audio_play");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001571 ci.stop_codec = true;
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001572 if (!pcmbuf_crossfade_init())
1573 pcmbuf_flush_audio();
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001574 codec_track_changed();
Miika Pekkarinend50ed122005-07-02 17:55:51 +00001575
Miika Pekkarinenb4bc1062005-06-09 07:19:16 +00001576 pcm_play_pause(true);
Miika Pekkarinen9e200e32005-06-09 20:01:09 +00001577 paused = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001578 queue_post(&audio_queue, AUDIO_PLAY, (void *)offset);
1579}
1580
1581void audio_stop(void)
1582{
1583 logf("audio_stop");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001584 queue_post(&audio_queue, AUDIO_STOP, 0);
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001585 while (playing || codec_loaded)
1586 yield();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001587}
1588
1589void audio_pause(void)
1590{
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001591 queue_post(&audio_queue, AUDIO_PAUSE, 0);
Miika Pekkarinen1ed292c2005-07-10 17:31:12 +00001592 while (!paused && playing)
1593 yield();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001594}
1595
1596void audio_resume(void)
1597{
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001598 queue_post(&audio_queue, AUDIO_RESUME, 0);
Miika Pekkarinen1ed292c2005-07-10 17:31:12 +00001599 while (paused && playing)
1600 yield();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001601}
1602
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001603void audio_next(void)
1604{
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001605 queue_post(&audio_queue, AUDIO_NEXT, 0);
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001606}
1607
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001608void audio_prev(void)
1609{
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001610 queue_post(&audio_queue, AUDIO_PREV, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001611}
1612
1613void audio_ff_rewind(int newpos)
1614{
1615 logf("rewind: %d", newpos);
Miika Pekkarinen2724d0b2005-07-01 21:00:02 +00001616 if (playing) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001617 ci.seek_time = newpos+1;
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001618 pcmbuf_play_stop();
Miika Pekkarinen2f6781d2005-07-11 20:43:02 +00001619 paused = false;
Miika Pekkarinen2724d0b2005-07-01 21:00:02 +00001620 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001621}
1622
1623void audio_flush_and_reload_tracks(void)
1624{
1625 logf("flush & reload");
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001626 queue_post(&audio_queue, AUDIO_FLUSH, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001627}
1628
1629void audio_error_clear(void)
1630{
1631}
1632
1633int audio_status(void)
1634{
1635 int ret = 0;
1636
1637 if (playing)
1638 ret |= AUDIO_STATUS_PLAY;
1639
1640 if (paused)
1641 ret |= AUDIO_STATUS_PAUSE;
1642
1643 return ret;
1644}
1645
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +00001646int audio_get_file_pos(void)
1647{
1648 return 0;
1649}
1650
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001651
1652/* Copied from mpeg.c. Should be moved somewhere else. */
Miika Pekkarinen5899ed52005-06-08 10:33:01 +00001653static void mp3_set_elapsed(struct mp3entry* id3)
1654{
1655 if ( id3->vbr ) {
1656 if ( id3->has_toc ) {
1657 /* calculate elapsed time using TOC */
1658 int i;
1659 unsigned int remainder, plen, relpos, nextpos;
1660
1661 /* find wich percent we're at */
1662 for (i=0; i<100; i++ )
1663 {
1664 if ( id3->offset < (int)(id3->toc[i] * (id3->filesize / 256)) )
1665 {
1666 break;
1667 }
1668 }
1669
1670 i--;
1671 if (i < 0)
1672 i = 0;
1673
1674 relpos = id3->toc[i];
1675
1676 if (i < 99)
1677 {
1678 nextpos = id3->toc[i+1];
1679 }
1680 else
1681 {
1682 nextpos = 256;
1683 }
1684
1685 remainder = id3->offset - (relpos * (id3->filesize / 256));
1686
1687 /* set time for this percent (divide before multiply to prevent
1688 overflow on long files. loss of precision is negligible on
1689 short files) */
1690 id3->elapsed = i * (id3->length / 100);
1691
1692 /* calculate remainder time */
1693 plen = (nextpos - relpos) * (id3->filesize / 256);
1694 id3->elapsed += (((remainder * 100) / plen) *
1695 (id3->length / 10000));
1696 }
1697 else {
1698 /* no TOC exists. set a rough estimate using average bitrate */
1699 int tpk = id3->length / (id3->filesize / 1024);
1700 id3->elapsed = id3->offset / 1024 * tpk;
1701 }
1702 }
1703 else
1704 /* constant bitrate == simple frame calculation */
1705 id3->elapsed = id3->offset / id3->bpf * id3->tpf;
1706}
1707
1708/* Copied from mpeg.c. Should be moved somewhere else. */
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001709int mp3_get_file_pos(void)
1710{
1711 int pos = -1;
1712 struct mp3entry *id3 = audio_current_track();
1713
1714 if (id3->vbr)
1715 {
1716 if (id3->has_toc)
1717 {
1718 /* Use the TOC to find the new position */
1719 unsigned int percent, remainder;
1720 int curtoc, nexttoc, plen;
1721
1722 percent = (id3->elapsed*100)/id3->length;
1723 if (percent > 99)
1724 percent = 99;
1725
1726 curtoc = id3->toc[percent];
1727
1728 if (percent < 99)
1729 nexttoc = id3->toc[percent+1];
1730 else
1731 nexttoc = 256;
1732
1733 pos = (id3->filesize/256)*curtoc;
1734
1735 /* Use the remainder to get a more accurate position */
1736 remainder = (id3->elapsed*100)%id3->length;
1737 remainder = (remainder*100)/id3->length;
1738 plen = (nexttoc - curtoc)*(id3->filesize/256);
1739 pos += (plen/100)*remainder;
1740 }
1741 else
1742 {
1743 /* No TOC exists, estimate the new position */
1744 pos = (id3->filesize / (id3->length / 1000)) *
1745 (id3->elapsed / 1000);
1746 }
1747 }
1748 else if (id3->bpf && id3->tpf)
1749 pos = (id3->elapsed/id3->tpf)*id3->bpf;
1750 else
1751 {
1752 return -1;
1753 }
1754
1755 if (pos >= (int)(id3->filesize - id3->id3v1len))
1756 {
1757 /* Don't seek right to the end of the file so that we can
1758 transition properly to the next song */
1759 pos = id3->filesize - id3->id3v1len - 1;
1760 }
1761 else if (pos < (int)id3->first_frame_offset)
1762 {
1763 /* skip past id3v2 tag and other leading garbage */
1764 pos = id3->first_frame_offset;
1765 }
1766 return pos;
1767}
1768
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +00001769#ifndef SIMULATOR
1770void audio_set_buffer_margin(int seconds)
1771{
1772 (void)seconds;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +00001773 logf("bufmargin: %d", seconds);
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +00001774}
1775#endif
1776
1777void mpeg_id3_options(bool _v1first)
1778{
1779 v1first = _v1first;
1780}
1781
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001782void test_buffer_event(struct mp3entry *id3, bool last_track)
1783{
Miika Pekkarinene21cf842005-07-03 19:20:40 +00001784 (void)id3;
1785 (void)last_track;
1786
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001787 logf("be:%d%s", last_track, id3->path);
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001788}
1789
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001790void test_unbuffer_event(struct mp3entry *id3, bool last_track)
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001791{
Miika Pekkarinene21cf842005-07-03 19:20:40 +00001792 (void)id3;
1793 (void)last_track;
1794
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001795 logf("ube:%d%s", last_track, id3->path);
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001796}
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001797
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001798void audio_init(void)
1799{
1800 logf("audio api init");
Miika Pekkarinend8cb7032005-06-26 19:41:29 +00001801 codecbuflen = audiobufend - audiobuf - PCMBUF_SIZE - PCMBUF_GUARD
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001802 - MALLOC_BUFSIZE - GUARD_BUFSIZE;
1803 //codecbuflen = 2*512*1024;
1804 codecbufused = 0;
Miika Pekkarinenb4bc1062005-06-09 07:19:16 +00001805 filling = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001806 codecbuf = &audiobuf[MALLOC_BUFSIZE];
1807 playing = false;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001808 codec_loaded = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001809 paused = false;
1810 track_changed = false;
Miika Pekkarinen94b917e2005-06-11 18:14:41 +00001811 current_fd = -1;
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001812 track_buffer_callback = NULL;
1813 track_unbuffer_callback = NULL;
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +00001814 track_changed_callback = NULL;
Miika Pekkarinen3eb962d2005-07-07 07:15:05 +00001815 /* Just to prevent cur_ti never be anything random. */
1816 cur_ti = &tracks[0];
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001817
Linus Nielsen Feltzing4406fa62005-06-05 23:28:40 +00001818 logf("abuf:%0x", PCMBUF_SIZE);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001819 logf("fbuf:%0x", codecbuflen);
1820 logf("mbuf:%0x", MALLOC_BUFSIZE);
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001821
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001822 audio_set_track_buffer_event(test_buffer_event);
1823 audio_set_track_unbuffer_event(test_unbuffer_event);
Miika Pekkarinene21cf842005-07-03 19:20:40 +00001824
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001825 /* Initialize codec api. */
1826 ci.read_filebuf = codec_filebuf_callback;
Miika Pekkarinen20b38972005-07-13 12:48:22 +00001827 ci.pcmbuf_insert = pcmbuf_insert_buffer;
1828 ci.pcmbuf_insert_split = codec_pcmbuf_insert_split_callback;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001829 ci.get_codec_memory = get_codec_memory_callback;
1830 ci.request_buffer = codec_request_buffer_callback;
1831 ci.advance_buffer = codec_advance_buffer_callback;
1832 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
1833 ci.request_next_track = codec_request_next_track_callback;
1834 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
1835 ci.seek_buffer = codec_seek_buffer_callback;
1836 ci.set_elapsed = codec_set_elapsed_callback;
Ryan Jacksond1917562005-07-12 16:45:38 +00001837 ci.set_offset = codec_set_offset_callback;
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +00001838 ci.configure = codec_configure_callback;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +00001839
1840 mutex_init(&mutex_bufferfill);
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001841 queue_init(&audio_queue);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001842 queue_init(&codec_queue);
1843
1844 create_thread(codec_thread, codec_stack, sizeof(codec_stack),
1845 codec_thread_name);
1846 create_thread(audio_thread, audio_stack, sizeof(audio_stack),
1847 audio_thread_name);
Miika Pekkarinene9412892005-06-15 15:27:52 +00001848#ifndef SIMULATOR
1849 audio_is_initialized = true;
1850#endif
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001851}
1852
1853