Fix gapless playback

On some devices the actual framecount per buffer of an AudioTrack
will be different than what was requested, which prevented the
track from being reused. Now we create a new AudioTrack with the
requested parameters, and then compare it to the track we already
have. If they match, we throw away the new track and reuse the
existing one.
b/6644559

Change-Id: Id3e8c4460436f52e59b98ecaeb01c94f02877c1d
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 20d6d7a..4bf2d3f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1542,51 +1542,10 @@
         }
     }
 
-    if (mRecycledTrack) {
-        // check if the existing track can be reused as-is, or if a new track needs to be created.
-
-        bool reuse = true;
-        if ((mCallbackData == NULL && mCallback != NULL) ||
-                (mCallbackData != NULL && mCallback == NULL)) {
-            // recycled track uses callbacks but the caller wants to use writes, or vice versa
-            ALOGV("can't chain callback and write");
-            reuse = false;
-        } else if ((mRecycledTrack->getSampleRate() != sampleRate) ||
-                (mRecycledTrack->channelCount() != channelCount) ||
-                (mRecycledTrack->frameCount() != frameCount)) {
-            ALOGV("samplerate, channelcount or framecount differ");
-            reuse = false;
-        } if (flags != mFlags) {
-            ALOGV("output flags differ");
-            reuse = false;
-        }
-        if (reuse) {
-            ALOGV("chaining to next output");
-            close();
-            mTrack = mRecycledTrack;
-            mRecycledTrack = NULL;
-            if (mCallbackData != NULL) {
-                mCallbackData->setOutput(this);
-            }
-            return OK;
-        }
-
-        // if we're not going to reuse the track, unblock and flush it
-        if (mCallbackData != NULL) {
-            mCallbackData->setOutput(NULL);
-            mCallbackData->endTrackSwitch();
-        }
-        mRecycledTrack->flush();
-        delete mRecycledTrack;
-        mRecycledTrack = NULL;
-        delete mCallbackData;
-        mCallbackData = NULL;
-        close();
-    }
-
     AudioTrack *t;
+    CallbackData *newcbd = NULL;
     if (mCallback != NULL) {
-        mCallbackData = new CallbackData(this);
+        newcbd = new CallbackData(this);
         t = new AudioTrack(
                 mStreamType,
                 sampleRate,
@@ -1595,7 +1554,7 @@
                 frameCount,
                 flags,
                 CallbackWrapper,
-                mCallbackData,
+                newcbd,
                 0,  // notification frames
                 mSessionId);
     } else {
@@ -1615,9 +1574,59 @@
     if ((t == 0) || (t->initCheck() != NO_ERROR)) {
         ALOGE("Unable to create audio track");
         delete t;
+        delete newcbd;
         return NO_INIT;
     }
 
+
+    if (mRecycledTrack) {
+        // check if the existing track can be reused as-is, or if a new track needs to be created.
+
+        bool reuse = true;
+        if ((mCallbackData == NULL && mCallback != NULL) ||
+                (mCallbackData != NULL && mCallback == NULL)) {
+            // recycled track uses callbacks but the caller wants to use writes, or vice versa
+            ALOGV("can't chain callback and write");
+            reuse = false;
+        } else if ((mRecycledTrack->getSampleRate() != sampleRate) ||
+                (mRecycledTrack->channelCount() != channelCount) ||
+                (mRecycledTrack->frameCount() != t->frameCount())) {
+            ALOGV("samplerate, channelcount or framecount differ: %d/%d Hz, %d/%d ch, %d/%d frames",
+                  mRecycledTrack->getSampleRate(), sampleRate,
+                  mRecycledTrack->channelCount(), channelCount,
+                  mRecycledTrack->frameCount(), t->frameCount());
+            reuse = false;
+        } else if (flags != mFlags) {
+            ALOGV("output flags differ %08x/%08x", flags, mFlags);
+            reuse = false;
+        }
+        if (reuse) {
+            ALOGV("chaining to next output");
+            close();
+            mTrack = mRecycledTrack;
+            mRecycledTrack = NULL;
+            if (mCallbackData != NULL) {
+                mCallbackData->setOutput(this);
+            }
+            delete t;
+            delete newcbd;
+            return OK;
+        }
+
+        // if we're not going to reuse the track, unblock and flush it
+        if (mCallbackData != NULL) {
+            mCallbackData->setOutput(NULL);
+            mCallbackData->endTrackSwitch();
+        }
+        mRecycledTrack->flush();
+        delete mRecycledTrack;
+        mRecycledTrack = NULL;
+        delete mCallbackData;
+        mCallbackData = NULL;
+        close();
+    }
+
+    mCallbackData = newcbd;
     ALOGV("setVolume");
     t->setVolume(mLeftVolume, mRightVolume);