Merge "AudioPolicy: callback for recording configuration change"
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
index 53cbf80..6666343 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
@@ -33,7 +33,7 @@
 // decrypted data.  In theory, the output size can be larger than the input
 // size, but in practice this will never happen for AES-CTR.
 ssize_t CryptoPlugin::decrypt(bool secure, const KeyId keyId, const Iv iv,
-                              Mode mode, const void* srcPtr,
+                              Mode mode, const Pattern &pattern, const void* srcPtr,
                               const SubSample* subSamples, size_t numSubSamples,
                               void* dstPtr, AString* errorDetailMsg) {
     if (secure) {
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
index fd38f28..de84c36 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
@@ -44,7 +44,7 @@
 
     virtual ssize_t decrypt(
             bool secure, const KeyId keyId, const Iv iv,
-            Mode mode, const void* srcPtr,
+            Mode mode, const Pattern &pattern, const void* srcPtr,
             const SubSample* subSamples, size_t numSubSamples,
             void* dstPtr, android::AString* errorDetailMsg);
 
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index c856d7d..1e80f8e 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -792,15 +792,17 @@
 
     ssize_t
     MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
-                              Mode mode, const void *srcPtr, const SubSample *subSamples,
-                              size_t numSubSamples, void *dstPtr, AString * /* errorDetailMsg */)
+            Mode mode, const Pattern &pattern, const void *srcPtr,
+            const SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr, AString * /* errorDetailMsg */)
     {
-        ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
+        ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, "
+              "pattern:{encryptBlocks=%d, skipBlocks=%d} src=%p, "
               "subSamples=%s, dst=%p)",
               (int)secure,
               arrayToString(key, sizeof(key)).string(),
               arrayToString(iv, sizeof(iv)).string(),
-              (int)mode, srcPtr,
+              (int)mode, pattern.mEncryptBlocks, pattern.mSkipBlocks, srcPtr,
               subSamplesToString(subSamples, numSubSamples).string(),
               dstPtr);
         return OK;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index db266f9..40d4e84 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -159,7 +159,7 @@
 
         ssize_t decrypt(bool secure,
             const uint8_t key[16], const uint8_t iv[16],
-            Mode mode, const void *srcPtr,
+            Mode mode, const Pattern &pattern, const void *srcPtr,
             const SubSample *subSamples, size_t numSubSamples,
             void *dstPtr, AString *errorDetailMsg);
     private:
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 114e194..2f95b90 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -321,6 +321,8 @@
                                       audio_io_handle_t *handle);
     static status_t stopAudioSource(audio_io_handle_t handle);
 
+    static status_t setMasterMono(bool mono);
+    static status_t getMasterMono(bool *mono);
 
     // ----------------------------------------------------------------------------
 
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 6b93f6f..ceca71a 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -165,6 +165,9 @@
                                       const audio_attributes_t *attributes,
                                       audio_io_handle_t *handle) = 0;
     virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+    virtual status_t setMasterMono(bool mono) = 0;
+    virtual status_t getMasterMono(bool *mono) = 0;
 };
 
 
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index ea316de..5e324ad 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -51,6 +51,7 @@
             const uint8_t key[16],
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
+            const CryptoPlugin::Pattern &pattern,
             const sp<IMemory> &sharedBuffer, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             void *dstPtr,
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index cdfa159..93ffa93 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -119,6 +119,7 @@
             const uint8_t key[16],
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
+            const CryptoPlugin::Pattern &pattern,
             int64_t presentationTimeUs,
             uint32_t flags,
             AString *errorDetailMsg = NULL);
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 4f6a1ef..034cb35 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -170,6 +170,11 @@
     AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
 } cryptoinfo_mode_t;
 
+typedef struct {
+    int32_t encryptBlocks;
+    int32_t skipBlocks;
+} cryptoinfo_pattern_t;
+
 /**
  * Create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
  * crypto info, rather than one obtained from AMediaExtractor.
@@ -199,6 +204,13 @@
 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
 
 /**
+ * Set the crypto pattern on an AMediaCryptoInfo object
+ */
+void AMediaCodecCryptoInfo_setPattern(
+        AMediaCodecCryptoInfo *info,
+        cryptoinfo_pattern_t *pattern);
+
+/**
  * The number of subsamples that make up the buffer's contents.
  */
 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*);
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1f3880f..e458f3c 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -305,8 +305,6 @@
         return mEpoch;
     }
 
-    size_t      getFramesFilled();
-
 private:
     Modulo<uint32_t> mEpoch;
 };
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 999e7eb..a1892e4 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -3097,7 +3097,10 @@
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
 
             effect_param_t *p = (effect_param_t *)pCmdData;
-
+            if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) {
+                android_errorWriteLog(0x534e4554, "26347509");
+                return -EINVAL;
+            }
             if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
                     cmdSize < (sizeof(effect_param_t) + p->psize) ||
                     pReplyData == NULL || replySize == NULL ||
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index a48a4e3..4dc8b45 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1956,7 +1956,10 @@
             //ALOGV("\tReverb_command cmdCode Case: "
             //        "EFFECT_CMD_GET_PARAM start");
             effect_param_t *p = (effect_param_t *)pCmdData;
-
+            if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) {
+                android_errorWriteLog(0x534e4554, "26347509");
+                return -EINVAL;
+            }
             if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
                     cmdSize < (sizeof(effect_param_t) + p->psize) ||
                     pReplyData == NULL || replySize == NULL ||
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 46622ea..1ea2003 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -1166,6 +1166,20 @@
     return aps->stopAudioSource(handle);
 }
 
+status_t AudioSystem::setMasterMono(bool mono)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setMasterMono(mono);
+}
+
+status_t AudioSystem::getMasterMono(bool *mono)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getMasterMono(mono);
+}
+
 // ---------------------------------------------------------------------------
 
 int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 9d5d996..9fad500 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -347,27 +347,6 @@
             (mFrameCountP2 - 1);
 }
 
-size_t ClientProxy::getFramesFilled() {
-    audio_track_cblk_t* cblk = mCblk;
-    int32_t front;
-    int32_t rear;
-
-    if (mIsOut) {
-        front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
-        rear = cblk->u.mStreaming.mRear;
-    } else {
-        rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
-        front = cblk->u.mStreaming.mFront;
-    }
-    ssize_t filled = rear - front;
-    // pipe should not be overfull
-    if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
-        ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
-        return 0;
-    }
-    return (size_t)filled;
-}
-
 // ---------------------------------------------------------------------------
 
 void AudioTrackClientProxy::flush()
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 76b5924..c95d4c4 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -74,6 +74,8 @@
     START_AUDIO_SOURCE,
     STOP_AUDIO_SOURCE,
     SET_AUDIO_PORT_CALLBACK_ENABLED,
+    SET_MASTER_MONO,
+    GET_MASTER_MONO,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -767,6 +769,37 @@
         status = (status_t)reply.readInt32();
         return status;
     }
+
+    virtual status_t setMasterMono(bool mono)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast<int32_t>(mono));
+        status_t status = remote()->transact(SET_MASTER_MONO, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast<status_t>(reply.readInt32());
+    }
+
+    virtual status_t getMasterMono(bool *mono)
+    {
+        if (mono == nullptr) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+        status_t status = remote()->transact(GET_MASTER_MONO, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast<status_t>(reply.readInt32());
+        if (status == NO_ERROR) {
+            *mono = static_cast<bool>(reply.readInt32());
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1311,6 +1344,25 @@
             return NO_ERROR;
         } break;
 
+        case SET_MASTER_MONO: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            bool mono = static_cast<bool>(data.readInt32());
+            status_t status = setMasterMono(mono);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+
+        case GET_MASTER_MONO: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            bool mono;
+            status_t status = getMasterMono(&mono);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(static_cast<int32_t>(mono));
+            }
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 7fb1acc..79059c6 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -98,7 +98,7 @@
             bool secure,
             const uint8_t key[16],
             const uint8_t iv[16],
-            CryptoPlugin::Mode mode,
+            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
             const sp<IMemory> &sharedBuffer, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             void *dstPtr,
@@ -107,6 +107,8 @@
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
         data.writeInt32(secure);
         data.writeInt32(mode);
+        data.writeInt32(pattern.mEncryptBlocks);
+        data.writeInt32(pattern.mSkipBlocks);
 
         static const uint8_t kDummy[16] = { 0 };
 
@@ -261,7 +263,11 @@
             CHECK_INTERFACE(ICrypto, data, reply);
 
             const char *mime = data.readCString();
-            reply->writeInt32(requiresSecureDecoderComponent(mime));
+            if (mime == NULL) {
+                reply->writeInt32(BAD_VALUE);
+            } else {
+                reply->writeInt32(requiresSecureDecoderComponent(mime));
+            }
 
             return OK;
         }
@@ -272,6 +278,9 @@
 
             bool secure = data.readInt32() != 0;
             CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
+            CryptoPlugin::Pattern pattern;
+            pattern.mEncryptBlocks = data.readInt32();
+            pattern.mSkipBlocks = data.readInt32();
 
             uint8_t key[16];
             data.read(key, sizeof(key));
@@ -282,6 +291,10 @@
             size_t totalSize = data.readInt32();
             sp<IMemory> sharedBuffer =
                 interface_cast<IMemory>(data.readStrongBinder());
+            if (sharedBuffer == NULL) {
+                reply->writeInt32(BAD_VALUE);
+                return OK;
+            }
             int32_t offset = data.readInt32();
 
             int32_t numSubSamples = data.readInt32();
@@ -330,7 +343,7 @@
                     secure,
                     key,
                     iv,
-                    mode,
+                    mode, pattern,
                     sharedBuffer, offset,
                     subSamples, numSubSamples,
                     secure ? secureBufferId : dstPtr,
diff --git a/media/libmedia/IMediaCodecList.cpp b/media/libmedia/IMediaCodecList.cpp
index e2df104..737f50c 100644
--- a/media/libmedia/IMediaCodecList.cpp
+++ b/media/libmedia/IMediaCodecList.cpp
@@ -157,6 +157,10 @@
         {
             CHECK_INTERFACE(IMediaCodecList, data, reply);
             const char *type = data.readCString();
+            if (type == NULL) {
+                reply->writeInt32(NAME_NOT_FOUND);
+                return NO_ERROR;
+            }
             bool isEncoder = static_cast<bool>(data.readInt32());
             size_t startIndex = static_cast<size_t>(data.readInt32());
             ssize_t index = findCodecByType(type, isEncoder, startIndex);
@@ -172,6 +176,10 @@
         {
             CHECK_INTERFACE(IMediaCodecList, data, reply);
             const char *name = data.readCString();
+            if (name == NULL) {
+                reply->writeInt32(NAME_NOT_FOUND);
+                return NO_ERROR;
+            }
             ssize_t index = findCodecByName(name);
             if (index > INT32_MAX || index < 0) {
                 index = NAME_NOT_FOUND;
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index dbf524e..0bee8d3 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -224,6 +224,11 @@
 
             const char* srcUrl = data.readCString();
 
+            if (httpService == NULL || srcUrl == NULL) {
+                reply->writeInt32(BAD_VALUE);
+                return NO_ERROR;
+            }
+
             KeyedVector<String8, String8> headers;
             size_t numHeaders = (size_t) data.readInt64();
             for (size_t i = 0; i < numHeaders; ++i) {
@@ -250,7 +255,11 @@
             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
             sp<IDataSource> source =
                 interface_cast<IDataSource>(data.readStrongBinder());
-            reply->writeInt32(setDataSource(source));
+            if (source == NULL) {
+                reply->writeInt32(BAD_VALUE);
+            } else {
+                reply->writeInt32(setDataSource(source));
+            }
             return NO_ERROR;
         } break;
         case GET_FRAME_AT_TIME: {
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 942aec3..c523629 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -444,6 +444,10 @@
             }
 
             const char* url = data.readCString();
+            if (httpService == NULL || url == NULL) {
+                reply->writeInt32(BAD_VALUE);
+                return NO_ERROR;
+            }
             KeyedVector<String8, String8> headers;
             int32_t numHeaders = data.readInt32();
             for (int i = 0; i < numHeaders; ++i) {
@@ -467,14 +471,22 @@
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             sp<IStreamSource> source =
                 interface_cast<IStreamSource>(data.readStrongBinder());
-            reply->writeInt32(setDataSource(source));
+            if (source == NULL) {
+                reply->writeInt32(BAD_VALUE);
+            } else {
+                reply->writeInt32(setDataSource(source));
+            }
             return NO_ERROR;
         }
         case SET_DATA_SOURCE_CALLBACK: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             sp<IDataSource> source =
                 interface_cast<IDataSource>(data.readStrongBinder());
-            reply->writeInt32(setDataSource(source));
+            if (source == NULL) {
+                reply->writeInt32(BAD_VALUE);
+            } else {
+                reply->writeInt32(setDataSource(source));
+            }
             return NO_ERROR;
         }
         case SET_VIDEO_SURFACETEXTURE: {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 05f8670..afc94ab 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -220,6 +220,10 @@
             const String16 opPackageName = data.readString16();
             sp<IRemoteDisplayClient> client(
                     interface_cast<IRemoteDisplayClient>(data.readStrongBinder()));
+            if (client == NULL) {
+                reply->writeStrongBinder(NULL);
+                return NO_ERROR;
+            }
             String8 iface(data.readString8());
             sp<IRemoteDisplay> display(listenForRemoteDisplay(opPackageName, client, iface));
             reply->writeStrongBinder(IInterface::asBinder(display));
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
index 4598686..6cb4440 100644
--- a/media/libmedia/IResourceManagerService.cpp
+++ b/media/libmedia/IResourceManagerService.cpp
@@ -132,6 +132,9 @@
             int64_t clientId = data.readInt64();
             sp<IResourceManagerClient> client(
                     interface_cast<IResourceManagerClient>(data.readStrongBinder()));
+            if (client == NULL) {
+                return NO_ERROR;
+            }
             Vector<MediaResource> resources;
             readFromParcel(data, &resources);
             addResource(pid, clientId, client, resources);
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index 840e453..8c0905c 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -111,7 +111,11 @@
                 sp<IMemory> mem =
                     interface_cast<IMemory>(data.readStrongBinder());
 
-                buffers.push(mem);
+                if (mem != NULL) {
+                    buffers.push(mem);
+                } else if (data.dataAvail() == 0) {
+                    break;
+                }
             }
             setBuffers(buffers);
             break;
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 147d35f..b57f6ef 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -239,6 +239,7 @@
         const uint8_t key[16],
         const uint8_t iv[16],
         CryptoPlugin::Mode mode,
+        const CryptoPlugin::Pattern &pattern,
         const sp<IMemory> &sharedBuffer, size_t offset,
         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
         void *dstPtr,
@@ -256,7 +257,7 @@
     const void *srcPtr = static_cast<uint8_t *>(sharedBuffer->pointer()) + offset;
 
     return mPlugin->decrypt(
-            secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr,
+            secure, key, iv, mode, pattern, srcPtr, subSamples, numSubSamples, dstPtr,
             errorDetailMsg);
 }
 
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index 99ea95d..7705f30 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -54,6 +54,7 @@
             const uint8_t key[16],
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
+            const CryptoPlugin::Pattern &pattern,
             const sp<IMemory> &sharedBuffer, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             void *dstPtr,
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a416381..dda0a57 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1246,7 +1246,10 @@
             if (client->mAudioOutput != NULL)
                 client->mAudioOutput->switchToNextOutput();
             client->mNextClient->start();
-            client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+            if (client->mNextClient->mClient != NULL) {
+                client->mNextClient->mClient->notify(
+                        MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+            }
         }
     }
 
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index ec06711..9a4a350 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -1,7 +1,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-include frameworks/av/media/libstagefright/codecs/common/Config.mk
 
 LOCAL_SRC_FILES:=                         \
         ACodec.cpp                        \
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 8c61108..77722be 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -688,6 +688,7 @@
         const uint8_t key[16],
         const uint8_t iv[16],
         CryptoPlugin::Mode mode,
+        const CryptoPlugin::Pattern &pattern,
         int64_t presentationTimeUs,
         uint32_t flags,
         AString *errorDetailMsg) {
@@ -703,6 +704,8 @@
     msg->setPointer("key", (void *)key);
     msg->setPointer("iv", (void *)iv);
     msg->setInt32("mode", mode);
+    msg->setInt32("encryptBlocks", pattern.mEncryptBlocks);
+    msg->setInt32("skipBlocks", pattern.mSkipBlocks);
     msg->setInt64("timeUs", presentationTimeUs);
     msg->setInt32("flags", flags);
     msg->setPointer("errorDetailMsg", errorDetailMsg);
@@ -2452,11 +2455,16 @@
         AString *errorDetailMsg;
         CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
 
+        CryptoPlugin::Pattern pattern;
+        CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
+        CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
+
         ssize_t result = mCrypto->decrypt(
                 (mFlags & kFlagIsSecure) != 0,
                 key,
                 iv,
                 mode,
+                pattern,
                 info->mSharedEncryptedBuffer,
                 offset,
                 subSamples,
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 88690cf..266f01b 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -1,6 +1,5 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
-include frameworks/av/media/libstagefright/codecs/common/Config.mk
 
 AAC_LIBRARY = fraunhofer
 
@@ -35,24 +34,28 @@
 	src/transform.c \
 	src/memalign.c
 
-ifeq ($(VOTT), v5)
-LOCAL_SRC_FILES += \
-	src/asm/ARMV5E/AutoCorrelation_v5.s \
-	src/asm/ARMV5E/band_nrg_v5.s \
-	src/asm/ARMV5E/CalcWindowEnergy_v5.s \
-	src/asm/ARMV5E/PrePostMDCT_v5.s \
-	src/asm/ARMV5E/R4R8First_v5.s \
-	src/asm/ARMV5E/Radix4FFT_v5.s
-endif
+ifneq ($(ARCH_ARM_HAVE_NEON),true)
+    LOCAL_SRC_FILES_arm := \
+        src/asm/ARMV5E/AutoCorrelation_v5.s \
+        src/asm/ARMV5E/band_nrg_v5.s \
+        src/asm/ARMV5E/CalcWindowEnergy_v5.s \
+        src/asm/ARMV5E/PrePostMDCT_v5.s \
+        src/asm/ARMV5E/R4R8First_v5.s \
+        src/asm/ARMV5E/Radix4FFT_v5.s
 
-ifeq ($(VOTT), v7)
-LOCAL_SRC_FILES += \
-	src/asm/ARMV5E/AutoCorrelation_v5.s \
-	src/asm/ARMV5E/band_nrg_v5.s \
-	src/asm/ARMV5E/CalcWindowEnergy_v5.s \
-	src/asm/ARMV7/PrePostMDCT_v7.s \
-	src/asm/ARMV7/R4R8First_v7.s \
-	src/asm/ARMV7/Radix4FFT_v7.s
+    LOCAL_CFLAGS_arm := -DARMV5E -DARM_INASM -DARMV5_INASM
+    LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
+else
+    LOCAL_SRC_FILES_arm := \
+        src/asm/ARMV5E/AutoCorrelation_v5.s \
+        src/asm/ARMV5E/band_nrg_v5.s \
+        src/asm/ARMV5E/CalcWindowEnergy_v5.s \
+        src/asm/ARMV7/PrePostMDCT_v7.s \
+        src/asm/ARMV7/R4R8First_v7.s \
+        src/asm/ARMV7/Radix4FFT_v7.s
+    LOCAL_CFLAGS_arm := -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM -DARMV6_INASM
+    LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
+    LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/src/asm/ARMV7
 endif
 
 LOCAL_MODULE := libstagefright_aacenc
@@ -71,17 +74,6 @@
 	$(LOCAL_PATH)/inc \
 	$(LOCAL_PATH)/basic_op
 
-ifeq ($(VOTT), v5)
-LOCAL_CFLAGS += -DARMV5E -DARM_INASM -DARMV5_INASM
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
-endif
-
-ifeq ($(VOTT), v7)
-LOCAL_CFLAGS += -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM -DARMV6_INASM
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
-endif
-
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
 LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index 5b90b33..4d12f82 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -1,8 +1,5 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
-include frameworks/av/media/libstagefright/codecs/common/Config.mk
-
-
 
 LOCAL_SRC_FILES := \
 	src/autocorr.c \
@@ -53,37 +50,39 @@
 	src/weight_a.c \
 	src/mem_align.c
 
+ifneq ($(ARCH_ARM_HAVE_NEON),true)
+    LOCAL_SRC_FILES_arm := \
+        src/asm/ARMV5E/convolve_opt.s \
+        src/asm/ARMV5E/cor_h_vec_opt.s \
+        src/asm/ARMV5E/Deemph_32_opt.s \
+        src/asm/ARMV5E/Dot_p_opt.s \
+        src/asm/ARMV5E/Filt_6k_7k_opt.s \
+        src/asm/ARMV5E/Norm_Corr_opt.s \
+        src/asm/ARMV5E/pred_lt4_1_opt.s \
+        src/asm/ARMV5E/residu_asm_opt.s \
+        src/asm/ARMV5E/scale_sig_opt.s \
+        src/asm/ARMV5E/Syn_filt_32_opt.s \
+        src/asm/ARMV5E/syn_filt_opt.s
 
-ifeq ($(VOTT), v5)
-LOCAL_SRC_FILES += \
-	src/asm/ARMV5E/convolve_opt.s \
-	src/asm/ARMV5E/cor_h_vec_opt.s \
-	src/asm/ARMV5E/Deemph_32_opt.s \
-	src/asm/ARMV5E/Dot_p_opt.s \
-	src/asm/ARMV5E/Filt_6k_7k_opt.s \
-	src/asm/ARMV5E/Norm_Corr_opt.s \
-	src/asm/ARMV5E/pred_lt4_1_opt.s \
-	src/asm/ARMV5E/residu_asm_opt.s \
-	src/asm/ARMV5E/scale_sig_opt.s \
-	src/asm/ARMV5E/Syn_filt_32_opt.s \
-	src/asm/ARMV5E/syn_filt_opt.s
+    LOCAL_CFLAGS_arm := -DARM -DASM_OPT
+    LOCAL_C_INCLUDES_arm = $(LOCAL_PATH)/src/asm/ARMV5E
+else
+    LOCAL_SRC_FILES_arm := \
+        src/asm/ARMV7/convolve_neon.s \
+        src/asm/ARMV7/cor_h_vec_neon.s \
+        src/asm/ARMV7/Deemph_32_neon.s \
+        src/asm/ARMV7/Dot_p_neon.s \
+        src/asm/ARMV7/Filt_6k_7k_neon.s \
+        src/asm/ARMV7/Norm_Corr_neon.s \
+        src/asm/ARMV7/pred_lt4_1_neon.s \
+        src/asm/ARMV7/residu_asm_neon.s \
+        src/asm/ARMV7/scale_sig_neon.s \
+        src/asm/ARMV7/Syn_filt_32_neon.s \
+        src/asm/ARMV7/syn_filt_neon.s
 
-endif
-
-ifeq ($(VOTT), v7)
-LOCAL_SRC_FILES += \
-	src/asm/ARMV7/convolve_neon.s \
-	src/asm/ARMV7/cor_h_vec_neon.s \
-	src/asm/ARMV7/Deemph_32_neon.s \
-	src/asm/ARMV7/Dot_p_neon.s \
-	src/asm/ARMV7/Filt_6k_7k_neon.s \
-	src/asm/ARMV7/Norm_Corr_neon.s \
-	src/asm/ARMV7/pred_lt4_1_neon.s \
-	src/asm/ARMV7/residu_asm_neon.s \
-	src/asm/ARMV7/scale_sig_neon.s \
-	src/asm/ARMV7/Syn_filt_32_neon.s \
-	src/asm/ARMV7/syn_filt_neon.s
-
+    LOCAL_CFLAGS_arm := -DARM -DARMV7 -DASM_OPT
+    LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
+    LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/src/asm/ARMV7
 endif
 
 LOCAL_MODULE := libstagefright_amrwbenc
@@ -101,17 +100,6 @@
 	$(LOCAL_PATH)/src \
 	$(LOCAL_PATH)/inc
 
-ifeq ($(VOTT), v5)
-LOCAL_CFLAGS += -DARM -DASM_OPT
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
-endif
-
-ifeq ($(VOTT), v7)
-LOCAL_CFLAGS += -DARM -DARMV7 -DASM_OPT
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
-endif
-
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
 #LOCAL_SANITIZE := signed-integer-overflow
diff --git a/media/libstagefright/codecs/common/Config.mk b/media/libstagefright/codecs/common/Config.mk
deleted file mode 100644
index a843cef..0000000
--- a/media/libstagefright/codecs/common/Config.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# This configure file is just for Linux projects against Android
-#
-
-VOPRJ :=
-VONJ :=
-
-# WARNING:
-# Using v7 breaks generic build
-ifeq ($(TARGET_ARCH),arm)
-VOTT := v5
-else
-VOTT := pc
-endif
-
-# Do we also need to check on ARCH_ARM_HAVE_ARMV7A? - probably not
-ifeq ($(TARGET_ARCH),arm)
-  ifeq ($(ARCH_ARM_HAVE_NEON),true)
-    VOTT := v7
-  endif
-endif
-
-VOTEST := 0
-
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 38618da..11581c1 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -28,19 +28,22 @@
  	src/pvmp3_stereo_proc.cpp \
  	src/pvmp3_reorder.cpp \
 
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += \
+LOCAL_SRC_FILES_arm += \
 	src/asm/pvmp3_polyphase_filter_window_gcc.s \
  	src/asm/pvmp3_mdct_18_gcc.s \
  	src/asm/pvmp3_dct_9_gcc.s \
 	src/asm/pvmp3_dct_16_gcc.s
-else
-LOCAL_SRC_FILES += \
+LOCAL_SRC_FILES_other_archs := \
  	src/pvmp3_polyphase_filter_window.cpp \
  	src/pvmp3_mdct_18.cpp \
  	src/pvmp3_dct_9.cpp \
  	src/pvmp3_dct_16.cpp
-endif
+
+LOCAL_SRC_FILES_arm64  := $(LOCAL_SRC_FILES_other_archs)
+LOCAL_SRC_FILES_mips   := $(LOCAL_SRC_FILES_other_archs)
+LOCAL_SRC_FILES_mips64 := $(LOCAL_SRC_FILES_other_archs)
+LOCAL_SRC_FILES_x86    := $(LOCAL_SRC_FILES_other_archs)
+LOCAL_SRC_FILES_x86_64 := $(LOCAL_SRC_FILES_other_archs)
 
 LOCAL_C_INCLUDES := \
         frameworks/av/media/libstagefright/include \
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk
index e7492b1..7159674 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.mk
+++ b/media/libstagefright/codecs/on2/h264dec/Android.mk
@@ -84,17 +84,15 @@
 	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S \
 	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S \
 
-ifeq ($(TARGET_ARCH),arm)
-  ifeq ($(ARCH_ARM_HAVE_NEON),true)
+
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
     LOCAL_ARM_NEON   := true
-#    LOCAL_CFLAGS     := -std=c99 -D._NEON -D._OMXDL
-    LOCAL_CFLAGS     := -DH264DEC_NEON -DH264DEC_OMXDL
-    LOCAL_SRC_FILES  += $(MY_ASM) $(MY_OMXDL_C_SRC) $(MY_OMXDL_ASM_SRC)
-    LOCAL_C_INCLUDES += $(LOCAL_PATH)/./source/arm_neon_asm_gcc
-    LOCAL_C_INCLUDES += $(LOCAL_PATH)/./omxdl/arm_neon/api \
+    LOCAL_CFLAGS_arm     := -DH264DEC_NEON -DH264DEC_OMXDL
+    LOCAL_SRC_FILES_arm  := $(MY_ASM) $(MY_OMXDL_C_SRC) $(MY_OMXDL_ASM_SRC)
+    LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/./source/arm_neon_asm_gcc
+    LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/./omxdl/arm_neon/api \
                         $(LOCAL_PATH)/./omxdl/arm_neon/vc/api \
                         $(LOCAL_PATH)/./omxdl/arm_neon/vc/m4p10/api
-  endif
 endif
 
 LOCAL_CLANG := true
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index a770f49..72823e2 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -23,7 +23,6 @@
 
 #include "include/SoftVideoEncoderOMXComponent.h"
 
-#include <hardware/gralloc.h>
 #include <media/hardware/HardwareAPI.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -71,7 +70,6 @@
       mBitrate(192000),
       mFramerate(30 << 16), // Q16 format
       mColorFormat(OMX_COLOR_FormatYUV420Planar),
-      mGrallocModule(NULL),
       mMinOutputBufferSize(384), // arbitrary, using one uncompressed macroblock
       mMinCompressionRatio(1),   // max output size is normally the input size
       mComponentRole(componentRole),
@@ -500,13 +498,6 @@
         return NULL;
     }
 
-    if (mGrallocModule == NULL) {
-        CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
-    }
-
-    const gralloc_module_t *grmodule =
-        (const gralloc_module_t *)mGrallocModule;
-
     buffer_handle_t handle;
     int format;
     size_t srcStride;
@@ -564,19 +555,21 @@
         return NULL;
     }
 
+    auto& mapper = GraphicBufferMapper::get();
+
     void *bits = NULL;
     struct android_ycbcr ycbcr;
     status_t res;
     if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-        res = grmodule->lock_ycbcr(
-                 grmodule, handle,
+        res = mapper.lockYCbCr(
+                 handle,
                  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
-                 0, 0, width, height, &ycbcr);
+                 Rect(width, height), &ycbcr);
     } else {
-        res = grmodule->lock(
-                 grmodule, handle,
+        res = mapper.lock(
+                 handle,
                  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
-                 0, 0, width, height, &bits);
+                 Rect(width, height), &bits);
     }
     if (res != OK) {
         ALOGE("Unable to lock image buffer %p for access", handle);
@@ -620,7 +613,7 @@
             break;
     }
 
-    if (grmodule->unlock(grmodule, handle) != OK) {
+    if (mapper.unlock(handle) != OK) {
         ALOGE("Unable to unlock image buffer %p for access", handle);
     }
 
diff --git a/media/mtp/MtpDebug.cpp b/media/mtp/MtpDebug.cpp
index 9f3037d..1c04bcf 100644
--- a/media/mtp/MtpDebug.cpp
+++ b/media/mtp/MtpDebug.cpp
@@ -101,6 +101,7 @@
     { "MTP_FORMAT_TIFF_IT",                         0x380E },
     { "MTP_FORMAT_JP2",                             0x380F },
     { "MTP_FORMAT_JPX",                             0x3810 },
+    { "MTP_FORMAT_DNG",                             0x3811 },
     { "MTP_FORMAT_UNDEFINED_FIRMWARE",              0xB802 },
     { "MTP_FORMAT_WINDOWS_IMAGE_FORMAT",            0xB881 },
     { "MTP_FORMAT_UNDEFINED_AUDIO",                 0xB900 },
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 30843a7..6f72a3e 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -866,15 +866,19 @@
     return currentHandle;
 }
 
-int MtpDevice::reapEventRequest(int handle) {
+int MtpDevice::reapEventRequest(int handle, uint32_t (*parameters)[3]) {
     Mutex::Autolock autoLock(mEventMutex);
-    if (!mProcessingEvent || mCurrentEventHandle != handle) {
+    if (!mProcessingEvent || mCurrentEventHandle != handle || !parameters) {
         return -1;
     }
     mProcessingEvent = false;
     const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
     const int result = mEventPacket.getEventCode();
-    return readSize == 0 ? 0 : result;
+    // MTP event has three parameters.
+    (*parameters)[0] = mEventPacket.getParameter(1);
+    (*parameters)[1] = mEventPacket.getParameter(2);
+    (*parameters)[2] = mEventPacket.getParameter(3);
+    return readSize != 0 ? result : 0;
 }
 
 void MtpDevice::discardEventRequest(int handle) {
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index 60f08ba..edc608f 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -124,8 +124,9 @@
     int                     submitEventRequest();
     // Waits for MTP event from the device and returns MTP event code. It blocks the current thread
     // until it receives an event from the device. |handle| should be a request handle returned
-    // by |submitEventRequest|. Returns 0 for cancellations. Returns -1 for errors.
-    int                     reapEventRequest(int handle);
+    // by |submitEventRequest|. The function writes event parameters to |parameters|. Returns 0 for
+    // cancellations. Returns -1 for errors.
+    int                     reapEventRequest(int handle, uint32_t (*parameters)[3]);
     // Cancels an event request. |handle| should be request handle returned by
     // |submitEventRequest|. If there is a thread blocked by |reapEventRequest| with the same
     // |handle|, the thread will resume.
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index 7b80d2e..adfb102 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -93,6 +93,7 @@
 #define MTP_FORMAT_TIFF_IT                              0x380E   // Tag Image File Format for Information Technology (graphic arts)
 #define MTP_FORMAT_JP2                                  0x380F   // JPEG2000 Baseline File Format
 #define MTP_FORMAT_JPX                                  0x3810   // JPEG2000 Extended File Format
+#define MTP_FORMAT_DNG                                  0x3811   // Digital Negative
 #define MTP_FORMAT_UNDEFINED_FIRMWARE                   0xB802
 #define MTP_FORMAT_WINDOWS_IMAGE_FORMAT                 0xB881
 #define MTP_FORMAT_UNDEFINED_AUDIO                      0xB900
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index cd0c462..8e36065 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -372,6 +372,7 @@
         uint8_t key[16];
         uint8_t iv[16];
         cryptoinfo_mode_t mode;
+        cryptoinfo_pattern_t pattern;
         size_t *clearbytes;
         size_t *encryptedbytes;
 } AMediaCodecCryptoInfo;
@@ -391,6 +392,10 @@
         subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
     }
 
+    CryptoPlugin::Pattern pattern;
+    pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
+    pattern.mSkipBlocks = crypto->pattern.skipBlocks;
+
     AString errormsg;
     status_t err  = codec->mCodec->queueSecureInputBuffer(idx,
             offset,
@@ -398,7 +403,8 @@
             crypto->numsubsamples,
             crypto->key,
             crypto->iv,
-            (CryptoPlugin::Mode) crypto->mode,
+            (CryptoPlugin::Mode)crypto->mode,
+            pattern,
             time,
             flags,
             &errormsg);
@@ -410,6 +416,12 @@
 }
 
 
+EXPORT
+void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
+        cryptoinfo_pattern_t *pattern) {
+    info->pattern.encryptBlocks = pattern->encryptBlocks;
+    info->pattern.skipBlocks = pattern->skipBlocks;
+}
 
 EXPORT
 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
@@ -431,6 +443,8 @@
     memcpy(ret->key, key, 16);
     memcpy(ret->iv, iv, 16);
     ret->mode = mode;
+    ret->pattern.encryptBlocks = 0;
+    ret->pattern.skipBlocks = 0;
 
     // clearbytes and encryptedbytes point at the actual data, which follows
     ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index d6624f7..3f99b43 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -37,6 +37,7 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
+#include <audio_utils/conversion.h>
 #include <audio_utils/format.h>
 #include "AudioMixer.h"
 #include "FastMixer.h"
@@ -64,7 +65,8 @@
     mFastTracksGen(0),
     mTotalNativeFramesWritten(0),
     // timestamp
-    mNativeFramesWrittenButNotPresented(0)   // the = 0 is to silence the compiler
+    mNativeFramesWrittenButNotPresented(0),   // the = 0 is to silence the compiler
+    mMasterMono(false)
 {
     // FIXME pass sInitial as parameter to base class constructor, and make it static local
     mPrevious = &sInitial;
@@ -417,6 +419,10 @@
             memset(mMixerBuffer, 0, mMixerBufferSize);
             mMixerBufferState = ZEROED;
         }
+
+        if (mMasterMono.load()) {  // memory_order_seq_cst
+            mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount);
+        }
         // prepare the buffer used to write to sink
         void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
         if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 06a68fb..e38878e 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_AUDIO_FAST_MIXER_H
 #define ANDROID_AUDIO_FAST_MIXER_H
 
+#include <atomic>
 #include "FastThread.h"
 #include "StateQueue.h"
 #include "FastMixerState.h"
@@ -36,6 +37,8 @@
 
             FastMixerStateQueue* sq();
 
+    virtual void setMasterMono(bool mono) { mMasterMono.store(mono); /* memory_order_seq_cst */ }
+
 private:
             FastMixerStateQueue mSQ;
 
@@ -82,6 +85,8 @@
     AudioTimestamp  mTimestamp;
     uint32_t        mNativeFramesWrittenButNotPresented;
 
+    // accessed without lock between multiple threads.
+    std::atomic_bool mMasterMono;
 };  // class FastMixer
 
 }   // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 7c9b81e..65166b0 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -36,6 +36,7 @@
 #include <hardware/audio.h>
 #include <audio_effects/effect_ns.h>
 #include <audio_effects/effect_aec.h>
+#include <audio_utils/conversion.h>
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
 #include <audio_utils/minifloat.h>
@@ -527,6 +528,7 @@
     case AUDIO_SOURCE_VOICE_RECOGNITION:    return "voice recognition";
     case AUDIO_SOURCE_VOICE_COMMUNICATION:  return "voice communication";
     case AUDIO_SOURCE_REMOTE_SUBMIX:        return "remote submix";
+    case AUDIO_SOURCE_UNPROCESSED:          return "unprocessed";
     case AUDIO_SOURCE_FM_TUNER:             return "FM tuner";
     case AUDIO_SOURCE_HOTWORD:              return "hotword";
     default:                                return "unknown";
@@ -669,7 +671,19 @@
 // sendSetParameterConfigEvent_l() must be called with ThreadBase::mLock held
 status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
 {
-    sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
+    sp<ConfigEvent> configEvent;
+    AudioParameter param(keyValuePair);
+    int value;
+    if (param.getInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), value) == NO_ERROR) {
+        setMasterMono_l(value != 0);
+        if (param.size() == 1) {
+            return NO_ERROR; // should be a solo parameter - we don't pass down
+        }
+        param.remove(String8(AUDIO_PARAMETER_MONO_OUTPUT));
+        configEvent = new SetParameterConfigEvent(param.toString());
+    } else {
+        configEvent = new SetParameterConfigEvent(keyValuePair);
+    }
     return sendConfigEvent_l(configEvent);
 }
 
@@ -1610,6 +1624,7 @@
     dprintf(fd, "  Mixer buffer: %p\n", mMixerBuffer);
     dprintf(fd, "  Effect buffer: %p\n", mEffectBuffer);
     dprintf(fd, "  Fast track availMask=%#x\n", mFastTrackAvailMask);
+    dprintf(fd, "  Standby delay ns=%lld\n", (long long)mStandbyDelayNs);
     AudioStreamOut *output = mOutput;
     audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE;
     String8 flagsAsString = outputFlagsToString(flags);
@@ -2534,7 +2549,8 @@
  - mSinkBufferSize from frame count * frame size
  - mActiveSleepTimeUs from activeSleepTimeUs()
  - mIdleSleepTimeUs from idleSleepTimeUs()
- - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only)
+ - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only) or forced to at least
+   kDefaultStandbyTimeInNsecs when connected to an A2DP device.
  - maxPeriod from frame count and sample rate (MIXER only)
 
 The parameters that affect these derived values are:
@@ -2553,6 +2569,15 @@
     mSinkBufferSize = mNormalFrameCount * mFrameSize;
     mActiveSleepTimeUs = activeSleepTimeUs();
     mIdleSleepTimeUs = idleSleepTimeUs();
+
+    // make sure standby delay is not too short when connected to an A2DP sink to avoid
+    // truncating audio when going to standby.
+    mStandbyDelayNs = AudioFlinger::mStandbyTimeInNsecs;
+    if ((mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) {
+        if (mStandbyDelayNs < kDefaultStandbyTimeInNsecs) {
+            mStandbyDelayNs = kDefaultStandbyTimeInNsecs;
+        }
+    }
 }
 
 void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamType)
@@ -2903,6 +2928,13 @@
                 void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
                 audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;
 
+                // mono blend occurs for mixer threads only (not direct or offloaded)
+                // and is handled here if we're going directly to the sink.
+                if (requireMonoBlend() && !mEffectBufferValid) {
+                    mono_blend(
+                            mMixerBuffer, mMixerBufferFormat, mChannelCount, mNormalFrameCount);
+                }
+
                 memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
                         mNormalFrameCount * mChannelCount);
             }
@@ -2938,6 +2970,11 @@
         // TODO use mSleepTimeUs == 0 as an additional condition.
         if (mEffectBufferValid) {
             //ALOGV("writing effect buffer to sink buffer format %#x", mFormat);
+
+            if (requireMonoBlend()) {
+                mono_blend(mEffectBuffer, mEffectBufferFormat, mChannelCount, mNormalFrameCount);
+            }
+
             memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
                     mNormalFrameCount * mChannelCount);
         }
@@ -3280,7 +3317,8 @@
     :   PlaybackThread(audioFlinger, output, id, device, type, systemReady),
         // mAudioMixer below
         // mFastMixer below
-        mFastMixerFutex(0)
+        mFastMixerFutex(0),
+        mMasterMono(false)
         // mOutputSink below
         // mPipeSink below
         // mNormalSink below
@@ -4272,6 +4310,7 @@
                                                        status_t& status)
 {
     bool reconfig = false;
+    bool a2dpDeviceChanged = false;
 
     status = NO_ERROR;
 
@@ -4348,6 +4387,8 @@
         // forward device change to effects that have requested to be
         // aware of attached audio device.
         if (value != AUDIO_DEVICE_NONE) {
+            a2dpDeviceChanged =
+                    (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
             mOutDevice = value;
             for (size_t i = 0; i < mEffectChains.size(); i++) {
                 mEffectChains[i]->setDevice_l(mOutDevice);
@@ -4391,7 +4432,7 @@
         sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
     }
 
-    return reconfig;
+    return reconfig || a2dpDeviceChanged;
 }
 
 
@@ -4404,6 +4445,7 @@
     PlaybackThread::dumpInternals(fd, args);
     dprintf(fd, "  Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
     dprintf(fd, "  AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
+    dprintf(fd, "  Master mono: %s\n", mMasterMono ? "on" : "off");
 
     // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
     // while we are dumping it.  It may be inconsistent, but it won't mutate!
@@ -4831,6 +4873,7 @@
                                                               status_t& status)
 {
     bool reconfig = false;
+    bool a2dpDeviceChanged = false;
 
     status = NO_ERROR;
 
@@ -4840,6 +4883,8 @@
         // forward device change to effects that have requested to be
         // aware of attached audio device.
         if (value != AUDIO_DEVICE_NONE) {
+            a2dpDeviceChanged =
+                    (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
             mOutDevice = value;
             for (size_t i = 0; i < mEffectChains.size(); i++) {
                 mEffectChains[i]->setDevice_l(mOutDevice);
@@ -4872,7 +4917,7 @@
         }
     }
 
-    return reconfig;
+    return reconfig || a2dpDeviceChanged;
 }
 
 uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() const
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 114d43c..8eed50d 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -400,6 +400,8 @@
                 String16 getWakeLockTag();
 
     virtual     void        preExit() { }
+    virtual     void        setMasterMono_l(bool mono __unused) { }
+    virtual     bool        requireMonoBlend() { return false; }
 
     friend class AudioFlinger;      // for mEffectChains
 
@@ -909,6 +911,7 @@
                 //          mFastMixer->sq()    // for mutating and pushing state
                 int32_t     mFastMixerFutex;    // for cold idle
 
+                std::atomic_bool mMasterMono;
 public:
     virtual     bool        hasFastMixer() const { return mFastMixer != 0; }
     virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const {
@@ -916,6 +919,15 @@
                               return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
                             }
 
+protected:
+    virtual     void       setMasterMono_l(bool mono) {
+                               mMasterMono.store(mono);
+                               if (mFastMixer != nullptr) { /* hasFastMixer() */
+                                   mFastMixer->setMasterMono(mMasterMono);
+                               }
+                           }
+                // the FastMixer performs mono blend if it exists.
+    virtual     bool       requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
 };
 
 class DirectOutputThread : public PlaybackThread {
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 42fb9e5..dd3f144 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -228,6 +228,9 @@
                                       audio_io_handle_t *handle,
                                       uid_t uid) = 0;
     virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+    virtual status_t setMasterMono(bool mono) = 0;
+    virtual status_t getMasterMono(bool *mono) = 0;
 };
 
 
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index dffeb7e..0c28fc9 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -10,10 +10,12 @@
     src/IOProfile.cpp \
     src/AudioPort.cpp \
     src/AudioProfile.cpp \
+    src/AudioRoute.cpp \
     src/AudioPolicyMix.cpp \
     src/AudioPatch.cpp \
     src/AudioInputDescriptor.cpp \
     src/AudioOutputDescriptor.cpp \
+    src/AudioCollections.cpp \
     src/EffectDescriptor.cpp \
     src/ConfigParsingUtils.cpp \
     src/SoundTriggerSession.cpp \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
new file mode 100644
index 0000000..814c5c2
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class AudioPort;
+class AudioRoute;
+
+class AudioPortVector : public Vector<sp<AudioPort> >
+{
+public:
+    sp<AudioPort> findByTagName(const String8 &tagName) const;
+};
+
+
+class AudioRouteVector : public Vector<sp<AudioRoute> >
+{
+public:
+    status_t dump(int fd) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 9aaaddf..12e42ea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "AudioCollections.h"
 #include "AudioProfile.h"
 #include <utils/String8.h>
 #include <utils/Vector.h>
@@ -28,6 +29,7 @@
 
 class HwModule;
 class AudioGain;
+class AudioRoute;
 typedef Vector<sp<AudioGain> > AudioGainCollection;
 
 class AudioPort : public virtual RefBase
@@ -44,6 +46,8 @@
     audio_port_type_t getType() const { return mType; }
     audio_port_role_t getRole() const { return mRole; }
 
+    virtual const String8 getTagName() const = 0;
+
     void setGains(const AudioGainCollection &gains) { mGains = gains; }
     const AudioGainCollection &getGains() const { return mGains; }
 
@@ -114,6 +118,9 @@
                 (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
     }
 
+    void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
+    const AudioRouteVector &getRoutes() const { return mRoutes; }
+
     void dump(int fd, int spaces, bool verbose = true) const;
     void log(const char* indent) const;
 
@@ -124,11 +131,12 @@
     void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
     void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
 
-    String8           mName;
+    String8  mName;
     audio_port_type_t mType;
     audio_port_role_t mRole;
     uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
     AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+    AudioRouteVector mRoutes; // Routes involving this port
     static volatile int32_t mNextUniqueId;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
new file mode 100644
index 0000000..67e197f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include "AudioCollections.h"
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+
+namespace android
+{
+
+class AudioPort;
+class DeviceDescriptor;
+
+typedef enum {
+    AUDIO_ROUTE_MUX = 0,
+    AUDIO_ROUTE_MIX = 1
+} audio_route_type_t;
+
+class AudioRoute  : public virtual RefBase
+{
+public:
+    AudioRoute(audio_route_type_t type) : mType(type) {}
+
+    void setSources(const AudioPortVector &sources) { mSources = sources; }
+    const AudioPortVector &getSources() const { return mSources; }
+
+    void setSink(const sp<AudioPort> &sink) { mSink = sink; }
+    const sp<AudioPort> &getSink() const { return mSink; }
+
+    audio_route_type_t getType() const { return mType; }
+
+    void dump(int fd, int spaces) const;
+
+private:
+    AudioPortVector mSources;
+    sp<AudioPort> mSink;
+    audio_route_type_t mType;
+
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 8ece51b..54fcd0b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -34,8 +34,9 @@
 
     virtual ~DeviceDescriptor() {}
 
+    virtual const String8 getTagName() const { return mTagName; }
+
     audio_devices_t type() const { return mDeviceType; }
-    const String8 getTagName() const { return mTagName; }
 
     bool equals(const sp<DeviceDescriptor>& other) const;
 
@@ -56,7 +57,7 @@
     String8 mAddress;
 
 private:
-    String8 mTagName;
+    String8 mTagName; // Unique human readable identifier for a device port found in conf file.
     audio_devices_t     mDeviceType;
     audio_port_handle_t mId;
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index f71a1a4..93d03e6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "DeviceDescriptor.h"
+#include "AudioRoute.h"
 #include <hardware/audio.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
@@ -46,7 +47,7 @@
 
 
     const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
-    void setDeclaredDevices(const DeviceVector &devices) { mDeclaredDevices = devices; }
+    void setDeclaredDevices(const DeviceVector &devices);
 
     const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }
 
@@ -57,6 +58,10 @@
     void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
     uint32_t getHalVersion() const { return mHalVersion; }
 
+    sp<DeviceDescriptor> getRouteSinkDevice(const sp<AudioRoute> &route) const;
+    DeviceVector getRouteSourceDevices(const sp<AudioRoute> &route) const;
+    void setRoutes(const AudioRouteVector &routes);
+
     status_t addOutputProfile(const sp<IOProfile> &profile);
     status_t addInputProfile(const sp<IOProfile> &profile);
     status_t addProfile(const sp<IOProfile> &profile);
@@ -70,6 +75,11 @@
 
     audio_module_handle_t getHandle() const { return mHandle; }
 
+    sp<AudioPort> findPortByTagName(const String8 &tagName) const
+    {
+        return mPorts.findByTagName(tagName);
+    }
+
     // TODO remove from here (split serialization)
     void dump(int fd);
 
@@ -79,8 +89,12 @@
     InputProfileCollection mInputProfiles;  // input profiles exposed by this module
 
 private:
+    void refreshSupportedDevices();
+
     uint32_t mHalVersion; // audio HAL API version
     DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
+    AudioRouteVector mRoutes;
+    AudioPortVector mPorts;
 };
 
 class HwModuleCollection : public Vector<sp<HwModule> >
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 310acff..eae9586 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -33,8 +33,11 @@
 class IOProfile : public AudioPort
 {
 public:
-    IOProfile(const String8 &name, audio_port_role_t role);
-    virtual ~IOProfile();
+    IOProfile(const String8 &name, audio_port_role_t role)
+        : AudioPort(name, AUDIO_PORT_TYPE_MIX, role) {}
+
+    // For a Profile aka MixPort, tag name and name are equivalent.
+    virtual const String8 getTagName() const { return getName(); }
 
     // This method is used for both output and input.
     // If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
@@ -101,8 +104,7 @@
     const DeviceVector &getSupportedDevices() const { return mSupportedDevices; }
 
 private:
-    DeviceVector  mSupportedDevices; // supported devices
-                                     // (devices this output can be routed to)
+    DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
 };
 
 class InputProfile : public IOProfile
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
new file mode 100644
index 0000000..f66af6b
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "APM::AudioCollections"
+//#define LOG_NDEBUG 0
+
+#include "AudioCollections.h"
+#include "AudioPort.h"
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android {
+
+sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
+{
+    sp<AudioPort> port = 0;
+    for (size_t i = 0; i < size(); i++) {
+        if (itemAt(i)->getTagName() == tagName) {
+            port = itemAt(i);
+            break;
+        }
+    }
+    return port;
+}
+
+status_t AudioRouteVector::dump(int fd) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "\nAudio Route dump (%zu):\n", size());
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < size(); i++) {
+        snprintf(buffer, SIZE, "- Route %zu:\n", i + 1);
+        write(fd, buffer, strlen(buffer));
+        itemAt(i)->dump(fd, 4);
+    }
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
new file mode 100644
index 0000000..79ad1f7
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "APM::AudioRoute"
+//#define LOG_NDEBUG 0
+
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android
+{
+
+void AudioRoute::dump(int fd, int spaces) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
+    result.append(buffer);
+
+    if (mSources.size() != 0) {
+        snprintf(buffer, SIZE, "%*s- Sources: \n", spaces, "");
+        result.append(buffer);
+        for (size_t i = 0; i < mSources.size(); i++) {
+            snprintf(buffer, SIZE, "%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
+            result.append(buffer);
+        }
+    }
+    result.append("\n");
+
+    write(fd, result.string(), result.size());
+}
+
+}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index d752485..538876c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -281,6 +281,10 @@
         snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
         result.append(buffer);
     }
+    if (!mTagName.isEmpty()) {
+        snprintf(buffer, SIZE, "%*s- tag name: %s\n", spaces, "", mTagName.string());
+        result.append(buffer);
+    }
     std::string deviceLiteral;
     if (DeviceConverter::toString(mDeviceType, deviceLiteral)) {
         snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index dce0890..93ab9c7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -61,6 +61,7 @@
 {
     profile->attach(this);
     mOutputProfiles.add(profile);
+    mPorts.add(profile);
     return NO_ERROR;
 }
 
@@ -68,6 +69,7 @@
 {
     profile->attach(this);
     mInputProfiles.add(profile);
+    mPorts.add(profile);
     return NO_ERROR;
 }
 
@@ -132,6 +134,88 @@
     return NO_ERROR;
 }
 
+void HwModule::setDeclaredDevices(const DeviceVector &devices)
+{
+    mDeclaredDevices = devices;
+    for (size_t i = 0; i < devices.size(); i++) {
+        mPorts.add(devices[i]);
+    }
+}
+
+sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
+{
+    sp<DeviceDescriptor> sinkDevice = 0;
+    if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
+        sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
+    }
+    return sinkDevice;
+}
+
+DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
+{
+    DeviceVector sourceDevices;
+    Vector <sp<AudioPort> > sources = route->getSources();
+    for (size_t i = 0; i < sources.size(); i++) {
+        if (sources[i]->getType() == AUDIO_PORT_TYPE_DEVICE) {
+            sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(sources[i]->getTagName()));
+        }
+    }
+    return sourceDevices;
+}
+
+void HwModule::setRoutes(const AudioRouteVector &routes)
+{
+    mRoutes = routes;
+    // Now updating the streams (aka IOProfile until now) supported devices
+    refreshSupportedDevices();
+}
+
+void HwModule::refreshSupportedDevices()
+{
+    // Now updating the streams (aka IOProfile until now) supported devices
+    for (size_t i = 0; i < mInputProfiles.size(); i++) {
+        sp<IOProfile> stream = mInputProfiles[i];
+        DeviceVector sourceDevices;
+        const AudioRouteVector &routes = stream->getRoutes();
+        for (size_t j = 0; j < routes.size(); j++) {
+            sp<AudioPort> sink = routes[j]->getSink();
+            if (sink == 0 || stream != sink) {
+                ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
+                continue;
+            }
+            DeviceVector sourceDevicesForRoute = getRouteSourceDevices(routes[j]);
+            if (sourceDevicesForRoute.isEmpty()) {
+                ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+                continue;
+            }
+            sourceDevices.add(sourceDevicesForRoute);
+        }
+        if (sourceDevices.isEmpty()) {
+            ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+            continue;
+        }
+        stream->setSupportedDevices(sourceDevices);
+    }
+    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+        sp<IOProfile> stream = mOutputProfiles[i];
+        DeviceVector sinkDevices;
+        const AudioRouteVector &routes = stream->getRoutes();
+        for (size_t j = 0; j < routes.size(); j++) {
+            sp<AudioPort> source = routes[j]->getSources().findByTagName(stream->getTagName());
+            if (source == 0 || stream != source) {
+                ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
+                continue;
+            }
+            sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(routes[j]);
+            if (sinkDevice == 0) {
+                ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
+                continue;
+            }
+            sinkDevices.add(sinkDevice);
+        }
+        stream->setSupportedDevices(sinkDevices);
+    }
+}
 
 void HwModule::dump(int fd)
 {
@@ -163,6 +247,10 @@
         }
     }
     mDeclaredDevices.dump(fd, String8("Declared"),  2, true);
+    if (!mRoutes.empty()) {
+        write(fd, "  - Audio Route:\n", strlen("  - Audio Route:\n"));
+        mRoutes.dump(fd);
+    }
 }
 
 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index fe38f54..6e0a071 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -24,15 +24,6 @@
 
 namespace android {
 
-IOProfile::IOProfile(const String8 &name, audio_port_role_t role)
-    : AudioPort(name, AUDIO_PORT_TYPE_MIX, role)
-{
-}
-
-IOProfile::~IOProfile()
-{
-}
-
 // checks if the IO profile is compatible with specified parameters.
 // Sampling rate, format and channel mask must be specified in order to
 // get a valid a match
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
index 497d555..ccb10ae 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
@@ -30,24 +30,16 @@
                                 context),
       mPolicySubsystem(static_cast<const PolicySubsystem *>(
                            instanceConfigurableElement->getBelongingSubsystem())),
-      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
-      mApplicableInputDevice(mDefaultApplicableInputDevice)
+      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
     mId = static_cast<audio_source_t>(context.getItemAsInteger(MappingKeyIdentifier));
     // Declares the strategy to audio policy engine
     mPolicyPluginInterface->addInputSource(getFormattedMappingValue(), mId);
 }
 
-bool InputSource::receiveFromHW(string & /*error*/)
-{
-    blackboardWrite(&mApplicableInputDevice, sizeof(mApplicableInputDevice));
-    return true;
-}
-
 bool InputSource::sendToHW(string & /*error*/)
 {
     uint32_t applicableInputDevice;
     blackboardRead(&applicableInputDevice, sizeof(applicableInputDevice));
-    mApplicableInputDevice = applicableInputDevice;
-    return mPolicyPluginInterface->setDeviceForInputSource(mId, mApplicableInputDevice);
+    return mPolicyPluginInterface->setDeviceForInputSource(mId, applicableInputDevice);
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
index 67c5b50..0db4f70 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
@@ -32,7 +32,6 @@
              const CMappingContext &context);
 
 protected:
-    virtual bool receiveFromHW(std::string &error);
     virtual bool sendToHW(std::string &error);
 
 private:
@@ -44,6 +43,4 @@
     android::AudioPolicyPluginInterface *mPolicyPluginInterface;
 
     audio_source_t mId; /**< input source identifier to link with audio.h. */
-    uint32_t mApplicableInputDevice; /**< applicable input device for this strategy. */
-    static const uint32_t mDefaultApplicableInputDevice = 0; /**< default input device. */
 };
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
index 1848813..5c536d5 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
@@ -31,8 +31,7 @@
                                 context),
       mPolicySubsystem(static_cast<const PolicySubsystem *>(
                            instanceConfigurableElement->getBelongingSubsystem())),
-      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
-      mApplicableOutputDevice(mDefaultApplicableOutputDevice)
+      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
     mId = static_cast<routing_strategy>(context.getItemAsInteger(MappingKeyIdentifier));
 
@@ -40,12 +39,6 @@
     mPolicyPluginInterface->addStrategy(getFormattedMappingValue(), mId);
 }
 
-bool Strategy::receiveFromHW(string & /*error*/)
-{
-    blackboardWrite(&mApplicableOutputDevice, sizeof(mApplicableOutputDevice));
-    return true;
-}
-
 bool Strategy::sendToHW(string & /*error*/)
 {
     uint32_t applicableOutputDevice;
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
index 9a9b3e4..cbb72e2 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
@@ -32,7 +32,6 @@
              const CMappingContext &context);
 
 protected:
-    virtual bool receiveFromHW(std::string &error);
     virtual bool sendToHW(std::string &error);
 
 private:
@@ -44,6 +43,4 @@
     android::AudioPolicyPluginInterface *mPolicyPluginInterface;
 
     android::routing_strategy mId; /**< strategy identifier to link with audio.h.*/
-    uint32_t mApplicableOutputDevice; /**< applicable output device for this strategy. */
-    static const uint32_t mDefaultApplicableOutputDevice = 0; /**< default output device. */
 };
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
index 1916b9b..eb7d78f 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
@@ -31,8 +31,7 @@
                                 context),
       mPolicySubsystem(static_cast<const PolicySubsystem *>(
                            instanceConfigurableElement->getBelongingSubsystem())),
-      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
-      mApplicableStrategy(mDefaultApplicableStrategy)
+      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
     mId = static_cast<audio_usage_t>(context.getItemAsInteger(MappingKeyIdentifier));
 
@@ -40,17 +39,10 @@
     mPolicyPluginInterface->addUsage(getFormattedMappingValue(), mId);
 }
 
-bool Usage::receiveFromHW(string & /*error*/)
-{
-    blackboardWrite(&mApplicableStrategy, sizeof(mApplicableStrategy));
-    return true;
-}
-
 bool Usage::sendToHW(string & /*error*/)
 {
     uint32_t applicableStrategy;
     blackboardRead(&applicableStrategy, sizeof(applicableStrategy));
-    mApplicableStrategy = applicableStrategy;
     return mPolicyPluginInterface->setStrategyForUsage(mId,
-                                              static_cast<routing_strategy>(mApplicableStrategy));
+                                              static_cast<routing_strategy>(applicableStrategy));
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
index 8e9b638..3b82f8c 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
@@ -32,7 +32,6 @@
              const CMappingContext &context);
 
 protected:
-    virtual bool receiveFromHW(std::string &error);
     virtual bool sendToHW(std::string &error);
 
 private:
@@ -44,6 +43,4 @@
     android::AudioPolicyPluginInterface *mPolicyPluginInterface;
 
     audio_usage_t mId; /**< usage identifier to link with audio.h. */
-    uint32_t mApplicableStrategy; /**< applicable strategy for this usage. */
-    static const uint32_t mDefaultApplicableStrategy = 0; /**< default strategy. */
 };
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 32341ec..074af50 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -246,10 +246,17 @@
     return mPolicyParameterMgr->getForceUse(usage);
 }
 
-status_t Engine::setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
-                                          const char *deviceAddress)
+status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                          audio_policy_dev_state_t /*state*/)
 {
-    return mPolicyParameterMgr->setDeviceConnectionState(devices, state, deviceAddress);
+    if (audio_is_output_device(devDesc->type())) {
+        return mPolicyParameterMgr->setAvailableOutputDevices(
+                    mApmObserver->getAvailableOutputDevices().types());
+    } else if (audio_is_input_device(devDesc->type())) {
+        return mPolicyParameterMgr->setAvailableInputDevices(
+                    mApmObserver->getAvailableInputDevices().types());
+    }
+    return BAD_TYPE;
 }
 
 template <>
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 79bc8ff..8a15e5e 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -86,8 +86,7 @@
         virtual android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
                                                            audio_policy_dev_state_t state)
         {
-            return mPolicyEngine->setDeviceConnectionState(devDesc->type(), state,
-                                                           devDesc->mAddress);
+            return mPolicyEngine->setDeviceConnectionState(devDesc, state);
         }
         virtual status_t initStreamVolume(audio_stream_type_t stream,
                                                    int indexMin, int indexMax)
@@ -180,9 +179,8 @@
     audio_mode_t getPhoneState() const;
     status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
     audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
-    status_t setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
-                                      const char *deviceAddress);
-
+    status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                      audio_policy_dev_state_t state);
     float volIndexToDb(device_category category, audio_stream_type_t stream, int indexInUi);
     status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
 
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index cfe49d4..3e40a2b 100755
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -387,41 +387,26 @@
     return interface->getLiteralValue(valueToCheck, literalValue);
 }
 
-status_t ParameterManagerWrapper::setDeviceConnectionState(audio_devices_t devices,
-                                                           audio_policy_dev_state_t state,
-                                                           const char */*deviceAddres*/)
+status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
 {
-    ISelectionCriterionInterface *criterion = NULL;
-
-    if (audio_is_output_devices(devices)) {
-        criterion = mPolicyCriteria[gOutputDeviceCriterionTag];
-    } else if (devices & AUDIO_DEVICE_BIT_IN) {
-        criterion = mPolicyCriteria[gInputDeviceCriterionTag];
-    } else {
-        return BAD_TYPE;
-    }
+    ISelectionCriterionInterface *criterion = mPolicyCriteria[gInputDeviceCriterionTag];
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for devices", __FUNCTION__);
+        ALOGE("%s: no criterion found for input devices", __FUNCTION__);
         return DEAD_OBJECT;
     }
+    criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
+    applyPlatformConfiguration();
+    return NO_ERROR;
+}
 
-    int32_t previousDevices = criterion->getCriterionState();
-    switch (state)
-    {
-    case AUDIO_POLICY_DEVICE_STATE_AVAILABLE:
-        criterion->setCriterionState(previousDevices |= devices);
-        break;
-
-    case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE:
-        if (devices & AUDIO_DEVICE_BIT_IN) {
-            devices &= ~AUDIO_DEVICE_BIT_IN;
-        }
-        criterion->setCriterionState(previousDevices &= ~devices);
-        break;
-
-    default:
-        return BAD_VALUE;
+status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
+{
+    ISelectionCriterionInterface *criterion = mPolicyCriteria[gOutputDeviceCriterionTag];
+    if (criterion == NULL) {
+        ALOGE("%s: no criterion found for output devices", __FUNCTION__);
+        return DEAD_OBJECT;
     }
+    criterion->setCriterionState(outputDevices);
     applyPlatformConfiguration();
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 3c5f2c0..4c1acfe 100755
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -103,18 +103,22 @@
     audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
 
     /**
-     * Set the connection state of device(s).
-     * It will set the associated policy parameter framework criterion.
+     * Set the available input devices i.e. set the associated policy parameter framework criterion
      *
-     * @param[in] devices mask of devices for which the state has changed.
-     * @param[in] state of availability of this(these) device(s).
-     * @param[in] deviceAddress: the mask might not be enough, as it may represents a type of
-     *            device, so address of the device will help precise identification.
+     * @param[in] inputDevices mask of available input devices.
      *
      * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
      */
-    status_t setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
-                                      const char *deviceAddress);
+    status_t setAvailableInputDevices(audio_devices_t inputDevices);
+
+    /**
+     * Set the available output devices i.e. set the associated policy parameter framework criterion
+     *
+     * @param[in] outputDevices mask of available output devices.
+     *
+     * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
+     */
+    status_t setAvailableOutputDevices(audio_devices_t outputDevices);
 
 private:
     /**
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index a66be09..b0df018 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -662,6 +662,7 @@
         break;
 
     case AUDIO_SOURCE_VOICE_RECOGNITION:
+    case AUDIO_SOURCE_UNPROCESSED:
     case AUDIO_SOURCE_HOTWORD:
         if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
                 availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index af8a2b9..04af88d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -842,15 +842,15 @@
         goto non_direct_output;
     }
 
-    // Do not allow offloading if one non offloadable effect is enabled. This prevents from
-    // creating an offloaded track and tearing it down immediately after start when audioflinger
-    // detects there is an active non offloadable effect.
+    // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
+    // This prevents creating an offloaded track and tearing it down immediately after start
+    // when audioflinger detects there is an active non offloadable effect.
     // FIXME: We should check the audio session here but we do not have it in this context.
     // This may prevent offloading in rare situations where effects are left active by apps
     // in the background.
 
     if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
-            !mEffects.isNonOffloadableEffectEnabled()) {
+            !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
         profile = getProfileForDirectOutput(device,
                                            samplingRate,
                                            format,
@@ -2090,6 +2090,8 @@
     result.append(buffer);
     snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
     result.append(buffer);
+    snprintf(buffer, SIZE, " Master mono: %s\n", mMasterMono ? "on" : "off");
+    result.append(buffer);
 
     write(fd, result.string(), result.size());
 
@@ -2117,6 +2119,10 @@
      offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
      offloadInfo.has_video);
 
+    if (mMasterMono) {
+        return false; // no offloading if mono is set.
+    }
+
     // Check if offload has been disabled
     char propValue[PROPERTY_VALUE_MAX];
     if (property_get("audio.offload.disable", propValue, "0")) {
@@ -2880,6 +2886,44 @@
     return status;
 }
 
+status_t AudioPolicyManager::setMasterMono(bool mono)
+{
+    if (mMasterMono == mono) {
+        return NO_ERROR;
+    }
+    mMasterMono = mono;
+    // if enabling mono we close all offloaded devices, which will invalidate the
+    // corresponding AudioTrack. The AudioTrack client/MediaPlayer is responsible
+    // for recreating the new AudioTrack as non-offloaded PCM.
+    //
+    // If disabling mono, we leave all tracks as is: we don't know which clients
+    // and tracks are able to be recreated as offloaded. The next "song" should
+    // play back offloaded.
+    if (mMasterMono) {
+        Vector<audio_io_handle_t> offloaded;
+        for (size_t i = 0; i < mOutputs.size(); ++i) {
+            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+            if (desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+                offloaded.push(desc->mIoHandle);
+            }
+        }
+        for (size_t i = 0; i < offloaded.size(); ++i) {
+            closeOutput(offloaded[i]);
+        }
+    }
+    // update master mono for all remaining outputs
+    for (size_t i = 0; i < mOutputs.size(); ++i) {
+        updateMono(mOutputs.keyAt(i));
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMasterMono(bool *mono)
+{
+    *mono = mMasterMono;
+    return NO_ERROR;
+}
+
 status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
 {
     ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
@@ -2946,7 +2990,8 @@
     mBeaconMuteRefCount(0),
     mBeaconPlayingRefCount(0),
     mBeaconMuted(false),
-    mTtsOutputAvailable(false)
+    mTtsOutputAvailable(false),
+    mMasterMono(false)
 {
     audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
     if (!engineInstance) {
@@ -3371,6 +3416,7 @@
 {
     outputDesc->setIoHandle(output);
     mOutputs.add(output, outputDesc);
+    updateMono(output); // update mono status when adding to output list
     nextAudioPortGeneration();
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 59163ca..37faac2 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -24,6 +24,7 @@
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
+#include <media/AudioParameter.h>
 #include <media/AudioPolicy.h>
 #include "AudioPolicyInterface.h"
 
@@ -231,6 +232,9 @@
                                           uid_t uid);
         virtual status_t stopAudioSource(audio_io_handle_t handle);
 
+        virtual status_t setMasterMono(bool mono);
+        virtual status_t getMasterMono(bool *mono);
+
         // Audio policy configuration file parsing (audio_policy.conf)
         // TODO candidates to be moved to ConfigParsingUtils
                 void defaultAudioPolicyConfig(void);
@@ -565,6 +569,7 @@
         bool mBeaconMuted;              // has STREAM_TTS been muted
         bool mTtsOutputAvailable;       // true if a dedicated output for TTS stream is available
 
+        bool mMasterMono;               // true if we wish to force all outputs to mono
         AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
 
 #ifdef AUDIO_POLICY_TEST
@@ -644,6 +649,11 @@
                                                           audio_policy_dev_state_t state,
                                                           const char *device_address,
                                                           const char *device_name);
+        void updateMono(audio_io_handle_t output) {
+            AudioParameter param;
+            param.addInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), (int)mMasterMono);
+            mpClientInterface->setParameters(output, param.toString());
+        }
 };
 
 };
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 282ddeb..f6f8276 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -323,7 +323,8 @@
     VOICE_CALL_SRC_TAG,
     CAMCORDER_SRC_TAG,
     VOICE_REC_SRC_TAG,
-    VOICE_COMM_SRC_TAG
+    VOICE_COMM_SRC_TAG,
+    UNPROCESSED_SRC_TAG
 };
 
 // returns the audio_source_t enum corresponding to the input source name or
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 8c976aa..c7486a5 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -560,7 +560,7 @@
         ALOGV("mAudioPolicyManager == NULL");
         return false;
     }
-
+    Mutex::Autolock _l(mLock);
     return mAudioPolicyManager->isOffloadSupported(info);
 }
 
@@ -700,4 +700,25 @@
     return mAudioPolicyManager->stopAudioSource(handle);
 }
 
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->setMasterMono(mono);
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->getMasterMono(mono);
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 13af3ef..08b2a3b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -619,4 +619,14 @@
     return INVALID_OPERATION;
 }
 
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 4c11d93..160f4f0 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -202,6 +202,9 @@
                                       audio_io_handle_t *handle);
     virtual status_t stopAudioSource(audio_io_handle_t handle);
 
+    virtual status_t setMasterMono(bool mono);
+    virtual status_t getMasterMono(bool *mono);
+
             status_t doStopOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   audio_session_t session);
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index a9a984a..21a75cd 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -11,9 +11,7 @@
 
 # service executable
 include $(CLEAR_VARS)
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
-LOCAL_ADDITIONAL_DEPENDENCIES += mediaextractor-seccomp.policy
-endif
+LOCAL_REQUIRED_MODULES_arm := mediaextractor-seccomp.policy
 LOCAL_SRC_FILES := main_extractorservice.cpp minijail/minijail.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils liblog libicuuc libminijail
 LOCAL_STATIC_LIBRARIES := libicuandroid_utils
diff --git a/services/mediaextractor/minijail/Android.mk b/services/mediaextractor/minijail/Android.mk
index 79182bd..17ff2c1 100644
--- a/services/mediaextractor/minijail/Android.mk
+++ b/services/mediaextractor/minijail/Android.mk
@@ -4,7 +4,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := mediaextractor-seccomp.policy
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy/
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
 
 # mediaextractor runs in 32-bit combatibility mode. For 64 bit architectures,
 # use the 32 bit policy
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
index f30b3ad..f23e38f 100644
--- a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
@@ -36,3 +36,4 @@
 setpriority: 1
 sigaltstack: 1
 brk: 1
+sched_setscheduler: 1