blob: 7c8be5d4057a57cb5e906c84bacd03208e541c81 [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"
49#include "pcm_playback.h"
50#include "buffer.h"
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000051#include "dsp.h"
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000052#ifdef HAVE_LCD_BITMAP
53#include "icons.h"
54#include "peakmeter.h"
55#include "action.h"
56#endif
57#include "lang.h"
58#include "bookmark.h"
59#include "misc.h"
60#include "sound.h"
Dave Chapman3ad485b2005-06-14 22:27:57 +000061#include "metadata.h"
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000062
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +000063static volatile bool codec_loaded;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000064static volatile bool playing;
65static volatile bool paused;
66
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000067#define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec";
68#define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec";
69#define CODEC_FLAC "/.rockbox/codecs/flac.codec";
70#define CODEC_WAV "/.rockbox/codecs/wav.codec";
71#define CODEC_A52 "/.rockbox/codecs/a52.codec";
72#define CODEC_MPC "/.rockbox/codecs/mpc.codec";
73#define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec";
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000074
Miika Pekkarinen431e8132005-06-19 18:41:53 +000075#define AUDIO_FILL_CYCLE (1024*256)
Miika Pekkarinende3b04e2005-06-29 14:46:27 +000076#define AUDIO_DEFAULT_WATERMARK (1024*512)
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +000077#define AUDIO_DEFAULT_FILECHUNK (1024*32)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000078
79#define AUDIO_PLAY 1
80#define AUDIO_STOP 2
81#define AUDIO_PAUSE 3
82#define AUDIO_RESUME 4
83#define AUDIO_NEXT 5
84#define AUDIO_PREV 6
85#define AUDIO_FF_REWIND 7
86#define AUDIO_FLUSH_RELOAD 8
87#define AUDIO_CODEC_DONE 9
Miika Pekkarinen58af47c2005-06-13 22:09:12 +000088#define AUDIO_FLUSH 10
Miika Pekkarinen431e8132005-06-19 18:41:53 +000089#define AUDIO_TRACK_CHANGED 11
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000090
91#define CODEC_LOAD 1
92#define CODEC_LOAD_DISK 2
93
94/* As defined in plugins/lib/xxx2wav.h */
95#define MALLOC_BUFSIZE (512*1024)
96#define GUARD_BUFSIZE (8*1024)
97
98/* TODO:
99 Handle playlist_peek in mpeg.c
100 Track changing
101*/
102
103extern bool audio_is_initialized;
104
105/* Buffer control thread. */
106static struct event_queue audio_queue;
107static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
108static const char audio_thread_name[] = "audio";
109
110/* Codec thread. */
111static struct event_queue codec_queue;
Jens Arnoldbb3ed3c2005-07-03 15:09:11 +0000112static long codec_stack[(DEFAULT_STACK_SIZE + 0x2500)/sizeof(long)] IDATA_ATTR;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000113static const char codec_thread_name[] = "codec";
114
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000115static struct mutex mutex_bufferfill;
116
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000117/* Is file buffer currently being refilled? */
118static volatile bool filling;
119
120/* Ring buffer where tracks and codecs are loaded. */
Linus Nielsen Feltzingecf2f7472005-06-22 02:47:54 +0000121static char *codecbuf;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000122
123/* Total size of the ring buffer. */
Linus Nielsen Feltzingb5a0f702005-06-22 14:03:04 +0000124int codecbuflen;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000125
126/* Bytes available in the buffer. */
Linus Nielsen Feltzingb5a0f702005-06-22 14:03:04 +0000127int codecbufused;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000128
129/* Ring buffer read and write indexes. */
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000130static volatile int buf_ridx;
131static volatile int buf_widx;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000132
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000133static int last_peek_offset;
134
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000135/* Track information (count in file buffer, read/write indexes for
136 track ring structure. */
Linus Nielsen Feltzing17098e12005-06-22 20:37:31 +0000137int track_count;
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000138static volatile int track_ridx;
139static volatile int track_widx;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000140static bool track_changed;
141
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000142/* Partially loaded song's file handle to continue buffering later. */
143static int current_fd;
144
145/* Information about how many bytes left on the buffer re-fill run. */
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000146static long fill_bytesleft;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000147
148/* Track info structure about songs in the file buffer. */
149static struct track_info tracks[MAX_TRACK];
150
151/* Pointer to track info structure about current song playing. */
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000152static struct track_info *cur_ti;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000153
154/* Codec API including function callbacks. */
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000155extern struct codec_api ci;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000156
157/* When we change a song and buffer is not in filling state, this
158 variable keeps information about whether to go a next/previous track. */
159static int new_track;
160
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000161/* Callback function to call when current track has really changed. */
162void (*track_changed_callback)(struct track_info *ti);
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000163void (*track_buffer_callback)(struct mp3entry *id3, bool last_track);
Miika Pekkarinen9bde0382005-07-03 18:36:24 +0000164void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track);
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000165
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000166/* Configuration */
167static int conf_bufferlimit;
168static int conf_watermark;
169static int conf_filechunk;
Miika Pekkarinen2326bea2005-06-10 13:43:12 +0000170
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +0000171static bool v1first = false;
172
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000173static void mp3_set_elapsed(struct mp3entry* id3);
174int mp3_get_file_pos(void);
175
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +0000176/* Simulator stubs. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000177#ifdef SIMULATOR
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000178bool pcm_insert_buffer(char *buf, long length)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000179{
180 (void)buf;
181 (void)length;
182
183 return true;
184}
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +0000185
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000186void pcm_flush_buffer(long length)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000187{
188 (void)length;
189}
190
191
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000192void* pcm_request_buffer(long length, long *realsize)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000193{
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000194 static char temp_audiobuffer[32768];
195
196 *realsize = MIN((int)sizeof(temp_audiobuffer), length);
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000197
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000198 return temp_audiobuffer;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000199}
200
Miika Pekkarinenc3fed622005-06-15 18:59:04 +0000201void audiobuffer_add_event(void (*event_handler)(void))
202{
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000203 event_handler();
Miika Pekkarinenc3fed622005-06-15 18:59:04 +0000204}
205
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +0000206unsigned int audiobuffer_get_latency()
207{
208 return 0;
209}
210
211void pcm_play_stop(void)
212{
213}
214
215bool pcm_is_playing(void)
216{
217 return false;
218}
219
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +0000220bool pcm_is_crossfade_active(void)
221{
222 return false;
223}
224
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +0000225bool pcm_is_lowdata(void)
226{
227 return false;
228}
229
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +0000230void pcm_flush_audio(void)
231{
232}
233
Miika Pekkarinen3e88b582005-06-20 14:27:06 +0000234bool pcm_crossfade_init(void)
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +0000235{
236 return false;
237}
238
239void pcm_set_boost_mode(bool state)
240{
241 (void)state;
242}
243
244bool pcm_is_crossfade_enabled(void)
245{
246 return false;
247}
248
249void pcm_play_pause(bool state)
250{
251 (void)state;
252}
253
254int ata_sleep(void)
255{
256 return 0;
257}
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000258#endif
259
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000260bool codec_audiobuffer_insert_callback(char *buf, long length)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000261{
262 char *dest;
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000263 long realsize;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000264 int factor;
265 int next_channel = 0;
266 int processed_length;
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000267 int mono = 0;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000268
269 /* If non-interleaved stereo mode. */
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000270 if (dsp_config.stereo_mode == STEREO_NONINTERLEAVED)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000271 next_channel = length / 2;
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000272 else if (dsp_config.stereo_mode == STEREO_MONO) {
273 length *= 2;
274 mono = 1;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000275 }
276
277 if (dsp_config.sample_depth > 16) {
278 length /= 2;
279 factor = 1;
280 } else {
281 factor = 0;
282 }
283
284 while (length > 0) {
285 /* Request a few extra bytes for resampling. */
286 /* FIXME: Required extra bytes SHOULD be calculated. */
287 while ((dest = pcm_request_buffer(length+16384, &realsize)) == NULL)
288 yield();
289
290 if (realsize < 16384) {
291 pcm_flush_buffer(0);
292 continue ;
293 }
294
295 realsize -= 16384;
296
297 if (next_channel) {
298 processed_length = dsp_process(dest, buf, realsize / 4) * 2;
299 dsp_process(dest, buf + next_channel, realsize / 4);
300 } else {
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000301 processed_length = dsp_process(dest, buf, realsize >> (mono + 1));
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000302 }
303 pcm_flush_buffer(processed_length);
304 length -= realsize;
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000305 buf += realsize << (factor + mono);
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000306 }
307
308 return true;
309}
310
311bool codec_audiobuffer_insert_split_callback(void *ch1, void *ch2,
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000312 long length)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000313{
314 char *dest;
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000315 long realsize;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000316 int factor;
317 int processed_length;
318
319 /* non-interleaved stereo mode. */
320 if (dsp_config.sample_depth > 16) {
321 factor = 0;
322 } else {
323 length /= 2;
324 factor = 1;
325 }
326
327 while (length > 0) {
328 /* Request a few extra bytes for resampling. */
329 while ((dest = pcm_request_buffer(length+4096, &realsize)) == NULL)
330 yield();
331
332 if (realsize < 4096) {
333 pcm_flush_buffer(0);
334 continue ;
335 }
336
337 realsize -= 4096;
338
339 processed_length = dsp_process(dest, ch1, realsize / 4) * 2;
340 dsp_process(dest, ch2, realsize / 4);
341 pcm_flush_buffer(processed_length);
342 length -= realsize;
343 ch1 += realsize >> factor;
344 ch2 += realsize >> factor;
345 }
346
347 return true;
348}
349
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000350void* get_codec_memory_callback(long *size)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000351{
352 *size = MALLOC_BUFSIZE;
353 return &audiobuf[0];
354}
355
356void codec_set_elapsed_callback(unsigned int value)
357{
358 unsigned int latency;
359
Miika Pekkarinencf18f962005-06-20 06:49:21 +0000360 if (ci.stop_codec)
361 return ;
362
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000363 latency = audiobuffer_get_latency();
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +0000364
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000365 if (value < latency) {
366 cur_ti->id3.elapsed = 0;
367 } else if (value - latency > cur_ti->id3.elapsed
368 || value - latency < cur_ti->id3.elapsed - 2) {
369 cur_ti->id3.elapsed = value - latency;
370 }
371}
372
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000373long codec_filebuf_callback(void *ptr, long size)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000374{
375 char *buf = (char *)ptr;
376 int copy_n;
377 int part_n;
378
379 if (ci.stop_codec || !playing)
380 return 0;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000381
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000382 copy_n = MIN((off_t)size, (off_t)cur_ti->available + cur_ti->filerem);
383
384 while (copy_n > cur_ti->available) {
385 yield();
386 if (ci.stop_codec)
387 return 0;
388 }
389
390 if (copy_n == 0)
391 return 0;
392
393 part_n = MIN(copy_n, codecbuflen - buf_ridx);
394 memcpy(buf, &codecbuf[buf_ridx], part_n);
395 if (part_n < copy_n) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000396 memcpy(&buf[part_n], &codecbuf[0], copy_n - part_n);
397 }
398
399 buf_ridx += copy_n;
400 if (buf_ridx >= codecbuflen)
401 buf_ridx -= codecbuflen;
402 ci.curpos += copy_n;
403 cur_ti->available -= copy_n;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000404 codecbufused -= copy_n;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000405
406 return copy_n;
407}
408
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000409void* codec_request_buffer_callback(long *realsize, long reqsize)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000410{
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000411 long part_n;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000412
413 if (ci.stop_codec || !playing) {
414 *realsize = 0;
415 return NULL;
416 }
417
418 *realsize = MIN((off_t)reqsize, (off_t)cur_ti->available + cur_ti->filerem);
419 if (*realsize == 0) {
420 return NULL;
421 }
422
423 while ((int)*realsize > cur_ti->available) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000424 yield();
425 if (ci.stop_codec) {
Miika Pekkarinen9ff373c2005-06-10 20:29:35 +0000426 *realsize = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000427 return NULL;
428 }
429 }
430
431 part_n = MIN((int)*realsize, codecbuflen - buf_ridx);
432 if (part_n < *realsize) {
433 part_n += GUARD_BUFSIZE;
434 if (part_n < *realsize)
435 *realsize = part_n;
436 memcpy(&codecbuf[codecbuflen], &codecbuf[0], *realsize -
437 (codecbuflen - buf_ridx));
438 }
439
440 return (char *)&codecbuf[buf_ridx];
441}
442
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000443static bool rebuffer_and_seek(int newpos)
444{
445 int fd;
446
447 logf("Re-buffering song");
448 mutex_lock(&mutex_bufferfill);
449
450 /* (Re-)open current track's file handle. */
451 fd = open(playlist_peek(0), O_RDONLY);
452 if (fd < 0) {
453 logf("Open failed!");
454 mutex_unlock(&mutex_bufferfill);
455 return false;
456 }
457 if (current_fd >= 0)
458 close(current_fd);
459 current_fd = fd;
460
461 /* Clear codec buffer. */
462 audio_invalidate_tracks();
463 codecbufused = 0;
464 buf_ridx = buf_widx = 0;
465 cur_ti->filerem = cur_ti->filesize - newpos;
466 cur_ti->filepos = newpos;
467 cur_ti->start_pos = newpos;
468 ci.curpos = newpos;
469 cur_ti->available = 0;
470 lseek(current_fd, newpos, SEEK_SET);
471 pcm_flush_audio();
472
473 mutex_unlock(&mutex_bufferfill);
474
Miika Pekkarinen2724d0b2005-07-01 21:00:02 +0000475 while (cur_ti->available == 0 && cur_ti->filerem > 0) {
476 yield();
477 if (ci.stop_codec)
478 return false;
479 }
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000480
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000481 return true;
482}
483
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000484void codec_advance_buffer_callback(long amount)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000485{
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000486 if (amount > cur_ti->available + cur_ti->filerem)
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000487 amount = cur_ti->available + cur_ti->filerem;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000488
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000489 if (amount > cur_ti->available) {
490 if (!rebuffer_and_seek(ci.curpos + amount))
491 ci.stop_codec = true;
492 return ;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000493 }
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000494
495 buf_ridx += amount;
496 if (buf_ridx >= codecbuflen)
497 buf_ridx -= codecbuflen;
498 cur_ti->available -= amount;
499 codecbufused -= amount;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000500 ci.curpos += amount;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000501 cur_ti->id3.offset = ci.curpos;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000502}
503
504void codec_advance_buffer_loc_callback(void *ptr)
505{
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000506 long amount;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000507
508 amount = (int)ptr - (int)&codecbuf[buf_ridx];
509 codec_advance_buffer_callback(amount);
510}
511
512off_t codec_mp3_get_filepos_callback(int newtime)
513{
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000514 off_t newpos;
515
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000516 cur_ti->id3.elapsed = newtime;
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000517 newpos = mp3_get_file_pos();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000518
519 return newpos;
520}
521
522bool codec_seek_buffer_callback(off_t newpos)
523{
524 int difference;
525
526 if (newpos < 0)
527 newpos = 0;
528
529 if (newpos >= cur_ti->filesize)
530 newpos = cur_ti->filesize - 1;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000531
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000532 difference = newpos - ci.curpos;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000533 /* Seeking forward */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000534 if (difference >= 0) {
535 logf("seek: +%d", difference);
536 codec_advance_buffer_callback(difference);
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +0000537 if (!pcm_is_crossfade_active())
538 pcm_play_stop();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000539 return true;
540 }
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000541
542 /* Seeking backward */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000543 difference = -difference;
544 if (ci.curpos - difference < 0)
545 difference = ci.curpos;
546
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000547 /* We need to reload the song. */
548 if (newpos < cur_ti->start_pos)
549 return rebuffer_and_seek(newpos);
550
551 /* Seeking inside buffer space. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000552 logf("seek: -%d", difference);
553 codecbufused += difference;
554 cur_ti->available += difference;
555 buf_ridx -= difference;
556 if (buf_ridx < 0)
557 buf_ridx = codecbuflen + buf_ridx;
558 ci.curpos -= difference;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +0000559 if (!pcm_is_crossfade_active())
Miika Pekkarinenb469e732005-07-02 17:45:12 +0000560 pcm_play_stop();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000561
562 return true;
563}
564
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000565void codec_configure_callback(int setting, void *value)
566{
567 switch (setting) {
568 case CODEC_SET_FILEBUF_WATERMARK:
569 conf_watermark = (unsigned int)value;
570 break;
571
572 case CODEC_SET_FILEBUF_CHUNKSIZE:
573 conf_filechunk = (unsigned int)value;
574 break;
575
576 case CODEC_SET_FILEBUF_LIMIT:
577 conf_bufferlimit = (unsigned int)value;
578 break;
579
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000580 case CODEC_DSP_ENABLE:
581 if ((bool)value)
582 ci.audiobuffer_insert = codec_audiobuffer_insert_callback;
583 else
584 ci.audiobuffer_insert = pcm_insert_buffer;
585 break ;
586
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000587 default:
Miika Pekkarinen65b840d2005-06-26 20:01:33 +0000588 if (!dsp_configure(setting, value)) {
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000589 logf("Illegal key: %d", setting);
Miika Pekkarinen65b840d2005-06-26 20:01:33 +0000590 }
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000591 }
592}
593
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000594void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
595 bool last_track))
596{
597 track_buffer_callback = handler;
598}
599
600void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3,
Miika Pekkarinen9bde0382005-07-03 18:36:24 +0000601 bool last_track))
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000602{
603 track_unbuffer_callback = handler;
604}
605
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000606void audio_set_track_changed_event(void (*handler)(struct track_info *ti))
607{
608 track_changed_callback = handler;
609}
610
Miika Pekkarinenc3fed622005-06-15 18:59:04 +0000611void codec_track_changed(void)
612{
613 track_changed = true;
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +0000614 queue_post(&audio_queue, AUDIO_TRACK_CHANGED, 0);
Miika Pekkarinenc3fed622005-06-15 18:59:04 +0000615}
616
Miika Pekkarinen3e33a0f2005-07-05 15:51:59 +0000617/* Give codecs or file buffering the right amount of processing time
618 to prevent pcm audio buffer from going empty. */
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000619void yield_codecs(void)
620{
Miika Pekkarinen61716dd2005-06-07 18:03:33 +0000621 yield();
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000622 if (!pcm_is_playing())
623 sleep(5);
Miika Pekkarinen3e33a0f2005-07-05 15:51:59 +0000624 while ((pcm_is_crossfade_active() || pcm_is_lowdata())
625 && !ci.stop_codec && playing && queue_empty(&audio_queue)
626 && codecbufused > (128*1024))
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000627 yield();
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000628}
629
Linus Nielsen Feltzingdf807982005-07-07 09:53:02 +0000630/* FIXME: This code should be made more generic and move to metadata.c */
631void strip_id3v1_tag(void)
632{
633 int i;
634 static const unsigned char tag[] = "TAG";
635 int tagptr;
636 bool found = true;
637
638 if (codecbufused >= 128)
639 {
640 tagptr = buf_widx - 128;
641 if (tagptr < 0)
642 tagptr += codecbuflen;
643
644 for(i = 0;i < 3;i++)
645 {
646 if(tagptr >= codecbuflen)
647 tagptr -= codecbuflen;
648
649 if(codecbuf[tagptr] != tag[i])
650 {
651 found = false;
652 break;
653 }
654
655 tagptr++;
656 }
657
658 if(found)
659 {
660 /* Skip id3v1 tag */
661 logf("Skipping ID3v1 tag\n");
662 buf_widx -= 128;
663 tracks[track_widx].available -= 128;
664 codecbufused -= 128;
665 }
666 }
667}
668
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000669void audio_fill_file_buffer(void)
670{
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000671 long i, size;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000672 int rc;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000673
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000674 if (current_fd < 0)
675 return ;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +0000676
677 /* Throw away buffered codec. */
678 if (tracks[track_widx].start_pos != 0)
679 tracks[track_widx].codecsize = 0;
680
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000681 i = 0;
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000682 size = MIN(tracks[track_widx].filerem, AUDIO_FILL_CYCLE);
683 while (i < size) {
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000684 /* Give codecs some processing time. */
685 yield_codecs();
686
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000687 if (fill_bytesleft == 0)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000688 break ;
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000689 rc = MIN(conf_filechunk, codecbuflen - buf_widx);
Miika Pekkarinen3e33f852005-07-10 06:58:02 +0000690 rc = MIN(rc, fill_bytesleft);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000691 rc = read(current_fd, &codecbuf[buf_widx], rc);
692 if (rc <= 0) {
693 tracks[track_widx].filerem = 0;
Linus Nielsen Feltzingdf807982005-07-07 09:53:02 +0000694 strip_id3v1_tag();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000695 break ;
696 }
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000697
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000698 buf_widx += rc;
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000699 if (buf_widx >= codecbuflen)
700 buf_widx -= codecbuflen;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000701 i += rc;
702 tracks[track_widx].available += rc;
Miika Pekkarinen3eb962d2005-07-07 07:15:05 +0000703 tracks[track_widx].filerem -= rc;
704 tracks[track_widx].filepos += rc;
Miika Pekkarinen85f49732005-06-27 19:29:49 +0000705 codecbufused += rc;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000706 fill_bytesleft -= rc;
707 }
708
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000709 /*logf("Filled:%d/%d", tracks[track_widx].available,
710 tracks[track_widx].filerem);*/
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000711}
712
713bool loadcodec(const char *trackname, bool start_play)
714{
715 char msgbuf[80];
716 off_t size;
717 int filetype;
718 int fd;
719 int i, rc;
720 const char *codec_path;
721 int copy_n;
722 int prev_track;
723
724 filetype = probe_file_format(trackname);
725 switch (filetype) {
726 case AFMT_OGG_VORBIS:
727 logf("Codec: Vorbis");
728 codec_path = CODEC_VORBIS;
729 break;
Jens Arnolde2cd5812005-06-18 09:51:10 +0000730 case AFMT_MPA_L1:
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000731 case AFMT_MPA_L2:
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000732 case AFMT_MPA_L3:
Jens Arnolde2cd5812005-06-18 09:51:10 +0000733 logf("Codec: MPA L1/L2/L3");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000734 codec_path = CODEC_MPA_L3;
735 break;
736 case AFMT_PCM_WAV:
737 logf("Codec: PCM WAV");
738 codec_path = CODEC_WAV;
739 break;
740 case AFMT_FLAC:
741 logf("Codec: FLAC");
742 codec_path = CODEC_FLAC;
743 break;
Dave Chapman55ed7d72005-06-11 10:08:17 +0000744 case AFMT_A52:
745 logf("Codec: A52");
746 codec_path = CODEC_A52;
747 break;
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000748 case AFMT_MPC:
749 logf("Codec: Musepack");
750 codec_path = CODEC_MPC;
751 break;
Dave Bryant57c6f6e2005-06-13 06:00:35 +0000752 case AFMT_WAVPACK:
753 logf("Codec: WAVPACK");
754 codec_path = CODEC_WAVPACK;
755 break;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000756 default:
757 logf("Codec: Unsupported");
758 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
759 splash(HZ*2, true, msgbuf);
760 codec_path = NULL;
761 }
762
Dave Chapman961c9a32005-06-18 16:24:27 +0000763 tracks[track_widx].id3.codectype = filetype;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000764 tracks[track_widx].codecsize = 0;
765 if (codec_path == NULL)
766 return false;
767
768 if (!start_play) {
769 prev_track = track_widx - 1;
770 if (prev_track < 0)
771 prev_track = MAX_TRACK-1;
Dave Chapman961c9a32005-06-18 16:24:27 +0000772 if (track_count > 0 && filetype == tracks[prev_track].id3.codectype) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000773 logf("Reusing prev. codec");
774 return true;
775 }
776 } else {
777 /* Load the codec directly from disk and save some memory. */
778 cur_ti = &tracks[track_widx];
779 ci.filesize = cur_ti->filesize;
780 ci.id3 = (struct mp3entry *)&cur_ti->id3;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000781 ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready;
782 ci.curpos = 0;
783 playing = true;
784 logf("Starting codec");
785 queue_post(&codec_queue, CODEC_LOAD_DISK, (void *)codec_path);
786 return true;
787 }
788
789 fd = open(codec_path, O_RDONLY);
790 if (fd < 0) {
791 logf("Codec doesn't exist!");
792 snprintf(msgbuf, sizeof(msgbuf)-1, "Couldn't load codec: %s", codec_path);
793 splash(HZ*2, true, msgbuf);
794 return false;
795 }
796
797 size = filesize(fd);
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000798 if ((off_t)fill_bytesleft < size + conf_watermark) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000799 logf("Not enough space");
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000800 fill_bytesleft = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000801 close(fd);
802 return false;
803 }
804
805 i = 0;
806 while (i < size) {
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000807 yield_codecs();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000808
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000809 copy_n = MIN(conf_filechunk, codecbuflen - buf_widx);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000810 rc = read(fd, &codecbuf[buf_widx], copy_n);
811 if (rc < 0)
812 return false;
813 buf_widx += rc;
Miika Pekkarinen3e33f852005-07-10 06:58:02 +0000814 codecbufused += rc;
815 fill_bytesleft -= rc;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000816 if (buf_widx >= codecbuflen)
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000817 buf_widx -= codecbuflen;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000818 i += rc;
819 }
820 close(fd);
821 logf("Done: %dB", i);
822
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000823 tracks[track_widx].codecsize = size;
824
825 return true;
826}
827
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000828bool read_next_metadata(void)
829{
830 int fd;
831 char *trackname;
832 int next_track;
833 int status;
834
Miika Pekkarinen527ce402005-07-10 08:46:12 +0000835 next_track = track_widx;
836 if (tracks[track_widx].taginfo_ready)
837 next_track++;
838
839 if (next_track >= MAX_TRACK)
840 next_track -= MAX_TRACK;
841
842 if (tracks[next_track].taginfo_ready)
843 return true;
844
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000845 trackname = playlist_peek(last_peek_offset);
846 if (!trackname)
847 return false;
848
849 fd = open(trackname, O_RDONLY);
850 if (fd < 0)
851 return false;
Miika Pekkarinen527ce402005-07-10 08:46:12 +0000852
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000853 /* Start buffer refilling also because we need to spin-up the disk. */
854 filling = true;
855 status = get_metadata(&tracks[next_track],fd,trackname,v1first);
Miika Pekkarinen8ad60cc2005-07-04 06:06:30 +0000856 track_changed = true;
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000857 close(fd);
858
859 return status;
860}
861
Miika Pekkarinena9ac3d12005-06-08 10:45:40 +0000862bool audio_load_track(int offset, bool start_play, int peek_offset)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000863{
864 char *trackname;
865 int fd;
866 off_t size;
867 int rc, i;
868 int copy_n;
Miika Pekkarinende3b04e2005-06-29 14:46:27 +0000869
Miika Pekkarinenb288dda2005-07-10 08:38:16 +0000870 /* Stop buffer filling if there is no free track entries.
871 Don't fill up the last track entry (we wan't to store next track
872 metadata there). */
873 if (track_count >= MAX_TRACK - 1) {
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000874 fill_bytesleft = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000875 return false;
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000876 }
877
878 /* Don't start loading track if the current write position already
879 contains a BUFFERED track. The entry may contain the metadata
880 which is ok. */
881 if (tracks[track_widx].filesize != 0)
882 return false;
883
884 /* Get track name from current playlist read position. */
Miika Pekkarinende3b04e2005-06-29 14:46:27 +0000885 logf("Buffering track:%d/%d", track_widx, track_ridx);
Miika Pekkarinena9ac3d12005-06-08 10:45:40 +0000886 trackname = playlist_peek(peek_offset);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000887 if (!trackname) {
Miika Pekkarinenc3fed622005-06-15 18:59:04 +0000888 logf("End-of-playlist");
889 conf_watermark = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000890 return false;
891 }
892
893 fd = open(trackname, O_RDONLY);
Miika Pekkarinende3b04e2005-06-29 14:46:27 +0000894 if (fd < 0) {
895 logf("Open failed");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000896 return false;
Miika Pekkarinende3b04e2005-06-29 14:46:27 +0000897 }
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000898
899 /* Initialize track entry. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000900 size = filesize(fd);
901 tracks[track_widx].filerem = size;
902 tracks[track_widx].filesize = size;
903 tracks[track_widx].filepos = 0;
904 tracks[track_widx].available = 0;
905 tracks[track_widx].taginfo_ready = false;
906 tracks[track_widx].playlist_offset = offset;
907
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000908 if (buf_widx >= codecbuflen)
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000909 buf_widx -= codecbuflen;
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000910
911 /* Set default values */
912 if (start_play) {
913 conf_bufferlimit = 0;
914 conf_watermark = AUDIO_DEFAULT_WATERMARK;
915 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000916 dsp_configure(DSP_RESET, 0);
917 ci.configure(CODEC_DSP_ENABLE, false);
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000918 }
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000919
920 /* Load the codec. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000921 tracks[track_widx].codecbuf = &codecbuf[buf_widx];
922 if (!loadcodec(trackname, start_play)) {
923 close(fd);
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000924 /* Stop buffer filling if codec load failed. */
925 fill_bytesleft = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000926 return false;
927 }
Miika Pekkarinend94cba62005-06-13 15:26:53 +0000928 // tracks[track_widx].filebuf = &codecbuf[buf_widx];
929 tracks[track_widx].start_pos = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000930
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000931 /* Get track metadata if we don't already have it. */
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000932 if (!tracks[track_widx].taginfo_ready) {
933 if (!get_metadata(&tracks[track_widx],fd,trackname,v1first)) {
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +0000934 logf("Metadata error!");
935 tracks[track_widx].filesize = 0;
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +0000936 close(fd);
937 return false;
938 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000939 }
Miika Pekkarinenaa30f042005-07-05 07:25:55 +0000940 tracks[track_widx].id3.elapsed = 0;
Dave Chapman3ad485b2005-06-14 22:27:57 +0000941
942 /* Starting playback from an offset is only support in MPA at the moment */
943 if (offset > 0) {
Miika Pekkarinen3eb962d2005-07-07 07:15:05 +0000944 switch (tracks[track_widx].id3.codectype) {
945 case AFMT_MPA_L2:
946 case AFMT_MPA_L3:
947 lseek(fd, offset, SEEK_SET);
948 tracks[track_widx].id3.offset = offset;
949 mp3_set_elapsed(&tracks[track_widx].id3);
950 tracks[track_widx].filepos = offset;
951 tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
952 ci.curpos = offset;
953 tracks[track_widx].start_pos = offset;
954 break;
955
956 case AFMT_WAVPACK:
957 lseek(fd, offset, SEEK_SET);
958 tracks[track_widx].id3.offset = offset;
959 tracks[track_widx].id3.elapsed = tracks[track_widx].id3.length / 2;
960 tracks[track_widx].filepos = offset;
961 tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
962 ci.curpos = offset;
963 tracks[track_widx].start_pos = offset;
964 break;
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000965 case AFMT_OGG_VORBIS:
966 tracks[track_widx].id3.offset = offset;
967 break;
Miika Pekkarinen3eb962d2005-07-07 07:15:05 +0000968 }
969 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000970
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000971 if (start_play) {
972 track_count++;
Miika Pekkarinen3e33f852005-07-10 06:58:02 +0000973 codec_track_changed();
Miika Pekkarinen58af47c2005-06-13 22:09:12 +0000974 }
Miika Pekkarinen2d79df52005-07-05 13:34:52 +0000975
976 /* Do some initial file buffering. */
Miika Pekkarinend94cba62005-06-13 15:26:53 +0000977 i = tracks[track_widx].start_pos;
Miika Pekkarinen431e8132005-06-19 18:41:53 +0000978 size = MIN(size, AUDIO_FILL_CYCLE);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000979 while (i < size) {
980 /* Give codecs some processing time to prevent glitches. */
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000981 yield_codecs();
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000982
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000983 if (fill_bytesleft == 0)
984 break ;
985
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000986 copy_n = MIN(conf_filechunk, codecbuflen - buf_widx);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000987 copy_n = MIN(size - i, copy_n);
988 copy_n = MIN((int)fill_bytesleft, copy_n);
989 rc = read(fd, &codecbuf[buf_widx], copy_n);
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +0000990 if (rc < copy_n) {
Miika Pekkarinenfe468b12005-06-09 19:31:35 +0000991 logf("File error!");
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +0000992 tracks[track_widx].filesize = 0;
993 tracks[track_widx].filerem = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +0000994 close(fd);
995 return false;
996 }
997 buf_widx += rc;
Miika Pekkarinen82c29272005-06-07 06:34:54 +0000998 if (buf_widx >= codecbuflen)
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +0000999 buf_widx -= codecbuflen;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001000 i += rc;
1001 tracks[track_widx].available += rc;
1002 tracks[track_widx].filerem -= rc;
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +00001003 codecbufused += rc;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001004 fill_bytesleft -= rc;
1005 }
1006
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001007 if (!start_play)
1008 track_count++;
1009
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001010 tracks[track_widx].filepos = i;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001011
Miika Pekkarinenef72f992005-06-14 14:36:46 +00001012 if (current_fd >= 0) {
1013 close(current_fd);
1014 current_fd = -1;
1015 }
1016
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001017 /* Leave the file handle open for faster buffer refill. */
1018 if (tracks[track_widx].filerem != 0) {
1019 current_fd = fd;
1020 logf("Partially buf:%d", tracks[track_widx].available);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001021 } else {
1022 logf("Completely buf.");
1023 close(fd);
Linus Nielsen Feltzingdf807982005-07-07 09:53:02 +00001024
1025 strip_id3v1_tag();
1026
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001027 if (++track_widx >= MAX_TRACK) {
1028 track_widx = 0;
1029 }
1030 tracks[track_widx].filerem = 0;
1031 }
1032
1033 return true;
1034}
1035
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001036void audio_play_start(int offset)
1037{
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001038 if (current_fd >= 0) {
1039 close(current_fd);
1040 current_fd = -1;
1041 }
Miika Pekkarinen0d63cbb2005-07-10 20:37:36 +00001042
Miika Pekkarinenfe468b12005-06-09 19:31:35 +00001043 memset(&tracks, 0, sizeof(struct track_info) * MAX_TRACK);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001044 sound_set(SOUND_VOLUME, global_settings.volume);
1045 track_count = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001046 track_widx = 0;
1047 track_ridx = 0;
1048 buf_ridx = 0;
1049 buf_widx = 0;
1050 codecbufused = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001051 pcm_set_boost_mode(true);
Miika Pekkarinencf18f962005-06-20 06:49:21 +00001052
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001053 fill_bytesleft = codecbuflen;
1054 filling = true;
1055 last_peek_offset = 0;
1056 if (audio_load_track(offset, true, 0)) {
1057 last_peek_offset++;
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001058 if (track_buffer_callback) {
1059 cur_ti->event_sent = true;
1060 track_buffer_callback(&cur_ti->id3, true);
1061 }
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001062 } else {
1063 logf("Failure");
1064 }
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001065
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001066 pcm_set_boost_mode(false);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001067}
1068
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001069void audio_clear_track_entries(void)
1070{
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001071 int cur_idx, event_count;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001072 int i;
1073
1074 cur_idx = track_widx;
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001075 event_count = 0;
1076 for (i = 0; i < MAX_TRACK - track_count; i++) {
1077 if (++cur_idx >= MAX_TRACK)
1078 cur_idx = 0;
1079
1080 if (tracks[cur_idx].event_sent)
1081 event_count++;
1082
1083 if (!track_unbuffer_callback)
1084 memset(&tracks[cur_idx], 0, sizeof(struct track_info));
1085 }
1086
1087 if (!track_unbuffer_callback)
1088 return ;
1089
1090 cur_idx = track_widx;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001091 for (i = 0; i < MAX_TRACK - track_count; i++) {
1092 if (++cur_idx >= MAX_TRACK)
1093 cur_idx = 0;
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001094
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001095 /* Send an event to notify that track has finished. */
1096 if (tracks[cur_idx].event_sent) {
1097 tracks[cur_idx].event_sent = true;
1098 event_count--;
1099 track_unbuffer_callback(&tracks[cur_idx].id3, event_count == 0);
1100 }
1101
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001102 memset(&tracks[cur_idx], 0, sizeof(struct track_info));
1103 }
1104}
1105
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001106/* Send callback events to notify about new tracks. */
1107static void generate_postbuffer_events(void)
1108{
1109 int i;
1110 int cur_ridx, event_count;
1111
1112 if (!track_buffer_callback)
1113 return ;
1114
1115 /* At first determine how many unsent events we have. */
1116 cur_ridx = track_ridx;
1117 event_count = 0;
1118 for (i = 0; i < track_count; i++) {
1119 if (!tracks[cur_ridx].event_sent)
1120 event_count++;
1121 if (++cur_ridx >= MAX_TRACK)
1122 cur_ridx -= MAX_TRACK;
1123 }
1124
1125 /* Now sent these events. */
1126 cur_ridx = track_ridx;
1127 for (i = 0; i < track_count; i++) {
1128 if (!tracks[cur_ridx].event_sent) {
1129 tracks[cur_ridx].event_sent = true;
1130 event_count--;
1131 track_buffer_callback(&tracks[cur_ridx].id3, event_count == 0);
1132 }
1133 if (++cur_ridx >= MAX_TRACK)
1134 cur_ridx -= MAX_TRACK;
1135 }
1136}
1137
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001138void initialize_buffer_fill(void)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001139{
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001140 int cur_idx, i;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001141
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001142
1143 fill_bytesleft = codecbuflen - codecbufused;
Miika Pekkarinenc520d692005-07-01 18:38:10 +00001144 cur_ti->start_pos = ci.curpos;
Miika Pekkarinende3b04e2005-06-29 14:46:27 +00001145
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001146 pcm_set_boost_mode(true);
1147
Miika Pekkarinende3b04e2005-06-29 14:46:27 +00001148 if (filling)
1149 return ;
1150
1151 filling = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001152
1153 /* Calculate real track count after throwing away old tracks. */
1154 cur_idx = track_ridx;
1155 for (i = 0; i < track_count; i++) {
1156 if (cur_idx == track_widx)
1157 break ;
1158
1159 if (++cur_idx >= MAX_TRACK)
1160 cur_idx = 0;
1161 }
1162
1163 track_count = i;
Miika Pekkarinen8d5822d2005-06-14 18:59:34 +00001164 if (tracks[track_widx].filesize != 0)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001165 track_count++;
1166
1167 /* Mark all other entries null. */
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001168 audio_clear_track_entries();
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001169}
1170
1171void audio_check_buffer(void)
1172{
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001173 /* Start buffer filling as necessary. */
1174 if ((codecbufused > conf_watermark || !queue_empty(&audio_queue)
1175 || !playing || ci.stop_codec || ci.reload_codec) && !filling)
1176 return ;
1177
Miika Pekkarinende3b04e2005-06-29 14:46:27 +00001178 initialize_buffer_fill();
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001179
1180 /* Limit buffering size at first run. */
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001181 if (conf_bufferlimit && fill_bytesleft > conf_bufferlimit
1182 - codecbufused) {
1183 fill_bytesleft = MAX(0, conf_bufferlimit - codecbufused);
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001184 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001185
1186 /* Try to load remainings of the file. */
1187 if (tracks[track_widx].filerem > 0)
1188 audio_fill_file_buffer();
1189
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001190 /* Increase track write index as necessary. */
1191 if (tracks[track_widx].filerem == 0 && tracks[track_widx].filesize != 0) {
1192 if (++track_widx == MAX_TRACK)
1193 track_widx = 0;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001194 }
1195
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001196 /* Load new files to fill the entire buffer. */
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001197 if (audio_load_track(0, false, last_peek_offset)) {
1198 last_peek_offset++;
1199 } else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) {
Miika Pekkarinen527ce402005-07-10 08:46:12 +00001200 /* Read next unbuffered track's metadata as necessary. */
1201 read_next_metadata();
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +00001202
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001203 generate_postbuffer_events();
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001204 filling = false;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001205 conf_bufferlimit = 0;
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001206 pcm_set_boost_mode(false);
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +00001207
Miika Pekkarinenb288dda2005-07-10 08:38:16 +00001208 if (playing)
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001209 ata_sleep();
1210 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001211}
1212
1213void audio_update_trackinfo(void)
1214{
1215 if (new_track >= 0) {
1216 buf_ridx += cur_ti->available;
1217 codecbufused -= cur_ti->available;
1218
1219 cur_ti = &tracks[track_ridx];
1220 buf_ridx += cur_ti->codecsize;
Miika Pekkarinen2ed0b192005-06-10 10:58:45 +00001221 codecbufused -= cur_ti->codecsize;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001222 if (buf_ridx >= codecbuflen)
1223 buf_ridx -= codecbuflen;
Miika Pekkarinen92ea04a2005-06-15 12:53:50 +00001224
Miika Pekkarinenb4bc1062005-06-09 07:19:16 +00001225 if (!filling)
1226 pcm_set_boost_mode(false);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001227 } else {
Miika Pekkarinen1c5b3922005-06-11 13:47:01 +00001228 buf_ridx -= ci.curpos + cur_ti->codecsize;
1229 codecbufused += ci.curpos + cur_ti->codecsize;
Miika Pekkarinenf4724102005-06-07 21:51:29 +00001230 cur_ti->available = cur_ti->filesize;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001231
1232 cur_ti = &tracks[track_ridx];
Miika Pekkarinen1c5b3922005-06-11 13:47:01 +00001233 buf_ridx -= cur_ti->filesize;
1234 codecbufused += cur_ti->filesize;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001235 cur_ti->available = cur_ti->filesize;
1236 if (buf_ridx < 0)
1237 buf_ridx = codecbuflen + buf_ridx;
1238 }
Miika Pekkarinenaa30f042005-07-05 07:25:55 +00001239
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001240 ci.filesize = cur_ti->filesize;
Miika Pekkarinena380d902005-06-11 18:05:16 +00001241 cur_ti->id3.elapsed = 0;
1242 cur_ti->id3.offset = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001243 ci.id3 = (struct mp3entry *)&cur_ti->id3;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001244 ci.curpos = 0;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +00001245 cur_ti->start_pos = 0;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001246 ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready;
Miika Pekkarinenb469e732005-07-02 17:45:12 +00001247 if (!pcm_crossfade_init())
1248 audiobuffer_add_event(codec_track_changed);
1249 else
1250 codec_track_changed();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001251}
1252
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001253static void audio_stop_playback(void)
1254{
1255 paused = false;
1256 playing = false;
1257 ci.stop_codec = true;
1258 if (current_fd >= 0) {
1259 close(current_fd);
1260 current_fd = -1;
1261 }
1262 pcm_play_stop();
1263 pcm_play_pause(true);
1264 track_count = 0;
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001265 audio_clear_track_entries();
1266 filling = false;
1267}
1268
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001269/* Request the next track with new codec. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001270void audio_change_track(void)
1271{
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001272 logf("change track");
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001273
1274 /* Wait for new track data. */
Miika Pekkarinen22960c32005-07-06 15:44:59 +00001275 while (track_count <= 1 && filling)
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001276 yield();
1277
1278 /* If we are not filling, then it must be end-of-playlist. */
Miika Pekkarinen22960c32005-07-06 15:44:59 +00001279 if (track_count <= 1) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001280 logf("No more tracks");
Miika Pekkarinenc3fed622005-06-15 18:59:04 +00001281 while (pcm_is_playing())
1282 yield();
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001283 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001284 return ;
1285 }
1286
1287 if (++track_ridx >= MAX_TRACK)
1288 track_ridx = 0;
1289
1290 audio_update_trackinfo();
1291 queue_post(&codec_queue, CODEC_LOAD, 0);
1292}
1293
Miika Pekkarinen645a2e12005-07-10 16:33:03 +00001294static int get_codec_base_type(int type)
1295{
1296 switch (type) {
1297 case AFMT_MPA_L1:
1298 case AFMT_MPA_L2:
1299 case AFMT_MPA_L3:
1300 return AFMT_MPA_L3;
1301 }
1302
1303 return type;
1304}
1305
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001306bool codec_request_next_track_callback(void)
1307{
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001308 if (ci.stop_codec || !playing)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001309 return false;
1310
1311 logf("Request new track");
1312
1313 /* Advance to next track. */
1314 if (ci.reload_codec && new_track > 0) {
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001315 if (!playlist_check(new_track))
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001316 return false;
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001317 last_peek_offset--;
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001318 playlist_next(new_track);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001319 if (++track_ridx == MAX_TRACK)
1320 track_ridx = 0;
Miika Pekkarinend6e79422005-07-05 15:19:22 +00001321
1322 /* Wait for new track data (codectype 0 is invalid). When a correct
1323 codectype is set, we can assume that the filesize is correct. */
1324 while (tracks[track_ridx].id3.codectype == 0 && filling
1325 && !ci.stop_codec)
1326 yield();
1327
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001328 if (tracks[track_ridx].filesize == 0) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001329 logf("Loading from disk...");
1330 new_track = 0;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +00001331 queue_post(&audio_queue, AUDIO_PLAY, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001332 return false;
1333 }
1334 }
1335
1336 /* Advance to previous track. */
1337 else if (ci.reload_codec && new_track < 0) {
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001338 if (!playlist_check(new_track))
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001339 return false;
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001340 last_peek_offset++;
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001341 playlist_next(new_track);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001342 if (--track_ridx < 0)
1343 track_ridx = MAX_TRACK-1;
1344 if (tracks[track_ridx].filesize == 0 ||
1345 codecbufused+ci.curpos+tracks[track_ridx].filesize
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001346 /*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001347 logf("Loading from disk...");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001348 new_track = 0;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +00001349 queue_post(&audio_queue, AUDIO_PLAY, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001350 return false;
1351 }
1352 }
1353
1354 /* Codec requested track change (next track). */
1355 else {
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001356 if (!playlist_check(1))
1357 return false;
Miika Pekkarinen2d79df52005-07-05 13:34:52 +00001358 last_peek_offset--;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +00001359 playlist_next(1);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001360 if (++track_ridx >= MAX_TRACK)
1361 track_ridx = 0;
1362
Miika Pekkarinend6e79422005-07-05 15:19:22 +00001363 /* Wait for new track data (codectype 0 is invalid). When a correct
1364 codectype is set, we can assume that the filesize is correct. */
1365 while (tracks[track_ridx].id3.codectype == 0 && filling
1366 && !ci.stop_codec)
1367 yield();
1368
1369 if (tracks[track_ridx].filesize == 0) {
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001370 logf("No more tracks [2]");
1371 ci.stop_codec = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001372 new_track = 0;
Miika Pekkarinen0d63cbb2005-07-10 20:37:36 +00001373 queue_post(&audio_queue, AUDIO_PLAY, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001374 return false;
1375 }
1376 }
1377
1378 ci.reload_codec = false;
1379
Miika Pekkarinen645a2e12005-07-10 16:33:03 +00001380 /* Check if the next codec is the same file. */
1381 if (get_codec_base_type(cur_ti->id3.codectype) !=
1382 get_codec_base_type(tracks[track_ridx].id3.codectype)) {
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001383 logf("New codec:%d/%d", cur_ti->id3.codectype,
1384 tracks[track_ridx].id3.codectype);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001385 if (--track_ridx < 0)
1386 track_ridx = MAX_TRACK-1;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001387 new_track = 0;
1388 return false;
1389 }
1390
1391 logf("On-the-fly change");
1392 audio_update_trackinfo();
1393 new_track = 0;
1394
1395 return true;
1396}
1397
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001398/* Invalidates all but currently playing track. */
1399void audio_invalidate_tracks(void)
1400{
1401 if (track_count == 0) {
1402 queue_post(&audio_queue, AUDIO_PLAY, 0);
1403 return ;
1404 }
1405
1406 track_count = 1;
Miika Pekkarinende3b04e2005-06-29 14:46:27 +00001407 last_peek_offset = 1;
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001408 track_widx = track_ridx;
1409 audio_clear_track_entries();
1410 codecbufused = cur_ti->available;
1411 buf_widx = buf_ridx + cur_ti->available;
1412 if (buf_widx >= codecbuflen)
1413 buf_widx -= codecbuflen;
Miika Pekkarinenf46c9f22005-07-03 18:03:20 +00001414 read_next_metadata();
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001415}
1416
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001417static void initiate_track_change(int peek_index)
1418{
1419 if (!playlist_check(peek_index))
1420 return ;
1421
1422 new_track = peek_index;
1423 ci.reload_codec = true;
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001424
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001425 /* Detect if disk is spinning.. */
1426 if (filling) {
1427 ci.stop_codec = true;
1428 playlist_next(peek_index);
1429 queue_post(&audio_queue, AUDIO_PLAY, 0);
1430 }
1431
1432 else if (!pcm_crossfade_init())
1433 pcm_flush_audio();
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001434
1435 codec_track_changed();
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001436}
1437
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001438void audio_thread(void)
1439{
1440 struct event ev;
1441
1442 while (1) {
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001443 yield_codecs();
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +00001444
1445 mutex_lock(&mutex_bufferfill);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001446 audio_check_buffer();
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +00001447 mutex_unlock(&mutex_bufferfill);
1448
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001449 queue_wait_w_tmo(&audio_queue, &ev, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001450 switch (ev.id) {
1451 case AUDIO_PLAY:
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001452 logf("starting...");
Miika Pekkarinen3b907072005-06-30 16:28:40 +00001453 playing = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001454 ci.stop_codec = true;
1455 ci.reload_codec = false;
1456 ci.seek_time = 0;
Miika Pekkarinen645a2e12005-07-10 16:33:03 +00001457 if (!pcm_crossfade_init() && !pcm_is_crossfade_active())
Miika Pekkarinena9203b42005-07-10 08:54:19 +00001458 pcm_flush_audio();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001459 audio_play_start((int)ev.data);
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001460 playlist_update_resume_info(audio_current_track());
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001461 break ;
1462
1463 case AUDIO_STOP:
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001464 if (playing)
1465 playlist_update_resume_info(audio_current_track());
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001466 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001467 break ;
1468
1469 case AUDIO_PAUSE:
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001470 logf("audio_pause");
1471 pcm_play_pause(false);
1472 paused = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001473 break ;
1474
1475 case AUDIO_RESUME:
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001476 logf("audio_resume");
1477 pcm_play_pause(true);
1478 paused = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001479 break ;
1480
1481 case AUDIO_NEXT:
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001482 logf("audio_next");
1483 initiate_track_change(1);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001484 break ;
1485
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001486 case AUDIO_PREV:
1487 logf("audio_prev");
1488 initiate_track_change(-1);
1489 break;
1490
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001491 case AUDIO_FLUSH:
1492 audio_invalidate_tracks();
1493 break ;
1494
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001495 case AUDIO_TRACK_CHANGED:
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +00001496 if (track_changed_callback)
1497 track_changed_callback(cur_ti);
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001498 playlist_update_resume_info(audio_current_track());
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001499 break ;
1500
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001501 case AUDIO_CODEC_DONE:
1502 //if (playing)
1503 // audio_change_track();
1504 break ;
1505
1506#ifndef SIMULATOR
1507 case SYS_USB_CONNECTED:
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001508 logf("USB Connection");
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001509 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001510 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1511 usb_wait_for_disconnect(&audio_queue);
1512 break ;
1513#endif
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001514 case SYS_TIMEOUT:
1515 if (playing)
1516 playlist_update_resume_info(audio_current_track());
1517 break;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001518 }
1519 }
1520}
1521
1522void codec_thread(void)
1523{
1524 struct event ev;
Miika Pekkarinen85f49732005-06-27 19:29:49 +00001525 long codecsize;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001526 int status;
1527 int wrap;
1528
1529 while (1) {
1530 status = 0;
1531 queue_wait(&codec_queue, &ev);
1532 switch (ev.id) {
1533 case CODEC_LOAD_DISK:
1534 ci.stop_codec = false;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001535 codec_loaded = true;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +00001536 status = codec_load_file((char *)ev.data);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001537 break ;
1538
1539 case CODEC_LOAD:
1540 logf("Codec start");
1541 codecsize = cur_ti->codecsize;
1542 if (codecsize == 0) {
1543 logf("Codec slot is empty!");
Miika Pekkarinen3e33f852005-07-10 06:58:02 +00001544 /* Wait for the pcm buffer to go empty */
1545 while (pcm_is_playing())
1546 yield();
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001547 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001548 break ;
1549 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001550
1551 ci.stop_codec = false;
1552 wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001553 codec_loaded = true;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001554 status = codec_load_ram(cur_ti->codecbuf, codecsize,
Daniel Stenberg1dd672f2005-06-22 19:41:30 +00001555 &codecbuf[0], wrap);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001556 break ;
1557
1558#ifndef SIMULATOR
1559 case SYS_USB_CONNECTED:
1560 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1561 usb_wait_for_disconnect(&codec_queue);
1562 break ;
1563#endif
1564 }
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001565
1566 codec_loaded = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001567
1568 switch (ev.id) {
1569 case CODEC_LOAD_DISK:
1570 case CODEC_LOAD:
Daniel Stenberg1dd672f2005-06-22 19:41:30 +00001571 if (status != CODEC_OK) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001572 logf("Codec failure");
Miika Pekkarinene0037ad2005-06-12 18:16:35 +00001573 splash(HZ*2, true, "Codec failure");
Miika Pekkarinen9c70b1b2005-07-02 17:03:19 +00001574 audio_stop_playback();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001575 } else {
1576 logf("Codec finished");
1577 }
1578
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001579 if (playing && !ci.stop_codec && !ci.reload_codec) {
1580 audio_change_track();
Miika Pekkarinenfe468b12005-06-09 19:31:35 +00001581 continue ;
1582 } else if (ci.stop_codec) {
1583 //playing = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001584 }
Miika Pekkarinenfe468b12005-06-09 19:31:35 +00001585 //queue_post(&audio_queue, AUDIO_CODEC_DONE, (void *)status);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001586 }
1587 }
1588}
1589
1590struct mp3entry* audio_current_track(void)
1591{
Miika Pekkarinenaa30f042005-07-05 07:25:55 +00001592 // logf("audio_current_track");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001593
1594 if (track_count > 0 && cur_ti->taginfo_ready)
1595 return (struct mp3entry *)&cur_ti->id3;
1596 else
1597 return NULL;
1598}
1599
1600struct mp3entry* audio_next_track(void)
1601{
1602 int next_idx = track_ridx + 1;
1603
1604 if (track_count == 0)
1605 return NULL;
1606
1607 if (next_idx >= MAX_TRACK)
1608 next_idx = 0;
1609
1610 if (!tracks[next_idx].taginfo_ready)
1611 return NULL;
1612
1613 //logf("audio_next_track");
1614
1615 return &tracks[next_idx].id3;
1616}
1617
1618bool audio_has_changed_track(void)
1619{
Miika Pekkarinend8cb7032005-06-26 19:41:29 +00001620 if (track_changed && track_count > 0 && playing) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001621 if (!cur_ti->taginfo_ready)
1622 return false;
1623 track_changed = false;
1624 return true;
1625 }
1626
1627 return false;
1628}
1629
1630void audio_play(int offset)
1631{
1632 logf("audio_play");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001633 ci.stop_codec = true;
Miika Pekkarinen3b907072005-06-30 16:28:40 +00001634 if (!pcm_crossfade_init())
1635 pcm_flush_audio();
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001636 codec_track_changed();
Miika Pekkarinend50ed122005-07-02 17:55:51 +00001637
Miika Pekkarinenb4bc1062005-06-09 07:19:16 +00001638 pcm_play_pause(true);
Miika Pekkarinen9e200e32005-06-09 20:01:09 +00001639 paused = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001640 queue_post(&audio_queue, AUDIO_PLAY, (void *)offset);
1641}
1642
1643void audio_stop(void)
1644{
1645 logf("audio_stop");
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001646 queue_post(&audio_queue, AUDIO_STOP, 0);
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001647 while (playing || codec_loaded)
1648 yield();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001649}
1650
1651void audio_pause(void)
1652{
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001653 queue_post(&audio_queue, AUDIO_PAUSE, 0);
Miika Pekkarinen1ed292c2005-07-10 17:31:12 +00001654 while (!paused && playing)
1655 yield();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001656}
1657
1658void audio_resume(void)
1659{
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001660 queue_post(&audio_queue, AUDIO_RESUME, 0);
Miika Pekkarinen1ed292c2005-07-10 17:31:12 +00001661 while (paused && playing)
1662 yield();
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001663}
1664
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001665void audio_next(void)
1666{
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001667 queue_post(&audio_queue, AUDIO_NEXT, 0);
Miika Pekkarinen431e8132005-06-19 18:41:53 +00001668}
1669
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001670void audio_prev(void)
1671{
Linus Nielsen Feltzingffd207f2005-07-06 19:40:17 +00001672 queue_post(&audio_queue, AUDIO_PREV, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001673}
1674
1675void audio_ff_rewind(int newpos)
1676{
1677 logf("rewind: %d", newpos);
Miika Pekkarinen2724d0b2005-07-01 21:00:02 +00001678 if (playing) {
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001679 ci.seek_time = newpos+1;
Miika Pekkarinen2724d0b2005-07-01 21:00:02 +00001680 pcm_play_stop();
Miika Pekkarinen2f6781d2005-07-11 20:43:02 +00001681 paused = false;
Miika Pekkarinen2724d0b2005-07-01 21:00:02 +00001682 }
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001683}
1684
1685void audio_flush_and_reload_tracks(void)
1686{
1687 logf("flush & reload");
Miika Pekkarinen58af47c2005-06-13 22:09:12 +00001688 queue_post(&audio_queue, AUDIO_FLUSH, 0);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001689}
1690
1691void audio_error_clear(void)
1692{
1693}
1694
1695int audio_status(void)
1696{
1697 int ret = 0;
1698
1699 if (playing)
1700 ret |= AUDIO_STATUS_PLAY;
1701
1702 if (paused)
1703 ret |= AUDIO_STATUS_PAUSE;
1704
1705 return ret;
1706}
1707
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +00001708int audio_get_file_pos(void)
1709{
1710 return 0;
1711}
1712
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001713
1714/* Copied from mpeg.c. Should be moved somewhere else. */
Miika Pekkarinen5899ed52005-06-08 10:33:01 +00001715static void mp3_set_elapsed(struct mp3entry* id3)
1716{
1717 if ( id3->vbr ) {
1718 if ( id3->has_toc ) {
1719 /* calculate elapsed time using TOC */
1720 int i;
1721 unsigned int remainder, plen, relpos, nextpos;
1722
1723 /* find wich percent we're at */
1724 for (i=0; i<100; i++ )
1725 {
1726 if ( id3->offset < (int)(id3->toc[i] * (id3->filesize / 256)) )
1727 {
1728 break;
1729 }
1730 }
1731
1732 i--;
1733 if (i < 0)
1734 i = 0;
1735
1736 relpos = id3->toc[i];
1737
1738 if (i < 99)
1739 {
1740 nextpos = id3->toc[i+1];
1741 }
1742 else
1743 {
1744 nextpos = 256;
1745 }
1746
1747 remainder = id3->offset - (relpos * (id3->filesize / 256));
1748
1749 /* set time for this percent (divide before multiply to prevent
1750 overflow on long files. loss of precision is negligible on
1751 short files) */
1752 id3->elapsed = i * (id3->length / 100);
1753
1754 /* calculate remainder time */
1755 plen = (nextpos - relpos) * (id3->filesize / 256);
1756 id3->elapsed += (((remainder * 100) / plen) *
1757 (id3->length / 10000));
1758 }
1759 else {
1760 /* no TOC exists. set a rough estimate using average bitrate */
1761 int tpk = id3->length / (id3->filesize / 1024);
1762 id3->elapsed = id3->offset / 1024 * tpk;
1763 }
1764 }
1765 else
1766 /* constant bitrate == simple frame calculation */
1767 id3->elapsed = id3->offset / id3->bpf * id3->tpf;
1768}
1769
1770/* Copied from mpeg.c. Should be moved somewhere else. */
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001771int mp3_get_file_pos(void)
1772{
1773 int pos = -1;
1774 struct mp3entry *id3 = audio_current_track();
1775
1776 if (id3->vbr)
1777 {
1778 if (id3->has_toc)
1779 {
1780 /* Use the TOC to find the new position */
1781 unsigned int percent, remainder;
1782 int curtoc, nexttoc, plen;
1783
1784 percent = (id3->elapsed*100)/id3->length;
1785 if (percent > 99)
1786 percent = 99;
1787
1788 curtoc = id3->toc[percent];
1789
1790 if (percent < 99)
1791 nexttoc = id3->toc[percent+1];
1792 else
1793 nexttoc = 256;
1794
1795 pos = (id3->filesize/256)*curtoc;
1796
1797 /* Use the remainder to get a more accurate position */
1798 remainder = (id3->elapsed*100)%id3->length;
1799 remainder = (remainder*100)/id3->length;
1800 plen = (nexttoc - curtoc)*(id3->filesize/256);
1801 pos += (plen/100)*remainder;
1802 }
1803 else
1804 {
1805 /* No TOC exists, estimate the new position */
1806 pos = (id3->filesize / (id3->length / 1000)) *
1807 (id3->elapsed / 1000);
1808 }
1809 }
1810 else if (id3->bpf && id3->tpf)
1811 pos = (id3->elapsed/id3->tpf)*id3->bpf;
1812 else
1813 {
1814 return -1;
1815 }
1816
1817 if (pos >= (int)(id3->filesize - id3->id3v1len))
1818 {
1819 /* Don't seek right to the end of the file so that we can
1820 transition properly to the next song */
1821 pos = id3->filesize - id3->id3v1len - 1;
1822 }
1823 else if (pos < (int)id3->first_frame_offset)
1824 {
1825 /* skip past id3v2 tag and other leading garbage */
1826 pos = id3->first_frame_offset;
1827 }
1828 return pos;
1829}
1830
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +00001831#ifndef SIMULATOR
1832void audio_set_buffer_margin(int seconds)
1833{
1834 (void)seconds;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +00001835 logf("bufmargin: %d", seconds);
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +00001836}
1837#endif
1838
1839void mpeg_id3_options(bool _v1first)
1840{
1841 v1first = _v1first;
1842}
1843
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001844void test_buffer_event(struct mp3entry *id3, bool last_track)
1845{
Miika Pekkarinene21cf842005-07-03 19:20:40 +00001846 (void)id3;
1847 (void)last_track;
1848
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001849 logf("be:%d%s", last_track, id3->path);
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001850}
1851
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001852void test_unbuffer_event(struct mp3entry *id3, bool last_track)
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001853{
Miika Pekkarinene21cf842005-07-03 19:20:40 +00001854 (void)id3;
1855 (void)last_track;
1856
Miika Pekkarinen5d9e0532005-07-08 20:01:06 +00001857 logf("ube:%d%s", last_track, id3->path);
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001858}
Miika Pekkarinen9bde0382005-07-03 18:36:24 +00001859
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001860void audio_init(void)
1861{
1862 logf("audio api init");
Miika Pekkarinend8cb7032005-06-26 19:41:29 +00001863 codecbuflen = audiobufend - audiobuf - PCMBUF_SIZE - PCMBUF_GUARD
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001864 - MALLOC_BUFSIZE - GUARD_BUFSIZE;
1865 //codecbuflen = 2*512*1024;
1866 codecbufused = 0;
Miika Pekkarinenb4bc1062005-06-09 07:19:16 +00001867 filling = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001868 codecbuf = &audiobuf[MALLOC_BUFSIZE];
1869 playing = false;
Miika Pekkarinen84d6f9e2005-06-29 20:50:58 +00001870 codec_loaded = false;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001871 paused = false;
1872 track_changed = false;
Miika Pekkarinen94b917e2005-06-11 18:14:41 +00001873 current_fd = -1;
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001874 track_buffer_callback = NULL;
1875 track_unbuffer_callback = NULL;
Miika Pekkarinen7d6d1222005-06-29 21:36:30 +00001876 track_changed_callback = NULL;
Miika Pekkarinen3eb962d2005-07-07 07:15:05 +00001877 /* Just to prevent cur_ti never be anything random. */
1878 cur_ti = &tracks[0];
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001879
Linus Nielsen Feltzing4406fa62005-06-05 23:28:40 +00001880 logf("abuf:%0x", PCMBUF_SIZE);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001881 logf("fbuf:%0x", codecbuflen);
1882 logf("mbuf:%0x", MALLOC_BUFSIZE);
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001883
Miika Pekkarinend54811f2005-07-02 16:52:30 +00001884 audio_set_track_buffer_event(test_buffer_event);
1885 audio_set_track_unbuffer_event(test_unbuffer_event);
Miika Pekkarinene21cf842005-07-03 19:20:40 +00001886
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001887 /* Initialize codec api. */
1888 ci.read_filebuf = codec_filebuf_callback;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +00001889 ci.audiobuffer_insert = pcm_insert_buffer;
1890 ci.audiobuffer_insert_split = codec_audiobuffer_insert_split_callback;
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001891 ci.get_codec_memory = get_codec_memory_callback;
1892 ci.request_buffer = codec_request_buffer_callback;
1893 ci.advance_buffer = codec_advance_buffer_callback;
1894 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
1895 ci.request_next_track = codec_request_next_track_callback;
1896 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
1897 ci.seek_buffer = codec_seek_buffer_callback;
1898 ci.set_elapsed = codec_set_elapsed_callback;
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +00001899 ci.configure = codec_configure_callback;
Miika Pekkarinenbbd42ad2005-07-01 18:22:04 +00001900
1901 mutex_init(&mutex_bufferfill);
Miika Pekkarinen82c29272005-06-07 06:34:54 +00001902 queue_init(&audio_queue);
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001903 queue_init(&codec_queue);
1904
1905 create_thread(codec_thread, codec_stack, sizeof(codec_stack),
1906 codec_thread_name);
1907 create_thread(audio_thread, audio_stack, sizeof(audio_stack),
1908 audio_thread_name);
Miika Pekkarinene9412892005-06-15 15:27:52 +00001909#ifndef SIMULATOR
1910 audio_is_initialized = true;
1911#endif
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001912}
1913
1914