summaryrefslogtreecommitdiff
path: root/apps/mpeg.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/mpeg.c')
-rw-r--r--apps/mpeg.c121
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;
140static bool checked_for_cuesheet = false; 140static bool checked_for_cuesheet = false;
141 141
142static const char mpeg_thread_name[] = "mpeg"; 142static const char mpeg_thread_name[] = "mpeg";
143static unsigned int audio_thread_id;
143static unsigned int mpeg_errno; 144static unsigned int mpeg_errno;
144 145
145static bool playing = false; /* We are playing an MP3 stream */ 146static 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 */ 496static void do_stop(void)
496static 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
512static void audio_reset_buffer_noalloc(void* buf, size_t bufsize);
513/* Buffer must not move. */
514static 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
551static struct buflib_callbacks ops = {
552 .move_callback = NULL,
553 .shrink_callback = shrink_callback,
554};
555
497unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) 556unsigned 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
2682static void audio_reset_buffer(void) 2736static 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
2750static 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
2697void audio_play(long offset) 2761void audio_play(long offset)
@@ -2923,13 +2987,6 @@ static void mpeg_thread(void)
2923void audio_init(void) 2987void 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