diff options
-rw-r--r-- | apps/codec_thread.c | 454 | ||||
-rw-r--r-- | apps/codec_thread.h | 21 | ||||
-rw-r--r-- | apps/codecs.c | 57 | ||||
-rw-r--r-- | apps/codecs.h | 21 | ||||
-rw-r--r-- | apps/codecs/aiff_enc.c | 13 | ||||
-rw-r--r-- | apps/codecs/mp3_enc.c | 13 | ||||
-rw-r--r-- | apps/codecs/wav_enc.c | 13 | ||||
-rw-r--r-- | apps/codecs/wavpack_enc.c | 15 | ||||
-rw-r--r-- | apps/pcmbuf.c | 67 | ||||
-rw-r--r-- | apps/pcmbuf.h | 1 | ||||
-rw-r--r-- | apps/playback.c | 355 | ||||
-rw-r--r-- | apps/playback.h | 5 | ||||
-rw-r--r-- | apps/plugin.c | 2 | ||||
-rw-r--r-- | apps/plugin.h | 8 | ||||
-rw-r--r-- | apps/plugins/test_codec.c | 19 | ||||
-rw-r--r-- | apps/recorder/pcm_record.c | 9 | ||||
-rw-r--r-- | apps/tagtree.c | 9 |
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 */ |
70 | volatile bool audio_codec_loaded SHAREDBSS_ATTR = false; /* Codec loaded? (C/A-) */ | 70 | |
71 | /* Type of codec loaded? (C/A) */ | ||
72 | static int current_codectype SHAREDBSS_ATTR = AFMT_UNKNOWN; | ||
71 | 73 | ||
72 | extern struct mp3entry *thistrack_id3, /* the currently playing track */ | 74 | extern 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 */ |
77 | extern 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 | */ | ||
82 | static bool codec_requested_stop = false; | ||
83 | |||
84 | extern struct event_queue audio_queue SHAREDBSS_ATTR; | 79 | extern struct event_queue audio_queue SHAREDBSS_ATTR; |
85 | extern struct event_queue codec_queue SHAREDBSS_ATTR; | 80 | |
86 | 81 | ||
87 | extern struct codec_api ci; /* from codecs.c */ | 82 | extern struct codec_api ci; /* from codecs.c */ |
88 | 83 | ||
89 | /* Codec thread */ | 84 | /* Codec thread */ |
90 | unsigned int codec_thread_id; /* For modifying thread priority later. | 85 | static unsigned int codec_thread_id; /* For modifying thread priority later */ |
91 | Used by playback.c and pcmbuf.c */ | 86 | static struct event_queue codec_queue SHAREDBSS_ATTR; |
92 | static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR; | 87 | static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR; |
93 | static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] | 88 | static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] |
94 | IBSS_ATTR; | 89 | IBSS_ATTR; |
95 | static const char codec_thread_name[] = "codec"; | 90 | static const char codec_thread_name[] = "codec"; |
96 | 91 | ||
97 | /* function prototypes */ | 92 | /* static routines */ |
98 | static bool codec_load_next_track(void); | 93 | static void codec_queue_ack(intptr_t ackme) |
94 | { | ||
95 | queue_reply(&codec_queue, ackme); | ||
96 | } | ||
99 | 97 | ||
98 | static 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 | ||
361 | static void codec_seek_complete_callback(void) | 355 | static 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 | ||
381 | static 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 | ||
391 | static bool codec_request_next_track_callback(void) | 375 | static 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 | ||
420 | static void codec_configure_callback(int setting, intptr_t value) | 424 | static 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 | ||
449 | static 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 */ |
497 | static void codec_thread(void) | 453 | static 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 | ||
674 | void make_codec_thread(void) | 551 | void 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 | |||
563 | void codec_thread_resume(void) | ||
564 | { | ||
565 | thread_thaw(codec_thread_id); | ||
566 | } | ||
567 | |||
568 | bool is_codec_thread(void) | ||
569 | { | ||
570 | return thread_get_current() == codec_thread_id; | ||
571 | } | ||
572 | |||
573 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
574 | int codec_thread_get_priority(void) | ||
575 | { | ||
576 | return thread_get_priority(codec_thread_id); | ||
577 | } | ||
578 | |||
579 | int 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 */ | ||
586 | intptr_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 | |||
599 | bool 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 | |||
626 | void 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 | |||
634 | int 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 */ | ||
27 | int get_codec_base_type(int type); | 28 | int get_codec_base_type(int type); |
28 | const char *get_codec_filename(int cod_spec); | 29 | const char *get_codec_filename(int cod_spec); |
30 | |||
31 | /* codec thread */ | ||
32 | |||
33 | /* Audio MUST be stopped before requesting callback! */ | ||
29 | void codec_thread_do_callback(void (*fn)(void), | 34 | void codec_thread_do_callback(void (*fn)(void), |
30 | unsigned int *codec_thread_id); | 35 | unsigned int *codec_thread_id); |
36 | |||
31 | void codec_init_codec_api(void); | 37 | void codec_init_codec_api(void); |
32 | void make_codec_thread(void); | 38 | void make_codec_thread(void); |
33 | 39 | void codec_thread_resume(void); | |
40 | bool is_codec_thread(void); | ||
41 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
42 | int codec_thread_get_priority(void); | ||
43 | int codec_thread_set_priority(int priority); | ||
34 | #endif | 44 | #endif |
45 | |||
46 | /* codec commands - on audio thread only! */ | ||
47 | intptr_t codec_ack_msg(intptr_t data, bool stop_codec); | ||
48 | bool codec_load(int hid, int cod_spec); | ||
49 | void codec_stop(void); | ||
50 | int 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 | ||
181 | static int codec_load_ram(void *handle, struct codec_api *api) | 178 | static 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 | ||
226 | int codec_load_buf(unsigned int hid, struct codec_api *api) | 219 | void * 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 | ||
246 | int codec_load_file(const char *plugin, struct codec_api *api) | 239 | void * 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 | |||
256 | int 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 | |||
271 | void 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 */ |
86 | enum codec_status { | 86 | enum 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[]; | |||
283 | void codec_get_full_path(char *path, const char *codec_root_fn); | 278 | void 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) */ |
286 | int codec_load_buf(unsigned int hid, struct codec_api *api); | 281 | void * codec_load_buf(int hid, struct codec_api *api); |
287 | int codec_load_file(const char* codec, struct codec_api *api); | 282 | void * codec_load_file(const char* codec, struct codec_api *api); |
283 | int codec_begin(void *handle); | ||
284 | void codec_close(void *handle); | ||
288 | 285 | ||
289 | /* defined by the codec */ | 286 | /* defined by the codec */ |
290 | enum codec_status codec_start(void); | 287 | enum 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) | |||
363 | enum codec_status codec_main(void) | 363 | enum 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) | |||
349 | enum codec_status codec_main(void) | 349 | enum 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; | |||
86 | static size_t pcmbuffer_fillpos IDATA_ATTR; | 87 | static size_t pcmbuffer_fillpos IDATA_ATTR; |
87 | 88 | ||
88 | /* Gapless playback */ | 89 | /* Gapless playback */ |
89 | static bool end_of_track IDATA_ATTR; | 90 | static bool track_transition IDATA_ATTR; |
90 | bool 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; | |||
131 | static int codec_thread_priority = PRIORITY_PLAYBACK; | 131 | static int codec_thread_priority = PRIORITY_PLAYBACK; |
132 | #endif | 132 | #endif |
133 | 133 | ||
134 | extern 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 */ |
487 | void 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 | ||
491 | void pcmbuf_start_track_change(bool auto_skip) | 509 | void 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); | |||
32 | void pcmbuf_play_start(void); | 32 | void pcmbuf_play_start(void); |
33 | void pcmbuf_play_stop(void); | 33 | void pcmbuf_play_stop(void); |
34 | void pcmbuf_pause(bool pause); | 34 | void pcmbuf_pause(bool pause); |
35 | void pcmbuf_monitor_track_change(bool monitor); | ||
35 | void pcmbuf_start_track_change(bool manual_skip); | 36 | void 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 */ |
109 | static volatile bool playing SHAREDBSS_ATTR = false;/* Is audio playing? (A) */ | 114 | static volatile bool playing SHAREDBSS_ATTR = false;/* Is audio playing? (A) */ |
110 | static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */ | 115 | static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */ |
111 | extern 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 */ |
114 | static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */ | 118 | static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */ |
@@ -186,7 +190,7 @@ static int last_peek_offset = 0; | |||
186 | static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/ | 190 | static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/ |
187 | 191 | ||
188 | /* Track change controls */ | 192 | /* Track change controls */ |
189 | bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */ | 193 | static bool automatic_skip = false; /* Who initiated in-progress skip? (A) */ |
190 | extern bool track_transition; /* Are we in a track transition? */ | 194 | extern bool track_transition; /* Are we in a track transition? */ |
191 | static bool dir_skip = false; /* Is a directory skip pending? (A) */ | 195 | static bool dir_skip = false; /* Is a directory skip pending? (A) */ |
192 | static bool new_playlist = false; /* Are we starting a new playlist? (A) */ | 196 | static 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 */ |
210 | struct event_queue audio_queue SHAREDBSS_ATTR; | 214 | struct event_queue audio_queue SHAREDBSS_ATTR; |
211 | struct event_queue codec_queue SHAREDBSS_ATTR; | ||
212 | static struct event_queue pcmbuf_queue SHAREDBSS_ATTR; | 215 | static struct event_queue pcmbuf_queue SHAREDBSS_ATTR; |
213 | 216 | ||
214 | extern struct codec_api ci; | 217 | extern struct codec_api ci; |
@@ -241,15 +244,8 @@ static void audio_stop_playback(void); | |||
241 | void audio_pcmbuf_position_callback(unsigned int time) | 244 | void 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) | |||
483 | bool audio_load_encoder(int afmt) | 479 | bool 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) | |||
508 | void audio_remove_encoder(void) | 490 | void 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 | ||
813 | bool audio_automatic_skip(void) | ||
814 | { | ||
815 | return automatic_skip; | ||
816 | } | ||
817 | |||
836 | int audio_get_file_pos(void) | 818 | int 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. */ |
1565 | static int audio_check_new_track(void) | 1550 | static 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 | |||
1572 | static 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 | ||
1708 | skip_done: | 1725 | skip_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 | ||
1714 | unsigned long audio_prev_elapsed(void) | 1746 | unsigned 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 */ | ||
1724 | static void audio_stop_codec_flush(void) | 1757 | static 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 | ||
1745 | static void audio_stop_playback(void) | 1778 | static 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 | ||
1950 | static 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 | |||
1977 | static 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 | |||
2250 | int *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); | |||
81 | void audio_pcmbuf_position_callback(unsigned int time) ICODE_ATTR; | 81 | void audio_pcmbuf_position_callback(unsigned int time) ICODE_ATTR; |
82 | void audio_post_track_change(bool pcmbuf); | 82 | void audio_post_track_change(bool pcmbuf); |
83 | int get_audio_hid(void); | 83 | int get_audio_hid(void); |
84 | int *get_codec_hid(void); | ||
85 | void audio_set_prev_elapsed(unsigned long setting); | 84 | void audio_set_prev_elapsed(unsigned long setting); |
86 | bool audio_buffer_state_trashed(void); | 85 | bool audio_buffer_state_trashed(void); |
86 | bool 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 */ | ||
520 | static void discard_codec(void) | ||
521 | { | ||
522 | /* ??? */ | ||
523 | } | ||
524 | |||
525 | |||
526 | static void set_offset(size_t value) | 519 | static 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) | |||
636 | static void codec_thread(void) | 628 | static 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 | ||
44 | extern unsigned int codec_thread_id; | ||
45 | |||
46 | /** General recording state **/ | 45 | /** General recording state **/ |
47 | static bool is_recording; /* We are recording */ | 46 | static bool is_recording; /* We are recording */ |
48 | static bool is_paused; /* We have paused */ | 47 | static 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 | ||
171 | static struct tree_context *tc; | 172 | static struct tree_context *tc; |
172 | 173 | ||
173 | #if CONFIG_CODEC == SWCODEC | ||
174 | extern bool automatic_skip; /* Who initiated in-progress skip? (C/A-) */ | ||
175 | #endif | ||
176 | |||
177 | static int get_token_str(char *buf, int size) | 174 | static 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 | ||