diff --git a/apps/playback.c b/apps/playback.c
index 9bbce17..88b3260 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -824,10 +824,15 @@ bufpanic:
panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen);
}

-
/* Buffer must not move. */
static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size)
{
+ struct queue_event ev;
+ static const long filter_list[][2] =
+ {
+ /* codec messages */
+ { Q_AUDIO_PLAY, Q_AUDIO_PLAY },
+ };
/* filebuflen is, at this point, the buffering.c buffer size,
* i.e. the audiobuf except voice, scratch mem, pcm, ... */
ssize_t extradata_size = old_size - filebuflen;
@@ -838,9 +843,23 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
if ((size - extradata_size) < 256*1024)
return BUFLIB_CB_CANNOT_SHRINK;

- long offset = audio_current_track()->offset;
- int status = audio_status();
+
/* TODO: Do it without stopping playback, if possible */
+ long offset = audio_current_track()->offset;
+ bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY;
+ /* There's one problem with stoping and resuming: If it happens in a too
+ * frequent fashion, the codecs lose the resume postion and playback
+ * begins from the beginning.
+ * To get use queue_post() to effectively delay the resume in case
+ * we're called another time. However this has another problem: id3->offset
+ * gets zero since playback is stopped. Therefore, try to peek at the
+ * preceeding queue_post to get the offset. This also lets us conviniently
+ * remove the queue event so Q_AUDIO_START is only processed once. */
+ bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, filter_list);
+
+ if (playing && offset > 0) /* current id3->offset is king */
+ ev.data = offset;
+
/* don't call audio_hard_stop() as it frees this handle */
if (thread_self() == audio_thread_id)
{ /* inline case Q_AUDIO_STOP (audio_hard_stop() response
@@ -868,12 +887,10 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
audio_reset_buffer_noalloc(start + wanted_size);
break;
}
- if ((status & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY)
+ if (playing || play_queued)
{
- if (thread_self() == audio_thread_id)
- audio_start_playback(offset, 0); /* inline Q_AUDIO_PLAY */
- else
- audio_play(offset);
+ /* post, to make subsequent calls not break the resume position */
+ audio_queue_post(Q_AUDIO_PLAY, ev.data);
}

return BUFLIB_CB_OK;