Implementation of stagefright-enabled MediaPlayerService::decode functionality

related-to-bug: 2359268
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index a5a1bb8..be06e33 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -62,7 +62,8 @@
     // AudioSink: abstraction layer for audio output
     class AudioSink : public RefBase {
     public:
-        typedef void (*AudioCallback)(
+        // Callback returns the number of bytes actually written to the buffer.
+        typedef size_t (*AudioCallback)(
                 AudioSink *audioSink, void *buffer, size_t size, void *cookie);
 
         virtual             ~AudioSink() {}
@@ -77,8 +78,7 @@
         virtual status_t    getPosition(uint32_t *position) = 0;
 
         // If no callback is specified, use the "write" API below to submit
-        // audio data. Otherwise return a full buffer of audio data on each
-        // callback.
+        // audio data.
         virtual status_t    open(
                 uint32_t sampleRate, int channelCount,
                 int format=AudioSystem::PCM_16_BIT,
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 843e051..8e5f05f 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -90,11 +90,11 @@
     static void AudioCallback(int event, void *user, void *info);
     void AudioCallback(int event, void *info);
 
-    static void AudioSinkCallback(
+    static size_t AudioSinkCallback(
             MediaPlayerBase::AudioSink *audioSink,
             void *data, size_t size, void *me);
 
-    void fillBuffer(void *data, size_t size);
+    size_t fillBuffer(void *data, size_t size);
 
     int64_t getRealTimeUsLocked() const;
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8e61011..55b06f4 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1597,9 +1597,12 @@
     AudioOutput *me = (AudioOutput *)cookie;
     AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
 
-    (*me->mCallback)(
+    size_t actualSize = (*me->mCallback)(
             me, buffer->raw, buffer->size, me->mCallbackCookie);
-    me->snoopWrite(buffer->raw, buffer->size);
+
+    if (actualSize > 0) {
+        me->snoopWrite(buffer->raw, actualSize);
+    }
 }
 
 #undef LOG_TAG
@@ -1629,14 +1632,75 @@
     return NO_ERROR;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+struct CallbackThread : public Thread {
+    CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink,
+                   MediaPlayerBase::AudioSink::AudioCallback cb,
+                   void *cookie);
+
+protected:
+    virtual ~CallbackThread();
+
+    virtual bool threadLoop();
+
+private:
+    wp<MediaPlayerBase::AudioSink> mSink;
+    MediaPlayerBase::AudioSink::AudioCallback mCallback;
+    void *mCookie;
+    void *mBuffer;
+    size_t mBufferSize;
+
+    CallbackThread(const CallbackThread &);
+    CallbackThread &operator=(const CallbackThread &);
+};
+
+CallbackThread::CallbackThread(
+        const wp<MediaPlayerBase::AudioSink> &sink,
+        MediaPlayerBase::AudioSink::AudioCallback cb,
+        void *cookie)
+    : mSink(sink),
+      mCallback(cb),
+      mCookie(cookie),
+      mBuffer(NULL),
+      mBufferSize(0) {
+}
+
+CallbackThread::~CallbackThread() {
+    if (mBuffer) {
+        free(mBuffer);
+        mBuffer = NULL;
+    }
+}
+
+bool CallbackThread::threadLoop() {
+    sp<MediaPlayerBase::AudioSink> sink = mSink.promote();
+    if (sink == NULL) {
+        return false;
+    }
+
+    if (mBuffer == NULL) {
+        mBufferSize = sink->bufferSize();
+        mBuffer = malloc(mBufferSize);
+    }
+
+    size_t actualSize =
+        (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie);
+
+    if (actualSize > 0) {
+        sink->write(mBuffer, actualSize);
+    }
+
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 status_t MediaPlayerService::AudioCache::open(
         uint32_t sampleRate, int channelCount, int format, int bufferCount,
         AudioCallback cb, void *cookie)
 {
     LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
-    if (cb != NULL) {
-        return UNKNOWN_ERROR;  // TODO: implement this.
-    }
     if (mHeap->getHeapID() < 0) {
         return NO_INIT;
     }
@@ -1645,9 +1709,25 @@
     mChannelCount = (uint16_t)channelCount;
     mFormat = (uint16_t)format;
     mMsecsPerFrame = 1.e3 / (float) sampleRate;
+
+    if (cb != NULL) {
+        mCallbackThread = new CallbackThread(this, cb, cookie);
+    }
     return NO_ERROR;
 }
 
+void MediaPlayerService::AudioCache::start() {
+    if (mCallbackThread != NULL) {
+        mCallbackThread->run("AudioCache callback");
+    }
+}
+
+void MediaPlayerService::AudioCache::stop() {
+    if (mCallbackThread != NULL) {
+        mCallbackThread->requestExitAndWait();
+    }
+}
+
 ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
 {
     LOGV("write(%p, %u)", buffer, size);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index ffe1ba0..5c03e47 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -139,9 +139,9 @@
                 int bufferCount = 1,
                 AudioCallback cb = NULL, void *cookie = NULL);
 
-        virtual void            start() {}
+        virtual void            start();
         virtual ssize_t         write(const void* buffer, size_t size);
-        virtual void            stop() {}
+        virtual void            stop();
         virtual void            flush() {}
         virtual void            pause() {}
         virtual void            close() {}
@@ -171,6 +171,8 @@
         uint32_t            mSize;
         int                 mError;
         bool                mCommandComplete;
+
+        sp<Thread>          mCallbackThread;
     };
 
 public:
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 4926920..12d7ee2 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -187,12 +187,12 @@
 }
 
 // static
-void AudioPlayer::AudioSinkCallback(
+size_t AudioPlayer::AudioSinkCallback(
         MediaPlayerBase::AudioSink *audioSink,
         void *buffer, size_t size, void *cookie) {
     AudioPlayer *me = (AudioPlayer *)cookie;
 
-    me->fillBuffer(buffer, size);
+    return me->fillBuffer(buffer, size);
 }
 
 void AudioPlayer::AudioCallback(int event, void *info) {
@@ -201,17 +201,18 @@
     }
 
     AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
-    fillBuffer(buffer->raw, buffer->size);
+    size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
+
+    buffer->size = numBytesWritten;
 }
 
-void AudioPlayer::fillBuffer(void *data, size_t size) {
+size_t AudioPlayer::fillBuffer(void *data, size_t size) {
     if (mNumFramesPlayed == 0) {
         LOGV("AudioCallback");
     }
 
     if (mReachedEOS) {
-        memset(data, 0, size);
-        return;
+        return 0;
     }
 
     size_t size_done = 0;
@@ -244,7 +245,6 @@
 
             if (err != OK) {
                 mReachedEOS = true;
-                memset((char *)data + size_done, 0, size_remaining);
                 break;
             }
 
@@ -285,7 +285,9 @@
     }
 
     Mutex::Autolock autoLock(mLock);
-    mNumFramesPlayed += size / mFrameSize;
+    mNumFramesPlayed += size_done / mFrameSize;
+
+    return size_done;
 }
 
 int64_t AudioPlayer::getRealTimeUs() {
diff --git a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
index 6b3093f..1434d3f 100644
--- a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
+++ b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
@@ -43,10 +43,9 @@
     private TestThread mThread;
 
     private static final int[] mTestFiles = new int[] {
-        // FIXME: Restore when Stagefright bug is fixed
         R.raw.organ441,
         R.raw.sine441,
-        //R.raw.test1,
+        R.raw.test1,
         R.raw.test2,
         R.raw.test3,
         R.raw.test4,