summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-02-23 14:31:13 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-02-23 14:31:13 +0000
commit65109732230849eeb9eec2f56f9e046ad6b476c3 (patch)
tree51096b18d823cfb05575335b91e3d1eb75ca4e27
parent43b38b71f5944c1a29060847b58d7e79f7dfe428 (diff)
downloadrockbox-65109732230849eeb9eec2f56f9e046ad6b476c3.tar.gz
rockbox-65109732230849eeb9eec2f56f9e046ad6b476c3.zip
Give playback engine better control over the codec. Codec simply follows commands and doesn't concern itself with audio state. Get track change notification in on the actual last buffer insert of the track because now audio simply waits for a track change notify from PCM on the last track and it must be sent reliably. This is still at an intermediate stage but works. Codecs and plugins become incompatible.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29387 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codec_thread.c454
-rw-r--r--apps/codec_thread.h21
-rw-r--r--apps/codecs.c57
-rw-r--r--apps/codecs.h21
-rw-r--r--apps/codecs/aiff_enc.c13
-rw-r--r--apps/codecs/mp3_enc.c13
-rw-r--r--apps/codecs/wav_enc.c13
-rw-r--r--apps/codecs/wavpack_enc.c15
-rw-r--r--apps/pcmbuf.c67
-rw-r--r--apps/pcmbuf.h1
-rw-r--r--apps/playback.c355
-rw-r--r--apps/playback.h5
-rw-r--r--apps/plugin.c2
-rw-r--r--apps/plugin.h8
-rw-r--r--apps/plugins/test_codec.c19
-rw-r--r--apps/recorder/pcm_record.c9
-rw-r--r--apps/tagtree.c9
17 files changed, 600 insertions, 482 deletions
diff --git a/apps/codec_thread.c b/apps/codec_thread.c
index 03ab5622e2..f166f2ba18 100644
--- a/apps/codec_thread.c
+++ b/apps/codec_thread.c
@@ -19,10 +19,10 @@
19 * KIND, either express or implied. 19 * KIND, either express or implied.
20 * 20 *
21 ****************************************************************************/ 21 ****************************************************************************/
22 22#include "config.h"
23#include "system.h"
23#include "playback.h" 24#include "playback.h"
24#include "codec_thread.h" 25#include "codec_thread.h"
25#include "system.h"
26#include "kernel.h" 26#include "kernel.h"
27#include "codecs.h" 27#include "codecs.h"
28#include "buffering.h" 28#include "buffering.h"
@@ -67,36 +67,38 @@
67 */ 67 */
68 68
69/* Main state control */ 69/* Main state control */
70volatile bool audio_codec_loaded SHAREDBSS_ATTR = false; /* Codec loaded? (C/A-) */ 70
71/* Type of codec loaded? (C/A) */
72static int current_codectype SHAREDBSS_ATTR = AFMT_UNKNOWN;
71 73
72extern struct mp3entry *thistrack_id3, /* the currently playing track */ 74extern struct mp3entry *thistrack_id3, /* the currently playing track */
73 *othertrack_id3; /* prev track during track-change-transition, or end of playlist, 75 *othertrack_id3; /* prev track during track-change-transition, or end of playlist,
74 * next track otherwise */ 76 * next track otherwise */
75 77
76/* Track change controls */ 78/* Track change controls */
77extern bool automatic_skip; /* Who initiated in-progress skip? (C/A-) */
78
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).
81 */
82static bool codec_requested_stop = false;
83
84extern struct event_queue audio_queue SHAREDBSS_ATTR; 79extern struct event_queue audio_queue SHAREDBSS_ATTR;
85extern struct event_queue codec_queue SHAREDBSS_ATTR; 80
86 81
87extern struct codec_api ci; /* from codecs.c */ 82extern struct codec_api ci; /* from codecs.c */
88 83
89/* Codec thread */ 84/* Codec thread */
90unsigned int codec_thread_id; /* For modifying thread priority later. 85static unsigned int codec_thread_id; /* For modifying thread priority later */
91 Used by playback.c and pcmbuf.c */ 86static struct event_queue codec_queue SHAREDBSS_ATTR;
92static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR; 87static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR;
93static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 88static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
94IBSS_ATTR; 89 IBSS_ATTR;
95static const char codec_thread_name[] = "codec"; 90static const char codec_thread_name[] = "codec";
96 91
97/* function prototypes */ 92/* static routines */
98static bool codec_load_next_track(void); 93static void codec_queue_ack(intptr_t ackme)
94{
95 queue_reply(&codec_queue, ackme);
96}
99 97
98static intptr_t codec_queue_send(long id, intptr_t data)
99{
100 return queue_send(&codec_queue, id, data);
101}
100 102
101/**************************************/ 103/**************************************/
102 104
@@ -183,7 +185,7 @@ void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
183 185
184 /* Codec thread will signal just before entering callback */ 186 /* Codec thread will signal just before entering callback */
185 LOGFQUEUE("codec >| Q_CODEC_DO_CALLBACK"); 187 LOGFQUEUE("codec >| Q_CODEC_DO_CALLBACK");
186 queue_send(&codec_queue, Q_CODEC_DO_CALLBACK, (intptr_t)fn); 188 codec_queue_send(Q_CODEC_DO_CALLBACK, (intptr_t)fn);
187} 189}
188 190
189 191
@@ -289,7 +291,7 @@ static size_t codec_filebuf_callback(void *ptr, size_t size)
289{ 291{
290 ssize_t copy_n; 292 ssize_t copy_n;
291 293
292 if (ci.stop_codec || !(audio_status() & AUDIO_STATUS_PLAY)) 294 if (ci.stop_codec)
293 return 0; 295 return 0;
294 296
295 copy_n = bufread(get_audio_hid(), size, ptr); 297 copy_n = bufread(get_audio_hid(), size, ptr);
@@ -311,24 +313,16 @@ static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
311 ssize_t ret; 313 ssize_t ret;
312 void *ptr; 314 void *ptr;
313 315
314 if (!(audio_status() & AUDIO_STATUS_PLAY))
315 {
316 *realsize = 0;
317 return NULL;
318 }
319
320 ret = bufgetdata(get_audio_hid(), reqsize, &ptr); 316 ret = bufgetdata(get_audio_hid(), reqsize, &ptr);
321 if (ret >= 0) 317 if (ret >= 0)
322 copy_n = MIN((size_t)ret, reqsize); 318 copy_n = MIN((size_t)ret, reqsize);
319 else
320 copy_n = 0;
323 321
324 if (copy_n == 0) 322 if (copy_n == 0)
325 { 323 ptr = NULL;
326 *realsize = 0;
327 return NULL;
328 }
329 324
330 *realsize = copy_n; 325 *realsize = copy_n;
331
332 return ptr; 326 return ptr;
333} /* codec_request_buffer_callback */ 327} /* codec_request_buffer_callback */
334 328
@@ -360,61 +354,71 @@ static bool codec_seek_buffer_callback(size_t newpos)
360 354
361static void codec_seek_complete_callback(void) 355static void codec_seek_complete_callback(void)
362{ 356{
357 struct queue_event ev;
358
363 logf("seek_complete"); 359 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)
369 {
370 /* Clear the buffer */
371 pcmbuf_play_stop();
372 dsp_configure(ci.dsp, DSP_FLUSH, 0);
373 360
374 /* If seeking-while-playing, resume pcm playback */ 361 /* Clear DSP */
375 if (!audio_paused) 362 dsp_configure(ci.dsp, DSP_FLUSH, 0);
376 pcmbuf_pause(false);
377 }
378 ci.seek_time = 0;
379}
380 363
381static void codec_discard_codec_callback(void) 364 /* Post notification to audio thread */
382{ 365 LOGFQUEUE("audio > Q_AUDIO_SEEK_COMPLETE");
383 int *codec_hid = get_codec_hid(); 366 queue_post(&audio_queue, Q_AUDIO_SEEK_COMPLETE, 0);
384 if (*codec_hid >= 0) 367
385 { 368 /* Wait for ACK */
386 bufclose(*codec_hid); 369 queue_wait(&codec_queue, &ev);
387 *codec_hid = -1; 370
388 } 371 /* ACK back in context */
372 codec_queue_ack(Q_AUDIO_SEEK_COMPLETE);
389} 373}
390 374
391static bool codec_request_next_track_callback(void) 375static bool codec_request_next_track_callback(void)
392{ 376{
393 int prev_codectype; 377 struct queue_event ev;
394 378
395 if (ci.stop_codec || !(audio_status() & AUDIO_STATUS_PLAY)) 379 logf("Request new track");
396 return false;
397 380
398 prev_codectype = get_codec_base_type(thistrack_id3->codectype); 381 audio_set_prev_elapsed(thistrack_id3->elapsed);
399 if (!codec_load_next_track()) 382
383#ifdef AB_REPEAT_ENABLE
384 ab_end_of_track_report();
385#endif
386
387 if (ci.stop_codec)
388 {
389 /* Handle ACK in outer loop */
390 LOGFQUEUE("codec: already stopping");
400 return false; 391 return false;
392 }
393
394 trigger_cpu_boost();
401 395
402 /* Seek to the beginning of the new track because if the struct 396 /* Post request to audio thread */
403 mp3entry was buffered, "elapsed" might not be zero (if the track has 397 LOGFQUEUE("codec > audio Q_AUDIO_CHECK_NEW_TRACK");
404 been played already but not unbuffered) */ 398 queue_post(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
405 codec_seek_buffer_callback(thistrack_id3->first_frame_offset); 399
406 /* Check if the next codec is the same file. */ 400 /* Wait for ACK */
407 if (prev_codectype == get_codec_base_type(thistrack_id3->codectype)) 401 queue_wait(&codec_queue, &ev);
402
403 if (ev.data == Q_CODEC_REQUEST_COMPLETE)
408 { 404 {
409 logf("New track loaded"); 405 /* Seek to the beginning of the new track because if the struct
410 codec_discard_codec_callback(); 406 mp3entry was buffered, "elapsed" might not be zero (if the track has
411 return true; 407 been played already but not unbuffered) */
408 codec_seek_buffer_callback(thistrack_id3->first_frame_offset);
412 } 409 }
413 else 410
411 /* ACK back in context */
412 codec_queue_ack(Q_AUDIO_CHECK_NEW_TRACK);
413
414 if (ev.data != Q_CODEC_REQUEST_COMPLETE || ci.stop_codec)
414 { 415 {
415 logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype); 416 LOGFQUEUE("codec <= request failed (%d)", ev.data);
416 return false; 417 return false;
417 } 418 }
419
420 LOGFQUEUE("codec <= Q_CODEC_REQEST_COMPLETE");
421 return true;
418} 422}
419 423
420static void codec_configure_callback(int setting, intptr_t value) 424static void codec_configure_callback(int setting, intptr_t value)
@@ -438,7 +442,6 @@ void codec_init_codec_api(void)
438 ci.seek_buffer = codec_seek_buffer_callback; 442 ci.seek_buffer = codec_seek_buffer_callback;
439 ci.seek_complete = codec_seek_complete_callback; 443 ci.seek_complete = codec_seek_complete_callback;
440 ci.request_next_track = codec_request_next_track_callback; 444 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; 445 ci.set_offset = codec_set_offset_callback;
443 ci.configure = codec_configure_callback; 446 ci.configure = codec_configure_callback;
444} 447}
@@ -446,61 +449,18 @@ void codec_init_codec_api(void)
446 449
447/* track change */ 450/* track change */
448 451
449static bool codec_load_next_track(void)
450{
451 intptr_t result = Q_CODEC_REQUEST_FAILED;
452
453 audio_set_prev_elapsed(thistrack_id3->elapsed);
454
455#ifdef AB_REPEAT_ENABLE
456 ab_end_of_track_report();
457#endif
458
459 logf("Request new track");
460
461 if (ci.new_track == 0)
462 {
463 ci.new_track++;
464 automatic_skip = true;
465 }
466
467 if (!ci.stop_codec)
468 {
469 trigger_cpu_boost();
470 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
471 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
472 }
473
474 switch (result)
475 {
476 case Q_CODEC_REQUEST_COMPLETE:
477 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
478 pcmbuf_start_track_change(automatic_skip);
479 return true;
480
481 case Q_CODEC_REQUEST_FAILED:
482 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
483 ci.new_track = 0;
484 ci.stop_codec = true;
485 codec_requested_stop = true;
486 return false;
487
488 default:
489 LOGFQUEUE("codec |< default");
490 ci.stop_codec = true;
491 codec_requested_stop = true;
492 return false;
493 }
494}
495
496/** CODEC THREAD */ 452/** CODEC THREAD */
497static void codec_thread(void) 453static void codec_thread(void)
498{ 454{
499 struct queue_event ev; 455 struct queue_event ev;
500 int status;
501 456
502 while (1) { 457
503 status = 0; 458 while (1)
459 {
460 int status = CODEC_OK;
461 void *handle = NULL;
462 int hid;
463 const char *codec_fn;
504 464
505#ifdef HAVE_CROSSFADE 465#ifdef HAVE_CROSSFADE
506 if (!pcmbuf_is_crossfade_active()) 466 if (!pcmbuf_is_crossfade_active())
@@ -508,171 +468,89 @@ static void codec_thread(void)
508 { 468 {
509 cancel_cpu_boost(); 469 cancel_cpu_boost();
510 } 470 }
511 471
512 queue_wait(&codec_queue, &ev); 472 queue_wait(&codec_queue, &ev);
513 codec_requested_stop = false;
514 473
515 switch (ev.id) { 474 switch (ev.id)
475 {
516 case Q_CODEC_LOAD_DISK: 476 case Q_CODEC_LOAD_DISK:
517 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK"); 477 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
518 queue_reply(&codec_queue, 1); 478 codec_fn = get_codec_filename(ev.data);
519 audio_codec_loaded = true; 479 if (!codec_fn)
520 ci.stop_codec = false; 480 break;
521 status = codec_load_file((const char *)ev.data, &ci); 481#ifdef AUDIO_HAVE_RECORDING
522 LOGFQUEUE("codec_load_file %s %d\n", (const char *)ev.data, status); 482 if (ev.data & CODEC_TYPE_ENCODER)
483 {
484 ev.id = Q_ENCODER_LOAD_DISK;
485 handle = codec_load_file(codec_fn, &ci);
486 if (handle)
487 codec_queue_ack(Q_ENCODER_LOAD_DISK);
488 }
489 else
490#endif
491 {
492 codec_queue_ack(Q_CODEC_LOAD_DISK);
493 handle = codec_load_file(codec_fn, &ci);
494 }
523 break; 495 break;
524 496
525 case Q_CODEC_LOAD: 497 case Q_CODEC_LOAD:
526 LOGFQUEUE("codec < Q_CODEC_LOAD"); 498 LOGFQUEUE("codec < Q_CODEC_LOAD");
527 if (*get_codec_hid() < 0) { 499 codec_queue_ack(Q_CODEC_LOAD);
528 logf("Codec slot is empty!"); 500 hid = (int)ev.data;
529 /* Wait for the pcm buffer to go empty */ 501 handle = codec_load_buf(hid, &ci);
530 while (pcm_is_playing()) 502 bufclose(hid);
531 yield();
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);
536 break;
537 }
538
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);
543 break; 503 break;
544 504
545 case Q_CODEC_DO_CALLBACK: 505 case Q_CODEC_DO_CALLBACK:
546 LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK"); 506 LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK");
547 queue_reply(&codec_queue, 1); 507 codec_queue_ack(Q_CODEC_DO_CALLBACK);
548 if ((void*)ev.data != NULL) 508 if ((void*)ev.data != NULL)
549 { 509 {
550 cpucache_invalidate(); 510 cpucache_commit_discard();
551 ((void (*)(void))ev.data)(); 511 ((void (*)(void))ev.data)();
552 cpucache_flush(); 512 cpucache_commit();
553 } 513 }
554 break; 514 break;
555 515
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");
564 break;
565#endif /* AUDIO_HAVE_RECORDING */
566
567 default: 516 default:
568 LOGFQUEUE("codec < default"); 517 LOGFQUEUE("codec < default : %ld", ev.id);
569 } 518 }
570 519
571 if (audio_codec_loaded) 520 if (handle)
572 { 521 {
522 /* Codec loaded - call the entrypoint */
523 yield();
524 logf("codec running");
525 status = codec_begin(handle);
526 logf("codec stopped");
527 codec_close(handle);
528 current_codectype = AFMT_UNKNOWN;
529
573 if (ci.stop_codec) 530 if (ci.stop_codec)
574 {
575 status = CODEC_OK; 531 status = CODEC_OK;
576 if (!(audio_status() & AUDIO_STATUS_PLAY))
577 pcmbuf_play_stop();
578
579 }
580 audio_codec_loaded = false;
581 } 532 }
582 533
583 switch (ev.id) { 534 switch (ev.id)
584 case Q_CODEC_LOAD_DISK: 535 {
585 case Q_CODEC_LOAD:
586 LOGFQUEUE("codec < Q_CODEC_LOAD");
587 if (audio_status() & AUDIO_STATUS_PLAY)
588 {
589 if (ci.new_track || status != CODEC_OK)
590 {
591 if (!ci.new_track)
592 {
593 logf("Codec failure, %d %d", ci.new_track, status);
594 splash(HZ*2, "Codec failure");
595 }
596
597 if (!codec_load_next_track())
598 {
599 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
600 /* End of playlist */
601 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
602 break;
603 }
604 }
605 else
606 {
607 logf("Codec finished");
608 if (ci.stop_codec)
609 {
610 /* Wait for the audio to stop playing before
611 * triggering the WPS exit */
612 while(pcm_is_playing())
613 {
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();
618 sleep(1);
619 }
620
621 if (codec_requested_stop)
622 {
623 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
624 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
625 }
626 break;
627 }
628 }
629
630 if (*get_codec_hid() >= 0)
631 {
632 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
633 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
634 }
635 else
636 {
637 const char *codec_fn =
638 get_codec_filename(thistrack_id3->codectype);
639 if (codec_fn)
640 {
641 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
642 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
643 (intptr_t)codec_fn);
644 }
645 }
646 }
647 break;
648
649#ifdef AUDIO_HAVE_RECORDING 536#ifdef AUDIO_HAVE_RECORDING
650 case Q_ENCODER_LOAD_DISK: 537 case Q_ENCODER_LOAD_DISK:
651 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); 538#endif
652 539 case Q_CODEC_LOAD_DISK:
653 if (status == CODEC_OK) 540 case Q_CODEC_LOAD:
654 break; 541 /* Notify about the status */
655 542 if (!handle)
656 logf("Encoder failure"); 543 status = CODEC_ERROR;
657 splash(HZ*2, "Encoder failure"); 544 LOGFQUEUE("codec > audio notify status: %d", status);
658 545 queue_post(&audio_queue, ev.id, status);
659 if (ci.enc_codec_loaded < 0)
660 break;
661
662 logf("Encoder failed to load");
663 ci.enc_codec_loaded = -1;
664 break; 546 break;
665#endif /* AUDIO_HAVE_RECORDING */ 547 }
666
667 default:
668 LOGFQUEUE("codec < default");
669
670 } /* end switch */
671 } 548 }
672} 549}
673 550
674void make_codec_thread(void) 551void make_codec_thread(void)
675{ 552{
553 queue_init(&codec_queue, false);
676 codec_thread_id = create_thread( 554 codec_thread_id = create_thread(
677 codec_thread, codec_stack, sizeof(codec_stack), 555 codec_thread, codec_stack, sizeof(codec_stack),
678 CREATE_THREAD_FROZEN, 556 CREATE_THREAD_FROZEN,
@@ -681,3 +559,79 @@ void make_codec_thread(void)
681 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list, 559 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list,
682 codec_thread_id); 560 codec_thread_id);
683} 561}
562
563void codec_thread_resume(void)
564{
565 thread_thaw(codec_thread_id);
566}
567
568bool is_codec_thread(void)
569{
570 return thread_get_current() == codec_thread_id;
571}
572
573#ifdef HAVE_PRIORITY_SCHEDULING
574int codec_thread_get_priority(void)
575{
576 return thread_get_priority(codec_thread_id);
577}
578
579int codec_thread_set_priority(int priority)
580{
581 return thread_set_priority(codec_thread_id, priority);
582}
583#endif /* HAVE_PRIORITY_SCHEDULING */
584
585/* functions for audio thread use */
586intptr_t codec_ack_msg(intptr_t data, bool stop_codec)
587{
588 intptr_t resp;
589 LOGFQUEUE("codec >| Q_CODEC_ACK: %d", data);
590 if (stop_codec)
591 ci.stop_codec = true;
592 resp = codec_queue_send(Q_CODEC_ACK, data);
593 if (stop_codec)
594 codec_stop();
595 LOGFQUEUE(" ack: %ld", resp);
596 return resp;
597}
598
599bool codec_load(int hid, int cod_spec)
600{
601 bool retval = false;
602
603 ci.stop_codec = false;
604 current_codectype = cod_spec;
605
606 if (hid >= 0)
607 {
608 LOGFQUEUE("audio >| codec Q_CODEC_LOAD: %d", hid);
609 retval = codec_queue_send(Q_CODEC_LOAD, hid) != Q_NULL;
610 }
611 else
612 {
613 LOGFQUEUE("audio >| codec Q_CODEC_LOAD_DISK: %d", cod_spec);
614 retval = codec_queue_send(Q_CODEC_LOAD_DISK, cod_spec) != Q_NULL;
615 }
616
617 if (!retval)
618 {
619 ci.stop_codec = true;
620 current_codectype = AFMT_UNKNOWN;
621 }
622
623 return retval;
624}
625
626void codec_stop(void)
627{
628 ci.stop_codec = true;
629 /* Wait until it's in the main loop */
630 while (codec_ack_msg(0, false) != Q_NULL);
631 current_codectype = AFMT_UNKNOWN;
632}
633
634int codec_loaded(void)
635{
636 return current_codectype;
637}
diff --git a/apps/codec_thread.h b/apps/codec_thread.h
index a849e07d39..7056e2cdf5 100644
--- a/apps/codec_thread.h
+++ b/apps/codec_thread.h
@@ -24,11 +24,30 @@
24 24
25#include <stdbool.h> 25#include <stdbool.h>
26 26
27/* codec identity */
27int get_codec_base_type(int type); 28int get_codec_base_type(int type);
28const char *get_codec_filename(int cod_spec); 29const char *get_codec_filename(int cod_spec);
30
31/* codec thread */
32
33/* Audio MUST be stopped before requesting callback! */
29void codec_thread_do_callback(void (*fn)(void), 34void codec_thread_do_callback(void (*fn)(void),
30 unsigned int *codec_thread_id); 35 unsigned int *codec_thread_id);
36
31void codec_init_codec_api(void); 37void codec_init_codec_api(void);
32void make_codec_thread(void); 38void make_codec_thread(void);
33 39void codec_thread_resume(void);
40bool is_codec_thread(void);
41#ifdef HAVE_PRIORITY_SCHEDULING
42int codec_thread_get_priority(void);
43int codec_thread_set_priority(int priority);
34#endif 44#endif
45
46/* codec commands - on audio thread only! */
47intptr_t codec_ack_msg(intptr_t data, bool stop_codec);
48bool codec_load(int hid, int cod_spec);
49void codec_stop(void);
50int codec_loaded(void);
51/* */
52
53#endif /* _CODEC_THREAD_H */
diff --git a/apps/codecs.c b/apps/codecs.c
index 646d5f289b..86e36edcf0 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -97,7 +97,6 @@ struct codec_api ci = {
97 NULL, /* seek_buffer */ 97 NULL, /* seek_buffer */
98 NULL, /* seek_complete */ 98 NULL, /* seek_complete */
99 NULL, /* request_next_track */ 99 NULL, /* request_next_track */
100 NULL, /* discard_codec */
101 NULL, /* set_offset */ 100 NULL, /* set_offset */
102 NULL, /* configure */ 101 NULL, /* configure */
103 102
@@ -149,8 +148,6 @@ struct codec_api ci = {
149#endif 148#endif
150 149
151#ifdef HAVE_RECORDING 150#ifdef HAVE_RECORDING
152 false, /* stop_encoder */
153 0, /* enc_codec_loaded */
154 enc_get_inputs, 151 enc_get_inputs,
155 enc_set_parameters, 152 enc_set_parameters,
156 enc_get_chunk, 153 enc_get_chunk,
@@ -178,11 +175,10 @@ void codec_get_full_path(char *path, const char *codec_root_fn)
178 CODECS_DIR, codec_root_fn); 175 CODECS_DIR, codec_root_fn);
179} 176}
180 177
181static int codec_load_ram(void *handle, struct codec_api *api) 178static void * codec_load_ram(void *handle, struct codec_api *api)
182{ 179{
183 struct codec_header *c_hdr = lc_get_header(handle); 180 struct codec_header *c_hdr = lc_get_header(handle);
184 struct lc_header *hdr = c_hdr ? &c_hdr->lc_hdr : NULL; 181 struct lc_header *hdr = c_hdr ? &c_hdr->lc_hdr : NULL;
185 int status;
186 182
187 if (hdr == NULL 183 if (hdr == NULL
188 || (hdr->magic != CODEC_MAGIC 184 || (hdr->magic != CODEC_MAGIC
@@ -199,14 +195,14 @@ static int codec_load_ram(void *handle, struct codec_api *api)
199 { 195 {
200 logf("codec header error"); 196 logf("codec header error");
201 lc_close(handle); 197 lc_close(handle);
202 return CODEC_ERROR; 198 return NULL;
203 } 199 }
204 200
205 if (hdr->api_version > CODEC_API_VERSION 201 if (hdr->api_version > CODEC_API_VERSION
206 || hdr->api_version < CODEC_MIN_API_VERSION) { 202 || hdr->api_version < CODEC_MIN_API_VERSION) {
207 logf("codec api version error"); 203 logf("codec api version error");
208 lc_close(handle); 204 lc_close(handle);
209 return CODEC_ERROR; 205 return NULL;
210 } 206 }
211 207
212#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 208#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
@@ -216,34 +212,31 @@ static int codec_load_ram(void *handle, struct codec_api *api)
216#endif 212#endif
217 213
218 *(c_hdr->api) = api; 214 *(c_hdr->api) = api;
219 status = c_hdr->entry_point();
220 215
221 lc_close(handle); 216 return handle;
222
223 return status;
224} 217}
225 218
226int codec_load_buf(unsigned int hid, struct codec_api *api) 219void * codec_load_buf(int hid, struct codec_api *api)
227{ 220{
228 int rc; 221 int rc;
229 void *handle; 222 void *handle;
230 rc = bufread(hid, CODEC_SIZE, codecbuf); 223 rc = bufread(hid, CODEC_SIZE, codecbuf);
231 if (rc < 0) { 224 if (rc < 0) {
232 logf("error loading codec"); 225 logf("Codec: cannot read buf handle");
233 return CODEC_ERROR; 226 return NULL;
234 } 227 }
228
235 handle = lc_open_from_mem(codecbuf, rc); 229 handle = lc_open_from_mem(codecbuf, rc);
236 if (handle == NULL) 230
237 { 231 if (handle == NULL) {
238 logf("error loading codec"); 232 logf("error loading codec");
239 return CODEC_ERROR; 233 return NULL;
240 } 234 }
241 235
242 api->discard_codec();
243 return codec_load_ram(handle, api); 236 return codec_load_ram(handle, api);
244} 237}
245 238
246int codec_load_file(const char *plugin, struct codec_api *api) 239void * codec_load_file(const char *plugin, struct codec_api *api)
247{ 240{
248 char path[MAX_PATH]; 241 char path[MAX_PATH];
249 void *handle; 242 void *handle;
@@ -253,10 +246,30 @@ int codec_load_file(const char *plugin, struct codec_api *api)
253 handle = lc_open(path, codecbuf, CODEC_SIZE); 246 handle = lc_open(path, codecbuf, CODEC_SIZE);
254 247
255 if (handle == NULL) { 248 if (handle == NULL) {
256 logf("Codec load error"); 249 logf("Codec: cannot read file");
257 splashf(HZ*2, "Couldn't load codec: %s", path); 250 return NULL;
258 return CODEC_ERROR;
259 } 251 }
260 252
261 return codec_load_ram(handle, api); 253 return codec_load_ram(handle, api);
262} 254}
255
256int codec_begin(void *handle)
257{
258 int status = CODEC_ERROR;
259 struct codec_header *c_hdr;
260
261 c_hdr = lc_get_header(handle);
262
263 if (c_hdr != NULL) {
264 logf("Codec: calling entry_point");
265 status = c_hdr->entry_point();
266 }
267
268 return status;
269}
270
271void codec_close(void *handle)
272{
273 if (handle)
274 lc_close(handle);
275}
diff --git a/apps/codecs.h b/apps/codecs.h
index c3ef7c154e..252dafd1f4 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -75,17 +75,16 @@
75#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ 75#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
76 76
77/* increase this every time the api struct changes */ 77/* increase this every time the api struct changes */
78#define CODEC_API_VERSION 35 78#define CODEC_API_VERSION 36
79 79
80/* update this to latest version if a change to the api struct breaks 80/* update this to latest version if a change to the api struct breaks
81 backwards compatibility (and please take the opportunity to sort in any 81 backwards compatibility (and please take the opportunity to sort in any
82 new function which are "waiting" at the end of the function table) */ 82 new function which are "waiting" at the end of the function table) */
83#define CODEC_MIN_API_VERSION 35 83#define CODEC_MIN_API_VERSION 36
84 84
85/* codec return codes */ 85/* codec return codes */
86enum codec_status { 86enum codec_status {
87 CODEC_OK = 0, 87 CODEC_OK = 0,
88 CODEC_USB_CONNECTED,
89 CODEC_ERROR = -1, 88 CODEC_ERROR = -1,
90}; 89};
91 90
@@ -106,13 +105,13 @@ struct codec_api {
106 105
107 /* Codec should periodically check if stop_codec is set to true. 106 /* Codec should periodically check if stop_codec is set to true.
108 In case it is, codec must return immediately */ 107 In case it is, codec must return immediately */
109 bool stop_codec; 108 volatile bool stop_codec;
110 /* Codec should periodically check if new_track is non zero. 109 /* Codec should periodically check if new_track is non zero.
111 When it is, the codec should request a new track. */ 110 When it is, the codec should request a new track. */
112 int new_track; 111 volatile int new_track;
113 /* If seek_time != 0, codec should seek to that song position (in ms) 112 /* If seek_time != 0, codec should seek to that song position (in ms)
114 if codec supports seeking. */ 113 if codec supports seeking. */
115 long seek_time; 114 volatile long seek_time;
116 115
117 /* The dsp instance to be used for audio output */ 116 /* The dsp instance to be used for audio output */
118 struct dsp_config *dsp; 117 struct dsp_config *dsp;
@@ -145,8 +144,6 @@ struct codec_api {
145 track is available and changed. If return value is false, 144 track is available and changed. If return value is false,
146 codec should exit immediately with PLUGIN_OK status. */ 145 codec should exit immediately with PLUGIN_OK status. */
147 bool (*request_next_track)(void); 146 bool (*request_next_track)(void);
148 /* Free the buffer area of the current codec after its loaded */
149 void (*discard_codec)(void);
150 147
151 void (*set_offset)(size_t value); 148 void (*set_offset)(size_t value);
152 /* Configure different codec buffer parameters. */ 149 /* Configure different codec buffer parameters. */
@@ -210,8 +207,6 @@ struct codec_api {
210#endif 207#endif
211 208
212#ifdef HAVE_RECORDING 209#ifdef HAVE_RECORDING
213 volatile bool stop_encoder;
214 volatile int enc_codec_loaded; /* <0=error, 0=pending, >0=ok */
215 void (*enc_get_inputs)(struct enc_inputs *inputs); 210 void (*enc_get_inputs)(struct enc_inputs *inputs);
216 void (*enc_set_parameters)(struct enc_parameters *params); 211 void (*enc_set_parameters)(struct enc_parameters *params);
217 struct enc_chunk_hdr * (*enc_get_chunk)(void); 212 struct enc_chunk_hdr * (*enc_get_chunk)(void);
@@ -283,8 +278,10 @@ extern unsigned char plugin_end_addr[];
283void codec_get_full_path(char *path, const char *codec_root_fn); 278void codec_get_full_path(char *path, const char *codec_root_fn);
284 279
285/* defined by the codec loader (codec.c) */ 280/* defined by the codec loader (codec.c) */
286int codec_load_buf(unsigned int hid, struct codec_api *api); 281void * codec_load_buf(int hid, struct codec_api *api);
287int codec_load_file(const char* codec, struct codec_api *api); 282void * codec_load_file(const char* codec, struct codec_api *api);
283int codec_begin(void *handle);
284void codec_close(void *handle);
288 285
289/* defined by the codec */ 286/* defined by the codec */
290enum codec_status codec_start(void); 287enum codec_status codec_start(void);
diff --git a/apps/codecs/aiff_enc.c b/apps/codecs/aiff_enc.c
index 2d55dff755..69496f70ac 100644
--- a/apps/codecs/aiff_enc.c
+++ b/apps/codecs/aiff_enc.c
@@ -363,16 +363,10 @@ static bool init_encoder(void)
363enum codec_status codec_main(void) 363enum codec_status codec_main(void)
364{ 364{
365 if (!init_encoder()) 365 if (!init_encoder())
366 {
367 ci->enc_codec_loaded = -1;
368 return CODEC_ERROR; 366 return CODEC_ERROR;
369 }
370
371 /* main application waits for this flag during encoder loading */
372 ci->enc_codec_loaded = 1;
373 367
374 /* main encoding loop */ 368 /* main encoding loop */
375 while(!ci->stop_encoder) 369 while(!ci->stop_codec)
376 { 370 {
377 uint32_t *src; 371 uint32_t *src;
378 372
@@ -380,7 +374,7 @@ enum codec_status codec_main(void)
380 { 374 {
381 struct enc_chunk_hdr *chunk; 375 struct enc_chunk_hdr *chunk;
382 376
383 if (ci->stop_encoder) 377 if (ci->stop_codec)
384 break; 378 break;
385 379
386 chunk = ci->enc_get_chunk(); 380 chunk = ci->enc_get_chunk();
@@ -400,8 +394,5 @@ enum codec_status codec_main(void)
400 /* reset parameters to initial state */ 394 /* reset parameters to initial state */
401 ci->enc_set_parameters(NULL); 395 ci->enc_set_parameters(NULL);
402 396
403 /* main application waits for this flag during encoder removing */
404 ci->enc_codec_loaded = 0;
405
406 return CODEC_OK; 397 return CODEC_OK;
407} /* codec_start */ 398} /* codec_start */
diff --git a/apps/codecs/mp3_enc.c b/apps/codecs/mp3_enc.c
index c66d755f08..e7893fd14a 100644
--- a/apps/codecs/mp3_enc.c
+++ b/apps/codecs/mp3_enc.c
@@ -2588,16 +2588,10 @@ enum codec_status codec_main(void)
2588{ 2588{
2589 /* Generic codec initialisation */ 2589 /* Generic codec initialisation */
2590 if (!enc_init()) 2590 if (!enc_init())
2591 {
2592 ci->enc_codec_loaded = -1;
2593 return CODEC_ERROR; 2591 return CODEC_ERROR;
2594 }
2595
2596 /* main application waits for this flag during encoder loading */
2597 ci->enc_codec_loaded = 1;
2598 2592
2599 /* main encoding loop */ 2593 /* main encoding loop */
2600 while (!ci->stop_encoder) 2594 while (!ci->stop_codec)
2601 { 2595 {
2602 char *buffer; 2596 char *buffer;
2603 2597
@@ -2605,7 +2599,7 @@ enum codec_status codec_main(void)
2605 { 2599 {
2606 struct enc_chunk_hdr *chunk; 2600 struct enc_chunk_hdr *chunk;
2607 2601
2608 if (ci->stop_encoder) 2602 if (ci->stop_codec)
2609 break; 2603 break;
2610 2604
2611 chunk = ci->enc_get_chunk(); 2605 chunk = ci->enc_get_chunk();
@@ -2630,8 +2624,5 @@ enum codec_status codec_main(void)
2630 /* reset parameters to initial state */ 2624 /* reset parameters to initial state */
2631 ci->enc_set_parameters(NULL); 2625 ci->enc_set_parameters(NULL);
2632 2626
2633 /* main application waits for this flag during encoder removing */
2634 ci->enc_codec_loaded = 0;
2635
2636 return CODEC_OK; 2627 return CODEC_OK;
2637} /* codec_start */ 2628} /* codec_start */
diff --git a/apps/codecs/wav_enc.c b/apps/codecs/wav_enc.c
index 193181d825..ef1a88ec23 100644
--- a/apps/codecs/wav_enc.c
+++ b/apps/codecs/wav_enc.c
@@ -349,16 +349,10 @@ static bool init_encoder(void)
349enum codec_status codec_main(void) 349enum codec_status codec_main(void)
350{ 350{
351 if (!init_encoder()) 351 if (!init_encoder())
352 {
353 ci->enc_codec_loaded = -1;
354 return CODEC_ERROR; 352 return CODEC_ERROR;
355 }
356
357 /* main application waits for this flag during encoder loading */
358 ci->enc_codec_loaded = 1;
359 353
360 /* main encoding loop */ 354 /* main encoding loop */
361 while(!ci->stop_encoder) 355 while(!ci->stop_codec)
362 { 356 {
363 uint32_t *src; 357 uint32_t *src;
364 358
@@ -366,7 +360,7 @@ enum codec_status codec_main(void)
366 { 360 {
367 struct enc_chunk_hdr *chunk; 361 struct enc_chunk_hdr *chunk;
368 362
369 if (ci->stop_encoder) 363 if (ci->stop_codec)
370 break; 364 break;
371 365
372 chunk = ci->enc_get_chunk(); 366 chunk = ci->enc_get_chunk();
@@ -386,8 +380,5 @@ enum codec_status codec_main(void)
386 /* reset parameters to initial state */ 380 /* reset parameters to initial state */
387 ci->enc_set_parameters(NULL); 381 ci->enc_set_parameters(NULL);
388 382
389 /* main application waits for this flag during encoder removing */
390 ci->enc_codec_loaded = 0;
391
392 return CODEC_OK; 383 return CODEC_OK;
393} /* codec_start */ 384} /* codec_start */
diff --git a/apps/codecs/wavpack_enc.c b/apps/codecs/wavpack_enc.c
index 66263cf1a1..d908e284be 100644
--- a/apps/codecs/wavpack_enc.c
+++ b/apps/codecs/wavpack_enc.c
@@ -393,16 +393,10 @@ enum codec_status codec_main(void)
393{ 393{
394 /* initialize params and config */ 394 /* initialize params and config */
395 if (!init_encoder()) 395 if (!init_encoder())
396 {
397 ci->enc_codec_loaded = -1;
398 return CODEC_ERROR; 396 return CODEC_ERROR;
399 }
400
401 /* main application waits for this flag during encoder loading */
402 ci->enc_codec_loaded = 1;
403 397
404 /* main encoding loop */ 398 /* main encoding loop */
405 while(!ci->stop_encoder) 399 while(!ci->stop_codec)
406 { 400 {
407 uint8_t *src; 401 uint8_t *src;
408 402
@@ -413,7 +407,7 @@ enum codec_status codec_main(void)
413 uint8_t *dst; 407 uint8_t *dst;
414 uint8_t *src_end; 408 uint8_t *src_end;
415 409
416 if(ci->stop_encoder) 410 if(ci->stop_codec)
417 break; 411 break;
418 412
419 abort_chunk = true; 413 abort_chunk = true;
@@ -442,7 +436,7 @@ enum codec_status codec_main(void)
442 chunk->num_pcm += PCM_SAMP_PER_CHUNK/4; 436 chunk->num_pcm += PCM_SAMP_PER_CHUNK/4;
443 ci->yield(); 437 ci->yield();
444 /* could've been stopped in some way */ 438 /* could've been stopped in some way */
445 abort_chunk = ci->stop_encoder || 439 abort_chunk = ci->stop_codec ||
446 (chunk->flags & CHUNKF_ABORT); 440 (chunk->flags & CHUNKF_ABORT);
447 } 441 }
448 442
@@ -467,8 +461,5 @@ enum codec_status codec_main(void)
467 /* reset parameters to initial state */ 461 /* reset parameters to initial state */
468 ci->enc_set_parameters(NULL); 462 ci->enc_set_parameters(NULL);
469 463
470 /* main application waits for this flag during encoder removing */
471 ci->enc_codec_loaded = 0;
472
473 return CODEC_OK; 464 return CODEC_OK;
474} /* codec_start */ 465} /* codec_start */
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 93ce4266c1..2cec40b7e7 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -26,6 +26,7 @@
26#include "pcmbuf.h" 26#include "pcmbuf.h"
27#include "pcm.h" 27#include "pcm.h"
28#include "playback.h" 28#include "playback.h"
29#include "codec_thread.h"
29 30
30/* Define LOGF_ENABLE to enable logf output in this file */ 31/* Define LOGF_ENABLE to enable logf output in this file */
31/*#define LOGF_ENABLE*/ 32/*#define LOGF_ENABLE*/
@@ -86,8 +87,7 @@ static size_t pcmbuffer_pos IDATA_ATTR;
86static size_t pcmbuffer_fillpos IDATA_ATTR; 87static size_t pcmbuffer_fillpos IDATA_ATTR;
87 88
88/* Gapless playback */ 89/* Gapless playback */
89static bool end_of_track IDATA_ATTR; 90static bool track_transition IDATA_ATTR;
90bool track_transition IDATA_ATTR;
91 91
92#ifdef HAVE_CROSSFADE 92#ifdef HAVE_CROSSFADE
93/* Crossfade buffer */ 93/* Crossfade buffer */
@@ -131,8 +131,6 @@ static bool flush_pcmbuf = false;
131static int codec_thread_priority = PRIORITY_PLAYBACK; 131static int codec_thread_priority = PRIORITY_PLAYBACK;
132#endif 132#endif
133 133
134extern unsigned int codec_thread_id;
135
136/* Helpful macros for use in conditionals this assumes some of the above 134/* Helpful macros for use in conditionals this assumes some of the above
137 * static variable names */ 135 * static variable names */
138#define COMMIT_IF_NEEDED if(pcmbuffer_fillpos > PCMBUF_TARGET_CHUNK || \ 136#define COMMIT_IF_NEEDED if(pcmbuffer_fillpos > PCMBUF_TARGET_CHUNK || \
@@ -223,9 +221,8 @@ static void commit_chunk(bool flush_next_time)
223 /* Fill in the values in the new buffer chunk */ 221 /* Fill in the values in the new buffer chunk */
224 pcmbuf_current->addr = &pcmbuffer[pcmbuffer_pos]; 222 pcmbuf_current->addr = &pcmbuffer[pcmbuffer_pos];
225 pcmbuf_current->size = size; 223 pcmbuf_current->size = size;
226 pcmbuf_current->end_of_track = end_of_track; 224 pcmbuf_current->end_of_track = false;
227 pcmbuf_current->link = NULL; 225 pcmbuf_current->link = NULL;
228 end_of_track = false; /* This is single use only */
229 226
230 if (read_chunk != NULL) 227 if (read_chunk != NULL)
231 { 228 {
@@ -297,7 +294,7 @@ static void boost_codec_thread(int pcm_fill_state)
297 * will starve if the codec thread's priority is boosted. */ 294 * will starve if the codec thread's priority is boosted. */
298 if (new_prio != codec_thread_priority) 295 if (new_prio != codec_thread_priority)
299 { 296 {
300 thread_set_priority(codec_thread_id, new_prio); 297 codec_thread_set_priority(new_prio);
301 voice_thread_set_priority(new_prio); 298 voice_thread_set_priority(new_prio);
302 codec_thread_priority = new_prio; 299 codec_thread_priority = new_prio;
303 } 300 }
@@ -327,7 +324,7 @@ static bool prepare_insert(size_t length)
327 /* Only codec thread initiates boost - voice boosts the cpu when playing 324 /* Only codec thread initiates boost - voice boosts the cpu when playing
328 a clip */ 325 a clip */
329#ifndef SIMULATOR 326#ifndef SIMULATOR
330 if (thread_get_current() == codec_thread_id) 327 if (is_codec_thread())
331#endif /* SIMULATOR */ 328#endif /* SIMULATOR */
332 { 329 {
333 /* boost cpu if necessary */ 330 /* boost cpu if necessary */
@@ -487,6 +484,27 @@ size_t pcmbuf_init(unsigned char *bufend)
487 484
488 485
489/** Track change */ 486/** Track change */
487void pcmbuf_monitor_track_change(bool monitor)
488{
489 pcm_play_lock();
490
491 if (last_chunksize != 0)
492 {
493 /* If monitoring, wait until this track runs out. Place in
494 currently playing chunk. If not, cancel notification. */
495 track_transition = monitor;
496 read_end_chunk->end_of_track = monitor;
497 }
498 else
499 {
500 /* Post now if PCM stopped and last buffer was sent. */
501 track_transition = false;
502 if (monitor)
503 audio_post_track_change(false);
504 }
505
506 pcm_play_unlock();
507}
490 508
491void pcmbuf_start_track_change(bool auto_skip) 509void pcmbuf_start_track_change(bool auto_skip)
492{ 510{
@@ -523,6 +541,11 @@ void pcmbuf_start_track_change(bool auto_skip)
523 { logf(" crossfade track change"); } 541 { logf(" crossfade track change"); }
524 else 542 else
525 { logf(" manual track change"); } 543 { logf(" manual track change"); }
544
545 pcm_play_lock();
546
547 /* Cancel any pending automatic gapless transition */
548 pcmbuf_monitor_track_change(false);
526 549
527 /* Notify the wps that the track change starts now */ 550 /* Notify the wps that the track change starts now */
528 audio_post_track_change(false); 551 audio_post_track_change(false);
@@ -535,26 +558,32 @@ void pcmbuf_start_track_change(bool auto_skip)
535 !pcm_is_playing()) 558 !pcm_is_playing())
536 { 559 {
537 pcmbuf_play_stop(); 560 pcmbuf_play_stop();
561 pcm_play_unlock();
538 return; 562 return;
539 } 563 }
540 564
541 trigger_cpu_boost();
542
543 /* Not enough data, or not crossfading, flush the old data instead */ 565 /* Not enough data, or not crossfading, flush the old data instead */
544 if (LOW_DATA(2) || !crossfade || low_latency_mode) 566 if (LOW_DATA(2) || !crossfade || low_latency_mode)
545 { 567 {
546 commit_chunk(true); 568 commit_chunk(true);
547 return;
548 } 569 }
549
550#ifdef HAVE_CROSSFADE 570#ifdef HAVE_CROSSFADE
551 /* Don't enable mix mode when skipping tracks manually. */ 571 else
552 crossfade_mixmode = auto_skip && global_settings.crossfade_fade_out_mixmode; 572 {
553 573 /* Don't enable mix mode when skipping tracks manually. */
554 crossfade_auto_skip = auto_skip; 574 crossfade_mixmode = auto_skip &&
575 global_settings.crossfade_fade_out_mixmode;
576
577 crossfade_auto_skip = auto_skip;
555 578
556 crossfade_track_change_started = crossfade; 579 crossfade_track_change_started = crossfade;
580 }
557#endif 581#endif
582 pcm_play_unlock();
583
584 /* Keep trigger outside the play lock or HW FIFO underruns can happen
585 since frequency scaling is *not* always fast */
586 trigger_cpu_boost();
558 } 587 }
559 else /* automatic and not crossfading, so do gapless track change */ 588 else /* automatic and not crossfading, so do gapless track change */
560 { 589 {
@@ -563,8 +592,7 @@ void pcmbuf_start_track_change(bool auto_skip)
563 * current track will be updated properly, and mark the current chunk 592 * current track will be updated properly, and mark the current chunk
564 * as the last one in the track. */ 593 * as the last one in the track. */
565 logf(" gapless track change"); 594 logf(" gapless track change");
566 track_transition = true; 595 pcmbuf_monitor_track_change(true);
567 end_of_track = true;
568 } 596 }
569} 597}
570 598
@@ -674,7 +702,6 @@ void pcmbuf_play_stop(void)
674 crossfade_track_change_started = false; 702 crossfade_track_change_started = false;
675 crossfade_active = false; 703 crossfade_active = false;
676#endif 704#endif
677 end_of_track = false;
678 track_transition = false; 705 track_transition = false;
679 flush_pcmbuf = false; 706 flush_pcmbuf = false;
680 DISPLAY_DESC("play_stop"); 707 DISPLAY_DESC("play_stop");
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index 992eb8063f..618b1babad 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -32,6 +32,7 @@ size_t pcmbuf_init(unsigned char *bufend);
32void pcmbuf_play_start(void); 32void pcmbuf_play_start(void);
33void pcmbuf_play_stop(void); 33void pcmbuf_play_stop(void);
34void pcmbuf_pause(bool pause); 34void pcmbuf_pause(bool pause);
35void pcmbuf_monitor_track_change(bool monitor);
35void pcmbuf_start_track_change(bool manual_skip); 36void pcmbuf_start_track_change(bool manual_skip);
36 37
37/* Crossfade */ 38/* Crossfade */
diff --git a/apps/playback.c b/apps/playback.c
index 5d91693cad..db07613bc8 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -22,7 +22,8 @@
22 22
23/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can 23/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
24 * play whilst audio is paused */ 24 * play whilst audio is paused */
25 25#include "config.h"
26#include "system.h"
26#include <string.h> 27#include <string.h>
27#include "playback.h" 28#include "playback.h"
28#include "codec_thread.h" 29#include "codec_thread.h"
@@ -92,6 +93,10 @@ static enum filling_state {
92 STATE_FULL, /* can't add any more tracks */ 93 STATE_FULL, /* can't add any more tracks */
93 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */ 94 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */
94 STATE_FINISHED, /* all remaining tracks are fully buffered */ 95 STATE_FINISHED, /* all remaining tracks are fully buffered */
96 STATE_ENDING, /* audio playback is ending */
97#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
98 STATE_USB, /* USB mode, ignore most messages */
99#endif
95} filling; 100} filling;
96 101
97/* As defined in plugins/lib/xxx2wav.h */ 102/* As defined in plugins/lib/xxx2wav.h */
@@ -108,7 +113,6 @@ static bool audio_thread_ready SHAREDBSS_ATTR = false;
108/* Main state control */ 113/* Main state control */
109static volatile bool playing SHAREDBSS_ATTR = false;/* Is audio playing? (A) */ 114static volatile bool playing SHAREDBSS_ATTR = false;/* Is audio playing? (A) */
110static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */ 115static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */
111extern volatile bool audio_codec_loaded; /* Codec loaded? (C/A-) */
112 116
113/* Ring buffer where compressed audio and codecs are loaded */ 117/* Ring buffer where compressed audio and codecs are loaded */
114static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */ 118static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
@@ -186,7 +190,7 @@ static int last_peek_offset = 0;
186static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/ 190static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
187 191
188/* Track change controls */ 192/* Track change controls */
189bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */ 193static bool automatic_skip = false; /* Who initiated in-progress skip? (A) */
190extern bool track_transition; /* Are we in a track transition? */ 194extern bool track_transition; /* Are we in a track transition? */
191static bool dir_skip = false; /* Is a directory skip pending? (A) */ 195static bool dir_skip = false; /* Is a directory skip pending? (A) */
192static bool new_playlist = false; /* Are we starting a new playlist? (A) */ 196static bool new_playlist = false; /* Are we starting a new playlist? (A) */
@@ -208,7 +212,6 @@ static size_t buffer_margin = 5; /* Buffer margin aka anti-skip buffer (A/C-) *
208 212
209/* Event queues */ 213/* Event queues */
210struct event_queue audio_queue SHAREDBSS_ATTR; 214struct event_queue audio_queue SHAREDBSS_ATTR;
211struct event_queue codec_queue SHAREDBSS_ATTR;
212static struct event_queue pcmbuf_queue SHAREDBSS_ATTR; 215static struct event_queue pcmbuf_queue SHAREDBSS_ATTR;
213 216
214extern struct codec_api ci; 217extern struct codec_api ci;
@@ -241,15 +244,8 @@ static void audio_stop_playback(void);
241void audio_pcmbuf_position_callback(unsigned int time) 244void audio_pcmbuf_position_callback(unsigned int time)
242{ 245{
243 time += othertrack_id3->elapsed; 246 time += othertrack_id3->elapsed;
244 247 othertrack_id3->elapsed = (time >= othertrack_id3->length)
245 if (time >= othertrack_id3->length) 248 ? othertrack_id3->length : time;
246 {
247 /* we just played the end of the track, so stop this callback */
248 track_transition = false;
249 othertrack_id3->elapsed = othertrack_id3->length;
250 }
251 else
252 othertrack_id3->elapsed = time;
253} 249}
254 250
255/* Post message from pcmbuf that the end of the previous track 251/* Post message from pcmbuf that the end of the previous track
@@ -483,22 +479,8 @@ unsigned char *audio_get_recording_buffer(size_t *buffer_size)
483bool audio_load_encoder(int afmt) 479bool audio_load_encoder(int afmt)
484{ 480{
485#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 481#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
486 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER); 482 LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: %d", afmt);
487 if (!enc_fn) 483 return queue_send(&audio_queue, Q_AUDIO_LOAD_ENCODER, afmt) > 0;
488 return false;
489
490 audio_remove_encoder();
491 ci.enc_codec_loaded = 0; /* clear any previous error condition */
492
493 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
494 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
495
496 while (ci.enc_codec_loaded == 0)
497 yield();
498
499 logf("codec loaded: %d", ci.enc_codec_loaded);
500
501 return ci.enc_codec_loaded > 0;
502#else 484#else
503 (void)afmt; 485 (void)afmt;
504 return true; 486 return true;
@@ -508,13 +490,8 @@ bool audio_load_encoder(int afmt)
508void audio_remove_encoder(void) 490void audio_remove_encoder(void)
509{ 491{
510#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 492#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
511 /* force encoder codec unload (if currently loaded) */ 493 LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: NULL");
512 if (ci.enc_codec_loaded <= 0) 494 queue_send(&audio_queue, Q_AUDIO_LOAD_ENCODER, AFMT_UNKNOWN);
513 return;
514
515 ci.stop_encoder = true;
516 while (ci.enc_codec_loaded > 0)
517 yield();
518#endif 495#endif
519} /* audio_remove_encoder */ 496} /* audio_remove_encoder */
520 497
@@ -833,6 +810,11 @@ int audio_status(void)
833 return ret; 810 return ret;
834} 811}
835 812
813bool audio_automatic_skip(void)
814{
815 return automatic_skip;
816}
817
836int audio_get_file_pos(void) 818int audio_get_file_pos(void)
837{ 819{
838 return 0; 820 return 0;
@@ -952,7 +934,7 @@ static void buffering_handle_finished_callback(void *data)
952 int next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK; 934 int next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK;
953 /* The metadata handle for the last loaded track has been buffered. 935 /* The metadata handle for the last loaded track has been buffered.
954 We can ask the audio thread to load the rest of the track's data. */ 936 We can ask the audio thread to load the rest of the track's data. */
955 LOGFQUEUE("audio >| audio Q_AUDIO_FINISH_LOAD"); 937 LOGFQUEUE("audio > audio Q_AUDIO_FINISH_LOAD");
956 queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0); 938 queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0);
957 if (tracks[next_idx].id3_hid == hid) 939 if (tracks[next_idx].id3_hid == hid)
958 send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL); 940 send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL);
@@ -1101,9 +1083,7 @@ static bool audio_loadcodec(bool start_play)
1101 ci.id3 = thistrack_id3; 1083 ci.id3 = thistrack_id3;
1102 ci.taginfo_ready = &CUR_TI->taginfo_ready; 1084 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1103 ci.curpos = 0; 1085 ci.curpos = 0;
1104 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); 1086 return codec_load(-1, id3->codectype);
1105 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1106 return true;
1107 } 1087 }
1108 else 1088 else
1109 { 1089 {
@@ -1115,15 +1095,20 @@ static bool audio_loadcodec(bool start_play)
1115 id3 = bufgetid3(tracks[track_widx].id3_hid); 1095 id3 = bufgetid3(tracks[track_widx].id3_hid);
1116 prev_id3 = bufgetid3(tracks[prev_track].id3_hid); 1096 prev_id3 = bufgetid3(tracks[prev_track].id3_hid);
1117 1097
1118 /* If the previous codec is the same as this one, there is no need 1098 /* If the previous codec is the same as this one and the current
1119 * to put another copy of it on the file buffer */ 1099 * one is the correct one, there is no need to put another copy of
1120 if (id3 && prev_id3 && 1100 * it on the file buffer */
1121 get_codec_base_type(id3->codectype) == 1101 if (id3 && prev_id3)
1122 get_codec_base_type(prev_id3->codectype)
1123 && audio_codec_loaded)
1124 { 1102 {
1125 logf("Reusing prev. codec"); 1103 int codt = get_codec_base_type(id3->codectype);
1126 return true; 1104 int prev_codt = get_codec_base_type(prev_id3->codectype);
1105 int cod_loaded = get_codec_base_type(codec_loaded());
1106
1107 if (codt == prev_codt && codt == cod_loaded)
1108 {
1109 logf("Reusing prev. codec");
1110 return true;
1111 }
1127 } 1112 }
1128 } 1113 }
1129 } 1114 }
@@ -1138,7 +1123,7 @@ static bool audio_loadcodec(bool start_play)
1138 if (hid < 0 && hid != ERR_UNSUPPORTED_TYPE) 1123 if (hid < 0 && hid != ERR_UNSUPPORTED_TYPE)
1139 return false; 1124 return false;
1140 1125
1141 if (hid > 0) 1126 if (hid >= 0)
1142 logf("Loaded codec"); 1127 logf("Loaded codec");
1143 else 1128 else
1144 logf("Buffering codec unsupported, load later from disk"); 1129 logf("Buffering codec unsupported, load later from disk");
@@ -1562,22 +1547,54 @@ static void audio_rebuffer(void)
1562 1547
1563/* Called on request from the codec to get a new track. This is the codec part 1548/* Called on request from the codec to get a new track. This is the codec part
1564 of the track transition. */ 1549 of the track transition. */
1565static int audio_check_new_track(void) 1550static void audio_last_track(bool automatic)
1566{ 1551{
1567 int track_count = audio_track_count(); 1552 if (automatic)
1568 int old_track_ridx = track_ridx; 1553 {
1554 ci.new_track = 0;
1555 automatic_skip = false;
1556
1557 if (filling != STATE_ENDING)
1558 {
1559 /* Monitor remaining PCM before stopping */
1560 filling = STATE_ENDING;
1561 pcmbuf_monitor_track_change(true);
1562 }
1563
1564 codec_stop();
1565 }
1566 else
1567 {
1568 audio_stop_playback();
1569 }
1570}
1571
1572static void audio_check_new_track(void)
1573{
1574 int track_count;
1575 int old_track_ridx;
1569 int i, idx; 1576 int i, idx;
1570 bool forward; 1577 bool forward;
1571 struct mp3entry *temp = thistrack_id3; 1578 struct mp3entry *temp;
1579
1580 if (ci.new_track == 0)
1581 {
1582 ci.new_track++;
1583 automatic_skip = true;
1584 }
1585
1586 track_count = audio_track_count();
1587 old_track_ridx = track_ridx;
1572 1588
1573 /* Now it's good time to send track finish events. */ 1589 /* Now it's good time to send track finish events. */
1574 send_event(PLAYBACK_EVENT_TRACK_FINISH, thistrack_id3); 1590 send_event(PLAYBACK_EVENT_TRACK_FINISH, thistrack_id3);
1575 /* swap the mp3entry pointers */ 1591 /* swap the mp3entry pointers */
1592 temp = thistrack_id3;
1576 thistrack_id3 = othertrack_id3; 1593 thistrack_id3 = othertrack_id3;
1577 othertrack_id3 = temp; 1594 othertrack_id3 = temp;
1578 ci.id3 = thistrack_id3; 1595 ci.id3 = thistrack_id3;
1579 memset(thistrack_id3, 0, sizeof(struct mp3entry)); 1596 memset(thistrack_id3, 0, sizeof(struct mp3entry));
1580 1597
1581 if (dir_skip) 1598 if (dir_skip)
1582 { 1599 {
1583 dir_skip = false; 1600 dir_skip = false;
@@ -1600,8 +1617,8 @@ static int audio_check_new_track(void)
1600 { 1617 {
1601 if (ci.new_track >= 0) 1618 if (ci.new_track >= 0)
1602 { 1619 {
1603 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED"); 1620 audio_last_track(true);
1604 return Q_CODEC_REQUEST_FAILED; 1621 return;
1605 } 1622 }
1606 ci.new_track++; 1623 ci.new_track++;
1607 } 1624 }
@@ -1612,8 +1629,9 @@ static int audio_check_new_track(void)
1612 1629
1613 if (playlist_next(ci.new_track) < 0) 1630 if (playlist_next(ci.new_track) < 0)
1614 { 1631 {
1615 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED"); 1632 /* End of list */
1616 return Q_CODEC_REQUEST_FAILED; 1633 audio_last_track(automatic_skip);
1634 return;
1617 } 1635 }
1618 1636
1619 if (new_playlist) 1637 if (new_playlist)
@@ -1646,7 +1664,6 @@ static int audio_check_new_track(void)
1646 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK; 1664 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
1647 buf_set_base_handle(CUR_TI->audio_hid); 1665 buf_set_base_handle(CUR_TI->audio_hid);
1648 1666
1649
1650 if (automatic_skip) 1667 if (automatic_skip)
1651 { 1668 {
1652 wps_offset = -ci.new_track; 1669 wps_offset = -ci.new_track;
@@ -1707,8 +1724,23 @@ static int audio_check_new_track(void)
1707 1724
1708skip_done: 1725skip_done:
1709 audio_update_trackinfo(); 1726 audio_update_trackinfo();
1710 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE"); 1727 pcmbuf_start_track_change(automatic_skip);
1711 return Q_CODEC_REQUEST_COMPLETE; 1728
1729 if (get_codec_base_type(codec_loaded()) ==
1730 get_codec_base_type(thistrack_id3->codectype))
1731 {
1732 /* codec is the same base type */
1733 logf("New track loaded");
1734 codec_ack_msg(Q_CODEC_REQUEST_COMPLETE, false);
1735 }
1736 else
1737 {
1738 /* a codec change is required */
1739 logf("New codec: %d/%d", thistrack_id3->codectype, codec_loaded());
1740 codec_ack_msg(Q_CODEC_REQUEST_COMPLETE, true);
1741 codec_load(tracks[track_ridx].codec_hid, thistrack_id3->codectype);
1742 tracks[track_ridx].codec_hid = -1; /* Codec thread will close it */
1743 }
1712} 1744}
1713 1745
1714unsigned long audio_prev_elapsed(void) 1746unsigned long audio_prev_elapsed(void)
@@ -1721,25 +1753,26 @@ void audio_set_prev_elapsed(unsigned long setting)
1721 prev_track_elapsed = setting; 1753 prev_track_elapsed = setting;
1722} 1754}
1723 1755
1756/* Stop the codec and reset the PCM buffer */
1724static void audio_stop_codec_flush(void) 1757static void audio_stop_codec_flush(void)
1725{ 1758{
1726 ci.stop_codec = true; 1759 bool pcm_playing;
1760
1727 pcmbuf_pause(true); 1761 pcmbuf_pause(true);
1728 1762
1729 while (audio_codec_loaded) 1763 codec_stop();
1730 yield();
1731 1764
1732 /* If the audio codec is not loaded any more, and the audio is still 1765 pcm_play_lock();
1733 * playing, it is now and _only_ now safe to call this function from the 1766
1734 * audio thread */ 1767 pcm_playing = pcm_is_playing();
1735 if (pcm_is_playing()) 1768
1736 { 1769 pcmbuf_play_stop();
1737 pcmbuf_play_stop(); 1770 queue_clear(&pcmbuf_queue);
1738 pcm_play_lock(); 1771
1739 queue_clear(&pcmbuf_queue); 1772 if (pcm_playing)
1740 pcm_play_unlock(); 1773 pcmbuf_pause(paused);
1741 } 1774
1742 pcmbuf_pause(paused); 1775 pcm_play_unlock();
1743} 1776}
1744 1777
1745static void audio_stop_playback(void) 1778static void audio_stop_playback(void)
@@ -1750,12 +1783,7 @@ static void audio_stop_playback(void)
1750 struct mp3entry *id3 = NULL; 1783 struct mp3entry *id3 = NULL;
1751 1784
1752 if (!ci.stop_codec) 1785 if (!ci.stop_codec)
1753 {
1754 /* Set this early, the outside code yields and may allow the codec
1755 to try to wait for a reply on a buffer wait */
1756 ci.stop_codec = true;
1757 id3 = audio_current_track(); 1786 id3 = audio_current_track();
1758 }
1759 1787
1760 /* Save the current playing spot, or NULL if the playlist has ended */ 1788 /* Save the current playing spot, or NULL if the playlist has ended */
1761 playlist_update_resume_info(id3); 1789 playlist_update_resume_info(id3);
@@ -1797,7 +1825,6 @@ static void audio_play_start(size_t offset)
1797 audio_set_output_source(AUDIO_SRC_PLAYBACK); 1825 audio_set_output_source(AUDIO_SRC_PLAYBACK);
1798#endif 1826#endif
1799 1827
1800 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
1801 paused = false; 1828 paused = false;
1802 audio_stop_codec_flush(); 1829 audio_stop_codec_flush();
1803 1830
@@ -1853,6 +1880,11 @@ static void audio_new_playlist(void)
1853{ 1880{
1854 /* Prepare to start a new fill from the beginning of the playlist */ 1881 /* Prepare to start a new fill from the beginning of the playlist */
1855 last_peek_offset = -1; 1882 last_peek_offset = -1;
1883
1884 /* Signal the codec to initiate a track change forward */
1885 new_playlist = true;
1886 ci.new_track = 1;
1887
1856 if (audio_have_tracks()) 1888 if (audio_have_tracks())
1857 { 1889 {
1858 if (paused) 1890 if (paused)
@@ -1866,10 +1898,6 @@ static void audio_new_playlist(void)
1866 CUR_TI->taginfo_ready = false; 1898 CUR_TI->taginfo_ready = false;
1867 } 1899 }
1868 1900
1869 /* Signal the codec to initiate a track change forward */
1870 new_playlist = true;
1871 ci.new_track = 1;
1872
1873 /* Officially playing */ 1901 /* Officially playing */
1874 queue_reply(&audio_queue, 1); 1902 queue_reply(&audio_queue, 1);
1875 1903
@@ -1919,6 +1947,59 @@ static void audio_finalise_track_change(void)
1919 playlist_update_resume_info(audio_current_track()); 1947 playlist_update_resume_info(audio_current_track());
1920} 1948}
1921 1949
1950static void audio_seek_complete(void)
1951{
1952 logf("audio_seek_complete");
1953
1954 if (!playing)
1955 return;
1956
1957 /* If seeking-while-playing, pcm_is_paused() is true.
1958 * If seeking-while-paused, audio_status PAUSE is true.
1959 * A seamless seek skips this section. */
1960 ci.seek_time = 0;
1961
1962 pcm_play_lock();
1963
1964 if (pcm_is_paused() || paused)
1965 {
1966 /* Clear the buffer */
1967 pcmbuf_play_stop();
1968
1969 /* If seeking-while-playing, resume PCM playback */
1970 if (!paused)
1971 pcmbuf_pause(false);
1972 }
1973
1974 pcm_play_unlock();
1975}
1976
1977static void audio_codec_status_message(long reason, int status)
1978{
1979 /* TODO: Push the errors up to the normal UI somewhere */
1980 switch (reason)
1981 {
1982 case Q_CODEC_LOAD_DISK:
1983 case Q_CODEC_LOAD:
1984 if (!playing)
1985 return;
1986
1987 if (status < 0)
1988 {
1989 splash(HZ*2, "Codec failure");
1990 audio_check_new_track();
1991 }
1992 break;
1993
1994#ifdef AUDIO_HAVE_RECORDING
1995 case Q_ENCODER_LOAD_DISK:
1996 if (status < 0)
1997 splash(HZ*2, "Encoder failure");
1998 break;
1999#endif /* AUDIO_HAVE_RECORDING */
2000 }
2001}
2002
1922/* 2003/*
1923 * Layout audio buffer as follows - iram buffer depends on target: 2004 * Layout audio buffer as follows - iram buffer depends on target:
1924 * [|SWAP:iram][|TALK]|FILE|GUARD|PCM|[SWAP:dram[|iram]|] 2005 * [|SWAP:iram][|TALK]|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
@@ -1986,14 +2067,42 @@ static void audio_thread(void)
1986 2067
1987 while (1) 2068 while (1)
1988 { 2069 {
1989 if (filling != STATE_FILLING && filling != STATE_IDLE) { 2070 switch (filling) {
1990 /* End of buffering, let's calculate the watermark and unboost */ 2071 case STATE_IDLE:
1991 set_filebuf_watermark(); 2072 queue_wait(&audio_queue, &ev);
1992 cancel_cpu_boost(); 2073 break;
1993 }
1994 2074
1995 if (!pcmbuf_queue_scan(&ev)) 2075#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1996 queue_wait_w_tmo(&audio_queue, &ev, HZ/2); 2076 case STATE_USB:
2077 queue_wait(&audio_queue, &ev);
2078 switch (ev.id) {
2079#ifdef AUDIO_HAVE_RECORDING
2080 /* Must monitor the encoder message for recording so it can
2081 remove it if we process the insertion before it does. It
2082 cannot simply be removed from under recording however. */
2083 case Q_AUDIO_LOAD_ENCODER:
2084 break;
2085#endif
2086 case SYS_USB_DISCONNECTED:
2087 filling = STATE_IDLE;
2088 default:
2089 continue;
2090 }
2091 break;
2092#endif /* CONFIG_PLATFORM */
2093
2094 default:
2095 /* End of buffering, let's calculate the watermark and
2096 unboost */
2097 set_filebuf_watermark();
2098 cancel_cpu_boost();
2099 /* Fall-through */
2100 case STATE_FILLING:
2101 case STATE_ENDING:
2102 if (!pcmbuf_queue_scan(&ev))
2103 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2104 break;
2105 }
1997 2106
1998 switch (ev.id) { 2107 switch (ev.id) {
1999 2108
@@ -2059,6 +2168,14 @@ static void audio_thread(void)
2059 if (!playing) 2168 if (!playing)
2060 break; 2169 break;
2061 2170
2171 if (filling == STATE_ENDING)
2172 {
2173 /* Temp workaround: There is no codec available */
2174 if (!paused)
2175 pcmbuf_pause(false);
2176 break;
2177 }
2178
2062 if ((long)ev.data == 0) 2179 if ((long)ev.data == 0)
2063 { 2180 {
2064 /* About to restart the track - send track finish 2181 /* About to restart the track - send track finish
@@ -2079,7 +2196,7 @@ static void audio_thread(void)
2079 2196
2080 case Q_AUDIO_CHECK_NEW_TRACK: 2197 case Q_AUDIO_CHECK_NEW_TRACK:
2081 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK"); 2198 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2082 queue_reply(&audio_queue, audio_check_new_track()); 2199 audio_check_new_track();
2083 break; 2200 break;
2084 2201
2085 case Q_AUDIO_DIR_SKIP: 2202 case Q_AUDIO_DIR_SKIP:
@@ -2095,8 +2212,29 @@ static void audio_thread(void)
2095 case Q_AUDIO_TRACK_CHANGED: 2212 case Q_AUDIO_TRACK_CHANGED:
2096 /* PCM track change done */ 2213 /* PCM track change done */
2097 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED"); 2214 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2098 audio_finalise_track_change(); 2215 if (filling != STATE_ENDING)
2216 audio_finalise_track_change();
2217 else if (playing)
2218 audio_stop_playback();
2219 break;
2220
2221 case Q_AUDIO_SEEK_COMPLETE:
2222 /* Codec seek done */
2223 LOGFQUEUE("audio < Q_AUDIO_SEEK_COMPLETE");
2224 audio_seek_complete();
2225 codec_ack_msg(Q_AUDIO_SEEK_COMPLETE, false);
2099 break; 2226 break;
2227
2228 case Q_CODEC_LOAD:
2229 case Q_CODEC_LOAD_DISK:
2230#ifdef AUDIO_HAVE_RECORDING
2231 case Q_ENCODER_LOAD_DISK:
2232#endif
2233 /* These are received when a codec has finished normally or
2234 upon a codec error */
2235 audio_codec_status_message(ev.id, ev.data);
2236 break;
2237
2100#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 2238#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
2101 case SYS_USB_CONNECTED: 2239 case SYS_USB_CONNECTED:
2102 LOGFQUEUE("audio < SYS_USB_CONNECTED"); 2240 LOGFQUEUE("audio < SYS_USB_CONNECTED");
@@ -2105,16 +2243,25 @@ static void audio_thread(void)
2105#ifdef PLAYBACK_VOICE 2243#ifdef PLAYBACK_VOICE
2106 voice_stop(); 2244 voice_stop();
2107#endif 2245#endif
2246 filling = STATE_USB;
2108 usb_acknowledge(SYS_USB_CONNECTED_ACK); 2247 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2109 usb_wait_for_disconnect(&audio_queue); 2248 break;
2249#endif
2250
2251#ifdef AUDIO_HAVE_RECORDING
2252 case Q_AUDIO_LOAD_ENCODER:
2253 if (playing)
2254 audio_stop_playback();
2255 else
2256 codec_stop(); /* If encoder still loaded, stop it */
2110 2257
2111 /* Mark all entries null. */ 2258 if (ev.data == AFMT_UNKNOWN)
2112 audio_clear_track_entries(); 2259 break;
2113 2260
2114 /* release tracks to make sure all handles are closed */ 2261 queue_reply(&audio_queue,
2115 audio_release_tracks(); 2262 codec_load(-1, ev.data | CODEC_TYPE_ENCODER));
2116 break; 2263 break;
2117#endif 2264#endif /* AUDIO_HAVE_RECORDING */
2118 2265
2119 case SYS_TIMEOUT: 2266 case SYS_TIMEOUT:
2120 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT"); 2267 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
@@ -2147,7 +2294,6 @@ void audio_init(void)
2147 to send messages. Thread creation will be delayed however so nothing 2294 to send messages. Thread creation will be delayed however so nothing
2148 starts running until ready if something yields such as talk_init. */ 2295 starts running until ready if something yields such as talk_init. */
2149 queue_init(&audio_queue, true); 2296 queue_init(&audio_queue, true);
2150 queue_init(&codec_queue, false);
2151 queue_init(&pcmbuf_queue, false); 2297 queue_init(&pcmbuf_queue, false);
2152 2298
2153 pcm_init(); 2299 pcm_init();
@@ -2227,7 +2373,7 @@ void audio_init(void)
2227#ifdef PLAYBACK_VOICE 2373#ifdef PLAYBACK_VOICE
2228 voice_thread_resume(); 2374 voice_thread_resume();
2229#endif 2375#endif
2230 thread_thaw(codec_thread_id); 2376 codec_thread_resume();
2231 thread_thaw(audio_thread_id); 2377 thread_thaw(audio_thread_id);
2232 2378
2233} /* audio_init */ 2379} /* audio_init */
@@ -2246,8 +2392,3 @@ int get_audio_hid()
2246{ 2392{
2247 return CUR_TI->audio_hid; 2393 return CUR_TI->audio_hid;
2248} 2394}
2249
2250int *get_codec_hid()
2251{
2252 return &tracks[track_ridx].codec_hid;
2253}
diff --git a/apps/playback.h b/apps/playback.h
index 475e2fb662..76c394603f 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -81,9 +81,9 @@ size_t audio_get_filebuflen(void);
81void audio_pcmbuf_position_callback(unsigned int time) ICODE_ATTR; 81void audio_pcmbuf_position_callback(unsigned int time) ICODE_ATTR;
82void audio_post_track_change(bool pcmbuf); 82void audio_post_track_change(bool pcmbuf);
83int get_audio_hid(void); 83int get_audio_hid(void);
84int *get_codec_hid(void);
85void audio_set_prev_elapsed(unsigned long setting); 84void audio_set_prev_elapsed(unsigned long setting);
86bool audio_buffer_state_trashed(void); 85bool audio_buffer_state_trashed(void);
86bool audio_automatic_skip(void);
87 87
88/* Define one constant that includes recording related functionality */ 88/* Define one constant that includes recording related functionality */
89#if defined(HAVE_RECORDING) && !defined(SIMULATOR) 89#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
@@ -101,6 +101,7 @@ enum {
101 Q_AUDIO_CHECK_NEW_TRACK, 101 Q_AUDIO_CHECK_NEW_TRACK,
102 Q_AUDIO_FLUSH, 102 Q_AUDIO_FLUSH,
103 Q_AUDIO_TRACK_CHANGED, 103 Q_AUDIO_TRACK_CHANGED,
104 Q_AUDIO_SEEK_COMPLETE,
104 Q_AUDIO_DIR_SKIP, 105 Q_AUDIO_DIR_SKIP,
105 Q_AUDIO_POSTINIT, 106 Q_AUDIO_POSTINIT,
106 Q_AUDIO_FILL_BUFFER, 107 Q_AUDIO_FILL_BUFFER,
@@ -112,11 +113,13 @@ enum {
112 Q_CODEC_LOAD_DISK, 113 Q_CODEC_LOAD_DISK,
113 114
114#ifdef AUDIO_HAVE_RECORDING 115#ifdef AUDIO_HAVE_RECORDING
116 Q_AUDIO_LOAD_ENCODER,
115 Q_ENCODER_LOAD_DISK, 117 Q_ENCODER_LOAD_DISK,
116 Q_ENCODER_RECORD, 118 Q_ENCODER_RECORD,
117#endif 119#endif
118 120
119 Q_CODEC_DO_CALLBACK, 121 Q_CODEC_DO_CALLBACK,
122 Q_CODEC_ACK,
120}; 123};
121 124
122#endif 125#endif
diff --git a/apps/plugin.c b/apps/plugin.c
index 690aee9bf3..192488ef81 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -691,6 +691,8 @@ static const struct plugin_api rockbox_api = {
691#if CONFIG_CODEC == SWCODEC 691#if CONFIG_CODEC == SWCODEC
692 codec_thread_do_callback, 692 codec_thread_do_callback,
693 codec_load_file, 693 codec_load_file,
694 codec_begin,
695 codec_close,
694 get_codec_filename, 696 get_codec_filename,
695 find_array_ptr, 697 find_array_ptr,
696 remove_array_ptr, 698 remove_array_ptr,
diff --git a/apps/plugin.h b/apps/plugin.h
index 77dedc539a..8c2d458c57 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -145,12 +145,12 @@ void* plugin_get_buffer(size_t *buffer_size);
145#define PLUGIN_MAGIC 0x526F634B /* RocK */ 145#define PLUGIN_MAGIC 0x526F634B /* RocK */
146 146
147/* increase this every time the api struct changes */ 147/* increase this every time the api struct changes */
148#define PLUGIN_API_VERSION 198 148#define PLUGIN_API_VERSION 199
149 149
150/* update this to latest version if a change to the api struct breaks 150/* update this to latest version if a change to the api struct breaks
151 backwards compatibility (and please take the opportunity to sort in any 151 backwards compatibility (and please take the opportunity to sort in any
152 new function which are "waiting" at the end of the function table) */ 152 new function which are "waiting" at the end of the function table) */
153#define PLUGIN_MIN_API_VERSION 198 153#define PLUGIN_MIN_API_VERSION 199
154 154
155/* plugin return codes */ 155/* plugin return codes */
156/* internal returns start at 0x100 to make exit(1..255) work */ 156/* internal returns start at 0x100 to make exit(1..255) work */
@@ -798,7 +798,9 @@ struct plugin_api {
798#if CONFIG_CODEC == SWCODEC 798#if CONFIG_CODEC == SWCODEC
799 void (*codec_thread_do_callback)(void (*fn)(void), 799 void (*codec_thread_do_callback)(void (*fn)(void),
800 unsigned int *audio_thread_id); 800 unsigned int *audio_thread_id);
801 int (*codec_load_file)(const char* codec, struct codec_api *api); 801 void * (*codec_load_file)(const char* codec, struct codec_api *api);
802 int (*codec_begin)(void *handle);
803 void (*codec_close)(void *handle);
802 const char *(*get_codec_filename)(int cod_spec); 804 const char *(*get_codec_filename)(int cod_spec);
803 void ** (*find_array_ptr)(void **arr, void *ptr); 805 void ** (*find_array_ptr)(void **arr, void *ptr);
804 int (*remove_array_ptr)(void **arr, void *ptr); 806 int (*remove_array_ptr)(void **arr, void *ptr);
diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c
index 9b00fdbb95..30757381bf 100644
--- a/apps/plugins/test_codec.c
+++ b/apps/plugins/test_codec.c
@@ -516,13 +516,6 @@ static bool request_next_track(void)
516} 516}
517 517
518 518
519/* Free the buffer area of the current codec after its loaded */
520static void discard_codec(void)
521{
522 /* ??? */
523}
524
525
526static void set_offset(size_t value) 519static void set_offset(size_t value)
527{ 520{
528 /* ??? */ 521 /* ??? */
@@ -576,7 +569,6 @@ static void init_ci(void)
576 ci.seek_buffer = seek_buffer; 569 ci.seek_buffer = seek_buffer;
577 ci.seek_complete = seek_complete; 570 ci.seek_complete = seek_complete;
578 ci.request_next_track = request_next_track; 571 ci.request_next_track = request_next_track;
579 ci.discard_codec = discard_codec;
580 ci.set_offset = set_offset; 572 ci.set_offset = set_offset;
581 ci.configure = configure; 573 ci.configure = configure;
582 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP, 574 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
@@ -636,12 +628,19 @@ static void init_ci(void)
636static void codec_thread(void) 628static void codec_thread(void)
637{ 629{
638 const char* codecname; 630 const char* codecname;
639 int res; 631 void *handle;
632 int res = CODEC_ERROR;
640 633
641 codecname = rb->get_codec_filename(track.id3.codectype); 634 codecname = rb->get_codec_filename(track.id3.codectype);
642 635
643 /* Load the codec and start decoding. */ 636 /* Load the codec and start decoding. */
644 res = rb->codec_load_file(codecname,&ci); 637 handle = rb->codec_load_file(codecname,&ci);
638
639 if (handle != NULL)
640 {
641 res = rb->codec_begin(handle);
642 rb->codec_close(handle);
643 }
645 644
646 /* Signal to the main thread that we are done */ 645 /* Signal to the main thread that we are done */
647 endtick = *rb->current_tick - rebuffertick; 646 endtick = *rb->current_tick - rebuffertick;
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c
index 6ecb75f608..8c9207f232 100644
--- a/apps/recorder/pcm_record.c
+++ b/apps/recorder/pcm_record.c
@@ -31,6 +31,7 @@
31#include "usb.h" 31#include "usb.h"
32#include "buffer.h" 32#include "buffer.h"
33#include "general.h" 33#include "general.h"
34#include "codec_thread.h"
34#include "audio.h" 35#include "audio.h"
35#include "sound.h" 36#include "sound.h"
36#include "metadata.h" 37#include "metadata.h"
@@ -41,8 +42,6 @@
41 42
42/***************************************************************************/ 43/***************************************************************************/
43 44
44extern unsigned int codec_thread_id;
45
46/** General recording state **/ 45/** General recording state **/
47static bool is_recording; /* We are recording */ 46static bool is_recording; /* We are recording */
48static bool is_paused; /* We have paused */ 47static bool is_paused; /* We have paused */
@@ -900,8 +899,8 @@ static void pcmrec_flush(unsigned flush_num)
900 num >= flood_watermark ? "num" : "time"); 899 num >= flood_watermark ? "num" : "time");
901 prio_pcmrec = thread_set_priority(THREAD_ID_CURRENT, 900 prio_pcmrec = thread_set_priority(THREAD_ID_CURRENT,
902 thread_get_priority(THREAD_ID_CURRENT) - 4); 901 thread_get_priority(THREAD_ID_CURRENT) - 4);
903 prio_codec = thread_set_priority(codec_thread_id, 902 prio_codec = codec_thread_set_priority(
904 thread_get_priority(codec_thread_id) - 4); 903 codec_thread_get_priority() - 4);
905 } 904 }
906#endif 905#endif
907 906
@@ -952,7 +951,7 @@ static void pcmrec_flush(unsigned flush_num)
952 /* return to original priorities */ 951 /* return to original priorities */
953 logf("pcmrec: unboost priority"); 952 logf("pcmrec: unboost priority");
954 thread_set_priority(THREAD_ID_CURRENT, prio_pcmrec); 953 thread_set_priority(THREAD_ID_CURRENT, prio_pcmrec);
955 thread_set_priority(codec_thread_id, prio_codec); 954 codec_thread_set_priority(prio_codec);
956 } 955 }
957 956
958 last_flush_tick = current_tick; /* save tick when we left */ 957 last_flush_tick = current_tick; /* save tick when we left */
diff --git a/apps/tagtree.c b/apps/tagtree.c
index ecc9f44d4d..575ab221ac 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -52,6 +52,7 @@
52#include "appevents.h" 52#include "appevents.h"
53#include "storage.h" 53#include "storage.h"
54#include "dir.h" 54#include "dir.h"
55#include "playback.h"
55 56
56#define str_or_empty(x) (x ? x : "(NULL)") 57#define str_or_empty(x) (x ? x : "(NULL)")
57 58
@@ -170,10 +171,6 @@ static int current_entry_count;
170 171
171static struct tree_context *tc; 172static struct tree_context *tc;
172 173
173#if CONFIG_CODEC == SWCODEC
174extern bool automatic_skip; /* Who initiated in-progress skip? (C/A-) */
175#endif
176
177static int get_token_str(char *buf, int size) 174static int get_token_str(char *buf, int size)
178{ 175{
179 /* Find the start. */ 176 /* Find the start. */
@@ -726,7 +723,7 @@ static void tagtree_track_finish_event(void *data)
726 first 15 seconds. */ 723 first 15 seconds. */
727 if (id3->elapsed == 0 724 if (id3->elapsed == 0
728#if CONFIG_CODEC == SWCODEC /* HWCODEC doesn't have automatic_skip */ 725#if CONFIG_CODEC == SWCODEC /* HWCODEC doesn't have automatic_skip */
729 || (id3->elapsed < 15 * 1000 && !automatic_skip) 726 || (id3->elapsed < 15 * 1000 && !audio_automatic_skip())
730#endif 727#endif
731 ) 728 )
732 { 729 {
@@ -766,7 +763,7 @@ static void tagtree_track_finish_event(void *data)
766 if (global_settings.autoresume_enable) 763 if (global_settings.autoresume_enable)
767 { 764 {
768 unsigned long offset 765 unsigned long offset
769 = automatic_skip ? 0 : id3->offset; 766 = audio_automatic_skip() ? 0 : id3->offset;
770 767
771 tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset); 768 tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset);
772 769