diff options
-rw-r--r-- | apps/plugin.c | 5 | ||||
-rw-r--r-- | apps/plugin.h | 4 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpegplayer.c | 438 |
3 files changed, 297 insertions, 150 deletions
diff --git a/apps/plugin.c b/apps/plugin.c index 793114539e..aff24e0059 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -488,13 +488,12 @@ static const struct plugin_api rockbox_api = { | |||
488 | #endif | 488 | #endif |
489 | /* new stuff at the end, sort into place next time | 489 | /* new stuff at the end, sort into place next time |
490 | the API gets incompatible */ | 490 | the API gets incompatible */ |
491 | #if NUM_CORES > 1 | 491 | |
492 | #if (CONFIG_CODEC == SWCODEC) | ||
492 | spinlock_init, | 493 | spinlock_init, |
493 | spinlock_lock, | 494 | spinlock_lock, |
494 | spinlock_unlock, | 495 | spinlock_unlock, |
495 | #endif | ||
496 | 496 | ||
497 | #if (CONFIG_CODEC == SWCODEC) | ||
498 | codec_load_file, | 497 | codec_load_file, |
499 | get_codec_filename, | 498 | get_codec_filename, |
500 | get_metadata, | 499 | get_metadata, |
diff --git a/apps/plugin.h b/apps/plugin.h index 0edbc87e37..920d804ab5 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -610,13 +610,11 @@ struct plugin_api { | |||
610 | /* new stuff at the end, sort into place next time | 610 | /* new stuff at the end, sort into place next time |
611 | the API gets incompatible */ | 611 | the API gets incompatible */ |
612 | 612 | ||
613 | #if NUM_CORES > 1 | 613 | #if (CONFIG_CODEC == SWCODEC) |
614 | void (*spinlock_init)(struct mutex *m); | 614 | void (*spinlock_init)(struct mutex *m); |
615 | void (*spinlock_lock)(struct mutex *m); | 615 | void (*spinlock_lock)(struct mutex *m); |
616 | void (*spinlock_unlock)(struct mutex *m); | 616 | void (*spinlock_unlock)(struct mutex *m); |
617 | #endif | ||
618 | 617 | ||
619 | #if (CONFIG_CODEC == SWCODEC) | ||
620 | int (*codec_load_file)(const char* codec, struct codec_api *api); | 618 | int (*codec_load_file)(const char* codec, struct codec_api *api); |
621 | const char *(*get_codec_filename)(int cod_spec); | 619 | const char *(*get_codec_filename)(int cod_spec); |
622 | bool (*get_metadata)(struct track_info* track, int fd, const char* trackname, | 620 | bool (*get_metadata)(struct track_info* track, int fd, const char* trackname, |
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index 7e18ab4963..cbd4999655 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c | |||
@@ -169,38 +169,16 @@ static int total_offset = 0; | |||
169 | static int num_drawn = 0; | 169 | static int num_drawn = 0; |
170 | static int count_start = 0; | 170 | static int count_start = 0; |
171 | 171 | ||
172 | /* Utility */ | ||
173 | |||
174 | /* Atomically add one long value to another - not core safe atm if ever needed */ | ||
175 | static inline void locked_add_long(volatile long *value, long amount) | ||
176 | { | ||
177 | #if defined (CPU_ARM) | ||
178 | /* Disable the fiq - this cuts an instruction out over using the | ||
179 | system functions */ | ||
180 | long cpsr, x; | ||
181 | asm volatile ( | ||
182 | "mrs %[sr], cpsr \r\n" | ||
183 | "orr %[sr], %[sr], #0x40 \r\n" | ||
184 | "msr cpsr_c, %[sr] \r\n" | ||
185 | "ldr %[x], [%[value]] \r\n" | ||
186 | "add %[x], %[x], %[amount] \r\n" | ||
187 | "str %[x], [%[value]] \r\n" | ||
188 | "bic %[sr], %[sr], #0x40 \r\n" | ||
189 | "msr cpsr_c, %[sr] \r\n" | ||
190 | : [sr]"=&r"(cpsr), [x]"=&r"(x) | ||
191 | : [value]"r"(value), [amount]"r"(amount) | ||
192 | ); | ||
193 | #elif defined (CPU_COLDFIRE) | ||
194 | add_l(amount, value); | ||
195 | #else | ||
196 | /* Don't know what this is so can't lock it */ | ||
197 | *value += amount; | ||
198 | #endif | ||
199 | } | ||
200 | |||
201 | /* Streams */ | 172 | /* Streams */ |
202 | typedef struct | 173 | typedef struct |
203 | { | 174 | { |
175 | struct thread_entry *thread; /* Stream's thread */ | ||
176 | int status; /* Current stream status */ | ||
177 | struct event ev; /* Event sent to steam */ | ||
178 | int have_msg; /* 1=event pending */ | ||
179 | int replied; /* 1=replied to last event */ | ||
180 | int reply; /* reply value */ | ||
181 | struct mutex msg_lock; /* serialization for event senders */ | ||
204 | uint8_t* curr_packet; /* Current stream packet beginning */ | 182 | uint8_t* curr_packet; /* Current stream packet beginning */ |
205 | uint8_t* curr_packet_end; /* Current stream packet end */ | 183 | uint8_t* curr_packet_end; /* Current stream packet end */ |
206 | 184 | ||
@@ -219,6 +197,138 @@ typedef struct | |||
219 | static Stream audio_str IBSS_ATTR; | 197 | static Stream audio_str IBSS_ATTR; |
220 | static Stream video_str IBSS_ATTR; | 198 | static Stream video_str IBSS_ATTR; |
221 | 199 | ||
200 | /* Messages */ | ||
201 | enum | ||
202 | { | ||
203 | STREAM_STOP, | ||
204 | STREAM_PLAY, | ||
205 | STREAM_PAUSE, | ||
206 | }; | ||
207 | |||
208 | /* Status */ | ||
209 | enum | ||
210 | { | ||
211 | STREAM_ERROR = -4, | ||
212 | STREAM_STOPPED = -3, | ||
213 | STREAM_TERMINATED = -2, | ||
214 | STREAM_DONE = -1, | ||
215 | STREAM_PLAYING = 0, | ||
216 | STREAM_PAUSED, | ||
217 | STREAM_BUFFERING | ||
218 | }; | ||
219 | |||
220 | /* Returns true if a message is waiting */ | ||
221 | static inline bool str_have_msg(Stream *str) | ||
222 | { | ||
223 | return str->have_msg != 0; | ||
224 | } | ||
225 | |||
226 | /* Waits until a message is sent */ | ||
227 | static void str_wait_msg(Stream *str) | ||
228 | { | ||
229 | /* NOTE: sleep(0) caused a prefectch abort at C0EDBABE on e200 - | ||
230 | will look into this oddness */ | ||
231 | #if 0 | ||
232 | int spin_count = 0; | ||
233 | #endif | ||
234 | |||
235 | while (str->have_msg == 0) | ||
236 | { | ||
237 | #if 0 | ||
238 | if (spin_count < 100) | ||
239 | { | ||
240 | rb->yield(); | ||
241 | spin_count++; | ||
242 | continue; | ||
243 | } | ||
244 | |||
245 | rb->sleep(0); | ||
246 | #endif | ||
247 | rb->yield(); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | /* Returns a message waiting or blocks until one is available - removes the | ||
252 | event */ | ||
253 | static bool str_get_msg(Stream *str, struct event *ev) | ||
254 | { | ||
255 | str_wait_msg(str); | ||
256 | ev->id = str->ev.id; | ||
257 | ev->data = str->ev.data; | ||
258 | str->have_msg = 0; | ||
259 | return true; | ||
260 | } | ||
261 | |||
262 | /* Peeks at the current message without blocking, returns the data but | ||
263 | does not remove the event */ | ||
264 | static bool str_look_msg(Stream *str, struct event *ev) | ||
265 | { | ||
266 | if (!str_have_msg(str)) | ||
267 | return false; | ||
268 | |||
269 | ev->id = str->ev.id; | ||
270 | ev->data = str->ev.data; | ||
271 | return true; | ||
272 | } | ||
273 | |||
274 | /* Replies to the last message pulled - has no effect if last message has not | ||
275 | been pulled or already replied */ | ||
276 | static void str_reply_msg(Stream *str, int reply) | ||
277 | { | ||
278 | if (str->replied == 1 || str->have_msg != 0) | ||
279 | return; | ||
280 | |||
281 | str->reply = reply; | ||
282 | str->replied = 1; | ||
283 | } | ||
284 | |||
285 | /* Sends a message to a stream and waits for a reply */ | ||
286 | static intptr_t str_send_msg(Stream *str, int id, intptr_t data) | ||
287 | { | ||
288 | /* NOTE: sleep(0) caused a prefectch abort at C0EDBABE on e200 - | ||
289 | will look into this oddness */ | ||
290 | #if 0 | ||
291 | int spin_count = 0; | ||
292 | #endif | ||
293 | |||
294 | intptr_t reply; | ||
295 | |||
296 | #if 0 | ||
297 | if (str->thread == rb->thread_get_current()) | ||
298 | return str->dispatch_fn(str, msg); | ||
299 | #endif | ||
300 | |||
301 | /* Only one thread at a time, please */ | ||
302 | rb->spinlock_lock(&str->msg_lock); | ||
303 | |||
304 | str->ev.id = id; | ||
305 | str->ev.data = data; | ||
306 | str->reply = 0; | ||
307 | str->replied = 0; | ||
308 | str->have_msg = 1; | ||
309 | |||
310 | while (str->replied == 0 && str->status != STREAM_TERMINATED) | ||
311 | { | ||
312 | #if 0 | ||
313 | if (spin_count < 100) | ||
314 | { | ||
315 | rb->yield(); | ||
316 | spin_count++; | ||
317 | continue; | ||
318 | } | ||
319 | |||
320 | rb->sleep(0); | ||
321 | #endif | ||
322 | rb->yield(); | ||
323 | } | ||
324 | |||
325 | reply = str->reply; | ||
326 | |||
327 | rb->spinlock_unlock(&str->msg_lock); | ||
328 | |||
329 | return reply; | ||
330 | } | ||
331 | |||
222 | /* NOTE: Putting the following variables in IRAM cause audio corruption | 332 | /* NOTE: Putting the following variables in IRAM cause audio corruption |
223 | on the ipod (reason unknown) | 333 | on the ipod (reason unknown) |
224 | */ | 334 | */ |
@@ -251,26 +361,6 @@ static struct event_queue msg_queue IBSS_ATTR; | |||
251 | #define MSG_BUFFER_NEARLY_EMPTY 1 | 361 | #define MSG_BUFFER_NEARLY_EMPTY 1 |
252 | #define MSG_EXIT_REQUESTED 2 | 362 | #define MSG_EXIT_REQUESTED 2 |
253 | 363 | ||
254 | /* Threads */ | ||
255 | static struct thread_entry* audiothread_id; | ||
256 | static struct thread_entry* videothread_id; | ||
257 | |||
258 | /* Status */ | ||
259 | enum | ||
260 | { | ||
261 | STREAM_PLAYING = 0, | ||
262 | STREAM_DONE, | ||
263 | STREAM_PAUSING, | ||
264 | STREAM_BUFFERING, | ||
265 | STREAM_ERROR, | ||
266 | PLEASE_STOP, | ||
267 | PLEASE_PAUSE, | ||
268 | THREAD_TERMINATED, | ||
269 | }; | ||
270 | |||
271 | volatile int audiostatus IBSS_ATTR; | ||
272 | volatile int videostatus IBSS_ATTR; | ||
273 | |||
274 | /* Various buffers */ | 364 | /* Various buffers */ |
275 | /* TODO: Can we reduce the PCM buffer size? */ | 365 | /* TODO: Can we reduce the PCM buffer size? */ |
276 | #define PCMBUFFER_SIZE ((512*1024)-PCMBUFFER_GUARD_SIZE) | 366 | #define PCMBUFFER_SIZE ((512*1024)-PCMBUFFER_GUARD_SIZE) |
@@ -700,7 +790,8 @@ struct pcm_frame_header /* Header added to pcm data every time a decoded | |||
700 | 790 | ||
701 | #define PCMBUF_PLAY_ALL 1l /* Forces buffer to play back all data */ | 791 | #define PCMBUF_PLAY_ALL 1l /* Forces buffer to play back all data */ |
702 | #define PCMBUF_PLAY_NONE LONG_MAX /* Keeps buffer from playing any data */ | 792 | #define PCMBUF_PLAY_NONE LONG_MAX /* Keeps buffer from playing any data */ |
703 | static volatile ssize_t pcmbuf_used IBSS_ATTR; | 793 | static volatile uint64_t pcmbuf_read IBSS_ATTR; |
794 | static volatile uint64_t pcmbuf_written IBSS_ATTR; | ||
704 | static volatile ssize_t pcmbuf_threshold IBSS_ATTR; | 795 | static volatile ssize_t pcmbuf_threshold IBSS_ATTR; |
705 | static struct pcm_frame_header *pcm_buffer IBSS_ATTR; | 796 | static struct pcm_frame_header *pcm_buffer IBSS_ATTR; |
706 | static struct pcm_frame_header *pcmbuf_end IBSS_ATTR; | 797 | static struct pcm_frame_header *pcmbuf_end IBSS_ATTR; |
@@ -711,6 +802,11 @@ static volatile uint32_t samplesplayed IBSS_ATTR; /* Our base clock */ | |||
711 | static volatile uint32_t samplestart IBSS_ATTR; /* Clock at playback start */ | 802 | static volatile uint32_t samplestart IBSS_ATTR; /* Clock at playback start */ |
712 | static volatile int32_t sampleadjust IBSS_ATTR; /* Clock drift adjustment */ | 803 | static volatile int32_t sampleadjust IBSS_ATTR; /* Clock drift adjustment */ |
713 | 804 | ||
805 | static ssize_t pcmbuf_used(void) | ||
806 | { | ||
807 | return (ssize_t)(pcmbuf_written - pcmbuf_read); | ||
808 | } | ||
809 | |||
714 | static bool init_pcmbuf(void) | 810 | static bool init_pcmbuf(void) |
715 | { | 811 | { |
716 | pcm_buffer = mpeg2_malloc(PCMBUFFER_SIZE + PCMBUFFER_GUARD_SIZE, -2); | 812 | pcm_buffer = mpeg2_malloc(PCMBUFFER_SIZE + PCMBUFFER_GUARD_SIZE, -2); |
@@ -721,7 +817,8 @@ static bool init_pcmbuf(void) | |||
721 | pcmbuf_head = pcm_buffer; | 817 | pcmbuf_head = pcm_buffer; |
722 | pcmbuf_tail = pcm_buffer; | 818 | pcmbuf_tail = pcm_buffer; |
723 | pcmbuf_end = SKIPBYTES(pcm_buffer, PCMBUFFER_SIZE); | 819 | pcmbuf_end = SKIPBYTES(pcm_buffer, PCMBUFFER_SIZE); |
724 | pcmbuf_used = 0; | 820 | pcmbuf_read = 0; |
821 | pcmbuf_written = 0; | ||
725 | 822 | ||
726 | return true; | 823 | return true; |
727 | } | 824 | } |
@@ -741,7 +838,7 @@ static void get_more(unsigned char** start, size_t* size) | |||
741 | static unsigned char silence[4412] __attribute__((aligned (4))) = { 0 }; | 838 | static unsigned char silence[4412] __attribute__((aligned (4))) = { 0 }; |
742 | size_t sz; | 839 | size_t sz; |
743 | 840 | ||
744 | if (pcmbuf_used >= pcmbuf_threshold) | 841 | if (pcmbuf_used() >= pcmbuf_threshold) |
745 | { | 842 | { |
746 | uint32_t time = pcmbuf_tail->time; | 843 | uint32_t time = pcmbuf_tail->time; |
747 | sz = pcmbuf_tail->size; | 844 | sz = pcmbuf_tail->size; |
@@ -750,7 +847,7 @@ static void get_more(unsigned char** start, size_t* size) | |||
750 | 847 | ||
751 | pcm_advance_buffer(&pcmbuf_tail, sz); | 848 | pcm_advance_buffer(&pcmbuf_tail, sz); |
752 | 849 | ||
753 | pcmbuf_used -= sz; | 850 | pcmbuf_read += sz; |
754 | 851 | ||
755 | sz -= sizeof (*pcmbuf_tail); | 852 | sz -= sizeof (*pcmbuf_tail); |
756 | 853 | ||
@@ -771,8 +868,8 @@ static void get_more(unsigned char** start, size_t* size) | |||
771 | 868 | ||
772 | samplesplayed += sz >> 2; | 869 | samplesplayed += sz >> 2; |
773 | 870 | ||
774 | if (pcmbuf_used < 0) | 871 | if (pcmbuf_read > pcmbuf_written) |
775 | pcmbuf_used = 0; | 872 | pcmbuf_read = pcmbuf_written; |
776 | } | 873 | } |
777 | 874 | ||
778 | /* Flushes the buffer - clock keeps counting */ | 875 | /* Flushes the buffer - clock keeps counting */ |
@@ -783,7 +880,8 @@ static void pcm_playback_flush(void) | |||
783 | if (was_playing) | 880 | if (was_playing) |
784 | rb->pcm_play_stop(); | 881 | rb->pcm_play_stop(); |
785 | 882 | ||
786 | pcmbuf_used = 0; | 883 | pcmbuf_read = 0; |
884 | pcmbuf_written = 0; | ||
787 | pcmbuf_head = pcmbuf_tail; | 885 | pcmbuf_head = pcmbuf_tail; |
788 | 886 | ||
789 | if (was_playing) | 887 | if (was_playing) |
@@ -855,11 +953,30 @@ static inline int32_t clip_sample(int32_t sample) | |||
855 | return sample; | 953 | return sample; |
856 | } | 954 | } |
857 | 955 | ||
858 | static void button_loop(void) | 956 | static int button_loop(void) |
859 | { | 957 | { |
860 | bool result; | 958 | bool result; |
861 | int vol, minvol, maxvol; | 959 | int vol, minvol, maxvol; |
862 | int button = rb->button_get(false); | 960 | int button; |
961 | |||
962 | if (str_have_msg(&audio_str)) | ||
963 | { | ||
964 | struct event ev; | ||
965 | str_get_msg(&audio_str, &ev); | ||
966 | |||
967 | if (ev.id == STREAM_STOP) | ||
968 | { | ||
969 | audio_str.status = STREAM_STOPPED; | ||
970 | str_reply_msg(&audio_str, 1); | ||
971 | goto quit; | ||
972 | } | ||
973 | else | ||
974 | { | ||
975 | str_reply_msg(&audio_str, 0); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | button = rb->button_get(false); | ||
863 | 980 | ||
864 | switch (button) | 981 | switch (button) |
865 | { | 982 | { |
@@ -897,13 +1014,8 @@ static void button_loop(void) | |||
897 | 1014 | ||
898 | case MPEG_MENU: | 1015 | case MPEG_MENU: |
899 | pcm_playback_play_pause(false); | 1016 | pcm_playback_play_pause(false); |
900 | if (videostatus != STREAM_DONE) { | 1017 | audio_str.status = STREAM_PAUSED; |
901 | videostatus=PLEASE_PAUSE; | 1018 | str_send_msg(&video_str, STREAM_PAUSE, 0); |
902 | |||
903 | /* Wait for video thread to stop */ | ||
904 | while (videostatus == PLEASE_PAUSE) { rb->sleep(HZ/25); } | ||
905 | } | ||
906 | |||
907 | #ifndef HAVE_LCD_COLOR | 1019 | #ifndef HAVE_LCD_COLOR |
908 | gray_show(false); | 1020 | gray_show(false); |
909 | #endif | 1021 | #endif |
@@ -919,21 +1031,23 @@ static void button_loop(void) | |||
919 | rb->lcd_setfont(FONT_SYSFIXED); | 1031 | rb->lcd_setfont(FONT_SYSFIXED); |
920 | 1032 | ||
921 | if (result) { | 1033 | if (result) { |
922 | audiostatus = PLEASE_STOP; | 1034 | str_send_msg(&video_str, STREAM_STOP, 0); |
923 | if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP; | 1035 | audio_str.status = STREAM_STOPPED; |
924 | } else { | 1036 | } else { |
925 | if (videostatus != STREAM_DONE) videostatus = STREAM_PLAYING; | 1037 | audio_str.status = STREAM_PLAYING; |
1038 | str_send_msg(&video_str, STREAM_PLAY, 0); | ||
926 | pcm_playback_play_pause(true); | 1039 | pcm_playback_play_pause(true); |
927 | } | 1040 | } |
928 | break; | 1041 | break; |
929 | 1042 | ||
930 | case MPEG_STOP: | 1043 | case MPEG_STOP: |
931 | audiostatus = PLEASE_STOP; | 1044 | str_send_msg(&video_str, STREAM_STOP, 0); |
932 | if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP; | 1045 | audio_str.status = STREAM_STOPPED; |
933 | break; | 1046 | break; |
934 | 1047 | ||
935 | case MPEG_PAUSE: | 1048 | case MPEG_PAUSE: |
936 | if (videostatus != STREAM_DONE) videostatus=PLEASE_PAUSE; | 1049 | str_send_msg(&video_str, STREAM_PAUSE, 0); |
1050 | audio_str.status = STREAM_PAUSED; | ||
937 | pcm_playback_play_pause(false); | 1051 | pcm_playback_play_pause(false); |
938 | 1052 | ||
939 | button = BUTTON_NONE; | 1053 | button = BUTTON_NONE; |
@@ -943,13 +1057,14 @@ static void button_loop(void) | |||
943 | do { | 1057 | do { |
944 | button = rb->button_get(true); | 1058 | button = rb->button_get(true); |
945 | if (button == MPEG_STOP) { | 1059 | if (button == MPEG_STOP) { |
946 | audiostatus = PLEASE_STOP; | 1060 | str_send_msg(&video_str, STREAM_STOP, 0); |
947 | if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP; | 1061 | audio_str.status = STREAM_STOPPED; |
948 | return; | 1062 | goto quit; |
949 | } | 1063 | } |
950 | } while (button != MPEG_PAUSE); | 1064 | } while (button != MPEG_PAUSE); |
951 | 1065 | ||
952 | if (videostatus != STREAM_DONE) videostatus = STREAM_PLAYING; | 1066 | str_send_msg(&video_str, STREAM_PLAY, 0); |
1067 | audio_str.status = STREAM_PLAYING; | ||
953 | pcm_playback_play_pause(true); | 1068 | pcm_playback_play_pause(true); |
954 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 1069 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
955 | rb->cpu_boost(true); | 1070 | rb->cpu_boost(true); |
@@ -958,10 +1073,13 @@ static void button_loop(void) | |||
958 | 1073 | ||
959 | default: | 1074 | default: |
960 | if(rb->default_event_handler(button) == SYS_USB_CONNECTED) { | 1075 | if(rb->default_event_handler(button) == SYS_USB_CONNECTED) { |
961 | audiostatus = PLEASE_STOP; | 1076 | str_send_msg(&video_str, STREAM_STOP, 0); |
962 | if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP; | 1077 | audio_str.status = STREAM_STOPPED; |
963 | } | 1078 | } |
964 | } | 1079 | } |
1080 | |||
1081 | quit: | ||
1082 | return audio_str.status; | ||
965 | } | 1083 | } |
966 | 1084 | ||
967 | static void audio_thread(void) | 1085 | static void audio_thread(void) |
@@ -996,10 +1114,8 @@ static void audio_thread(void) | |||
996 | int mad_stat; | 1114 | int mad_stat; |
997 | size_t len; | 1115 | size_t len; |
998 | 1116 | ||
999 | button_loop(); | 1117 | if (button_loop() < 0) |
1000 | 1118 | goto done; | |
1001 | if (audiostatus == PLEASE_STOP) | ||
1002 | goto done; | ||
1003 | 1119 | ||
1004 | if (pts->size <= 0) | 1120 | if (pts->size <= 0) |
1005 | { | 1121 | { |
@@ -1146,10 +1262,21 @@ static void audio_thread(void) | |||
1146 | 1262 | ||
1147 | /* Leave at least 32KB free (this will be the currently | 1263 | /* Leave at least 32KB free (this will be the currently |
1148 | playing chunk) */ | 1264 | playing chunk) */ |
1149 | while (pcmbuf_used + wait_for > PCMBUFFER_SIZE) | 1265 | while (pcmbuf_used() + wait_for > PCMBUFFER_SIZE) |
1150 | { | 1266 | { |
1151 | if (audiostatus == PLEASE_STOP) | 1267 | if (str_have_msg(&audio_str)) |
1152 | goto done; | 1268 | { |
1269 | struct event ev; | ||
1270 | str_look_msg(&audio_str, &ev); | ||
1271 | |||
1272 | if (ev.id == STREAM_STOP) | ||
1273 | { | ||
1274 | str_get_msg(&audio_str, &ev); | ||
1275 | str_reply_msg(&audio_str, 1); | ||
1276 | goto stop_and_wait; | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1153 | rb->priority_yield(); | 1280 | rb->priority_yield(); |
1154 | } | 1281 | } |
1155 | 1282 | ||
@@ -1192,56 +1319,56 @@ static void audio_thread(void) | |||
1192 | 1319 | ||
1193 | pcm_advance_buffer(&pcmbuf_head, size); | 1320 | pcm_advance_buffer(&pcmbuf_head, size); |
1194 | 1321 | ||
1195 | if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used >= 64*1024) | 1322 | if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used() >= 64*1024) |
1196 | { | 1323 | { |
1197 | /* We've reached our size treshold so start playing back the | 1324 | /* We've reached our size treshold so start playing back the |
1198 | audio in the buffer and set the buffer to play all data */ | 1325 | audio in the buffer and set the buffer to play all data */ |
1199 | audiostatus = STREAM_PLAYING; | 1326 | audio_str.status = STREAM_PLAYING; |
1200 | pcmbuf_threshold = PCMBUF_PLAY_ALL; | 1327 | pcmbuf_threshold = PCMBUF_PLAY_ALL; |
1201 | pcm_playback_seek_time(pcmbuf_tail->time); | 1328 | pcm_playback_seek_time(pcmbuf_tail->time); |
1202 | } | 1329 | } |
1203 | 1330 | ||
1204 | /* Make this data available to DMA */ | 1331 | /* Make this data available to DMA */ |
1205 | locked_add_long(&pcmbuf_used, size); | 1332 | pcmbuf_written += size; |
1206 | } | 1333 | } |
1207 | 1334 | ||
1208 | rb->yield(); | 1335 | rb->yield(); |
1209 | } /* end decoding loop */ | 1336 | } /* end decoding loop */ |
1210 | 1337 | ||
1211 | done: | 1338 | done: |
1212 | if (audiostatus != PLEASE_STOP) | 1339 | if (audio_str.status == STREAM_STOPPED) |
1340 | goto stop_and_wait; | ||
1341 | |||
1342 | /* Force any residue to play if audio ended before reaching the | ||
1343 | threshold */ | ||
1344 | if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used() > 0) | ||
1213 | { | 1345 | { |
1214 | /* Force any residue to play if audio ended before reaching the | 1346 | pcm_playback_play(pcmbuf_tail->time); |
1215 | threshold */ | 1347 | pcmbuf_threshold = PCMBUF_PLAY_ALL; |
1216 | if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used > 0) | 1348 | } |
1217 | { | ||
1218 | pcm_playback_play(pcmbuf_tail->time); | ||
1219 | pcmbuf_threshold = PCMBUF_PLAY_ALL; | ||
1220 | } | ||
1221 | 1349 | ||
1222 | if (rb->pcm_is_playing() && !rb->pcm_is_paused()) | 1350 | if (rb->pcm_is_playing() && !rb->pcm_is_paused()) |
1351 | { | ||
1352 | /* Wait for audio to finish */ | ||
1353 | while (pcmbuf_used() > 0) | ||
1223 | { | 1354 | { |
1224 | /* Wait for audio to finish */ | 1355 | if (button_loop() == STREAM_STOPPED) |
1225 | while (pcmbuf_used > 0 && audiostatus != PLEASE_STOP) | 1356 | break; |
1226 | { | 1357 | rb->sleep(HZ/10); |
1227 | button_loop(); | ||
1228 | rb->sleep(HZ/10); | ||
1229 | } | ||
1230 | } | 1358 | } |
1231 | } | 1359 | } |
1232 | 1360 | ||
1233 | audiostatus = STREAM_DONE; | 1361 | stop_and_wait: |
1362 | |||
1363 | audio_str.status = STREAM_DONE; | ||
1234 | 1364 | ||
1235 | /* Process events until finished */ | 1365 | /* Process events until finished */ |
1236 | while (audiostatus != PLEASE_STOP) | 1366 | while (button_loop() != STREAM_STOPPED) |
1237 | { | ||
1238 | button_loop(); | ||
1239 | rb->sleep(HZ/4); | 1367 | rb->sleep(HZ/4); |
1240 | } | ||
1241 | 1368 | ||
1242 | pcm_playback_stop(); | 1369 | pcm_playback_stop(); |
1243 | 1370 | ||
1244 | audiostatus = THREAD_TERMINATED; | 1371 | audio_str.status = STREAM_TERMINATED; |
1245 | rb->remove_thread(NULL); | 1372 | rb->remove_thread(NULL); |
1246 | } | 1373 | } |
1247 | 1374 | ||
@@ -1260,6 +1387,7 @@ static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR; | |||
1260 | 1387 | ||
1261 | static void video_thread(void) | 1388 | static void video_thread(void) |
1262 | { | 1389 | { |
1390 | struct event ev; | ||
1263 | const mpeg2_info_t * info; | 1391 | const mpeg2_info_t * info; |
1264 | mpeg2_state_t state; | 1392 | mpeg2_state_t state; |
1265 | char str[80]; | 1393 | char str[80]; |
@@ -1280,7 +1408,7 @@ static void video_thread(void) | |||
1280 | { | 1408 | { |
1281 | rb->splash(0, "mpeg2_init failed"); | 1409 | rb->splash(0, "mpeg2_init failed"); |
1282 | /* Commit suicide */ | 1410 | /* Commit suicide */ |
1283 | videostatus = THREAD_TERMINATED; | 1411 | video_str.status = STREAM_TERMINATED; |
1284 | rb->remove_thread(NULL); | 1412 | rb->remove_thread(NULL); |
1285 | } | 1413 | } |
1286 | 1414 | ||
@@ -1302,24 +1430,36 @@ static void video_thread(void) | |||
1302 | 1430 | ||
1303 | /* Wait if the audio thread is buffering - i.e. before | 1431 | /* Wait if the audio thread is buffering - i.e. before |
1304 | the first frames are decoded */ | 1432 | the first frames are decoded */ |
1305 | while (audiostatus == STREAM_BUFFERING) | 1433 | while (audio_str.status == STREAM_BUFFERING) |
1306 | rb->priority_yield(); | 1434 | rb->priority_yield(); |
1307 | 1435 | ||
1308 | while (1) | 1436 | while (1) |
1309 | { | 1437 | { |
1310 | if (videostatus == PLEASE_STOP) | 1438 | /* quickly check mailbox first */ |
1311 | { | 1439 | if (str_have_msg(&video_str)) |
1312 | break; | ||
1313 | } | ||
1314 | else if (videostatus == PLEASE_PAUSE) | ||
1315 | { | 1440 | { |
1316 | videostatus = STREAM_PAUSING; | 1441 | while (1) |
1317 | flush_icache(); | 1442 | { |
1443 | str_get_msg(&video_str, &ev); | ||
1318 | 1444 | ||
1319 | while (videostatus == STREAM_PAUSING) | 1445 | switch (ev.id) |
1320 | rb->sleep(HZ/10); | 1446 | { |
1447 | case STREAM_STOP: | ||
1448 | video_str.status = STREAM_STOPPED; | ||
1449 | str_reply_msg(&video_str, 1); | ||
1450 | goto done; | ||
1451 | case STREAM_PAUSE: | ||
1452 | flush_icache(); | ||
1453 | video_str.status = STREAM_PAUSED; | ||
1454 | str_reply_msg(&video_str, 1); | ||
1455 | continue; | ||
1456 | } | ||
1321 | 1457 | ||
1322 | continue; | 1458 | break; |
1459 | } | ||
1460 | |||
1461 | video_str.status = STREAM_PLAYING; | ||
1462 | str_reply_msg(&video_str, 1); | ||
1323 | } | 1463 | } |
1324 | 1464 | ||
1325 | state = mpeg2_parse (mpeg2dec); | 1465 | state = mpeg2_parse (mpeg2dec); |
@@ -1551,8 +1691,16 @@ static void video_thread(void) | |||
1551 | rb->priority_yield(); | 1691 | rb->priority_yield(); |
1552 | 1692 | ||
1553 | /* Make sure not to get stuck waiting here forever */ | 1693 | /* Make sure not to get stuck waiting here forever */ |
1554 | if (videostatus != STREAM_PLAYING) | 1694 | if (str_have_msg(&video_str)) |
1555 | goto rendering_finished; | 1695 | { |
1696 | str_look_msg(&video_str, &ev); | ||
1697 | |||
1698 | if (ev.id != STREAM_PLAY) | ||
1699 | goto rendering_finished; | ||
1700 | |||
1701 | str_get_msg(&video_str, &ev); | ||
1702 | str_reply_msg(&video_str, 1); | ||
1703 | } | ||
1556 | 1704 | ||
1557 | eta_audio = get_stream_time(); | 1705 | eta_audio = get_stream_time(); |
1558 | } | 1706 | } |
@@ -1599,13 +1747,21 @@ static void video_thread(void) | |||
1599 | done: | 1747 | done: |
1600 | flush_icache(); | 1748 | flush_icache(); |
1601 | 1749 | ||
1602 | videostatus = STREAM_DONE; | 1750 | video_str.status = STREAM_DONE; |
1603 | 1751 | ||
1604 | while (videostatus != PLEASE_STOP) | 1752 | while (1) |
1605 | rb->sleep(HZ/5); | 1753 | { |
1754 | str_get_msg(&video_str, &ev); | ||
1755 | |||
1756 | if (ev.id == STREAM_STOP) | ||
1757 | break; | ||
1758 | |||
1759 | str_reply_msg(&video_str, 0); | ||
1760 | } | ||
1606 | 1761 | ||
1607 | videostatus = THREAD_TERMINATED; | ||
1608 | /* Commit suicide */ | 1762 | /* Commit suicide */ |
1763 | str_reply_msg(&video_str, 1); | ||
1764 | video_str.status = STREAM_TERMINATED; | ||
1609 | rb->remove_thread(NULL); | 1765 | rb->remove_thread(NULL); |
1610 | } | 1766 | } |
1611 | 1767 | ||
@@ -1756,8 +1912,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
1756 | video_str.buffer_remaining = disk_buf_len; | 1912 | video_str.buffer_remaining = disk_buf_len; |
1757 | audio_str.buffer_remaining = disk_buf_len; | 1913 | audio_str.buffer_remaining = disk_buf_len; |
1758 | 1914 | ||
1759 | audiostatus = STREAM_BUFFERING; | 1915 | rb->spinlock_init(&audio_str.msg_lock); |
1760 | videostatus = STREAM_PLAYING; | 1916 | rb->spinlock_init(&video_str.msg_lock); |
1917 | audio_str.status = STREAM_BUFFERING; | ||
1918 | video_str.status = STREAM_PLAYING; | ||
1761 | 1919 | ||
1762 | #ifndef HAVE_LCD_COLOR | 1920 | #ifndef HAVE_LCD_COLOR |
1763 | gray_show(true); | 1921 | gray_show(true); |
@@ -1766,13 +1924,13 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
1766 | init_stream_lock(); | 1924 | init_stream_lock(); |
1767 | 1925 | ||
1768 | /* We put the video thread on the second processor for multi-core targets. */ | 1926 | /* We put the video thread on the second processor for multi-core targets. */ |
1769 | if ((videothread_id = rb->create_thread(video_thread, | 1927 | if ((video_str.thread = rb->create_thread(video_thread, |
1770 | (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) | 1928 | (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) |
1771 | IF_COP(, COP, true))) == NULL) | 1929 | IF_COP(, COP, true))) == NULL) |
1772 | { | 1930 | { |
1773 | rb->splash(HZ, "Cannot create video thread!"); | 1931 | rb->splash(HZ, "Cannot create video thread!"); |
1774 | } | 1932 | } |
1775 | else if ((audiothread_id = rb->create_thread(audio_thread, | 1933 | else if ((audio_str.thread = rb->create_thread(audio_thread, |
1776 | (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK) | 1934 | (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK) |
1777 | IF_COP(, CPU, false))) == NULL) | 1935 | IF_COP(, CPU, false))) == NULL) |
1778 | { | 1936 | { |
@@ -1784,7 +1942,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
1784 | rb->lcd_setfont(FONT_SYSFIXED); | 1942 | rb->lcd_setfont(FONT_SYSFIXED); |
1785 | 1943 | ||
1786 | /* Wait until both threads have finished their work */ | 1944 | /* Wait until both threads have finished their work */ |
1787 | while ((audiostatus != STREAM_DONE) || (videostatus != STREAM_DONE)) | 1945 | while ((audio_str.status >= 0) || (video_str.status >= 0)) |
1788 | { | 1946 | { |
1789 | size_t audio_remaining = audio_str.buffer_remaining; | 1947 | size_t audio_remaining = audio_str.buffer_remaining; |
1790 | size_t video_remaining = video_str.buffer_remaining; | 1948 | size_t video_remaining = video_str.buffer_remaining; |
@@ -1797,7 +1955,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
1797 | bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail)); | 1955 | bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail)); |
1798 | 1956 | ||
1799 | while (( bytes_to_read > 0) && (file_remaining > 0) && | 1957 | while (( bytes_to_read > 0) && (file_remaining > 0) && |
1800 | ((audiostatus != STREAM_DONE) || (videostatus != STREAM_DONE))) { | 1958 | ((audio_str.status >= 0) || (video_str.status >= 0))) { |
1801 | size_t n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read)); | 1959 | size_t n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read)); |
1802 | 1960 | ||
1803 | bytes_to_read -= n; | 1961 | bytes_to_read -= n; |
@@ -1825,19 +1983,11 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
1825 | } | 1983 | } |
1826 | 1984 | ||
1827 | /* Stop the threads and wait for them to terminate */ | 1985 | /* Stop the threads and wait for them to terminate */ |
1828 | if (videothread_id != NULL && videostatus != THREAD_TERMINATED) | 1986 | if (video_str.thread != NULL) |
1829 | { | 1987 | str_send_msg(&video_str, STREAM_STOP, 0); |
1830 | videostatus = PLEASE_STOP; | ||
1831 | while (videostatus != THREAD_TERMINATED) | ||
1832 | rb->yield(); | ||
1833 | } | ||
1834 | 1988 | ||
1835 | if (audiothread_id != NULL && audiostatus != THREAD_TERMINATED) | 1989 | if (audio_str.thread != NULL) |
1836 | { | 1990 | str_send_msg(&audio_str, STREAM_STOP, 0); |
1837 | audiostatus = PLEASE_STOP; | ||
1838 | while (audiostatus != THREAD_TERMINATED) | ||
1839 | rb->yield(); | ||
1840 | } | ||
1841 | 1991 | ||
1842 | rb->sleep(HZ/10); | 1992 | rb->sleep(HZ/10); |
1843 | 1993 | ||