diff options
-rw-r--r-- | apps/playback.c | 34 |
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. */ |
829 | static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size) | 828 | static 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; |