Add gapless playback support for NuPlayer

This makes NuPlayer use a SkipCutBuffer when needed, and adds a new
AudioSink method to retrieve the number of frames written so far, so
NuPlayerRenderer can calculate how much data it can write without blocking.
Also make some more methods const.

Change-Id: Id7d253ad8a7b85e9a84ca2baafbe32817b16c744
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 544d501..11cea3b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -39,6 +39,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/SkipCutBuffer.h>
 #include <gui/ISurfaceTexture.h>
 
 #include "avc_utils.h"
@@ -63,10 +64,13 @@
       mSkipRenderingVideoUntilMediaTimeUs(-1ll),
       mVideoLateByUs(0ll),
       mNumFramesTotal(0ll),
-      mNumFramesDropped(0ll) {
+      mNumFramesDropped(0ll),
+      mSkipCutBuffer(NULL) {
 }
 
 NuPlayer::~NuPlayer() {
+    delete mSkipCutBuffer;
+    mSkipCutBuffer = NULL;
 }
 
 void NuPlayer::setUID(uid_t uid) {
@@ -234,6 +238,32 @@
 
             mSource->start();
 
+            sp<MetaData> meta = mSource->getFormat(true /* audio */);
+            if (meta != NULL) {
+                int32_t delay = 0;
+                if (!meta->findInt32(kKeyEncoderDelay, &delay)) {
+                    delay = 0;
+                }
+                int32_t padding = 0;
+                if (!meta->findInt32(kKeyEncoderPadding, &padding)) {
+                    padding = 0;
+                }
+                int32_t numchannels = 0;
+                if (delay + padding) {
+                    if (meta->findInt32(kKeyChannelCount, &numchannels)) {
+                        size_t frameSize = numchannels * sizeof(int16_t);
+                        if (mSkipCutBuffer) {
+                            size_t prevbuffersize = mSkipCutBuffer->size();
+                            if (prevbuffersize != 0) {
+                                ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbuffersize);
+                            }
+                            delete mSkipCutBuffer;
+                        }
+                        mSkipCutBuffer = new SkipCutBuffer(delay * frameSize, padding * frameSize);
+                    }
+                }
+            }
+
             mRenderer = new Renderer(
                     mAudioSink,
                     new AMessage(kWhatRendererNotify, id()));
@@ -844,6 +874,10 @@
         skipUntilMediaTimeUs = -1;
     }
 
+    if (audio && mSkipCutBuffer) {
+        mSkipCutBuffer->submit(buffer);
+    }
+
     mRenderer->queueBuffer(audio, buffer, reply);
 }