From 789294ffb7092770a3b14a900308383c224776d1 Mon Sep 17 00:00:00 2001
From: Thomas Martitz <[email protected]>
Date: Thu, 8 Sep 2011 01:46:46 +0200
Subject: [PATCH] Buflib/swcodec: Improve playback stopping behavior on
 allocation.

Reuse playback's Q_AUDIO_REMAKE_AUDIO_BUFFER capabilities to set the new
playback buffer, instead of stopping/restarting manual. This strongly
reduces the visibility of the short audio stop.
---
 apps/playback.c |   59 ++++++++++++++++++++++--------------------------------
 1 files changed, 24 insertions(+), 35 deletions(-)

diff --git a/apps/playback.c b/apps/playback.c
index dbe28dd..fd7ab48 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -744,7 +744,7 @@ size_t audio_buffer_available(void)
 
 /* Set up the audio buffer for playback
  * filebuflen must be pre-initialized with the maximum size */
-static void audio_reset_buffer_noalloc(void* filebuf)
+static void audio_reset_buffer_noalloc(void)
 {
     /*
      * Layout audio buffer as follows:
@@ -761,6 +761,7 @@ static void audio_reset_buffer_noalloc(void* filebuf)
     /* Initially set up file buffer as all space available */
     size_t allocsize;
 
+    void* filebuf = core_get_data(audiobuf_handle);
     /* Subtract whatever voice needs */
     allocsize = talkbuf_init(filebuf);
     allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
@@ -828,44 +829,30 @@ bufpanic:
 /* Buffer must not move. */
 static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size)
 {
-    long offset = audio_current_track()->offset;
-    int status = audio_status();
-    /* TODO: Do it without stopping playback, if possible */
-    /* 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
-         * if we're in the audio thread */
-        audio_stop_playback();
-        queue_clear(&audio_queue);
-    }
-    else
-        audio_queue_send(Q_AUDIO_STOP, 1);
-#ifdef PLAYBACK_VOICE
-    voice_stop();
-#endif
     /* we should be free to change the buffer now */
     size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK);
     ssize_t size = (ssize_t)old_size - wanted_size;
-    /* set final buffer size before calling audio_reset_buffer_noalloc() */
-    filebuflen = size;
     switch (hints & BUFLIB_SHRINK_POS_MASK)
     {
         case BUFLIB_SHRINK_POS_BACK:
             core_shrink(handle, start, size);
-            audio_reset_buffer_noalloc(start);
             break;
         case BUFLIB_SHRINK_POS_FRONT:
             core_shrink(handle, start + wanted_size, size);
-            audio_reset_buffer_noalloc(start + wanted_size);
             break;
     }
-    if ((status & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY)
-    {
-        if (thread_self() == audio_thread_id)
-            audio_start_playback(offset, 0);  /* inline Q_AUDIO_PLAY */
-        else
-            audio_play(offset);
+    /* set final buffer size before calling audio_start_playback()
+     * (which calls audio_reset_buffer_noalloc() which needs the new size) */
+    filebuflen = size;
+    /* TODO: Do it without stopping playback, if possible */
+    /* don't call audio_hard_stop() as it frees this handle */
+    if (thread_self() == audio_thread_id)
+    {   /* inline case Q_AUDIO_REMAKE_AUDIO_BUFFER to avoid deadlock if
+         * we're in the audio thread */
+        audio_start_playback(0, AUDIO_START_RESTART | AUDIO_START_NEWBUF);
     }
+    else
+        audio_queue_send(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0);
 
     return BUFLIB_CB_OK;
 }
@@ -883,9 +870,8 @@ static void audio_reset_buffer(void)
         audiobuf_handle = 0;
     }
     audiobuf_handle = core_alloc_maximum("audiobuf", &filebuflen, &ops);
-    unsigned char *filebuf = core_get_data(audiobuf_handle);
 
-    audio_reset_buffer_noalloc(filebuf);
+    audio_reset_buffer_noalloc();
 }
 
 /* Set the buffer margin to begin rebuffering when 'seconds' from empty */
@@ -1944,7 +1930,7 @@ audio_finish_load_track_exit:
 }
 
 /* Start a new track load */
-static int audio_fill_file_buffer(void)
+static int audio_fill_file_buffer(bool realloc)
 {
     if (play_status == PLAY_STOPPED)
         return LOAD_TRACK_ERR_FAILED;
@@ -1955,7 +1941,10 @@ static int audio_fill_file_buffer(void)
        file size shouldn't have changed so we can go straight from
        AUDIOBUF_STATE_VOICED_ONLY to AUDIOBUF_STATE_INITIALIZED */
     if (buffer_state != AUDIOBUF_STATE_INITIALIZED)
-        audio_reset_buffer();
+    {
+        realloc ?
+            audio_reset_buffer() : audio_reset_buffer_noalloc();
+    }
 
     logf("Starting buffer fill");
 
@@ -1994,7 +1983,7 @@ static int audio_reset_and_rebuffer(
     playlist_peek_offset = peek_offset;
 
     /* Fill the buffer */
-    return audio_fill_file_buffer();
+    return audio_fill_file_buffer(true);
 }
 
 /* Handle buffering events
@@ -2051,7 +2040,7 @@ static void audio_on_buffering(int event)
    (Q_AUDIO_FILL_BUFFER) */
 static void audio_on_fill_buffer(void)
 {
-    audio_handle_track_load_status(audio_fill_file_buffer());
+    audio_handle_track_load_status(audio_fill_file_buffer(true));
 }
 
 /* Handle posted load track finish event
@@ -2467,8 +2456,8 @@ static void audio_start_playback(size_t offset, unsigned int flags)
         send_event(PLAYBACK_EVENT_START_PLAYBACK, NULL);
     }
 
-    /* Fill the buffer */
-    int trackstat = audio_fill_file_buffer();
+    /* Fill the buffer, assumed to be setup already here, thus realloc=false */
+    int trackstat = audio_fill_file_buffer(false);
 
     if (trackstat >= LOAD_TRACK_OK)
     {
@@ -2860,7 +2849,7 @@ static void audio_on_audio_flush(void)
         audio_update_and_announce_next_track(NULL);
 
         /* Ignore return since it's about the next track, not this one */
-        audio_fill_file_buffer();
+        audio_fill_file_buffer(true);
 
         if (skip_pending == TRACK_SKIP_NONE)
             break;
-- 
1.7.5.4