summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-11-05 10:01:22 +0000
committerThomas Martitz <kugel@rockbox.org>2011-11-05 10:01:22 +0000
commitd7e1070827d763d7d2c31332d9d3bb7540f3bca5 (patch)
treee6370a03b622fc2b82ce81e3e7cd925cda6c8868
parentec5d6ea7bbb300e5a5320b815c072aa8615891be (diff)
downloadrockbox-d7e1070827d763d7d2c31332d9d3bb7540f3bca5.tar.gz
rockbox-d7e1070827d763d7d2c31332d9d3bb7540f3bca5.zip
Fix FS#12279 - playback starts from the beginning when changing themes.
Very frequent start-stop cycles (as caused by frequent core_alloc() calls) of audio makes the codecs lose the resume position, and this causes playback from the beginning. To work around, use queue_post() instead of queue_send() to delay the resume so that it only resumes once per core_alloc() set. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30900 a1c6a512-1295-4272-9138-f99709370657
-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;