GenericSource: enable autonomous buffering

Also fix possible racing conditions. Now buffering control is time based
only.
Test: media post submit tests passed
Bug: 66952371
Change-Id: Ia115787511b2f3e612167a61c8df3a9a2b2d9abf
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 4729d59..94e3395 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -49,9 +49,6 @@
 static const int kHighWaterMarkMs         = 5000;  // 5secs
 static const int kHighWaterMarkRebufferMs = 15000;  // 15secs
 
-static const int kLowWaterMarkKB  = 40;
-static const int kHighWaterMarkKB = 200;
-
 NuPlayer::GenericSource::GenericSource(
         const sp<AMessage> &notify,
         bool uidValid,
@@ -62,6 +59,11 @@
       mAudioLastDequeueTimeUs(0),
       mVideoTimeUs(0),
       mVideoLastDequeueTimeUs(0),
+      mPrevBufferPercentage(-1),
+      mPollBufferingGeneration(0),
+      mSentPauseOnBuffering(false),
+      mAudioDataGeneration(0),
+      mVideoDataGeneration(0),
       mFetchSubtitleDataGeneration(0),
       mFetchTimedTextDataGeneration(0),
       mDurationUs(-1ll),
@@ -77,7 +79,7 @@
     ALOGV("GenericSource");
     CHECK(mediaClock != NULL);
 
-    mBufferingMonitor = new BufferingMonitor(notify);
+    getDefaultBufferingSettings(&mBufferingSettings);
     resetDataSource();
 }
 
@@ -95,14 +97,7 @@
     mOffset = 0;
     mLength = 0;
     mStarted = false;
-    mStopRead = true;
-
-    if (mBufferingMonitorLooper != NULL) {
-        mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id());
-        mBufferingMonitorLooper->stop();
-        mBufferingMonitorLooper = NULL;
-    }
-    mBufferingMonitor->stop();
+    mPreparing = false;
 
     mIsDrmProtected = false;
     mIsDrmReleased = false;
@@ -114,6 +109,7 @@
         const sp<IMediaHTTPService> &httpService,
         const char *url,
         const KeyedVector<String8, String8> *headers) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource url: %s", url);
 
     resetDataSource();
@@ -132,6 +128,7 @@
 
 status_t NuPlayer::GenericSource::setDataSource(
         int fd, int64_t offset, int64_t length) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
 
     resetDataSource();
@@ -146,6 +143,7 @@
 }
 
 status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource (source: %p)", source.get());
 
     resetDataSource();
@@ -154,6 +152,7 @@
 }
 
 sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
+    Mutex::Autolock _l(mLock);
     return mFileMeta;
 }
 
@@ -268,12 +267,36 @@
 
 status_t NuPlayer::GenericSource::getDefaultBufferingSettings(
         BufferingSettings* buffering /* nonnull */) {
-    mBufferingMonitor->getDefaultBufferingSettings(buffering);
+    buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+    buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
+    buffering->mInitialWatermarkMs = kHighWaterMarkMs;
+    buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
+    buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
+
+    ALOGV("getDefaultBufferingSettings{%s}", buffering->toString().string());
     return OK;
 }
 
 status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) {
-    return mBufferingMonitor->setBufferingSettings(buffering);
+    ALOGV("setBufferingSettings{%s}", buffering.toString().string());
+
+    if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+            || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+            || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
+                && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+    mBufferingSettings = buffering;
+    if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+        mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+    }
+    if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
+        mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+        mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
+    }
+    return OK;
 }
 
 status_t NuPlayer::GenericSource::startSources() {
@@ -309,6 +332,7 @@
 
 status_t NuPlayer::GenericSource::setBuffers(
         bool audio, Vector<MediaBuffer *> &buffers) {
+    Mutex::Autolock _l(mLock);
     if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
         return mVideoTrack.mSource->setBuffers(buffers);
     }
@@ -316,13 +340,10 @@
 }
 
 bool NuPlayer::GenericSource::isStreaming() const {
+    Mutex::Autolock _l(mLock);
     return mIsStreaming;
 }
 
-void NuPlayer::GenericSource::setOffloadAudio(bool offload) {
-    mBufferingMonitor->setOffloadAudio(offload);
-}
-
 NuPlayer::GenericSource::~GenericSource() {
     ALOGV("~GenericSource");
     if (mLooper != NULL) {
@@ -333,6 +354,7 @@
 }
 
 void NuPlayer::GenericSource::prepareAsync() {
+    Mutex::Autolock _l(mLock);
     ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
 
     if (mLooper == NULL) {
@@ -434,7 +456,7 @@
     }
 
     if (mVideoTrack.mSource != NULL) {
-        sp<MetaData> meta = doGetFormatMeta(false /* audio */);
+        sp<MetaData> meta = getFormatMeta_l(false /* audio */);
         sp<AMessage> msg = new AMessage;
         err = convertMetaDataToMessage(meta, &msg);
         if(err != OK) {
@@ -468,47 +490,39 @@
     }
 
     if (mIsStreaming) {
-        if (mBufferingMonitorLooper == NULL) {
-            mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate,
-                    mIsStreaming);
-
-            mBufferingMonitorLooper = new ALooper;
-            mBufferingMonitorLooper->setName("GSBMonitor");
-            mBufferingMonitorLooper->start();
-            mBufferingMonitorLooper->registerHandler(mBufferingMonitor);
-        }
-
-        mBufferingMonitor->ensureCacheIsFetching();
-        mBufferingMonitor->restartPollBuffering();
+        mCachedSource->resumeFetchingIfNecessary();
+        mPreparing = true;
+        schedulePollBuffering();
     } else {
         notifyPrepared();
     }
+
+    if (mAudioTrack.mSource != NULL) {
+        postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
+    }
+
+    if (mVideoTrack.mSource != NULL) {
+        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
+    }
 }
 
 void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
     if (err != OK) {
-        {
-            sp<DataSource> dataSource = mDataSource;
-            sp<NuCachedSource2> cachedSource = mCachedSource;
-            sp<DataSource> httpSource = mHttpSource;
-            {
-                Mutex::Autolock _l(mDisconnectLock);
-                mDataSource.clear();
-                mCachedSource.clear();
-                mHttpSource.clear();
-            }
-        }
-        mBitrate = -1;
+        mDataSource.clear();
+        mCachedSource.clear();
+        mHttpSource.clear();
 
-        mBufferingMonitor->cancelPollBuffering();
+        mBitrate = -1;
+        mPrevBufferPercentage = -1;
+        ++mPollBufferingGeneration;
     }
     notifyPrepared(err);
 }
 
 void NuPlayer::GenericSource::start() {
+    Mutex::Autolock _l(mLock);
     ALOGI("start");
 
-    mStopRead = false;
     if (mAudioTrack.mSource != NULL) {
         postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
     }
@@ -518,28 +532,27 @@
     }
 
     mStarted = true;
-
-    (new AMessage(kWhatStart, this))->post();
 }
 
 void NuPlayer::GenericSource::stop() {
+    Mutex::Autolock _l(mLock);
     mStarted = false;
 }
 
 void NuPlayer::GenericSource::pause() {
+    Mutex::Autolock _l(mLock);
     mStarted = false;
 }
 
 void NuPlayer::GenericSource::resume() {
+    Mutex::Autolock _l(mLock);
     mStarted = true;
-
-    (new AMessage(kWhatResume, this))->post();
 }
 
 void NuPlayer::GenericSource::disconnect() {
     sp<DataSource> dataSource, httpSource;
     {
-        Mutex::Autolock _l(mDisconnectLock);
+        Mutex::Autolock _l(mLock);
         dataSource = mDataSource;
         httpSource = mHttpSource;
     }
@@ -558,7 +571,24 @@
     return OK;
 }
 
+void NuPlayer::GenericSource::sendCacheStats() {
+    int32_t kbps = 0;
+    status_t err = UNKNOWN_ERROR;
+
+    if (mCachedSource != NULL) {
+        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
+    }
+
+    if (err == OK) {
+        sp<AMessage> notify = dupNotify();
+        notify->setInt32("what", kWhatCacheStats);
+        notify->setInt32("bandwidth", kbps);
+        notify->post();
+    }
+}
+
 void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
+    Mutex::Autolock _l(mLock);
     switch (msg->what()) {
       case kWhatPrepareAsync:
       {
@@ -627,6 +657,8 @@
           track->mSource = source;
           track->mSource->start();
           track->mIndex = trackIndex;
+          ++mAudioDataGeneration;
+          ++mVideoDataGeneration;
 
           int64_t timeUs, actualTimeUs;
           const bool formatChange = true;
@@ -644,68 +676,19 @@
           break;
       }
 
-      case kWhatStart:
-      case kWhatResume:
-      {
-          mBufferingMonitor->restartPollBuffering();
-          break;
-      }
-
-      case kWhatGetFormat:
-      {
-          onGetFormatMeta(msg);
-          break;
-      }
-
-      case kWhatGetSelectedTrack:
-      {
-          onGetSelectedTrack(msg);
-          break;
-      }
-
-      case kWhatGetTrackInfo:
-      {
-          onGetTrackInfo(msg);
-          break;
-      }
-
-      case kWhatSelectTrack:
-      {
-          onSelectTrack(msg);
-          break;
-      }
-
-      case kWhatSeek:
-      {
-          onSeek(msg);
-          break;
-      }
-
       case kWhatReadBuffer:
       {
           onReadBuffer(msg);
           break;
       }
 
-      case kWhatPrepareDrm:
+      case kWhatPollBuffering:
       {
-          status_t status = onPrepareDrm(msg);
-          sp<AMessage> response = new AMessage;
-          response->setInt32("status", status);
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
-          break;
-      }
-
-      case kWhatReleaseDrm:
-      {
-          status_t status = onReleaseDrm();
-          sp<AMessage> response = new AMessage;
-          response->setInt32("status", status);
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
+          int32_t generation;
+          CHECK(msg->findInt32("generation", &generation));
+          if (generation == mPollBufferingGeneration) {
+              onPollBuffering();
+          }
           break;
       }
 
@@ -820,34 +803,11 @@
 }
 
 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
-    sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
-    msg->setInt32("audio", audio);
-
-    sp<AMessage> response;
-    sp<RefBase> format;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findObject("format", &format));
-        return static_cast<MetaData*>(format.get());
-    } else {
-        return NULL;
-    }
+    Mutex::Autolock _l(mLock);
+    return getFormatMeta_l(audio);
 }
 
-void NuPlayer::GenericSource::onGetFormatMeta(const sp<AMessage>& msg) const {
-    int32_t audio;
-    CHECK(msg->findInt32("audio", &audio));
-
-    sp<AMessage> response = new AMessage;
-    sp<MetaData> format = doGetFormatMeta(audio);
-    response->setObject("format", format);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
+sp<MetaData> NuPlayer::GenericSource::getFormatMeta_l(bool audio) {
     sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
 
     if (source == NULL) {
@@ -859,6 +819,7 @@
 
 status_t NuPlayer::GenericSource::dequeueAccessUnit(
         bool audio, sp<ABuffer> *accessUnit) {
+    Mutex::Autolock _l(mLock);
     // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
     // the codec's crypto object has gone away (b/37960096).
     // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
@@ -884,10 +845,30 @@
 
     status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
 
-    // start pulling in more buffers if we only have one (or no) buffer left
+    // start pulling in more buffers if cache is running low
     // so that decoder has less chance of being starved
-    if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
-        postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+    if (!mIsStreaming) {
+        if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
+            postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+        }
+    } else {
+        int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+        int64_t restartBufferingMarkUs =
+             mBufferingSettings.mRebufferingWatermarkHighMs * 1000ll / 2;
+        if (finalResult == OK) {
+            if (durationUs < restartBufferingMarkUs) {
+                postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+            }
+            if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
+                && !mSentPauseOnBuffering && !mPreparing) {
+                mCachedSource->resumeFetchingIfNecessary();
+                sendCacheStats();
+                mSentPauseOnBuffering = true;
+                sp<AMessage> notify = dupNotify();
+                notify->setInt32("what", kWhatPauseOnBufferingStart);
+                notify->post();
+            }
+        }
     }
 
     if (result != OK) {
@@ -907,7 +888,6 @@
     CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
     if (audio) {
         mAudioLastDequeueTimeUs = timeUs;
-        mBufferingMonitor->updateDequeuedBufferTime(timeUs);
     } else {
         mVideoLastDequeueTimeUs = timeUs;
     }
@@ -932,43 +912,18 @@
 }
 
 status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
+    Mutex::Autolock _l(mLock);
     *durationUs = mDurationUs;
     return OK;
 }
 
 size_t NuPlayer::GenericSource::getTrackCount() const {
+    Mutex::Autolock _l(mLock);
     return mSources.size();
 }
 
 sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
-    sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
-    msg->setSize("trackIndex", trackIndex);
-
-    sp<AMessage> response;
-    sp<RefBase> format;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findObject("format", &format));
-        return static_cast<AMessage*>(format.get());
-    } else {
-        return NULL;
-    }
-}
-
-void NuPlayer::GenericSource::onGetTrackInfo(const sp<AMessage>& msg) const {
-    size_t trackIndex;
-    CHECK(msg->findSize("trackIndex", &trackIndex));
-
-    sp<AMessage> response = new AMessage;
-    sp<AMessage> format = doGetTrackInfo(trackIndex);
-    response->setObject("format", format);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-sp<AMessage> NuPlayer::GenericSource::doGetTrackInfo(size_t trackIndex) const {
+    Mutex::Autolock _l(mLock);
     size_t trackCount = mSources.size();
     if (trackIndex >= trackCount) {
         return NULL;
@@ -1018,35 +973,7 @@
 }
 
 ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
-    sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
-    msg->setInt32("type", type);
-
-    sp<AMessage> response;
-    int32_t index;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("index", &index));
-        return index;
-    } else {
-        return -1;
-    }
-}
-
-void NuPlayer::GenericSource::onGetSelectedTrack(const sp<AMessage>& msg) const {
-    int32_t tmpType;
-    CHECK(msg->findInt32("type", &tmpType));
-    media_track_type type = (media_track_type)tmpType;
-
-    sp<AMessage> response = new AMessage;
-    ssize_t index = doGetSelectedTrack(type);
-    response->setInt32("index", index);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
+    Mutex::Autolock _l(mLock);
     const Track *track = NULL;
     switch (type) {
     case MEDIA_TRACK_TYPE_VIDEO:
@@ -1073,38 +1000,9 @@
 }
 
 status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
+    Mutex::Autolock _l(mLock);
     ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
-    sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
-    msg->setInt32("trackIndex", trackIndex);
-    msg->setInt32("select", select);
-    msg->setInt64("timeUs", timeUs);
 
-    sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("err", &err));
-    }
-
-    return err;
-}
-
-void NuPlayer::GenericSource::onSelectTrack(const sp<AMessage>& msg) {
-    int32_t trackIndex, select;
-    int64_t timeUs;
-    CHECK(msg->findInt32("trackIndex", &trackIndex));
-    CHECK(msg->findInt32("select", &select));
-    CHECK(msg->findInt64("timeUs", &timeUs));
-
-    sp<AMessage> response = new AMessage;
-    status_t err = doSelectTrack(trackIndex, select, timeUs);
-    response->setInt32("err", err);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
     if (trackIndex >= mSources.size()) {
         return BAD_INDEX;
     }
@@ -1196,46 +1094,11 @@
 }
 
 status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
-    sp<AMessage> msg = new AMessage(kWhatSeek, this);
-    msg->setInt64("seekTimeUs", seekTimeUs);
-    msg->setInt32("mode", mode);
-
-    sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("err", &err));
-    }
-
-    return err;
-}
-
-void NuPlayer::GenericSource::onSeek(const sp<AMessage>& msg) {
-    int64_t seekTimeUs;
-    int32_t mode;
-    CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
-    CHECK(msg->findInt32("mode", &mode));
-
-    sp<AMessage> response = new AMessage;
-    status_t err = doSeek(seekTimeUs, (MediaPlayerSeekMode)mode);
-    response->setInt32("err", err);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
-    mBufferingMonitor->updateDequeuedBufferTime(-1ll);
-
-    // If the Widevine source is stopped, do not attempt to read any
-    // more buffers.
-    //
-    // TODO: revisit after widevine is removed.  May be able to
-    // combine mStopRead with mStarted.
-    if (mStopRead) {
-        return INVALID_OPERATION;
-    }
+    Mutex::Autolock _l(mLock);
+    ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
     if (mVideoTrack.mSource != NULL) {
+        ++mVideoDataGeneration;
+
         int64_t actualTimeUs;
         readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
 
@@ -1246,6 +1109,7 @@
     }
 
     if (mAudioTrack.mSource != NULL) {
+        ++mAudioDataGeneration;
         readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayerSeekMode::SEEK_CLOSEST);
         mAudioLastDequeueTimeUs = seekTimeUs;
     }
@@ -1260,12 +1124,8 @@
         mFetchTimedTextDataGeneration++;
     }
 
-    // If currently buffering, post kWhatBufferingEnd first, so that
-    // NuPlayer resumes. Otherwise, if cache hits high watermark
-    // before new polling happens, no one will resume the playback.
-    mBufferingMonitor->stopBufferingIfNecessary();
-    mBufferingMonitor->restartPollBuffering();
-
+    ++mPollBufferingGeneration;
+    schedulePollBuffering();
     return OK;
 }
 
@@ -1368,9 +1228,29 @@
     return ab;
 }
 
-void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
-    Mutex::Autolock _l(mReadBufferLock);
+int32_t NuPlayer::GenericSource::getDataGeneration(media_track_type type) const {
+    int32_t generation = -1;
+    switch (type) {
+    case MEDIA_TRACK_TYPE_VIDEO:
+        generation = mVideoDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_AUDIO:
+        generation = mAudioDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_TIMEDTEXT:
+        generation = mFetchTimedTextDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_SUBTITLE:
+        generation = mFetchSubtitleDataGeneration;
+        break;
+    default:
+        break;
+    }
 
+    return generation;
+}
+
+void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
     if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
         mPendingReadBufferTypes |= (1 << trackType);
         sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
@@ -1383,25 +1263,13 @@
     int32_t tmpType;
     CHECK(msg->findInt32("trackType", &tmpType));
     media_track_type trackType = (media_track_type)tmpType;
+    mPendingReadBufferTypes &= ~(1 << trackType);
     readBuffer(trackType);
-    {
-        // only protect the variable change, as readBuffer may
-        // take considerable time.
-        Mutex::Autolock _l(mReadBufferLock);
-        mPendingReadBufferTypes &= ~(1 << trackType);
-    }
 }
 
 void NuPlayer::GenericSource::readBuffer(
         media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode,
         int64_t *actualTimeUs, bool formatChange) {
-    // Do not read data if Widevine source is stopped
-    //
-    // TODO: revisit after widevine is removed.  May be able to
-    // combine mStopRead with mStarted.
-    if (mStopRead) {
-        return;
-    }
     Track *track;
     size_t maxBuffers = 1;
     switch (trackType) {
@@ -1445,10 +1313,12 @@
         options.setNonBlocking();
     }
 
+    int32_t generation = getDataGeneration(trackType);
     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
         Vector<MediaBuffer *> mediaBuffers;
         status_t err = NO_ERROR;
 
+        mLock.unlock();
         if (couldReadMultiple) {
             err = track->mSource->readMultiple(
                     &mediaBuffers, maxBuffers - numBuffers, &options);
@@ -1459,11 +1329,21 @@
                 mediaBuffers.push_back(mbuf);
             }
         }
+        mLock.lock();
 
         options.clearNonPersistent();
 
         size_t id = 0;
         size_t count = mediaBuffers.size();
+
+        // in case track has been changed since we don't have lock for some time.
+        if (generation != getDataGeneration(trackType)) {
+            for (; id < count; ++id) {
+                mediaBuffers[id]->release();
+            }
+            break;
+        }
+
         for (; id < count; ++id) {
             int64_t timeUs;
             MediaBuffer *mbuf = mediaBuffers[id];
@@ -1474,10 +1354,8 @@
             }
             if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
                 mAudioTimeUs = timeUs;
-                mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs);
             } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
                 mVideoTimeUs = timeUs;
-                mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs);
             }
 
             queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
@@ -1524,6 +1402,39 @@
             break;
         }
     }
+
+    if (mIsStreaming
+        && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
+        status_t finalResult;
+        int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+
+        int64_t markUs = (mPreparing ? mBufferingSettings.mInitialWatermarkMs
+            : mBufferingSettings.mRebufferingWatermarkHighMs) * 1000ll;
+        if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+            if (mPreparing || mSentPauseOnBuffering) {
+                Track *counterTrack =
+                    (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
+                if (counterTrack->mSource != NULL) {
+                    durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
+                }
+                if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+                    if (mPreparing) {
+                        notifyPrepared();
+                        mPreparing = false;
+                    } else {
+                        sendCacheStats();
+                        mSentPauseOnBuffering = false;
+                        sp<AMessage> notify = dupNotify();
+                        notify->setInt32("what", kWhatResumeOnBufferingEnd);
+                        notify->post();
+                    }
+                }
+            }
+            return;
+        }
+
+        postReadBuffer(trackType);
+    }
 }
 
 void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
@@ -1541,160 +1452,7 @@
     }
 }
 
-NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> &notify)
-    : mNotify(notify),
-      mDurationUs(-1ll),
-      mBitrate(-1ll),
-      mIsStreaming(false),
-      mAudioTimeUs(0),
-      mVideoTimeUs(0),
-      mPollBufferingGeneration(0),
-      mPrepareBuffering(false),
-      mBuffering(false),
-      mPrevBufferPercentage(-1),
-      mOffloadAudio(false),
-      mFirstDequeuedBufferRealUs(-1ll),
-      mFirstDequeuedBufferMediaUs(-1ll),
-      mlastDequeuedBufferMediaUs(-1ll) {
-      getDefaultBufferingSettings(&mSettings);
-}
-
-NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings(
-        BufferingSettings *buffering /* nonnull */) {
-    buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
-    buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE;
-    buffering->mInitialWatermarkMs = kHighWaterMarkMs;
-    buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
-    buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
-    buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB;
-    buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB;
-
-    ALOGV("BufferingMonitor::getDefaultBufferingSettings{%s}",
-            buffering->toString().string());
-}
-
-status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings(
-        const BufferingSettings &buffering) {
-    ALOGV("BufferingMonitor::setBufferingSettings{%s}",
-            buffering.toString().string());
-
-    Mutex::Autolock _l(mLock);
-    if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
-            || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
-                && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)
-            || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
-                && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) {
-        return BAD_VALUE;
-    }
-    mSettings = buffering;
-    if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
-        mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
-    }
-    if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
-        mSettings.mRebufferingWatermarkHighMs = INT32_MAX;
-    }
-    if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark;
-        mSettings.mRebufferingWatermarkHighKB = INT32_MAX;
-    }
-    return OK;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare(
-        const sp<NuCachedSource2> &cachedSource,
-        int64_t durationUs,
-        int64_t bitrate,
-        bool isStreaming) {
-    Mutex::Autolock _l(mLock);
-    prepare_l(cachedSource, durationUs, bitrate, isStreaming);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stop() {
-    Mutex::Autolock _l(mLock);
-    prepare_l(NULL /* cachedSource */, -1 /* durationUs */,
-            -1 /* bitrate */, false /* isStreaming */);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() {
-    Mutex::Autolock _l(mLock);
-    cancelPollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() {
-    Mutex::Autolock _l(mLock);
-    if (mIsStreaming) {
-        cancelPollBuffering_l();
-        onPollBuffering_l();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() {
-    Mutex::Autolock _l(mLock);
-    stopBufferingIfNecessary_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() {
-    Mutex::Autolock _l(mLock);
-    ensureCacheIsFetching_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) {
-    Mutex::Autolock _l(mLock);
-    if (isAudio) {
-        mAudioTimeUs = timeUs;
-    } else {
-        mVideoTimeUs = timeUs;
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) {
-    Mutex::Autolock _l(mLock);
-    mOffloadAudio = offload;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) {
-    Mutex::Autolock _l(mLock);
-    if (mediaUs < 0) {
-        mFirstDequeuedBufferRealUs = -1ll;
-        mFirstDequeuedBufferMediaUs = -1ll;
-    } else if (mFirstDequeuedBufferRealUs < 0) {
-        mFirstDequeuedBufferRealUs = ALooper::GetNowUs();
-        mFirstDequeuedBufferMediaUs = mediaUs;
-    }
-    mlastDequeuedBufferMediaUs = mediaUs;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
-        const sp<NuCachedSource2> &cachedSource,
-        int64_t durationUs,
-        int64_t bitrate,
-        bool isStreaming) {
-
-    mCachedSource = cachedSource;
-    mDurationUs = durationUs;
-    mBitrate = bitrate;
-    mIsStreaming = isStreaming;
-    mAudioTimeUs = 0;
-    mVideoTimeUs = 0;
-    mPrepareBuffering = (cachedSource != NULL);
-    cancelPollBuffering_l();
-    mOffloadAudio = false;
-    mFirstDequeuedBufferRealUs = -1ll;
-    mFirstDequeuedBufferMediaUs = -1ll;
-    mlastDequeuedBufferMediaUs = -1ll;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() {
-    mBuffering = false;
-    ++mPollBufferingGeneration;
-    mPrevBufferPercentage = -1;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) {
+void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
     // Buffering percent could go backward as it's estimated from remaining
     // data and last access time. This could cause the buffering position
     // drawn on media control to jitter slightly. Remember previously reported
@@ -1707,106 +1465,28 @@
 
     mPrevBufferPercentage = percentage;
 
-    ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage);
+    ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
 
-    sp<AMessage> msg = mNotify->dup();
-    msg->setInt32("what", kWhatBufferingUpdate);
-    msg->setInt32("percentage", percentage);
-    msg->post();
+    sp<AMessage> notify = dupNotify();
+    notify->setInt32("what", kWhatBufferingUpdate);
+    notify->setInt32("percentage", percentage);
+    notify->post();
 }
 
-void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() {
-    if (mPrepareBuffering) {
-        return;
-    }
-
-    if (!mBuffering) {
-        ALOGD("startBufferingIfNecessary_l");
-
-        mBuffering = true;
-
-        ensureCacheIsFetching_l();
-        sendCacheStats_l();
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatPauseOnBufferingStart);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() {
-    if (mPrepareBuffering) {
-        ALOGD("stopBufferingIfNecessary_l, mBuffering=%d", mBuffering);
-
-        mPrepareBuffering = false;
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatPrepared);
-        notify->setInt32("err", OK);
-        notify->post();
-
-        return;
-    }
-
-    if (mBuffering) {
-        ALOGD("stopBufferingIfNecessary_l");
-        mBuffering = false;
-
-        sendCacheStats_l();
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatResumeOnBufferingEnd);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() {
-    int32_t kbps = 0;
-    status_t err = UNKNOWN_ERROR;
-
-    if (mCachedSource != NULL) {
-        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
-    }
-
-    if (err == OK) {
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatCacheStats);
-        notify->setInt32("bandwidth", kbps);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() {
-    if (mCachedSource != NULL) {
-        mCachedSource->resumeFetchingIfNecessary();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() {
+void NuPlayer::GenericSource::schedulePollBuffering() {
     sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
     msg->setInt32("generation", mPollBufferingGeneration);
     // Enquires buffering status every second.
     msg->post(1000000ll);
 }
 
-int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() {
-    if (mAudioTimeUs > 0) {
-        return mAudioTimeUs;
-    } else if (mVideoTimeUs > 0) {
-        return mVideoTimeUs;
-    } else {
-        return 0;
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() {
+void NuPlayer::GenericSource::onPollBuffering() {
     status_t finalStatus = UNKNOWN_ERROR;
     int64_t cachedDurationUs = -1ll;
     ssize_t cachedDataRemaining = -1;
 
     if (mCachedSource != NULL) {
-        cachedDataRemaining =
-                mCachedSource->approxDataRemaining(&finalStatus);
+        cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
 
         if (finalStatus == OK) {
             off64_t size;
@@ -1824,157 +1504,49 @@
     }
 
     if (finalStatus != OK) {
-        ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus);
+        ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
 
         if (finalStatus == ERROR_END_OF_STREAM) {
-            notifyBufferingUpdate_l(100);
+            notifyBufferingUpdate(100);
         }
 
-        stopBufferingIfNecessary_l();
         return;
     }
 
     if (cachedDurationUs >= 0ll) {
         if (mDurationUs > 0ll) {
-            int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
+            int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
             int percentage = 100.0 * cachedPosUs / mDurationUs;
             if (percentage > 100) {
                 percentage = 100;
             }
 
-            notifyBufferingUpdate_l(percentage);
+            notifyBufferingUpdate(percentage);
         }
 
-        ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
-
-        if (mPrepareBuffering) {
-            if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) {
-                stopBufferingIfNecessary_l();
-            }
-        } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
-            if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
-                // Take into account the data cached in downstream components to try to avoid
-                // unnecessary pause.
-                if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
-                    int64_t downStreamCacheUs =
-                        mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
-                            - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
-                    if (downStreamCacheUs > 0) {
-                        cachedDurationUs += downStreamCacheUs;
-                    }
-                }
-
-                if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
-                    startBufferingIfNecessary_l();
-                }
-            } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) {
-                stopBufferingIfNecessary_l();
-            }
-        }
-    } else if (cachedDataRemaining >= 0
-            && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
-                cachedDataRemaining);
-
-        if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) {
-            startBufferingIfNecessary_l();
-        } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) {
-            stopBufferingIfNecessary_l();
-        }
+        ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
     }
 
-    schedulePollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-      case kWhatPollBuffering:
-      {
-          int32_t generation;
-          CHECK(msg->findInt32("generation", &generation));
-          Mutex::Autolock _l(mLock);
-          if (generation == mPollBufferingGeneration) {
-              onPollBuffering_l();
-          }
-          break;
-      }
-      default:
-          TRESPASS();
-          break;
-    }
+    schedulePollBuffering();
 }
 
 // Modular DRM
 status_t NuPlayer::GenericSource::prepareDrm(
-        const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto)
-{
+        const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto) {
+    Mutex::Autolock _l(mLock);
     ALOGV("prepareDrm");
 
-    sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
-    // synchronous call so just passing the address but with local copies of "const" args
-    uint8_t UUID[16];
-    memcpy(UUID, uuid, sizeof(UUID));
-    Vector<uint8_t> sessionId = drmSessionId;
-    msg->setPointer("uuid", (void*)UUID);
-    msg->setPointer("drmSessionId", (void*)&sessionId);
-    msg->setPointer("crypto", (void*)crypto);
-
-    sp<AMessage> response;
-    status_t status = msg->postAndAwaitResponse(&response);
-
-    if (status == OK && response != NULL) {
-        CHECK(response->findInt32("status", &status));
-        ALOGV_IF(status == OK, "prepareDrm: mCrypto: %p (%d)", crypto->get(),
-                (*crypto != NULL ? (*crypto)->getStrongCount() : 0));
-        ALOGD("prepareDrm ret: %d ", status);
-    } else {
-        ALOGE("prepareDrm err: %d", status);
-    }
-
-    return status;
-}
-
-status_t NuPlayer::GenericSource::releaseDrm()
-{
-    ALOGV("releaseDrm");
-
-    sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
-
-    // synchronous call to update the source states before the player proceedes with crypto cleanup
-    sp<AMessage> response;
-    status_t status = msg->postAndAwaitResponse(&response);
-
-    if (status == OK && response != NULL) {
-        ALOGD("releaseDrm ret: OK ");
-    } else {
-        ALOGE("releaseDrm err: %d", status);
-    }
-
-    return status;
-}
-
-status_t NuPlayer::GenericSource::onPrepareDrm(const sp<AMessage> &msg)
-{
-    ALOGV("onPrepareDrm ");
-
     mIsDrmProtected = false;
     mIsDrmReleased = false;
     mIsSecure = false;
 
-    uint8_t *uuid;
-    Vector<uint8_t> *drmSessionId;
-    sp<ICrypto> *outCrypto;
-    CHECK(msg->findPointer("uuid", (void**)&uuid));
-    CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
-    CHECK(msg->findPointer("crypto", (void**)&outCrypto));
-
     status_t status = OK;
-    sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, *drmSessionId, status);
+    sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, drmSessionId, status);
     if (crypto == NULL) {
-        ALOGE("onPrepareDrm: createCrypto failed. status: %d", status);
+        ALOGE("prepareDrm: createCrypto failed. status: %d", status);
         return status;
     }
-    ALOGV("onPrepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
+    ALOGV("prepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
             DrmUUID::toHexString(uuid).string());
 
     *outCrypto = crypto;
@@ -1983,14 +1555,14 @@
 
     if (mMimes.size() == 0) {
         status = UNKNOWN_ERROR;
-        ALOGE("onPrepareDrm: Unexpected. Must have at least one track. status: %d", status);
+        ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status);
         return status;
     }
 
     // first mime in this list is either the video track, or the first audio track
     const char *mime = mMimes[0].string();
     mIsSecure = crypto->requiresSecureDecoderComponent(mime);
-    ALOGV("onPrepareDrm: requiresSecureDecoderComponent mime: %s  isSecure: %d",
+    ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s  isSecure: %d",
             mime, mIsSecure);
 
     // Checking the member flags while in the looper to send out the notification.
@@ -2004,18 +1576,27 @@
             FLAG_CAN_SEEK_FORWARD |
             FLAG_CAN_SEEK);
 
+    if (status == OK) {
+        ALOGV("prepareDrm: mCrypto: %p (%d)", outCrypto->get(),
+                (*outCrypto != NULL ? (*outCrypto)->getStrongCount() : 0));
+        ALOGD("prepareDrm ret: %d ", status);
+    } else {
+        ALOGE("prepareDrm err: %d", status);
+    }
     return status;
 }
 
-status_t NuPlayer::GenericSource::onReleaseDrm()
-{
+status_t NuPlayer::GenericSource::releaseDrm() {
+    Mutex::Autolock _l(mLock);
+    ALOGV("releaseDrm");
+
     if (mIsDrmProtected) {
         mIsDrmProtected = false;
         // to prevent returning any more buffer after stop/releaseDrm (b/37960096)
         mIsDrmReleased = true;
-        ALOGV("onReleaseDrm: mIsDrmProtected is reset.");
+        ALOGV("releaseDrm: mIsDrmProtected is reset.");
     } else {
-        ALOGE("onReleaseDrm: mIsDrmProtected is already false.");
+        ALOGE("releaseDrm: mIsDrmProtected is already false.");
     }
 
     return OK;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 8188a14..f4debc1 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -86,13 +86,11 @@
 
     virtual bool isStreaming() const;
 
-    virtual void setOffloadAudio(bool offload);
-
     // Modular DRM
     virtual void signalBufferReturned(MediaBuffer *buffer);
 
     virtual status_t prepareDrm(
-            const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto);
+            const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto);
 
     virtual status_t releaseDrm();
 
@@ -114,17 +112,10 @@
         kWhatSendTimedTextData,
         kWhatChangeAVSource,
         kWhatPollBuffering,
-        kWhatGetFormat,
-        kWhatGetSelectedTrack,
-        kWhatSelectTrack,
-        kWhatSeek,
         kWhatReadBuffer,
         kWhatStart,
         kWhatResume,
         kWhatSecureDecodersInstantiated,
-        // Modular DRM
-        kWhatPrepareDrm,
-        kWhatReleaseDrm,
     };
 
     struct Track {
@@ -133,84 +124,6 @@
         sp<AnotherPacketSource> mPackets;
     };
 
-    // Helper to monitor buffering status. The polling happens every second.
-    // When necessary, it will send out buffering events to the player.
-    struct BufferingMonitor : public AHandler {
-    public:
-        explicit BufferingMonitor(const sp<AMessage> &notify);
-
-        void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
-        status_t setBufferingSettings(const BufferingSettings &buffering);
-
-        // Set up state.
-        void prepare(const sp<NuCachedSource2> &cachedSource,
-                int64_t durationUs,
-                int64_t bitrate,
-                bool isStreaming);
-        // Stop and reset buffering monitor.
-        void stop();
-        // Cancel the current monitor task.
-        void cancelPollBuffering();
-        // Restart the monitor task.
-        void restartPollBuffering();
-        // Stop buffering task and send out corresponding events.
-        void stopBufferingIfNecessary();
-        // Make sure data source is getting data.
-        void ensureCacheIsFetching();
-        // Update media time of just extracted buffer from data source.
-        void updateQueuedTime(bool isAudio, int64_t timeUs);
-
-        // Set the offload mode.
-        void setOffloadAudio(bool offload);
-        // Update media time of last dequeued buffer which is sent to the decoder.
-        void updateDequeuedBufferTime(int64_t mediaUs);
-
-    protected:
-        virtual ~BufferingMonitor();
-        virtual void onMessageReceived(const sp<AMessage> &msg);
-
-    private:
-        enum {
-            kWhatPollBuffering,
-        };
-
-        sp<AMessage> mNotify;
-
-        sp<NuCachedSource2> mCachedSource;
-        int64_t mDurationUs;
-        int64_t mBitrate;
-        bool mIsStreaming;
-
-        int64_t mAudioTimeUs;
-        int64_t mVideoTimeUs;
-        int32_t mPollBufferingGeneration;
-        bool mPrepareBuffering;
-        bool mBuffering;
-        int32_t mPrevBufferPercentage;
-
-        mutable Mutex mLock;
-
-        BufferingSettings mSettings;
-        bool mOffloadAudio;
-        int64_t mFirstDequeuedBufferRealUs;
-        int64_t mFirstDequeuedBufferMediaUs;
-        int64_t mlastDequeuedBufferMediaUs;
-
-        void prepare_l(const sp<NuCachedSource2> &cachedSource,
-                int64_t durationUs,
-                int64_t bitrate,
-                bool isStreaming);
-        void cancelPollBuffering_l();
-        void notifyBufferingUpdate_l(int32_t percentage);
-        void startBufferingIfNecessary_l();
-        void stopBufferingIfNecessary_l();
-        void sendCacheStats_l();
-        void ensureCacheIsFetching_l();
-        int64_t getLastReadPosition_l();
-        void onPollBuffering_l();
-        void schedulePollBuffering_l();
-    };
-
     Vector<sp<IMediaSource> > mSources;
     Track mAudioTrack;
     int64_t mAudioTimeUs;
@@ -221,6 +134,13 @@
     Track mSubtitleTrack;
     Track mTimedTextTrack;
 
+    BufferingSettings mBufferingSettings;
+    int32_t mPrevBufferPercentage;
+    int32_t mPollBufferingGeneration;
+    bool mSentPauseOnBuffering;
+
+    int32_t mAudioDataGeneration;
+    int32_t mVideoDataGeneration;
     int32_t mFetchSubtitleDataGeneration;
     int32_t mFetchTimedTextDataGeneration;
     int64_t mDurationUs;
@@ -243,17 +163,14 @@
     sp<DataSource> mHttpSource;
     sp<MetaData> mFileMeta;
     bool mStarted;
-    bool mStopRead;
+    bool mPreparing;
     int64_t mBitrate;
-    sp<BufferingMonitor> mBufferingMonitor;
     uint32_t mPendingReadBufferTypes;
     sp<ABuffer> mGlobalTimedText;
 
-    mutable Mutex mReadBufferLock;
-    mutable Mutex mDisconnectLock;
+    mutable Mutex mLock;
 
     sp<ALooper> mLooper;
-    sp<ALooper> mBufferingMonitorLooper;
 
     void resetDataSource();
 
@@ -265,21 +182,6 @@
     void finishPrepareAsync();
     status_t startSources();
 
-    void onGetFormatMeta(const sp<AMessage>& msg) const;
-    sp<MetaData> doGetFormatMeta(bool audio) const;
-
-    void onGetTrackInfo(const sp<AMessage>& msg) const;
-    sp<AMessage> doGetTrackInfo(size_t trackIndex) const;
-
-    void onGetSelectedTrack(const sp<AMessage>& msg) const;
-    ssize_t doGetSelectedTrack(media_track_type type) const;
-
-    void onSelectTrack(const sp<AMessage>& msg);
-    status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
-
-    void onSeek(const sp<AMessage>& msg);
-    status_t doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
-
     void onPrepareAsync();
 
     void fetchTextData(
@@ -314,6 +216,15 @@
     void queueDiscontinuityIfNeeded(
             bool seeking, bool formatChange, media_track_type trackType, Track *track);
 
+    void schedulePollBuffering();
+    void onPollBuffering();
+    void notifyBufferingUpdate(int32_t percentage);
+
+    void sendCacheStats();
+
+    sp<MetaData> getFormatMeta_l(bool audio);
+    int32_t getDataGeneration(media_track_type type) const;
+
     // Modular DRM
     // The source is DRM protected and is prepared for DRM.
     bool mIsDrmProtected;
@@ -322,8 +233,6 @@
     Vector<String8> mMimes;
 
     status_t checkDrmInfo();
-    status_t onPrepareDrm(const sp<AMessage> &msg);
-    status_t onReleaseDrm();
 
     DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
 };