diff options
Diffstat (limited to 'apps/mpeg.c')
-rw-r--r-- | apps/mpeg.c | 121 |
1 files changed, 89 insertions, 32 deletions
diff --git a/apps/mpeg.c b/apps/mpeg.c index 595f943545..0b1413e195 100644 --- a/apps/mpeg.c +++ b/apps/mpeg.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include "mp3_playback.h" | 39 | #include "mp3_playback.h" |
40 | #include "talk.h" | 40 | #include "talk.h" |
41 | #include "sound.h" | 41 | #include "sound.h" |
42 | #include "bitswap.h" | 42 | #include "system.h" |
43 | #include "appevents.h" | 43 | #include "appevents.h" |
44 | #include "playlist.h" | 44 | #include "playlist.h" |
45 | #include "cuesheet.h" | 45 | #include "cuesheet.h" |
@@ -140,6 +140,7 @@ static struct cuesheet *curr_cuesheet = NULL; | |||
140 | static bool checked_for_cuesheet = false; | 140 | static bool checked_for_cuesheet = false; |
141 | 141 | ||
142 | static const char mpeg_thread_name[] = "mpeg"; | 142 | static const char mpeg_thread_name[] = "mpeg"; |
143 | static unsigned int audio_thread_id; | ||
143 | static unsigned int mpeg_errno; | 144 | static unsigned int mpeg_errno; |
144 | 145 | ||
145 | static bool playing = false; /* We are playing an MP3 stream */ | 146 | static bool playing = false; /* We are playing an MP3 stream */ |
@@ -492,20 +493,81 @@ unsigned long mpeg_get_last_header(void) | |||
492 | #endif /* !SIMULATOR */ | 493 | #endif /* !SIMULATOR */ |
493 | } | 494 | } |
494 | 495 | ||
495 | /* Buffer must not move. And not shrink for now */ | 496 | static void do_stop(void) |
496 | static struct buflib_callbacks ops = { NULL, NULL }; | 497 | { |
498 | is_playing = false; | ||
499 | paused = false; | ||
500 | |||
501 | #ifndef SIMULATOR | ||
502 | if (playing) | ||
503 | playlist_update_resume_info(audio_current_track()); | ||
504 | |||
505 | stop_playing(); | ||
506 | mpeg_stop_done = true; | ||
507 | #else | ||
508 | playing = false; | ||
509 | #endif | ||
510 | } | ||
511 | |||
512 | static void audio_reset_buffer_noalloc(void* buf, size_t bufsize); | ||
513 | /* Buffer must not move. */ | ||
514 | static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size) | ||
515 | { | ||
516 | long offset = audio_current_track()->offset; | ||
517 | int status = audio_status(); | ||
518 | /* TODO: Do it without stopping playback, if possible */ | ||
519 | /* don't call audio_hard_stop() as it frees this handle */ | ||
520 | if (thread_self() == audio_thread_id) | ||
521 | { /* inline case MPEG_STOP (audio_stop()) response | ||
522 | * if we're in the audio thread since audio_stop() otherwise deadlocks */ | ||
523 | do_stop(); | ||
524 | } | ||
525 | else | ||
526 | audio_stop(); | ||
527 | talk_buffer_steal(); /* we obtain control over the buffer */ | ||
528 | |||
529 | /* we should be free to change the buffer now */ | ||
530 | size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK); | ||
531 | ssize_t size = (ssize_t)old_size - wanted_size; | ||
532 | switch (hints & BUFLIB_SHRINK_POS_MASK) | ||
533 | { | ||
534 | case BUFLIB_SHRINK_POS_BACK: | ||
535 | core_shrink(handle, start, size); | ||
536 | audio_reset_buffer_noalloc(start, size); | ||
537 | break; | ||
538 | case BUFLIB_SHRINK_POS_FRONT: | ||
539 | core_shrink(handle, start + wanted_size, size); | ||
540 | audio_reset_buffer_noalloc(start + wanted_size, size); | ||
541 | break; | ||
542 | } | ||
543 | if (!(status & AUDIO_STATUS_PAUSE)) | ||
544 | { /* safe to call even from the audio thread (due to queue_post()) */ | ||
545 | audio_play(offset); | ||
546 | } | ||
547 | |||
548 | return BUFLIB_CB_OK; | ||
549 | } | ||
550 | |||
551 | static struct buflib_callbacks ops = { | ||
552 | .move_callback = NULL, | ||
553 | .shrink_callback = shrink_callback, | ||
554 | }; | ||
555 | |||
497 | unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) | 556 | unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) |
498 | { | 557 | { |
499 | (void)talk_buf; /* always grab the voice buffer for now */ | 558 | (void)talk_buf; /* always grab the voice buffer for now */ |
500 | 559 | ||
501 | if (buffer_size) /* special case for talk_init() */ | 560 | if (buffer_size) /* special case for talk_init() */ |
561 | audio_hard_stop(); | ||
562 | |||
563 | if (!audiobuf_handle) | ||
502 | { | 564 | { |
503 | size_t bufsize; | 565 | size_t bufsize; |
504 | audio_hard_stop(); | ||
505 | /* audio_hard_stop() frees audiobuf, so re-aquire */ | 566 | /* audio_hard_stop() frees audiobuf, so re-aquire */ |
506 | audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops); | 567 | audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops); |
507 | audiobuflen = bufsize; | 568 | audiobuflen = bufsize; |
508 | *buffer_size = audiobuflen; | 569 | if (buffer_size) |
570 | *buffer_size = audiobuflen; | ||
509 | } | 571 | } |
510 | mpeg_audiobuf = core_get_data(audiobuf_handle); | 572 | mpeg_audiobuf = core_get_data(audiobuf_handle); |
511 | 573 | ||
@@ -1314,15 +1376,7 @@ static void mpeg_thread(void) | |||
1314 | break; | 1376 | break; |
1315 | 1377 | ||
1316 | case MPEG_STOP: | 1378 | case MPEG_STOP: |
1317 | DEBUGF("MPEG_STOP\n"); | 1379 | do_stop(); |
1318 | is_playing = false; | ||
1319 | paused = false; | ||
1320 | |||
1321 | if (playing) | ||
1322 | playlist_update_resume_info(audio_current_track()); | ||
1323 | |||
1324 | stop_playing(); | ||
1325 | mpeg_stop_done = true; | ||
1326 | break; | 1380 | break; |
1327 | 1381 | ||
1328 | case MPEG_PAUSE: | 1382 | case MPEG_PAUSE: |
@@ -2679,19 +2733,29 @@ size_t audio_buffer_available(void) | |||
2679 | return core_available(); | 2733 | return core_available(); |
2680 | } | 2734 | } |
2681 | 2735 | ||
2682 | static void audio_reset_buffer(void) | 2736 | static void audio_reset_buffer_noalloc(void* buf, size_t bufsize) |
2683 | { | 2737 | { |
2684 | talk_buffer_steal(); /* will use the mp3 buffer */ | 2738 | talk_buffer_steal(); /* will use the mp3 buffer */ |
2739 | mpeg_audiobuf = buf; | ||
2740 | audiobuflen = bufsize; | ||
2741 | if (global_settings.cuesheet) | ||
2742 | { /* enable cuesheet support */ | ||
2743 | curr_cuesheet = (struct cuesheet*)mpeg_audiobuf; | ||
2744 | mpeg_audiobuf = SKIPBYTES(mpeg_audiobuf, sizeof(struct cuesheet)); | ||
2745 | audiobuflen -= sizeof(struct cuesheet); | ||
2746 | } | ||
2747 | talkbuf_init(mpeg_audiobuf); | ||
2748 | } | ||
2749 | |||
2750 | static void audio_reset_buffer(void) | ||
2751 | { | ||
2752 | size_t bufsize = audiobuflen; | ||
2685 | 2753 | ||
2686 | /* alloc buffer if it's was never allocated or freed by audio_hard_stop() */ | 2754 | /* alloc buffer if it's was never allocated or freed by audio_hard_stop() */ |
2687 | if (!audiobuf_handle) | 2755 | if (!audiobuf_handle) |
2688 | { | ||
2689 | size_t bufsize; /* dont break strict-aliasing */ | ||
2690 | audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops); | 2756 | audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops); |
2691 | mpeg_audiobuf = core_get_data(audiobuf_handle); | 2757 | |
2692 | audiobuflen = bufsize; | 2758 | audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize); |
2693 | } | ||
2694 | talkbuf_init(mpeg_audiobuf); | ||
2695 | } | 2759 | } |
2696 | 2760 | ||
2697 | void audio_play(long offset) | 2761 | void audio_play(long offset) |
@@ -2923,13 +2987,6 @@ static void mpeg_thread(void) | |||
2923 | void audio_init(void) | 2987 | void audio_init(void) |
2924 | { | 2988 | { |
2925 | mpeg_errno = 0; | 2989 | mpeg_errno = 0; |
2926 | /* cuesheet support */ | ||
2927 | if (global_settings.cuesheet) | ||
2928 | { | ||
2929 | int handle = core_alloc("cuesheet", sizeof(struct cuesheet)); | ||
2930 | if (handle > 0) | ||
2931 | curr_cuesheet = core_get_data(handle); | ||
2932 | } | ||
2933 | 2990 | ||
2934 | talk_init(); | 2991 | talk_init(); |
2935 | audio_reset_buffer(); | 2992 | audio_reset_buffer(); |
@@ -2937,10 +2994,10 @@ void audio_init(void) | |||
2937 | #ifndef SIMULATOR | 2994 | #ifndef SIMULATOR |
2938 | queue_init(&mpeg_queue, true); | 2995 | queue_init(&mpeg_queue, true); |
2939 | #endif /* !SIMULATOR */ | 2996 | #endif /* !SIMULATOR */ |
2940 | create_thread(mpeg_thread, mpeg_stack, | 2997 | audio_thread_id = create_thread(mpeg_thread, mpeg_stack, |
2941 | sizeof(mpeg_stack), 0, mpeg_thread_name | 2998 | sizeof(mpeg_stack), 0, mpeg_thread_name |
2942 | IF_PRIO(, PRIORITY_SYSTEM) | 2999 | IF_PRIO(, PRIORITY_SYSTEM) |
2943 | IF_COP(, CPU)); | 3000 | IF_COP(, CPU)); |
2944 | 3001 | ||
2945 | memset(trackdata, 0, sizeof(trackdata)); | 3002 | memset(trackdata, 0, sizeof(trackdata)); |
2946 | 3003 | ||