diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/mpegplayer/audio_thread.c | 57 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpegplayer.h | 7 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/pcm_output.c | 150 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/pcm_output.h | 10 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/stream_thread.h | 1 |
5 files changed, 141 insertions, 84 deletions
diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c index 9e3968007f..ecb8b1ffae 100644 --- a/apps/plugins/mpegplayer/audio_thread.c +++ b/apps/plugins/mpegplayer/audio_thread.c | |||
@@ -112,7 +112,7 @@ static inline void audiodesc_queue_add_tail(void) | |||
112 | audio_queue.write++; | 112 | audio_queue.write++; |
113 | } | 113 | } |
114 | 114 | ||
115 | /* Increments the queue tail position - leaves one slot as current */ | 115 | /* Increments the queue head position - leaves one slot as current */ |
116 | static inline bool audiodesc_queue_remove_head(void) | 116 | static inline bool audiodesc_queue_remove_head(void) |
117 | { | 117 | { |
118 | if (audio_queue.write == audio_queue.read) | 118 | if (audio_queue.write == audio_queue.read) |
@@ -375,8 +375,6 @@ static void audio_thread_msg(struct audio_thread_data *td) | |||
375 | case TSTATE_INIT: | 375 | case TSTATE_INIT: |
376 | td->state = TSTATE_DECODE; | 376 | td->state = TSTATE_DECODE; |
377 | case TSTATE_DECODE: | 377 | case TSTATE_DECODE: |
378 | case TSTATE_RENDER_WAIT: | ||
379 | case TSTATE_RENDER_WAIT_END: | ||
380 | break; | 378 | break; |
381 | 379 | ||
382 | case TSTATE_EOS: | 380 | case TSTATE_EOS: |
@@ -455,7 +453,6 @@ static void audio_thread_msg(struct audio_thread_data *td) | |||
455 | { | 453 | { |
456 | case TSTATE_DECODE: | 454 | case TSTATE_DECODE: |
457 | case TSTATE_RENDER_WAIT: | 455 | case TSTATE_RENDER_WAIT: |
458 | case TSTATE_RENDER_WAIT_END: | ||
459 | /* These return when in playing state */ | 456 | /* These return when in playing state */ |
460 | return; | 457 | return; |
461 | } | 458 | } |
@@ -512,7 +509,6 @@ static void audio_thread(void) | |||
512 | /* These states are the only ones that should return */ | 509 | /* These states are the only ones that should return */ |
513 | case TSTATE_DECODE: goto audio_decode; | 510 | case TSTATE_DECODE: goto audio_decode; |
514 | case TSTATE_RENDER_WAIT: goto render_wait; | 511 | case TSTATE_RENDER_WAIT: goto render_wait; |
515 | case TSTATE_RENDER_WAIT_END: goto render_wait_end; | ||
516 | /* Anything else is interpreted as an exit */ | 512 | /* Anything else is interpreted as an exit */ |
517 | default: | 513 | default: |
518 | { | 514 | { |
@@ -538,29 +534,28 @@ static void audio_thread(void) | |||
538 | case STREAM_DATA_END: | 534 | case STREAM_DATA_END: |
539 | { | 535 | { |
540 | if (audio_queue.used > MAD_BUFFER_GUARD) | 536 | if (audio_queue.used > MAD_BUFFER_GUARD) |
541 | break; | 537 | break; /* Still have frames to decode */ |
542 | 538 | ||
543 | /* Used up remainder of compressed audio buffer. | 539 | /* Used up remainder of compressed audio buffer. Wait for |
544 | * Force any residue to play if audio ended before | 540 | * samples on PCM buffer to finish playing. */ |
545 | * reaching the threshold */ | ||
546 | td.state = TSTATE_RENDER_WAIT_END; | ||
547 | audio_queue_reset(); | 541 | audio_queue_reset(); |
548 | 542 | ||
549 | render_wait_end: | 543 | while (1) |
550 | pcm_output_drain(); | ||
551 | |||
552 | while (pcm_output_used() > (ssize_t)PCMOUT_LOW_WM) | ||
553 | { | 544 | { |
545 | if (pcm_output_empty()) | ||
546 | { | ||
547 | td.state = TSTATE_EOS; | ||
548 | stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0); | ||
549 | break; | ||
550 | } | ||
551 | |||
552 | pcm_output_drain(); | ||
554 | str_get_msg_w_tmo(&audio_str, &td.ev, 1); | 553 | str_get_msg_w_tmo(&audio_str, &td.ev, 1); |
554 | |||
555 | if (td.ev.id != SYS_TIMEOUT) | 555 | if (td.ev.id != SYS_TIMEOUT) |
556 | goto message_process; | 556 | break; |
557 | } | 557 | } |
558 | 558 | ||
559 | td.state = TSTATE_EOS; | ||
560 | if (td.status == STREAM_PLAYING) | ||
561 | stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0); | ||
562 | |||
563 | rb->yield(); | ||
564 | goto message_wait; | 559 | goto message_wait; |
565 | } /* STREAM_DATA_END: */ | 560 | } /* STREAM_DATA_END: */ |
566 | } | 561 | } |
@@ -606,11 +601,9 @@ static void audio_thread(void) | |||
606 | 601 | ||
607 | /* This is too hard - bail out */ | 602 | /* This is too hard - bail out */ |
608 | td.state = TSTATE_EOS; | 603 | td.state = TSTATE_EOS; |
609 | |||
610 | if (td.status == STREAM_PLAYING) | ||
611 | stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0); | ||
612 | |||
613 | td.status = STREAM_ERROR; | 604 | td.status = STREAM_ERROR; |
605 | stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0); | ||
606 | |||
614 | goto message_wait; | 607 | goto message_wait; |
615 | } | 608 | } |
616 | 609 | ||
@@ -643,15 +636,15 @@ static void audio_thread(void) | |||
643 | render_wait: | 636 | render_wait: |
644 | if (synth.pcm.length > 0) | 637 | if (synth.pcm.length > 0) |
645 | { | 638 | { |
646 | struct pcm_frame_header *dst_hdr = pcm_output_get_buffer(); | ||
647 | const char *src[2] = | 639 | const char *src[2] = |
648 | { (char *)synth.pcm.samples[0], (char *)synth.pcm.samples[1] }; | 640 | { (char *)synth.pcm.samples[0], (char *)synth.pcm.samples[1] }; |
649 | int out_count = (synth.pcm.length * CLOCK_RATE | 641 | int out_count = (synth.pcm.length * CLOCK_RATE |
650 | + (td.samplerate - 1)) / td.samplerate; | 642 | + (td.samplerate - 1)) / td.samplerate; |
651 | ssize_t size = sizeof(*dst_hdr) + out_count*4; | 643 | unsigned char *out_buf; |
644 | ssize_t size = out_count*4; | ||
652 | 645 | ||
653 | /* Wait for required amount of free buffer space */ | 646 | /* Wait for required amount of free buffer space */ |
654 | while (pcm_output_free() < size) | 647 | while ((out_buf = pcm_output_get_buffer(&size)) == NULL) |
655 | { | 648 | { |
656 | /* Wait one frame */ | 649 | /* Wait one frame */ |
657 | int timeout = out_count*HZ / td.samplerate; | 650 | int timeout = out_count*HZ / td.samplerate; |
@@ -660,21 +653,17 @@ static void audio_thread(void) | |||
660 | goto message_process; | 653 | goto message_process; |
661 | } | 654 | } |
662 | 655 | ||
663 | out_count = rb->dsp_process(td.dsp, dst_hdr->data, src, | 656 | out_count = rb->dsp_process(td.dsp, out_buf, src, synth.pcm.length); |
664 | synth.pcm.length); | ||
665 | 657 | ||
666 | if (out_count <= 0) | 658 | if (out_count <= 0) |
667 | break; | 659 | break; |
668 | 660 | ||
669 | dst_hdr->size = sizeof(*dst_hdr) + out_count*4; | 661 | /* Make this data available to DMA */ |
670 | dst_hdr->time = audio_queue.curr->time; | 662 | pcm_output_commit_data(out_count*4, audio_queue.curr->time); |
671 | 663 | ||
672 | /* As long as we're on this timestamp, the time is just | 664 | /* As long as we're on this timestamp, the time is just |
673 | incremented by the number of samples */ | 665 | incremented by the number of samples */ |
674 | audio_queue.curr->time += out_count; | 666 | audio_queue.curr->time += out_count; |
675 | |||
676 | /* Make this data available to DMA */ | ||
677 | pcm_output_add_data(); | ||
678 | } | 667 | } |
679 | 668 | ||
680 | rb->yield(); | 669 | rb->yield(); |
diff --git a/apps/plugins/mpegplayer/mpegplayer.h b/apps/plugins/mpegplayer/mpegplayer.h index 79c25f6109..7333d87d6e 100644 --- a/apps/plugins/mpegplayer/mpegplayer.h +++ b/apps/plugins/mpegplayer/mpegplayer.h | |||
@@ -51,14 +51,13 @@ | |||
51 | /* Define this as "1" to have a test tone instead of silence clip */ | 51 | /* Define this as "1" to have a test tone instead of silence clip */ |
52 | #define SILENCE_TEST_TONE 0 | 52 | #define SILENCE_TEST_TONE 0 |
53 | 53 | ||
54 | /* NOTE: Sizes make no frame header allowance when considering duration */ | ||
54 | #define PCMOUT_BUFSIZE (CLOCK_RATE/2*4) /* 1/2s */ | 55 | #define PCMOUT_BUFSIZE (CLOCK_RATE/2*4) /* 1/2s */ |
55 | #define PCMOUT_GUARD_SAMPLES ((CLOCK_RATE*576+7999)/8000) /* Worst upsampling case */ | 56 | #define PCMOUT_GUARD_SIZE (PCMOUT_BUFSIZE) /* guarantee contiguous sizes */ |
56 | #define PCMOUT_GUARD_SIZE (PCMOUT_GUARD_SAMPLES*4 + sizeof (struct pcm_frame_header)) | ||
57 | #define PCMOUT_ALLOC_SIZE (PCMOUT_BUFSIZE + PCMOUT_GUARD_SIZE) | 57 | #define PCMOUT_ALLOC_SIZE (PCMOUT_BUFSIZE + PCMOUT_GUARD_SIZE) |
58 | /* Start pcm playback @ 25% full */ | 58 | /* Start pcm playback @ 25% full */ |
59 | #define PCMOUT_PLAY_WM (PCMOUT_BUFSIZE/4) | 59 | #define PCMOUT_PLAY_WM (PCMOUT_BUFSIZE/4) |
60 | /* No valid audio frame is smaller */ | 60 | #define PCMOUT_LOW_WM (0) |
61 | #define PCMOUT_LOW_WM (sizeof (struct pcm_frame_header)) | ||
62 | 61 | ||
63 | /** disk buffer **/ | 62 | /** disk buffer **/ |
64 | #define DISK_BUF_LOW_WATERMARK (1024*1024) | 63 | #define DISK_BUF_LOW_WATERMARK (1024*1024) |
diff --git a/apps/plugins/mpegplayer/pcm_output.c b/apps/plugins/mpegplayer/pcm_output.c index a5d8f86e5b..0b8ad7701a 100644 --- a/apps/plugins/mpegplayer/pcm_output.c +++ b/apps/plugins/mpegplayer/pcm_output.c | |||
@@ -36,21 +36,30 @@ static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_tail IBSS_ATTR; | |||
36 | 36 | ||
37 | /* Bytes */ | 37 | /* Bytes */ |
38 | static ssize_t pcmbuf_curr_size IBSS_ATTR; /* Size of currently playing frame */ | 38 | static ssize_t pcmbuf_curr_size IBSS_ATTR; /* Size of currently playing frame */ |
39 | static uint64_t pcmbuf_read IBSS_ATTR; /* Number of bytes read by DMA */ | 39 | static ssize_t pcmbuf_read IBSS_ATTR; /* Number of bytes read by DMA */ |
40 | static uint64_t pcmbuf_written IBSS_ATTR; /* Number of bytes written by source */ | 40 | static ssize_t pcmbuf_written IBSS_ATTR; /* Number of bytes written by source */ |
41 | static ssize_t pcmbuf_threshold IBSS_ATTR; /* Non-silence threshold */ | 41 | static ssize_t pcmbuf_threshold IBSS_ATTR; /* Non-silence threshold */ |
42 | 42 | ||
43 | /* Clock */ | 43 | /* Clock */ |
44 | static uint32_t clock_base IBSS_ATTR; /* Our base clock */ | ||
45 | static uint32_t clock_start IBSS_ATTR; /* Clock at playback start */ | 44 | static uint32_t clock_start IBSS_ATTR; /* Clock at playback start */ |
46 | static int32_t clock_adjust IBSS_ATTR; /* Clock drift adjustment */ | 45 | static uint32_t volatile clock_tick IBSS_ATTR; /* Our base clock */ |
46 | static uint32_t volatile clock_time IBSS_ATTR; /* Timestamp adjusted */ | ||
47 | 47 | ||
48 | int pcm_skipped = 0; | 48 | static int pcm_skipped = 0; |
49 | int pcm_underruns = 0; | 49 | static int pcm_underruns = 0; |
50 | 50 | ||
51 | /* Small silence clip. ~5.80ms @ 44.1kHz */ | 51 | /* Small silence clip. ~5.80ms @ 44.1kHz */ |
52 | static int16_t silence[256*2] ALIGNED_ATTR(4) = { 0 }; | 52 | static int16_t silence[256*2] ALIGNED_ATTR(4) = { 0 }; |
53 | 53 | ||
54 | /* Delete all buffer contents */ | ||
55 | static void pcm_reset_buffer(void) | ||
56 | { | ||
57 | pcmbuf_threshold = PCMOUT_PLAY_WM; | ||
58 | pcmbuf_curr_size = pcmbuf_read = pcmbuf_written = 0; | ||
59 | pcmbuf_head = pcmbuf_tail = pcm_buffer; | ||
60 | pcm_skipped = pcm_underruns = 0; | ||
61 | } | ||
62 | |||
54 | /* Advance a PCM buffer pointer by size bytes circularly */ | 63 | /* Advance a PCM buffer pointer by size bytes circularly */ |
55 | static inline void pcm_advance_buffer(struct pcm_frame_header **p, | 64 | static inline void pcm_advance_buffer(struct pcm_frame_header **p, |
56 | size_t size) | 65 | size_t size) |
@@ -60,15 +69,16 @@ static inline void pcm_advance_buffer(struct pcm_frame_header **p, | |||
60 | *p = SKIPBYTES(*p, -PCMOUT_BUFSIZE); | 69 | *p = SKIPBYTES(*p, -PCMOUT_BUFSIZE); |
61 | } | 70 | } |
62 | 71 | ||
63 | /* Inline internally but not externally */ | 72 | /* Return physical space used */ |
64 | inline ssize_t pcm_output_used(void) | 73 | static inline ssize_t pcm_output_bytes_used(void) |
65 | { | 74 | { |
66 | return (ssize_t)(pcmbuf_written - pcmbuf_read); | 75 | return pcmbuf_written - pcmbuf_read; /* wrap-safe */ |
67 | } | 76 | } |
68 | 77 | ||
69 | inline ssize_t pcm_output_free(void) | 78 | /* Return physical space free */ |
79 | static inline ssize_t pcm_output_bytes_free(void) | ||
70 | { | 80 | { |
71 | return (ssize_t)(PCMOUT_BUFSIZE - pcmbuf_written + pcmbuf_read); | 81 | return PCMOUT_BUFSIZE - pcm_output_bytes_used(); |
72 | } | 82 | } |
73 | 83 | ||
74 | /* Audio DMA handler */ | 84 | /* Audio DMA handler */ |
@@ -80,7 +90,7 @@ static void get_more(unsigned char **start, size_t *size) | |||
80 | pcmbuf_read += pcmbuf_curr_size; | 90 | pcmbuf_read += pcmbuf_curr_size; |
81 | pcmbuf_curr_size = 0; | 91 | pcmbuf_curr_size = 0; |
82 | 92 | ||
83 | sz = pcm_output_used(); | 93 | sz = pcm_output_bytes_used(); |
84 | 94 | ||
85 | if (sz > pcmbuf_threshold) | 95 | if (sz > pcmbuf_threshold) |
86 | { | 96 | { |
@@ -89,16 +99,15 @@ static void get_more(unsigned char **start, size_t *size) | |||
89 | while (1) | 99 | while (1) |
90 | { | 100 | { |
91 | uint32_t time = pcmbuf_head->time; | 101 | uint32_t time = pcmbuf_head->time; |
92 | int32_t offset = time - (clock_base + clock_adjust); | 102 | int32_t offset = time - clock_time; |
93 | 103 | ||
94 | sz = pcmbuf_head->size; | 104 | sz = pcmbuf_head->size; |
95 | 105 | ||
96 | if (sz < (ssize_t)(sizeof(pcmbuf_head) + 4) || | 106 | if (sz < (ssize_t)(PCM_HDR_SIZE + 4) || |
97 | (sz & 3) != 0) | 107 | (sz & 3) != 0) |
98 | { | 108 | { |
99 | /* Just show a warning about this - will never happen | 109 | /* Just show a warning about this - will never happen |
100 | * without a bug in the audio thread code or a clobbered | 110 | * without a corrupted buffer */ |
101 | * buffer */ | ||
102 | DEBUGF("get_more: invalid size (%ld)\n", (long)sz); | 111 | DEBUGF("get_more: invalid size (%ld)\n", (long)sz); |
103 | } | 112 | } |
104 | 113 | ||
@@ -108,11 +117,12 @@ static void get_more(unsigned char **start, size_t *size) | |||
108 | pcm_advance_buffer(&pcmbuf_head, sz); | 117 | pcm_advance_buffer(&pcmbuf_head, sz); |
109 | pcmbuf_read += sz; | 118 | pcmbuf_read += sz; |
110 | pcm_skipped++; | 119 | pcm_skipped++; |
111 | if (pcmbuf_read < pcmbuf_written) | 120 | if (pcm_output_bytes_used() > 0) |
112 | continue; | 121 | continue; |
113 | 122 | ||
114 | /* Ran out so revert to default watermark */ | 123 | /* Ran out so revert to default watermark */ |
115 | pcmbuf_threshold = PCMOUT_PLAY_WM; | 124 | pcmbuf_threshold = PCMOUT_PLAY_WM; |
125 | pcm_underruns++; | ||
116 | } | 126 | } |
117 | else if (offset < 100*CLOCK_RATE/1000) | 127 | else if (offset < 100*CLOCK_RATE/1000) |
118 | { | 128 | { |
@@ -122,15 +132,15 @@ static void get_more(unsigned char **start, size_t *size) | |||
122 | pcm_advance_buffer(&pcmbuf_head, sz); | 132 | pcm_advance_buffer(&pcmbuf_head, sz); |
123 | pcmbuf_curr_size = sz; | 133 | pcmbuf_curr_size = sz; |
124 | 134 | ||
125 | sz -= sizeof (struct pcm_frame_header); | 135 | sz -= PCM_HDR_SIZE; |
126 | 136 | ||
127 | *size = sz; | 137 | *size = sz; |
128 | 138 | ||
129 | /* Audio is time master - keep clock synchronized */ | 139 | /* Audio is time master - keep clock synchronized */ |
130 | clock_adjust = time - clock_base; | 140 | clock_time = time + (sz >> 2); |
131 | 141 | ||
132 | /* Update base clock */ | 142 | /* Update base clock */ |
133 | clock_base += sz >> 2; | 143 | clock_tick += sz >> 2; |
134 | return; | 144 | return; |
135 | } | 145 | } |
136 | /* Frame will be dropped - play silence clip */ | 146 | /* Frame will be dropped - play silence clip */ |
@@ -150,22 +160,57 @@ static void get_more(unsigned char **start, size_t *size) | |||
150 | *start = (unsigned char *)silence; | 160 | *start = (unsigned char *)silence; |
151 | *size = sizeof (silence); | 161 | *size = sizeof (silence); |
152 | 162 | ||
153 | clock_base += sizeof (silence) / 4; | 163 | clock_tick += sizeof (silence) / 4; |
164 | clock_time += sizeof (silence) / 4; | ||
154 | 165 | ||
155 | if (pcmbuf_read > pcmbuf_written) | 166 | if (sz < 0) |
156 | pcmbuf_read = pcmbuf_written; | 167 | pcmbuf_read = pcmbuf_written; |
157 | } | 168 | } |
158 | 169 | ||
159 | struct pcm_frame_header * pcm_output_get_buffer(void) | 170 | /** Public interface **/ |
171 | |||
172 | /* Return a buffer pointer if at least size bytes are available and if so, | ||
173 | * give the actual free space */ | ||
174 | unsigned char * pcm_output_get_buffer(ssize_t *size) | ||
160 | { | 175 | { |
161 | return pcmbuf_tail; | 176 | ssize_t sz = *size; |
177 | ssize_t free = pcm_output_bytes_free() - PCM_HDR_SIZE; | ||
178 | |||
179 | if (sz >= 0 && free >= sz) | ||
180 | { | ||
181 | *size = free; /* return actual free space (- header) */ | ||
182 | return pcmbuf_tail->data; | ||
183 | } | ||
184 | |||
185 | /* Leave *size alone so caller doesn't have to reinit */ | ||
186 | return NULL; | ||
162 | } | 187 | } |
163 | 188 | ||
164 | void pcm_output_add_data(void) | 189 | /* Commit the buffer returned by pcm_ouput_get_buffer; timestamp is PCM |
190 | * clock time units, not video format time units */ | ||
191 | bool pcm_output_commit_data(ssize_t size, uint32_t timestamp) | ||
165 | { | 192 | { |
166 | size_t size = pcmbuf_tail->size; | 193 | if (size <= 0 || (size & 3)) |
194 | return false; /* invalid */ | ||
195 | |||
196 | size += PCM_HDR_SIZE; | ||
197 | |||
198 | if (size > pcm_output_bytes_free()) | ||
199 | return false; /* too big */ | ||
200 | |||
201 | pcmbuf_tail->size = size; | ||
202 | pcmbuf_tail->time = timestamp; | ||
203 | |||
167 | pcm_advance_buffer(&pcmbuf_tail, size); | 204 | pcm_advance_buffer(&pcmbuf_tail, size); |
168 | pcmbuf_written += size; | 205 | pcmbuf_written += size; |
206 | |||
207 | return true; | ||
208 | } | ||
209 | |||
210 | /* Returns 'true' if the buffer is completely empty */ | ||
211 | bool pcm_output_empty(void) | ||
212 | { | ||
213 | return pcm_output_bytes_used() <= 0; | ||
169 | } | 214 | } |
170 | 215 | ||
171 | /* Flushes the buffer - clock keeps counting */ | 216 | /* Flushes the buffer - clock keeps counting */ |
@@ -182,10 +227,7 @@ void pcm_output_flush(void) | |||
182 | if (playing) | 227 | if (playing) |
183 | rb->pcm_play_stop(); | 228 | rb->pcm_play_stop(); |
184 | 229 | ||
185 | pcmbuf_threshold = PCMOUT_PLAY_WM; | 230 | pcm_reset_buffer(); |
186 | pcmbuf_curr_size = pcmbuf_read = pcmbuf_written = 0; | ||
187 | pcmbuf_head = pcmbuf_tail = pcm_buffer; | ||
188 | pcm_skipped = pcm_underruns = 0; | ||
189 | 231 | ||
190 | /* Restart if playing state was current */ | 232 | /* Restart if playing state was current */ |
191 | if (playing && !paused) | 233 | if (playing && !paused) |
@@ -201,25 +243,54 @@ void pcm_output_set_clock(uint32_t time) | |||
201 | { | 243 | { |
202 | rb->pcm_play_lock(); | 244 | rb->pcm_play_lock(); |
203 | 245 | ||
204 | clock_base = time; | ||
205 | clock_start = time; | 246 | clock_start = time; |
206 | clock_adjust = 0; | 247 | clock_tick = time; |
248 | clock_time = time; | ||
207 | 249 | ||
208 | rb->pcm_play_unlock(); | 250 | rb->pcm_play_unlock(); |
209 | } | 251 | } |
210 | 252 | ||
253 | /* Return the clock as synchronized by audio frame timestamps */ | ||
211 | uint32_t pcm_output_get_clock(void) | 254 | uint32_t pcm_output_get_clock(void) |
212 | { | 255 | { |
213 | return clock_base + clock_adjust | 256 | uint32_t time, rem; |
214 | - (rb->pcm_get_bytes_waiting() >> 2); | 257 | |
258 | /* Reread if data race detected - rem will be 0 if driver hasn't yet | ||
259 | * updated to the new buffer size. Also be sure pcm state doesn't | ||
260 | * cause indefinite loop. | ||
261 | * | ||
262 | * FYI: NOT scrutinized for rd/wr reordering on different cores. */ | ||
263 | do | ||
264 | { | ||
265 | time = clock_time; | ||
266 | rem = rb->pcm_get_bytes_waiting() >> 2; | ||
267 | } | ||
268 | while (UNLIKELY(time != clock_time || | ||
269 | (rem == 0 && rb->pcm_is_playing() && !rb->pcm_is_paused()))); | ||
270 | |||
271 | return time - rem; | ||
272 | |||
215 | } | 273 | } |
216 | 274 | ||
275 | /* Return the raw clock as counted from the last pcm_output_set_clock | ||
276 | * call */ | ||
217 | uint32_t pcm_output_get_ticks(uint32_t *start) | 277 | uint32_t pcm_output_get_ticks(uint32_t *start) |
218 | { | 278 | { |
279 | uint32_t tick, rem; | ||
280 | |||
281 | /* Same procedure as pcm_output_get_clock */ | ||
282 | do | ||
283 | { | ||
284 | tick = clock_tick; | ||
285 | rem = rb->pcm_get_bytes_waiting() >> 2; | ||
286 | } | ||
287 | while (UNLIKELY(tick != clock_tick || | ||
288 | (rem == 0 && rb->pcm_is_playing() && !rb->pcm_is_paused()))); | ||
289 | |||
219 | if (start) | 290 | if (start) |
220 | *start = clock_start; | 291 | *start = clock_start; |
221 | 292 | ||
222 | return clock_base - (rb->pcm_get_bytes_waiting() >> 2); | 293 | return tick - rem; |
223 | } | 294 | } |
224 | 295 | ||
225 | /* Pauses/Starts pcm playback - and the clock */ | 296 | /* Pauses/Starts pcm playback - and the clock */ |
@@ -267,12 +338,13 @@ bool pcm_output_init(void) | |||
267 | if (pcm_buffer == NULL) | 338 | if (pcm_buffer == NULL) |
268 | return false; | 339 | return false; |
269 | 340 | ||
270 | pcmbuf_threshold = PCMOUT_PLAY_WM; | ||
271 | pcmbuf_head = pcm_buffer; | ||
272 | pcmbuf_tail = pcm_buffer; | ||
273 | pcmbuf_end = SKIPBYTES(pcm_buffer, PCMOUT_BUFSIZE); | 341 | pcmbuf_end = SKIPBYTES(pcm_buffer, PCMOUT_BUFSIZE); |
274 | pcmbuf_curr_size = pcmbuf_read = pcmbuf_written = 0; | ||
275 | 342 | ||
343 | pcm_reset_buffer(); | ||
344 | |||
345 | /* Some targets could play at the movie frequency without resampling but | ||
346 | * as of now DSP assumes a certain frequency (always 44100Hz) so | ||
347 | * resampling will be needed for other movie audio rates. */ | ||
276 | rb->pcm_set_frequency(NATIVE_FREQUENCY); | 348 | rb->pcm_set_frequency(NATIVE_FREQUENCY); |
277 | 349 | ||
278 | #if INPUT_SRC_CAPS != 0 | 350 | #if INPUT_SRC_CAPS != 0 |
diff --git a/apps/plugins/mpegplayer/pcm_output.h b/apps/plugins/mpegplayer/pcm_output.h index 9335235daa..1a00ac48e6 100644 --- a/apps/plugins/mpegplayer/pcm_output.h +++ b/apps/plugins/mpegplayer/pcm_output.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #ifndef PCM_OUTPUT_H | 23 | #ifndef PCM_OUTPUT_H |
24 | #define PCM_OUTPUT_H | 24 | #define PCM_OUTPUT_H |
25 | 25 | ||
26 | #define PCM_HDR_SIZE (sizeof (struct pcm_frame_header)) | ||
26 | struct pcm_frame_header /* Header added to pcm data every time a decoded | 27 | struct pcm_frame_header /* Header added to pcm data every time a decoded |
27 | audio frame is sent out */ | 28 | audio frame is sent out */ |
28 | { | 29 | { |
@@ -31,8 +32,6 @@ struct pcm_frame_header /* Header added to pcm data every time a decoded | |||
31 | unsigned char data[]; /* open array of audio data */ | 32 | unsigned char data[]; /* open array of audio data */ |
32 | } ALIGNED_ATTR(4); | 33 | } ALIGNED_ATTR(4); |
33 | 34 | ||
34 | extern int pcm_skipped, pcm_underruns; | ||
35 | |||
36 | bool pcm_output_init(void); | 35 | bool pcm_output_init(void); |
37 | void pcm_output_exit(void); | 36 | void pcm_output_exit(void); |
38 | void pcm_output_flush(void); | 37 | void pcm_output_flush(void); |
@@ -42,9 +41,8 @@ uint32_t pcm_output_get_ticks(uint32_t *start); | |||
42 | void pcm_output_play_pause(bool play); | 41 | void pcm_output_play_pause(bool play); |
43 | void pcm_output_stop(void); | 42 | void pcm_output_stop(void); |
44 | void pcm_output_drain(void); | 43 | void pcm_output_drain(void); |
45 | struct pcm_frame_header * pcm_output_get_buffer(void); | 44 | unsigned char * pcm_output_get_buffer(ssize_t *size); |
46 | void pcm_output_add_data(void); | 45 | bool pcm_output_commit_data(ssize_t size, uint32_t timestamp); |
47 | ssize_t pcm_output_used(void); | 46 | bool pcm_output_empty(void); |
48 | ssize_t pcm_output_free(void); | ||
49 | 47 | ||
50 | #endif /* PCM_OUTPUT_H */ | 48 | #endif /* PCM_OUTPUT_H */ |
diff --git a/apps/plugins/mpegplayer/stream_thread.h b/apps/plugins/mpegplayer/stream_thread.h index 5791a49e7f..dfa6e8c9a1 100644 --- a/apps/plugins/mpegplayer/stream_thread.h +++ b/apps/plugins/mpegplayer/stream_thread.h | |||
@@ -73,7 +73,6 @@ enum thread_states | |||
73 | TSTATE_DECODE, /* is in a decoding state */ | 73 | TSTATE_DECODE, /* is in a decoding state */ |
74 | TSTATE_RENDER, /* is in a rendering state */ | 74 | TSTATE_RENDER, /* is in a rendering state */ |
75 | TSTATE_RENDER_WAIT, /* is waiting to render */ | 75 | TSTATE_RENDER_WAIT, /* is waiting to render */ |
76 | TSTATE_RENDER_WAIT_END, /* is waiting on remaining data */ | ||
77 | }; | 76 | }; |
78 | 77 | ||
79 | /* Commands that streams respond to */ | 78 | /* Commands that streams respond to */ |