1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005-2007 Miika Pekkarinen
11 * Copyright (C) 2007-2008 Nicolas Pennequin
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include "codec_thread.h"
28 #include "buffering.h"
35 /* Define LOGF_ENABLE to enable logf output in this file */
36 /*#define LOGF_ENABLE*/
39 /* macros to enable logf for queues
40 logging on SYS_TIMEOUT can be disabled */
42 /* Define this for logf output of all queuing except SYS_TIMEOUT */
43 #define PLAYBACK_LOGQUEUES
44 /* Define this to logf SYS_TIMEOUT messages */
45 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
48 #ifdef PLAYBACK_LOGQUEUES
49 #define LOGFQUEUE logf
51 #define LOGFQUEUE(...)
54 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
55 #define LOGFQUEUE_SYS_TIMEOUT logf
57 #define LOGFQUEUE_SYS_TIMEOUT(...)
61 /* Variables are commented with the threads that use them:
62 * A=audio, C=codec, V=voice. A suffix of - indicates that
63 * the variable is read but not updated on that thread.
65 * Unless otherwise noted, the extern variables are located
69 /* Main state control */
70 volatile bool audio_codec_loaded SHAREDBSS_ATTR
= false; /* Codec loaded? (C/A-) */
72 extern struct mp3entry
*thistrack_id3
, /* the currently playing track */
73 *othertrack_id3
; /* prev track during track-change-transition, or end of playlist,
74 * next track otherwise */
76 /* Track change controls */
77 extern bool automatic_skip
; /* Who initiated in-progress skip? (C/A-) */
79 /* Set to true if the codec thread should send an audio stop request
80 * (typically because the end of the playlist has been reached).
82 static bool codec_requested_stop
= false;
84 extern struct event_queue audio_queue SHAREDBSS_ATTR
;
85 extern struct event_queue codec_queue SHAREDBSS_ATTR
;
87 extern struct codec_api ci
; /* from codecs.c */
90 unsigned int codec_thread_id
; /* For modifying thread priority later.
91 Used by playback.c and pcmbuf.c */
92 static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR
;
93 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
95 static const char codec_thread_name
[] = "codec";
97 /* function prototypes */
98 static bool codec_load_next_track(void);
101 /**************************************/
103 /** misc external functions */
105 /* Used to check whether a new codec must be loaded. See array audio_formats[]
107 int get_codec_base_type(int type
)
109 int base_type
= type
;
114 base_type
= AFMT_MPA_L3
;
118 base_type
= AFMT_MPC_SV7
;
121 case AFMT_MP4_AAC_HE
:
122 base_type
= AFMT_MP4_AAC
;
137 base_type
= AFMT_SAP
;
146 const char *get_codec_filename(int cod_spec
)
150 #ifdef HAVE_RECORDING
151 /* Can choose decoder or encoder if one available */
152 int type
= cod_spec
& CODEC_TYPE_MASK
;
153 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
155 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
156 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
158 fname
= (type
== CODEC_TYPE_ENCODER
) ?
159 audio_formats
[afmt
].codec_enc_root_fn
:
160 audio_formats
[afmt
].codec_root_fn
;
163 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
164 afmt
, fname
? fname
: "<unknown>");
165 #else /* !HAVE_RECORDING */
167 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
168 cod_spec
= AFMT_UNKNOWN
;
169 fname
= audio_formats
[cod_spec
].codec_root_fn
;
170 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
171 #endif /* HAVE_RECORDING */
174 } /* get_codec_filename */
176 /* Borrow the codec thread and return the ID */
177 void codec_thread_do_callback(void (*fn
)(void), unsigned int *id
)
179 /* Set id before telling thread to call something; it may be
180 * needed before this function returns. */
182 *id
= codec_thread_id
;
184 /* Codec thread will signal just before entering callback */
185 LOGFQUEUE("codec >| Q_CODEC_DO_CALLBACK");
186 queue_send(&codec_queue
, Q_CODEC_DO_CALLBACK
, (intptr_t)fn
);
190 /** codec API callbacks */
192 static void* codec_get_buffer(size_t *size
)
194 if (codec_size
>= CODEC_SIZE
)
196 *size
= CODEC_SIZE
- codec_size
;
197 return &codecbuf
[codec_size
];
200 static void codec_pcmbuf_insert_callback(
201 const void *ch1
, const void *ch2
, int count
)
203 const char *src
[2] = { ch1
, ch2
};
207 int out_count
= dsp_output_count(ci
.dsp
, count
);
211 /* Prevent audio from a previous track from playing */
212 if (ci
.new_track
|| ci
.stop_codec
)
215 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
219 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
223 /* Get the real input_size for output_size bytes, guarding
224 * against resampling buffer overflows. */
225 inp_count
= dsp_input_count(ci
.dsp
, out_count
);
230 /* Input size has grown, no error, just don't write more than length */
231 if (inp_count
> count
)
234 out_count
= dsp_process(ci
.dsp
, dest
, src
, inp_count
);
239 pcmbuf_write_complete(out_count
);
243 } /* codec_pcmbuf_insert_callback */
245 static void codec_set_elapsed_callback(unsigned long value
)
250 #ifdef AB_REPEAT_ENABLE
251 ab_position_report(value
);
254 unsigned long latency
= pcmbuf_get_latency();
256 thistrack_id3
->elapsed
= 0;
259 unsigned long elapsed
= value
- latency
;
260 if (elapsed
> thistrack_id3
->elapsed
||
261 elapsed
< thistrack_id3
->elapsed
- 2)
263 thistrack_id3
->elapsed
= elapsed
;
268 static void codec_set_offset_callback(size_t value
)
273 unsigned long latency
= pcmbuf_get_latency() * thistrack_id3
->bitrate
/ 8;
275 thistrack_id3
->offset
= 0;
277 thistrack_id3
->offset
= value
- latency
;
280 /* helper function, not a callback */
281 static void codec_advance_buffer_counters(size_t amount
)
283 bufadvance(get_audio_hid(), amount
);
287 /* copy up-to size bytes into ptr and return the actual size copied */
288 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
292 if (ci
.stop_codec
|| !(audio_status() & AUDIO_STATUS_PLAY
))
295 copy_n
= bufread(get_audio_hid(), size
, ptr
);
297 /* Nothing requested OR nothing left */
301 /* Update read and other position pointers */
302 codec_advance_buffer_counters(copy_n
);
304 /* Return the actual amount of data copied to the buffer */
306 } /* codec_filebuf_callback */
308 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
310 size_t copy_n
= reqsize
;
314 if (!(audio_status() & AUDIO_STATUS_PLAY
))
320 ret
= bufgetdata(get_audio_hid(), reqsize
, &ptr
);
322 copy_n
= MIN((size_t)ret
, reqsize
);
333 } /* codec_request_buffer_callback */
335 static void codec_advance_buffer_callback(size_t amount
)
337 codec_advance_buffer_counters(amount
);
338 codec_set_offset_callback(ci
.curpos
);
341 static void codec_advance_buffer_loc_callback(void *ptr
)
343 size_t amount
= buf_get_offset(get_audio_hid(), ptr
);
344 codec_advance_buffer_callback(amount
);
347 static bool codec_seek_buffer_callback(size_t newpos
)
349 logf("codec_seek_buffer_callback");
351 int ret
= bufseek(get_audio_hid(), newpos
);
361 static void codec_seek_complete_callback(void)
363 logf("seek_complete");
364 /* If seeking-while-playing, pcm_is_paused() is true.
365 * If seeking-while-paused, audio_status PAUSE is true.
366 * A seamless seek skips this section. */
367 bool audio_paused
= audio_status() & AUDIO_STATUS_PAUSE
;
368 if (pcm_is_paused() || audio_paused
)
370 /* Clear the buffer */
372 dsp_configure(ci
.dsp
, DSP_FLUSH
, 0);
374 /* If seeking-while-playing, resume pcm playback */
381 static void codec_discard_codec_callback(void)
383 int *codec_hid
= get_codec_hid();
386 bufclose(*codec_hid
);
391 static bool codec_request_next_track_callback(void)
395 if (ci
.stop_codec
|| !(audio_status() & AUDIO_STATUS_PLAY
))
398 prev_codectype
= get_codec_base_type(thistrack_id3
->codectype
);
399 if (!codec_load_next_track())
402 /* Seek to the beginning of the new track because if the struct
403 mp3entry was buffered, "elapsed" might not be zero (if the track has
404 been played already but not unbuffered) */
405 codec_seek_buffer_callback(thistrack_id3
->first_frame_offset
);
406 /* Check if the next codec is the same file. */
407 if (prev_codectype
== get_codec_base_type(thistrack_id3
->codectype
))
409 logf("New track loaded");
410 codec_discard_codec_callback();
415 logf("New codec:%d/%d", thistrack_id3
->codectype
, prev_codectype
);
420 static void codec_configure_callback(int setting
, intptr_t value
)
422 if (!dsp_configure(ci
.dsp
, setting
, value
))
423 { logf("Illegal key:%d", setting
); }
426 /* Initialize codec API */
427 void codec_init_codec_api(void)
429 ci
.dsp
= (struct dsp_config
*)dsp_configure(NULL
, DSP_MYDSP
,
431 ci
.codec_get_buffer
= codec_get_buffer
;
432 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
433 ci
.set_elapsed
= codec_set_elapsed_callback
;
434 ci
.read_filebuf
= codec_filebuf_callback
;
435 ci
.request_buffer
= codec_request_buffer_callback
;
436 ci
.advance_buffer
= codec_advance_buffer_callback
;
437 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
438 ci
.seek_buffer
= codec_seek_buffer_callback
;
439 ci
.seek_complete
= codec_seek_complete_callback
;
440 ci
.request_next_track
= codec_request_next_track_callback
;
441 ci
.discard_codec
= codec_discard_codec_callback
;
442 ci
.set_offset
= codec_set_offset_callback
;
443 ci
.configure
= codec_configure_callback
;
449 static bool codec_load_next_track(void)
451 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
453 audio_set_prev_elapsed(thistrack_id3
->elapsed
);
455 #ifdef AB_REPEAT_ENABLE
456 ab_end_of_track_report();
459 logf("Request new track");
461 if (ci
.new_track
== 0)
464 automatic_skip
= true;
470 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
471 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
476 case Q_CODEC_REQUEST_COMPLETE
:
477 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
478 pcmbuf_start_track_change(automatic_skip
);
481 case Q_CODEC_REQUEST_FAILED
:
482 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
484 ci
.stop_codec
= true;
485 codec_requested_stop
= true;
489 LOGFQUEUE("codec |< default");
490 ci
.stop_codec
= true;
491 codec_requested_stop
= true;
497 static void codec_thread(void)
499 struct queue_event ev
;
505 #ifdef HAVE_CROSSFADE
506 if (!pcmbuf_is_crossfade_active())
512 queue_wait(&codec_queue
, &ev
);
513 codec_requested_stop
= false;
516 case Q_CODEC_LOAD_DISK
:
517 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
518 queue_reply(&codec_queue
, 1);
519 audio_codec_loaded
= true;
520 ci
.stop_codec
= false;
521 status
= codec_load_file((const char *)ev
.data
, &ci
);
522 LOGFQUEUE("codec_load_file %s %d\n", (const char *)ev
.data
, status
);
526 LOGFQUEUE("codec < Q_CODEC_LOAD");
527 if (*get_codec_hid() < 0) {
528 logf("Codec slot is empty!");
529 /* Wait for the pcm buffer to go empty */
530 while (pcm_is_playing())
532 /* This must be set to prevent an infinite loop */
533 ci
.stop_codec
= true;
534 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
535 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
539 audio_codec_loaded
= true;
540 ci
.stop_codec
= false;
541 status
= codec_load_buf(*get_codec_hid(), &ci
);
542 LOGFQUEUE("codec_load_buf %d\n", status
);
545 case Q_CODEC_DO_CALLBACK
:
546 LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK");
547 queue_reply(&codec_queue
, 1);
548 if ((void*)ev
.data
!= NULL
)
550 cpucache_invalidate();
551 ((void (*)(void))ev
.data
)();
556 #ifdef AUDIO_HAVE_RECORDING
557 case Q_ENCODER_LOAD_DISK
:
558 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
559 audio_codec_loaded
= false; /* Not audio codec! */
560 logf("loading encoder");
561 ci
.stop_encoder
= false;
562 status
= codec_load_file((const char *)ev
.data
, &ci
);
563 logf("encoder stopped");
565 #endif /* AUDIO_HAVE_RECORDING */
568 LOGFQUEUE("codec < default");
571 if (audio_codec_loaded
)
576 if (!(audio_status() & AUDIO_STATUS_PLAY
))
580 audio_codec_loaded
= false;
584 case Q_CODEC_LOAD_DISK
:
586 LOGFQUEUE("codec < Q_CODEC_LOAD");
587 if (audio_status() & AUDIO_STATUS_PLAY
)
589 if (ci
.new_track
|| status
!= CODEC_OK
)
593 logf("Codec failure, %d %d", ci
.new_track
, status
);
594 splash(HZ
*2, "Codec failure");
597 if (!codec_load_next_track())
599 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
600 /* End of playlist */
601 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
607 logf("Codec finished");
610 /* Wait for the audio to stop playing before
611 * triggering the WPS exit */
612 while(pcm_is_playing())
614 /* There has been one too many struct pointer swaps by now
615 * so even though it says othertrack_id3, its the correct one! */
616 othertrack_id3
->elapsed
=
617 othertrack_id3
->length
- pcmbuf_get_latency();
621 if (codec_requested_stop
)
623 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
624 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
630 if (*get_codec_hid() >= 0)
632 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
633 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
637 const char *codec_fn
=
638 get_codec_filename(thistrack_id3
->codectype
);
641 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
642 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
649 #ifdef AUDIO_HAVE_RECORDING
650 case Q_ENCODER_LOAD_DISK
:
651 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
653 if (status
== CODEC_OK
)
656 logf("Encoder failure");
657 splash(HZ
*2, "Encoder failure");
659 if (ci
.enc_codec_loaded
< 0)
662 logf("Encoder failed to load");
663 ci
.enc_codec_loaded
= -1;
665 #endif /* AUDIO_HAVE_RECORDING */
668 LOGFQUEUE("codec < default");
674 void make_codec_thread(void)
676 codec_thread_id
= create_thread(
677 codec_thread
, codec_stack
, sizeof(codec_stack
),
678 CREATE_THREAD_FROZEN
,
679 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
681 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
,