diff options
Diffstat (limited to 'apps/codec_thread.c')
-rw-r--r-- | apps/codec_thread.c | 454 |
1 files changed, 204 insertions, 250 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 | } | ||