Merge changes I7835e753,I5fe4d3e7

* changes:
  AudioPolicyManager: abort when client is removed while active
  AudioOutputDescriptor: improve refcount logging
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index fde09df18..c5df5c7 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -9,6 +9,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index ea56734..9b0f4e7 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -33,16 +33,16 @@
 // how many Sonivox output buffers to aggregate into one MediaBufferBase
 static const int NUM_COMBINE_BUFFERS = 4;
 
-class MidiSource : public MediaTrackHelper {
+class MidiSource : public MediaTrackHelperV2 {
 
 public:
     MidiSource(
             MidiEngine &engine,
-            MetaDataBase &trackMetadata);
+            AMediaFormat *trackMetadata);
 
-    virtual status_t start(MetaDataBase *params);
+    virtual status_t start(AMediaFormat *params);
     virtual status_t stop();
-    virtual status_t getFormat(MetaDataBase&);
+    virtual status_t getFormat(AMediaFormat *);
 
     virtual status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
@@ -52,7 +52,7 @@
 
 private:
     MidiEngine &mEngine;
-    MetaDataBase &mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
     bool mInitCheck;
     bool mStarted;
 
@@ -69,7 +69,7 @@
 
 MidiSource::MidiSource(
         MidiEngine &engine,
-        MetaDataBase &trackMetadata)
+        AMediaFormat *trackMetadata)
     : mEngine(engine),
       mTrackMetadata(trackMetadata),
       mInitCheck(false),
@@ -87,7 +87,7 @@
     }
 }
 
-status_t MidiSource::start(MetaDataBase * /* params */)
+status_t MidiSource::start(AMediaFormat * /* params */)
 {
     ALOGV("MidiSource::start");
 
@@ -108,9 +108,9 @@
     return OK;
 }
 
-status_t MidiSource::getFormat(MetaDataBase &meta)
+status_t MidiSource::getFormat(AMediaFormat *meta)
 {
-    meta = mTrackMetadata;
+    AMediaFormat_copy(meta, mTrackMetadata);
     return OK;
 }
 
@@ -143,8 +143,8 @@
 // MidiEngine
 
 MidiEngine::MidiEngine(CDataSource *dataSource,
-        MetaDataBase *fileMetadata,
-        MetaDataBase *trackMetadata) :
+        AMediaFormat *fileMetadata,
+        AMediaFormat *trackMetadata) :
             mGroup(NULL),
             mEasData(NULL),
             mEasHandle(NULL),
@@ -170,16 +170,20 @@
     }
 
     if (fileMetadata != NULL) {
-        fileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MIDI);
+        AMediaFormat_setString(fileMetadata, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MIDI);
     }
 
     if (trackMetadata != NULL) {
-        trackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-        trackMetadata->setInt64(kKeyDuration, 1000ll * temp); // milli->micro
+        AMediaFormat_setString(trackMetadata, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+        AMediaFormat_setInt64(
+                trackMetadata, AMEDIAFORMAT_KEY_DURATION, 1000ll * temp); // milli->micro
         mEasConfig = EAS_Config();
-        trackMetadata->setInt32(kKeySampleRate, mEasConfig->sampleRate);
-        trackMetadata->setInt32(kKeyChannelCount, mEasConfig->numChannels);
-        trackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+        AMediaFormat_setInt32(
+                trackMetadata, AMEDIAFORMAT_KEY_SAMPLE_RATE, mEasConfig->sampleRate);
+        AMediaFormat_setInt32(
+                trackMetadata, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mEasConfig->numChannels);
+        AMediaFormat_setInt32(
+                trackMetadata, AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
     }
     mIsInitialized = true;
 }
@@ -268,13 +272,17 @@
       mInitCheck(false)
 {
     ALOGV("MidiExtractor ctor");
-    mEngine = new MidiEngine(mDataSource, &mFileMetadata, &mTrackMetadata);
+    mFileMetadata = AMediaFormat_new();
+    mTrackMetadata = AMediaFormat_new();
+    mEngine = new MidiEngine(mDataSource, mFileMetadata, mTrackMetadata);
     mInitCheck = mEngine->initCheck();
 }
 
 MidiExtractor::~MidiExtractor()
 {
     ALOGV("MidiExtractor dtor");
+    AMediaFormat_delete(mFileMetadata);
+    AMediaFormat_delete(mTrackMetadata);
 }
 
 size_t MidiExtractor::countTracks()
@@ -282,7 +290,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrackHelper *MidiExtractor::getTrack(size_t index)
+MediaTrackHelperV2 *MidiExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
@@ -291,20 +299,20 @@
 }
 
 status_t MidiExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     ALOGV("MidiExtractor::getTrackMetaData");
     if (mInitCheck != OK || index > 0) {
         return UNKNOWN_ERROR;
     }
-    meta = mTrackMetadata;
+    AMediaFormat_copy(meta, mTrackMetadata);
     return OK;
 }
 
-status_t MidiExtractor::getMetaData(MetaDataBase &meta)
+status_t MidiExtractor::getMetaData(AMediaFormat *meta)
 {
     ALOGV("MidiExtractor::getMetaData");
-    meta = mFileMetadata;
+    AMediaFormat_copy(meta, mFileMetadata);
     return OK;
 }
 
@@ -323,26 +331,27 @@
 
 }
 
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("ef6cca0a-f8a2-43e6-ba5f-dfcd7c9a7ef2"),
         1,
         "MIDI Extractor",
         {
-            [](
-                    CDataSource *source,
-                    float *confidence,
-                    void **,
-                    FreeMetaFunc *) -> CreatorFunc {
+            .v2 = [](
+                CDataSource *source,
+                float *confidence,
+                void **,
+                FreeMetaFunc *) -> CreatorFuncV2 {
                 if (SniffMidi(source, confidence)) {
                     return [](
                             CDataSource *source,
-                            void *) -> CMediaExtractor* {
-                        return wrap(new MidiExtractor(source));};
+                            void *) -> CMediaExtractorV2* {
+                        return wrapV2(new MidiExtractor(source));};
                 }
                 return NULL;
             }
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 2147297..d82c5be 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -22,8 +22,8 @@
 #include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MediaBufferBase.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MetaDataBase.h>
 #include <media/MidiIoWrapper.h>
+#include <media/NdkMediaFormat.h>
 #include <utils/String8.h>
 #include <libsonivox/eas.h>
 
@@ -32,8 +32,8 @@
 class MidiEngine {
 public:
     explicit MidiEngine(CDataSource *dataSource,
-            MetaDataBase *fileMetadata,
-            MetaDataBase *trackMetadata);
+            AMediaFormat *fileMetadata,
+            AMediaFormat *trackMetadata);
     ~MidiEngine();
 
     status_t initCheck();
@@ -51,16 +51,16 @@
     bool mIsInitialized;
 };
 
-class MidiExtractor : public MediaExtractorPluginHelper {
+class MidiExtractor : public MediaExtractorPluginHelperV2 {
 
 public:
     explicit MidiExtractor(CDataSource *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "MidiExtractor"; }
 
 protected:
@@ -69,10 +69,10 @@
 private:
     CDataSource *mDataSource;
     status_t mInitCheck;
-    MetaDataBase mFileMetadata;
+    AMediaFormat *mFileMetadata;
 
     // There is only one track
-    MetaDataBase mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
 
     MidiEngine *mEngine;
 
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 0e61589..ece9e6a 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -185,18 +185,26 @@
         mNumberOfBursts = numBursts;
     }
 
+    int32_t getFramesPerCallback() const {
+        return mFramesPerCallback;
+    }
+    void setFramesPerCallback(int32_t size) {
+        mFramesPerCallback = size;
+    }
+
     /**
      * Apply these parameters to a stream builder.
      * @param builder
      */
     void applyParameters(AAudioStreamBuilder *builder) const {
-        AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
-        AAudioStreamBuilder_setFormat(builder, mFormat);
-        AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
         AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity);
+        AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
         AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
-        AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
+        AAudioStreamBuilder_setFormat(builder, mFormat);
+        AAudioStreamBuilder_setFramesPerDataCallback(builder, mFramesPerCallback);
         AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
+        AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
+        AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
 
         // Call P functions if supported.
         loadFutureFunctions();
@@ -232,6 +240,7 @@
     aaudio_input_preset_t      mInputPreset     = AAUDIO_UNSPECIFIED;
 
     int32_t                    mNumberOfBursts  = AAUDIO_UNSPECIFIED;
+    int32_t                    mFramesPerCallback = AAUDIO_UNSPECIFIED;
 };
 
 class AAudioArgsParser : public AAudioParameters {
@@ -297,6 +306,9 @@
                 case 'y':
                     setContentType(atoi(&arg[2]));
                     break;
+                case 'z':
+                    setFramesPerCallback(atoi(&arg[2]));
+                    break;
                 default:
                     unrecognized = true;
                     break;
@@ -350,6 +362,7 @@
         printf("      -u{usage} eg. 14 for AAUDIO_USAGE_GAME\n");
         printf("      -x to use EXCLUSIVE mode\n");
         printf("      -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
+        printf("      -z{callbackSize} or block size, in frames, default = 0\n");
     }
 
     static aaudio_performance_mode_t parsePerformanceMode(char c) {
@@ -406,6 +419,9 @@
         printf("  Capacity:     requested = %d, actual = %d\n", getBufferCapacity(),
                AAudioStream_getBufferCapacityInFrames(stream));
 
+        printf("  CallbackSize: requested = %d, actual = %d\n", getFramesPerCallback(),
+               AAudioStream_getFramesPerDataCallback(stream));
+
         printf("  SharingMode:  requested = %s, actual = %s\n",
                getSharingModeText(getSharingMode()),
                getSharingModeText(AAudioStream_getSharingMode(stream)));
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index dbf00a9..40e22ac 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -57,6 +57,9 @@
 
     // Try to create an AudioRecord
 
+    const aaudio_session_id_t requestedSessionId = builder.getSessionId();
+    const audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
     // TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                               ? 2 : getSamplesPerFrame();
@@ -66,17 +69,21 @@
                         : builder.getBufferCapacity();
 
 
-    audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
+    audio_input_flags_t flags;
     aaudio_performance_mode_t perfMode = getPerformanceMode();
     switch (perfMode) {
         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
-            flags = (audio_input_flags_t) (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW);
+            // If the app asks for a sessionId then it means they want to use effects.
+            // So don't use RAW flag.
+            flags = (audio_input_flags_t) ((requestedSessionId == AAUDIO_SESSION_ID_NONE)
+                    ? (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW)
+                    : (AUDIO_INPUT_FLAG_FAST));
             break;
 
         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
         case AAUDIO_PERFORMANCE_MODE_NONE:
         default:
-            // No flags.
+            flags = AUDIO_INPUT_FLAG_NONE;
             break;
     }
 
@@ -141,9 +148,6 @@
             .tags = ""
     };
 
-    aaudio_session_id_t requestedSessionId = builder.getSessionId();
-    audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
-
     // ----------- open the AudioRecord ---------------------
     // Might retry, but never more than once.
     for (int i = 0; i < 2; i ++) {
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 1572f0d..1ac2558 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -59,18 +59,25 @@
         return result;
     }
 
+    const aaudio_session_id_t requestedSessionId = builder.getSessionId();
+    const audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
     // Try to create an AudioTrack
     // Use stereo if unspecified.
     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                               ? 2 : getSamplesPerFrame();
     audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
 
-    audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+    audio_output_flags_t flags;
     aaudio_performance_mode_t perfMode = getPerformanceMode();
     switch(perfMode) {
         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
             // Bypass the normal mixer and go straight to the FAST mixer.
-            flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW);
+            // If the app asks for a sessionId then it means they want to use effects.
+            // So don't use RAW flag.
+            flags = (audio_output_flags_t) ((requestedSessionId == AAUDIO_SESSION_ID_NONE)
+                    ? (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)
+                    : (AUDIO_OUTPUT_FLAG_FAST));
             break;
 
         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
@@ -81,6 +88,7 @@
         case AAUDIO_PERFORMANCE_MODE_NONE:
         default:
             // No flags. Use a normal mixer in front of the FAST mixer.
+            flags = AUDIO_OUTPUT_FLAG_NONE;
             break;
     }
 
@@ -135,11 +143,6 @@
             .tags = ""
     };
 
-    static_assert(AAUDIO_UNSPECIFIED == AUDIO_SESSION_ALLOCATE, "Session IDs should match");
-
-    aaudio_session_id_t requestedSessionId = builder.getSessionId();
-    audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
-
     mAudioTrack = new AudioTrack();
     mAudioTrack->set(
             AUDIO_STREAM_DEFAULT,  // ignored because we pass attributes below
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 272bc30..7d67262 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -31,18 +31,6 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <utils/Errors.h>
 
-// TODO: remove forward declaration when AMediaExtractor_disconnect is offcially added to NDK
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-media_status_t AMediaExtractor_disconnect(AMediaExtractor *);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
 namespace android {
 
 static const size_t kAESBlockSize = 16;  // AES_BLOCK_SIZE
@@ -1080,14 +1068,6 @@
     return OK;
 }
 
-status_t AMediaExtractorWrapper::disconnect() {
-    if (mAMediaExtractor != NULL) {
-        media_status_t err = AMediaExtractor_disconnect(mAMediaExtractor);
-        return translateErrorCode(err);
-    }
-    return DEAD_OBJECT;
-}
-
 AMediaExtractor *AMediaExtractorWrapper::getAMediaExtractor() const {
     return mAMediaExtractor;
 }
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index c97d171..191665a 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -287,8 +287,6 @@
 
     status_t release();
 
-    status_t disconnect();
-
     status_t setDataSource(int fd, off64_t offset, off64_t length);
 
     status_t setDataSource(const char *location);
diff --git a/media/libmediaextractor/include/media/DataSourceBase.h b/media/libmediaextractor/include/media/DataSourceBase.h
index fc620fd..af5b83d 100644
--- a/media/libmediaextractor/include/media/DataSourceBase.h
+++ b/media/libmediaextractor/include/media/DataSourceBase.h
@@ -66,9 +66,7 @@
 
     virtual void close() {};
 
-    virtual void disconnect() {}
-
-    virtual ssize_t getAvailableSize(status_t * /*err*/) {
+    virtual status_t getAvailableSize(off64_t /*offset*/, off64_t * /*size*/) {
         return -1;
     }
 
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
index 57d1147..f41a431 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
@@ -147,9 +147,10 @@
     }
 
     uint32_t psshSize = pssh.tellp();
-    const uint8_t* psshPtr = reinterpret_cast<const uint8_t*>(pssh.str().c_str());
-    const char *psshHex = DrmUUID::arrayToHex(psshPtr, psshSize).string();
-    ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  PSSH: size: %u %s", psshSize, psshHex);
+    std::string psshBase = pssh.str();
+    const auto* psshPtr = reinterpret_cast<const uint8_t*>(psshBase.c_str());
+    ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  PSSH: size: %u %s", psshSize,
+            DrmUUID::arrayToHex(psshPtr, psshSize).string());
 
     // 1) Write PSSH bytes
     playerMsg->add_values()->set_bytes_value(
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 68adf3c..f720667 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -5384,7 +5384,7 @@
         AudioEncoding pcmEncoding = kAudioEncodingPcm16bit;
         (void)mConfigFormat->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);
         AudioEncoding codecPcmEncoding = kAudioEncodingPcm16bit;
-        (void)mOutputFormat->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);
+        (void)mOutputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);
 
         mConverter[kPortIndexOutput] = AudioConverter::Create(codecPcmEncoding, pcmEncoding);
         if (mConverter[kPortIndexOutput] != NULL) {
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 18f4b12..7025af7 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -256,6 +256,10 @@
     return ERROR_UNSUPPORTED;
 }
 
+void NuCachedSource2::close() {
+    disconnect();
+}
+
 void NuCachedSource2::disconnect() {
     if (mSource->flags() & kIsHTTPBasedSource) {
         ALOGV("disconnecting HTTPBasedSource");
@@ -567,12 +571,19 @@
     return mCacheOffset + mCache->totalSize();
 }
 
-size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
+status_t NuCachedSource2::getAvailableSize(off64_t offset, off64_t *size) {
     Mutex::Autolock autoLock(mLock);
-    return approxDataRemaining_l(finalStatus);
+    status_t finalStatus = UNKNOWN_ERROR;
+    *size = approxDataRemaining_l(offset, &finalStatus);
+    return finalStatus;
 }
 
-size_t NuCachedSource2::approxDataRemaining_l(status_t *finalStatus) const {
+size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
+    Mutex::Autolock autoLock(mLock);
+    return approxDataRemaining_l(mLastAccessPos, finalStatus);
+}
+
+size_t NuCachedSource2::approxDataRemaining_l(off64_t offset, status_t *finalStatus) const {
     *finalStatus = mFinalStatus;
 
     if (mFinalStatus != OK && mNumRetriesLeft > 0) {
@@ -580,9 +591,10 @@
         *finalStatus = OK;
     }
 
+    offset = offset >= 0 ? offset : mLastAccessPos;
     off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
-    if (mLastAccessPos < lastBytePosCached) {
-        return lastBytePosCached - mLastAccessPos;
+    if (offset < lastBytePosCached) {
+        return lastBytePosCached - offset;
     }
     return 0;
 }
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index e42d8d0..f94648c 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -204,12 +204,6 @@
     return OK;
 }
 
-void NuMediaExtractor::disconnect() {
-    if (mDataSource != NULL) {
-        mDataSource->disconnect();
-    }
-}
-
 status_t NuMediaExtractor::updateDurationAndBitrate() {
     if (mImpl->countTracks() > kMaxTrackCount) {
         return ERROR_UNSUPPORTED;
@@ -786,9 +780,8 @@
         int64_t *durationUs, bool *eos) const {
     Mutex::Autolock autoLock(mLock);
 
-    status_t finalStatus;
-    ssize_t cachedDataRemaining =
-        mDataSource->getAvailableSize(&finalStatus);
+    off64_t cachedDataRemaining = -1;
+    status_t finalStatus = mDataSource->getAvailableSize(-1, &cachedDataRemaining);
 
     int64_t bitrate;
     if (cachedDataRemaining >= 0
diff --git a/media/libstagefright/http/ClearMediaHTTP.cpp b/media/libstagefright/http/ClearMediaHTTP.cpp
index bfbad1e..9557c8a 100644
--- a/media/libstagefright/http/ClearMediaHTTP.cpp
+++ b/media/libstagefright/http/ClearMediaHTTP.cpp
@@ -74,6 +74,10 @@
     return success ? OK : UNKNOWN_ERROR;
 }
 
+void ClearMediaHTTP::close() {
+    disconnect();
+}
+
 void ClearMediaHTTP::disconnect() {
     mName = String8("ClearMediaHTTP(<disconnected>)");
     if (mInitCheck != OK) {
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index f4aab25..596efb8 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -37,6 +37,8 @@
 
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
 
+    virtual void close();
+
     virtual void disconnect();
 
     virtual status_t getSize(off64_t *size);
@@ -51,9 +53,7 @@
         return mName;
     }
 
-    ssize_t getAvailableSize(status_t *finalStatus) {
-        return approxDataRemaining(finalStatus);
-    }
+    status_t getAvailableSize(off64_t offset, off64_t *size);
 
     ////////////////////////////////////////////////////////////////////////////
 
@@ -139,7 +139,7 @@
     ssize_t readInternal(off64_t offset, void *data, size_t size);
     status_t seekInternal_l(off64_t offset);
 
-    size_t approxDataRemaining_l(status_t *finalStatus) const;
+    size_t approxDataRemaining_l(off64_t offset, status_t *finalStatus) const;
 
     void restartPrefetcherIfNecessary_l(
             bool ignoreLowWaterThreshold = false, bool force = false);
diff --git a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
index 7fe9c74..72907a9 100644
--- a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
+++ b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
@@ -34,6 +34,8 @@
             const KeyedVector<String8, String8> *headers,
             off64_t offset);
 
+    virtual void close();
+
     virtual void disconnect();
 
     virtual status_t initCheck() const;
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 54a7095..641ccfa 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -64,8 +64,6 @@
 
     status_t setMediaCas(const HInterfaceToken &casToken);
 
-    void disconnect();
-
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
 
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 417f1df..05c8582 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -39,6 +39,7 @@
         "NdkMediaCrypto.cpp",
         "NdkMediaDataSource.cpp",
         "NdkMediaExtractor.cpp",
+        "NdkMediaError.cpp",
         "NdkMediaFormat.cpp",
         "NdkMediaMuxer.cpp",
         "NdkMediaDrm.cpp",
@@ -106,6 +107,7 @@
 
     srcs: [
         "NdkMediaDataSourceCallbacks.cpp",
+        "NdkMediaError.cpp",
     ],
 
     include_dirs: [
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 2c44fa3..75477b4 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -246,5 +246,10 @@
     mSource->close = close;
 }
 
+EXPORT
+void AMediaDataSource_close(AMediaDataSource *mSource) {
+    return mSource->close(mSource->userdata);
+}
+
 } // extern "C"
 
diff --git a/media/ndk/NdkMediaDataSourceCallbacks.cpp b/media/ndk/NdkMediaDataSourceCallbacks.cpp
index 4338048..1efcaa0 100644
--- a/media/ndk/NdkMediaDataSourceCallbacks.cpp
+++ b/media/ndk/NdkMediaDataSourceCallbacks.cpp
@@ -17,6 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NdkMediaDataSourceCallbacks"
 
+#include "NdkMediaErrorPriv.h"
 #include "NdkMediaDataSourceCallbacksPriv.h"
 #include <media/DataSource.h>
 
diff --git a/media/ndk/NdkMediaError.cpp b/media/ndk/NdkMediaError.cpp
new file mode 100644
index 0000000..2facd8c
--- /dev/null
+++ b/media/ndk/NdkMediaError.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/NdkMediaError.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+using namespace android;
+
+media_status_t translate_error(status_t err) {
+
+    if (err == OK) {
+        return AMEDIA_OK;
+    } else if (err == ERROR_END_OF_STREAM) {
+        return AMEDIA_ERROR_END_OF_STREAM;
+    } else if (err == ERROR_IO) {
+        return AMEDIA_ERROR_IO;
+    }
+
+    ALOGE("sf error code: %d", err);
+    return AMEDIA_ERROR_UNKNOWN;
+}
+
+status_t reverse_translate_error(media_status_t err) {
+
+    if (err == AMEDIA_OK) {
+        return OK;
+    } else if (err == AMEDIA_ERROR_END_OF_STREAM) {
+        return ERROR_END_OF_STREAM;
+    } else if (err == AMEDIA_ERROR_IO) {
+        return ERROR_IO;
+    }
+
+    ALOGE("ndk error code: %d", err);
+    return UNKNOWN_ERROR;
+}
diff --git a/media/ndk/NdkMediaErrorPriv.h b/media/ndk/NdkMediaErrorPriv.h
new file mode 100644
index 0000000..f5e2f02
--- /dev/null
+++ b/media/ndk/NdkMediaErrorPriv.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDK_MEDIA_ERROR_PRIV_H
+#define _NDK_MEDIA_ERROR_PRIV_H
+
+#include <media/NdkMediaError.h>
+#include <utils/Errors.h>
+
+using namespace android;
+
+media_status_t translate_error(status_t);
+
+status_t reverse_translate_error(media_status_t);
+
+#endif // _NDK_MEDIA_ERROR_PRIV_H
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index f00a19c..ff1c8a9 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -21,6 +21,7 @@
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaExtractor.h>
 #include <media/NdkMediaFormatPriv.h>
+#include "NdkMediaErrorPriv.h"
 #include "NdkMediaDataSourcePriv.h"
 
 
@@ -40,19 +41,6 @@
 
 using namespace android;
 
-static media_status_t translate_error(status_t err) {
-    if (err == OK) {
-        return AMEDIA_OK;
-    } else if (err == ERROR_END_OF_STREAM) {
-        return AMEDIA_ERROR_END_OF_STREAM;
-    } else if (err == ERROR_IO) {
-        return AMEDIA_ERROR_IO;
-    }
-
-    ALOGE("sf error code: %d", err);
-    return AMEDIA_ERROR_UNKNOWN;
-}
-
 struct AMediaExtractor {
     sp<NuMediaExtractor> mImpl;
     sp<ABuffer> mPsshBuf;
@@ -464,11 +452,5 @@
     return AMEDIA_OK;
 }
 
-EXPORT
-media_status_t AMediaExtractor_disconnect(AMediaExtractor * ex) {
-    ex->mImpl->disconnect();
-    return AMEDIA_OK;
-}
-
 } // extern "C"
 
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index b213fa9..ab709ac 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -21,6 +21,7 @@
 #include <media/NdkMediaMuxer.h>
 #include <media/NdkMediaCodec.h>
 #include <media/NdkMediaFormatPriv.h>
+#include "NdkMediaErrorPriv.h"
 
 
 #include <utils/Log.h>
@@ -36,14 +37,6 @@
 
 using namespace android;
 
-static media_status_t translate_error(status_t err) {
-    if (err == OK) {
-        return AMEDIA_OK;
-    }
-    ALOGE("sf error code: %d", err);
-    return AMEDIA_ERROR_UNKNOWN;
-}
-
 struct AMediaMuxer {
     sp<MediaMuxer> mImpl;
 
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 021029b..297d4bc 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -43,14 +43,9 @@
 /*
  * AMediaDataSource's callbacks will be invoked on an implementation-defined thread
  * or thread pool. No guarantees are provided about which thread(s) will be used for
- * callbacks. However, it is guaranteed that AMediaDataSource's callbacks will only
- * ever be invoked by a single thread at a time.
- *
- * There will be a thread synchronization point between each call to ensure that
- * modifications to the state of your AMediaDataSource are visible to future
- * calls. This means you don't need to do your own synchronization unless you're
- * modifying the AMediaDataSource from another thread while it's being used by the
- * framework.
+ * callbacks. For example, |close| can be invoked from a different thread than the
+ * thread invoking |readAt|. As such, the Implementations of AMediaDataSource callbacks
+ * must be threadsafe.
  */
 
 /**
@@ -74,9 +69,19 @@
 typedef ssize_t (*AMediaDataSourceGetSize)(void *userdata);
 
 /**
- * Called to close the data source and release associated resources.
- * The NDK media framework guarantees that after |close| is called
- * no future callbacks will be invoked on the data source.
+ * Called to close the data source, unblock reads, and release associated
+ * resources.
+ *
+ * The NDK media framework guarantees that after the first |close| is
+ * called, no future callbacks will be invoked on the data source except
+ * for |close| itself.
+ *
+ * Closing a data source allows readAt calls that were blocked waiting
+ * for I/O data to return promptly.
+ *
+ * When using AMediaDataSource as input to AMediaExtractor, closing
+ * has the effect of unblocking slow reads inside of setDataSource
+ * and readSampleData.
  */
 typedef void (*AMediaDataSourceClose)(void *userdata);
 
@@ -161,6 +166,18 @@
 
 #endif  /*__ANDROID_API__ >= 28 */
 
+#if __ANDROID_API__ >= 29
+
+/**
+ * Close the data source, unblock reads, and release associated resources.
+ *
+ * Please refer to the definition of AMediaDataSourceClose for
+ * additional details.
+ */
+void AMediaDataSource_close(AMediaDataSource*) __INTRODUCED_IN(29);
+
+#endif  /*__ANDROID_API__ >= 29 */
+
 __END_DECLS
 
 #endif // _NDK_MEDIA_DATASOURCE_H
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index a805e87..d13edfc 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -142,6 +142,7 @@
     AMediaDataSource_setReadAt;   # introduced=28
     AMediaDataSource_setUserdata; # introduced=28
     AMediaDataSource_newUri;      # introduced=29
+    AMediaDataSource_close;       # introduced=29
     AMediaDrm_closeSession;
     AMediaDrm_createByUUID;
     AMediaDrm_decrypt;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 6fa0b81..5ea82a7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1013,6 +1013,23 @@
         String8 address = outputDevices.size() > 0 ? outputDevices.itemAt(0)->mAddress
                 : String8("");
 
+        // MSD patch may be using the only output stream that can service this request. Release
+        // MSD patch to prioritize this request over any active output on MSD.
+        AudioPatchCollection msdPatches = getMsdPatches();
+        for (size_t i = 0; i < msdPatches.size(); i++) {
+            const auto& patch = msdPatches[i];
+            for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
+                const struct audio_port_config *sink = &patch->mPatch.sinks[j];
+                if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
+                        (sink->ext.device.type & device) != AUDIO_DEVICE_NONE &&
+                        (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
+                                AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
+                    releaseAudioPatch(patch->mHandle, mUidCached);
+                    break;
+                }
+            }
+        }
+
         status = outputDesc->open(config, device, address, stream, *flags, &output);
 
         // only accept an output with the requested parameters
@@ -4565,6 +4582,22 @@
 
     removeOutput(output);
     mPreviousOutputs = mOutputs;
+
+    // MSD patches may have been released to support a non-MSD direct output. Reset MSD patch if
+    // no direct outputs are open.
+    if (getMsdAudioOutDeviceTypes() != AUDIO_DEVICE_NONE) {
+        bool directOutputOpen = false;
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            if (mOutputs[i]->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+                directOutputOpen = true;
+                break;
+            }
+        }
+        if (!directOutputOpen) {
+            ALOGV("no direct outputs open, reset MSD patch");
+            setMsdPatch();
+        }
+    }
 }
 
 void AudioPolicyManager::closeInput(audio_io_handle_t input)