diff options
Diffstat (limited to 'apps/plugins/mpegplayer/audio_thread.c')
-rw-r--r-- | apps/plugins/mpegplayer/audio_thread.c | 93 |
1 files changed, 49 insertions, 44 deletions
diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c index 78d28e40c5..2bb766ad88 100644 --- a/apps/plugins/mpegplayer/audio_thread.c +++ b/apps/plugins/mpegplayer/audio_thread.c | |||
@@ -27,10 +27,13 @@ | |||
27 | struct pts_queue_slot; | 27 | struct pts_queue_slot; |
28 | struct audio_thread_data | 28 | struct audio_thread_data |
29 | { | 29 | { |
30 | struct queue_event ev; /* Our event queue to receive commands */ | 30 | struct queue_event ev; /* Our event queue to receive commands */ |
31 | int state; /* Thread state */ | 31 | int state; /* Thread state */ |
32 | int status; /* Media status (STREAM_PLAYING, etc.) */ | 32 | int status; /* Media status (STREAM_PLAYING, etc.) */ |
33 | int mad_errors; /* A count of the errors in each frame */ | 33 | int mad_errors; /* A count of the errors in each frame */ |
34 | unsigned samplerate; /* Current stream sample rate */ | ||
35 | int nchannels; /* Number of audio channels */ | ||
36 | struct dsp_config *dsp; /* The DSP we're using */ | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | /* The audio stack is stolen from the core codec thread (but not in uisim) */ | 39 | /* The audio stack is stolen from the core codec thread (but not in uisim) */ |
@@ -402,6 +405,8 @@ static void audio_thread_msg(struct audio_thread_data *td) | |||
402 | 405 | ||
403 | td->status = STREAM_STOPPED; | 406 | td->status = STREAM_STOPPED; |
404 | td->state = TSTATE_INIT; | 407 | td->state = TSTATE_INIT; |
408 | td->samplerate = 0; | ||
409 | td->nchannels = 0; | ||
405 | 410 | ||
406 | init_mad(); | 411 | init_mad(); |
407 | td->mad_errors = 0; | 412 | td->mad_errors = 0; |
@@ -460,12 +465,19 @@ static void audio_thread(void) | |||
460 | { | 465 | { |
461 | struct audio_thread_data td; | 466 | struct audio_thread_data td; |
462 | 467 | ||
468 | rb->memset(&td, 0, sizeof (td)); | ||
463 | td.status = STREAM_STOPPED; | 469 | td.status = STREAM_STOPPED; |
464 | td.state = TSTATE_EOS; | 470 | td.state = TSTATE_EOS; |
465 | 471 | ||
466 | /* We need this here to init the EMAC for Coldfire targets */ | 472 | /* We need this here to init the EMAC for Coldfire targets */ |
467 | init_mad(); | 473 | init_mad(); |
468 | 474 | ||
475 | td.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP, | ||
476 | CODEC_IDX_AUDIO); | ||
477 | rb->sound_set_pitch(1000); | ||
478 | rb->dsp_configure(td.dsp, DSP_RESET, 0); | ||
479 | rb->dsp_configure(td.dsp, DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); | ||
480 | |||
469 | goto message_wait; | 481 | goto message_wait; |
470 | 482 | ||
471 | /* This is the decoding loop. */ | 483 | /* This is the decoding loop. */ |
@@ -594,64 +606,56 @@ static void audio_thread(void) | |||
594 | mad_synth_frame(&synth, &frame); | 606 | mad_synth_frame(&synth, &frame); |
595 | 607 | ||
596 | /** Output **/ | 608 | /** Output **/ |
609 | if (frame.header.samplerate != td.samplerate) | ||
610 | { | ||
611 | td.samplerate = frame.header.samplerate; | ||
612 | rb->dsp_configure(td.dsp, DSP_SWITCH_FREQUENCY, | ||
613 | td.samplerate); | ||
614 | } | ||
597 | 615 | ||
598 | /* TODO: Output through core dsp. We'll still use our own PCM buffer | 616 | if (MAD_NCHANNELS(&frame.header) != td.nchannels) |
599 | since the core pcm buffer has no timestamping or clock facilities */ | 617 | { |
618 | td.nchannels = MAD_NCHANNELS(&frame.header); | ||
619 | rb->dsp_configure(td.dsp, DSP_SET_STEREO_MODE, | ||
620 | td.nchannels == 1 ? | ||
621 | STEREO_MONO : STEREO_NONINTERLEAVED); | ||
622 | } | ||
623 | |||
624 | td.state = TSTATE_RENDER_WAIT; | ||
600 | 625 | ||
601 | /* Add a frame of audio to the pcm buffer. Maximum is 1152 samples. */ | 626 | /* Add a frame of audio to the pcm buffer. Maximum is 1152 samples. */ |
602 | render_wait: | 627 | render_wait: |
603 | if (synth.pcm.length > 0) | 628 | if (synth.pcm.length > 0) |
604 | { | 629 | { |
605 | struct pcm_frame_header *pcm_insert = pcm_output_get_buffer(); | 630 | struct pcm_frame_header *dst_hdr = pcm_output_get_buffer(); |
606 | int16_t *audio_data = (int16_t *)pcm_insert->data; | 631 | const char *src[2] = |
607 | unsigned length = synth.pcm.length; | 632 | { (char *)synth.pcm.samples[0], (char *)synth.pcm.samples[1] }; |
608 | ssize_t size = sizeof(*pcm_insert) + length*4; | 633 | int out_count = (synth.pcm.length * CLOCK_RATE |
609 | 634 | + (td.samplerate - 1)) / td.samplerate; | |
610 | td.state = TSTATE_RENDER_WAIT; | 635 | ssize_t size = sizeof(*dst_hdr) + out_count*4; |
611 | 636 | ||
612 | /* Wait for required amount of free buffer space */ | 637 | /* Wait for required amount of free buffer space */ |
613 | while (pcm_output_free() < size) | 638 | while (pcm_output_free() < size) |
614 | { | 639 | { |
615 | /* Wait one frame */ | 640 | /* Wait one frame */ |
616 | int timeout = synth.pcm.length*HZ / synth.pcm.samplerate; | 641 | int timeout = out_count*HZ / td.samplerate; |
617 | str_get_msg_w_tmo(&audio_str, &td.ev, MAX(timeout, 1)); | 642 | str_get_msg_w_tmo(&audio_str, &td.ev, MAX(timeout, 1)); |
618 | if (td.ev.id != SYS_TIMEOUT) | 643 | if (td.ev.id != SYS_TIMEOUT) |
619 | goto message_process; | 644 | goto message_process; |
620 | } | 645 | } |
621 | 646 | ||
622 | pcm_insert->time = audio_queue.curr->time; | 647 | out_count = rb->dsp_process(td.dsp, dst_hdr->data, src, |
623 | pcm_insert->size = size; | 648 | synth.pcm.length); |
624 | 649 | ||
625 | /* As long as we're on this timestamp, the time is just incremented | 650 | if (out_count <= 0) |
626 | by the number of samples */ | 651 | break; |
627 | audio_queue.curr->time += length; | ||
628 | |||
629 | if (MAD_NCHANNELS(&frame.header) == 2) | ||
630 | { | ||
631 | int32_t *left = &synth.pcm.samples[0][0]; | ||
632 | int32_t *right = &synth.pcm.samples[1][0]; | ||
633 | 652 | ||
634 | do | 653 | dst_hdr->size = sizeof(*dst_hdr) + out_count*4; |
635 | { | 654 | dst_hdr->time = audio_queue.curr->time; |
636 | /* libmad outputs s3.28 */ | ||
637 | *audio_data++ = clip_sample(*left++ >> 13); | ||
638 | *audio_data++ = clip_sample(*right++ >> 13); | ||
639 | } | ||
640 | while (--length > 0); | ||
641 | } | ||
642 | else /* mono */ | ||
643 | { | ||
644 | int32_t *mono = &synth.pcm.samples[0][0]; | ||
645 | 655 | ||
646 | do | 656 | /* As long as we're on this timestamp, the time is just |
647 | { | 657 | incremented by the number of samples */ |
648 | int32_t s = clip_sample(*mono++ >> 13); | 658 | audio_queue.curr->time += out_count; |
649 | *audio_data++ = s; | ||
650 | *audio_data++ = s; | ||
651 | } | ||
652 | while (--length > 0); | ||
653 | } | ||
654 | /**/ | ||
655 | 659 | ||
656 | /* Make this data available to DMA */ | 660 | /* Make this data available to DMA */ |
657 | pcm_output_add_data(); | 661 | pcm_output_add_data(); |
@@ -712,9 +716,10 @@ bool audio_thread_init(void) | |||
712 | rb->queue_init(audio_str.hdr.q, false); | 716 | rb->queue_init(audio_str.hdr.q, false); |
713 | rb->queue_enable_queue_send(audio_str.hdr.q, &audio_str_queue_send); | 717 | rb->queue_enable_queue_send(audio_str.hdr.q, &audio_str_queue_send); |
714 | 718 | ||
719 | /* One-up on the priority since the core DSP over-yields internally */ | ||
715 | audio_str.thread = rb->create_thread( | 720 | audio_str.thread = rb->create_thread( |
716 | audio_thread, audio_stack, audio_stack_size, 0, | 721 | audio_thread, audio_stack, audio_stack_size, 0, |
717 | "mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, CPU)); | 722 | "mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK-1) IF_COP(, CPU)); |
718 | 723 | ||
719 | if (audio_str.thread == NULL) | 724 | if (audio_str.thread == NULL) |
720 | return false; | 725 | return false; |