summaryrefslogtreecommitdiff
path: root/apps/playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playback.c')
-rw-r--r--apps/playback.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 9bbce17a0a..51a46bdf7e 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -824,10 +824,15 @@ bufpanic:
824 panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen); 824 panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen);
825} 825}
826 826
827
828/* Buffer must not move. */ 827/* Buffer must not move. */
829static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size) 828static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size)
830{ 829{
830 struct queue_event ev;
831 static const long filter_list[][2] =
832 {
833 /* codec messages */
834 { Q_AUDIO_PLAY, Q_AUDIO_PLAY },
835 };
831 /* filebuflen is, at this point, the buffering.c buffer size, 836 /* filebuflen is, at this point, the buffering.c buffer size,
832 * i.e. the audiobuf except voice, scratch mem, pcm, ... */ 837 * i.e. the audiobuf except voice, scratch mem, pcm, ... */
833 ssize_t extradata_size = old_size - filebuflen; 838 ssize_t extradata_size = old_size - filebuflen;
@@ -838,9 +843,24 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
838 if ((size - extradata_size) < 256*1024) 843 if ((size - extradata_size) < 256*1024)
839 return BUFLIB_CB_CANNOT_SHRINK; 844 return BUFLIB_CB_CANNOT_SHRINK;
840 845
841 long offset = audio_current_track()->offset; 846
842 int status = audio_status();
843 /* TODO: Do it without stopping playback, if possible */ 847 /* TODO: Do it without stopping playback, if possible */
848 long offset = audio_current_track()->offset;
849 bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY;
850 /* There's one problem with stoping and resuming: If it happens in a too
851 * frequent fashion, the codecs lose the resume postion and playback
852 * begins from the beginning.
853 * To work around use queue_post() to effectively delay the resume in case
854 * we're called another time. However this has another problem: id3->offset
855 * gets zero since playback is stopped. Therefore, try to peek at the
856 * queue_post from the last call to get the correct offset. This also
857 * lets us conviniently remove the queue event so Q_AUDIO_START is only
858 * processed once. */
859 bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, filter_list);
860
861 if (playing && offset > 0) /* current id3->offset is king */
862 ev.data = offset;
863
844 /* don't call audio_hard_stop() as it frees this handle */ 864 /* don't call audio_hard_stop() as it frees this handle */
845 if (thread_self() == audio_thread_id) 865 if (thread_self() == audio_thread_id)
846 { /* inline case Q_AUDIO_STOP (audio_hard_stop() response 866 { /* inline case Q_AUDIO_STOP (audio_hard_stop() response
@@ -868,12 +888,10 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
868 audio_reset_buffer_noalloc(start + wanted_size); 888 audio_reset_buffer_noalloc(start + wanted_size);
869 break; 889 break;
870 } 890 }
871 if ((status & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY) 891 if (playing || play_queued)
872 { 892 {
873 if (thread_self() == audio_thread_id) 893 /* post, to make subsequent calls not break the resume position */
874 audio_start_playback(offset, 0); /* inline Q_AUDIO_PLAY */ 894 audio_queue_post(Q_AUDIO_PLAY, ev.data);
875 else
876 audio_play(offset);
877 } 895 }
878 896
879 return BUFLIB_CB_OK; 897 return BUFLIB_CB_OK;