Merge "libstagefright: Add Opus support to ACodec::getPortFormat"
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index 94f560d..c2a8f1b 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -47,7 +47,7 @@
         "ro.revision",
         "dalvik.vm.heapgrowthlimit",
         "dalvik.vm.heapsize",
-        "persist.sys.dalvik.vm.lib.1",
+        "persist.sys.dalvik.vm.lib.2",
         //"ro.product.cpu.abi",
         //"ro.bootloader",
         //"this-never-appears!",
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 402b479..a79a9ff 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -274,6 +274,31 @@
     // check presence of audio flinger service.
     // returns NO_ERROR if binding to service succeeds, DEAD_OBJECT otherwise
     static status_t checkAudioFlinger();
+
+    /* List available audio ports and their attributes */
+    static status_t listAudioPorts(audio_port_role_t role,
+                                   audio_port_type_t type,
+                                   unsigned int *num_ports,
+                                   struct audio_port *ports,
+                                   unsigned int *generation);
+
+    /* Get attributes for a given audio port */
+    static status_t getAudioPort(struct audio_port *port);
+
+    /* Create an audio patch between several source and sink ports */
+    static status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle);
+
+    /* Release an audio patch */
+    static status_t releaseAudioPatch(audio_patch_handle_t handle);
+
+    /* List existing audio patches */
+    static status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches,
+                                      unsigned int *generation);
+    /* Set audio port configuration */
+    static status_t setAudioPortConfig(const struct audio_port_config *config);
+
     // ----------------------------------------------------------------------------
 
 private:
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 7db6a48..c742810 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -214,6 +214,27 @@
     // and should be called at most once.  For a definition of what "low RAM" means, see
     // android.app.ActivityManager.isLowRamDevice().
     virtual status_t setLowRamDevice(bool isLowRamDevice) = 0;
+
+    /* List available audio ports and their attributes */
+    virtual status_t listAudioPorts(unsigned int *num_ports,
+                                    struct audio_port *ports) = 0;
+
+    /* Get attributes for a given audio port */
+    virtual status_t getAudioPort(struct audio_port *port) = 0;
+
+    /* Create an audio patch between several source and sink ports */
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle) = 0;
+
+    /* Release an audio patch */
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+    /* List existing audio patches */
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches) = 0;
+    /* Set audio port configuration */
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
+
 };
 
 
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 09b9ea6..6b6df6e 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -99,6 +99,31 @@
    // Check if offload is possible for given format, stream type, sample rate,
     // bit rate, duration, video and streaming or offload property is enabled
     virtual bool isOffloadSupported(const audio_offload_info_t& info) = 0;
+
+    /* List available audio ports and their attributes */
+    virtual status_t listAudioPorts(audio_port_role_t role,
+                                    audio_port_type_t type,
+                                    unsigned int *num_ports,
+                                    struct audio_port *ports,
+                                    unsigned int *generation) = 0;
+
+    /* Get attributes for a given audio port */
+    virtual status_t getAudioPort(struct audio_port *port) = 0;
+
+    /* Create an audio patch between several source and sink ports */
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle) = 0;
+
+    /* Release an audio patch */
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+    /* List existing audio patches */
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches,
+                                      unsigned int *generation) = 0;
+    /* Set audio port configuration */
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
+
 };
 
 
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 2f000d7..c07f4c9 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -163,17 +163,6 @@
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs);
 
-typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
-
-/**
- * Set a callback to be called when a new buffer is available, or there was a format
- * or buffer change.
- * Note that you cannot perform any operations on the mediacodec from within the callback.
- * If you need to perform mediacodec operations, you must do so on a different thread.
- */
-media_status_t AMediaCodec_setNotificationCallback(
-        AMediaCodec*, OnCodecEvent callback, void *userdata);
-
 
 typedef enum {
     AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 2f16444..845ee20 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -831,6 +831,55 @@
     return aps->isOffloadSupported(info);
 }
 
+status_t AudioSystem::listAudioPorts(audio_port_role_t role,
+                                     audio_port_type_t type,
+                                     unsigned int *num_ports,
+                                     struct audio_port *ports,
+                                     unsigned int *generation)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->listAudioPorts(role, type, num_ports, ports, generation);
+}
+
+status_t AudioSystem::getAudioPort(struct audio_port *port)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getAudioPort(port);
+}
+
+status_t AudioSystem::createAudioPatch(const struct audio_patch *patch,
+                                   audio_patch_handle_t *handle)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->createAudioPatch(patch, handle);
+}
+
+status_t AudioSystem::releaseAudioPatch(audio_patch_handle_t handle)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->releaseAudioPatch(handle);
+}
+
+status_t AudioSystem::listAudioPatches(unsigned int *num_patches,
+                                  struct audio_patch *patches,
+                                  unsigned int *generation)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->listAudioPatches(num_patches, patches, generation);
+}
+
+status_t AudioSystem::setAudioPortConfig(const struct audio_port_config *config)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setAudioPortConfig(config);
+}
+
 // ---------------------------------------------------------------------------
 
 void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 0e2463e..687fa76 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -74,6 +74,12 @@
     GET_PRIMARY_OUTPUT_SAMPLING_RATE,
     GET_PRIMARY_OUTPUT_FRAME_COUNT,
     SET_LOW_RAM_DEVICE,
+    LIST_AUDIO_PORTS,
+    GET_AUDIO_PORT,
+    CREATE_AUDIO_PATCH,
+    RELEASE_AUDIO_PATCH,
+    LIST_AUDIO_PATCHES,
+    SET_AUDIO_PORT_CONFIG
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -801,7 +807,101 @@
         remote()->transact(SET_LOW_RAM_DEVICE, data, &reply);
         return reply.readInt32();
     }
-
+    virtual status_t listAudioPorts(unsigned int *num_ports,
+                                    struct audio_port *ports)
+    {
+        if (num_ports == NULL || *num_ports == 0 || ports == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(*num_ports);
+        status_t status = remote()->transact(LIST_AUDIO_PORTS, data, &reply);
+        if (status != NO_ERROR ||
+                (status = (status_t)reply.readInt32()) != NO_ERROR) {
+            return status;
+        }
+        *num_ports = (unsigned int)reply.readInt32();
+        reply.read(ports, *num_ports * sizeof(struct audio_port));
+        return status;
+    }
+    virtual status_t getAudioPort(struct audio_port *port)
+    {
+        if (port == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(port, sizeof(struct audio_port));
+        status_t status = remote()->transact(GET_AUDIO_PORT, data, &reply);
+        if (status != NO_ERROR ||
+                (status = (status_t)reply.readInt32()) != NO_ERROR) {
+            return status;
+        }
+        reply.read(port, sizeof(struct audio_port));
+        return status;
+    }
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle)
+    {
+        if (patch == NULL || handle == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(patch, sizeof(struct audio_patch));
+        data.write(handle, sizeof(audio_patch_handle_t));
+        status_t status = remote()->transact(CREATE_AUDIO_PATCH, data, &reply);
+        if (status != NO_ERROR ||
+                (status = (status_t)reply.readInt32()) != NO_ERROR) {
+            return status;
+        }
+        reply.read(handle, sizeof(audio_patch_handle_t));
+        return status;
+    }
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(&handle, sizeof(audio_patch_handle_t));
+        status_t status = remote()->transact(RELEASE_AUDIO_PATCH, data, &reply);
+        if (status != NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches)
+    {
+        if (num_patches == NULL || *num_patches == 0 || patches == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(*num_patches);
+        status_t status = remote()->transact(LIST_AUDIO_PATCHES, data, &reply);
+        if (status != NO_ERROR ||
+                (status = (status_t)reply.readInt32()) != NO_ERROR) {
+            return status;
+        }
+        *num_patches = (unsigned int)reply.readInt32();
+        reply.read(patches, *num_patches * sizeof(struct audio_patch));
+        return status;
+    }
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config)
+    {
+        if (config == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(config, sizeof(struct audio_port_config));
+        status_t status = remote()->transact(SET_AUDIO_PORT_CONFIG, data, &reply);
+        if (status != NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -1199,6 +1299,76 @@
             reply->writeInt32(setLowRamDevice(isLowRamDevice));
             return NO_ERROR;
         } break;
+        case LIST_AUDIO_PORTS: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            unsigned int num_ports = data.readInt32();
+            struct audio_port *ports =
+                    (struct audio_port *)calloc(num_ports,
+                                                           sizeof(struct audio_port));
+            status_t status = listAudioPorts(&num_ports, ports);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(num_ports);
+                reply->write(&ports, num_ports * sizeof(struct audio_port));
+            }
+            free(ports);
+            return NO_ERROR;
+        } break;
+        case GET_AUDIO_PORT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            struct audio_port port;
+            data.read(&port, sizeof(struct audio_port));
+            status_t status = getAudioPort(&port);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&port, sizeof(struct audio_port));
+            }
+            return NO_ERROR;
+        } break;
+        case CREATE_AUDIO_PATCH: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            struct audio_patch patch;
+            data.read(&patch, sizeof(struct audio_patch));
+            audio_patch_handle_t handle;
+            data.read(&handle, sizeof(audio_patch_handle_t));
+            status_t status = createAudioPatch(&patch, &handle);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&handle, sizeof(audio_patch_handle_t));
+            }
+            return NO_ERROR;
+        } break;
+        case RELEASE_AUDIO_PATCH: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            audio_patch_handle_t handle;
+            data.read(&handle, sizeof(audio_patch_handle_t));
+            status_t status = releaseAudioPatch(handle);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+        case LIST_AUDIO_PATCHES: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            unsigned int num_patches = data.readInt32();
+            struct audio_patch *patches =
+                    (struct audio_patch *)calloc(num_patches,
+                                                 sizeof(struct audio_patch));
+            status_t status = listAudioPatches(&num_patches, patches);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(num_patches);
+                reply->write(&patches, num_patches * sizeof(struct audio_patch));
+            }
+            free(patches);
+            return NO_ERROR;
+        } break;
+        case SET_AUDIO_PORT_CONFIG: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            struct audio_port_config config;
+            data.read(&config, sizeof(struct audio_port_config));
+            status_t status = setAudioPortConfig(&config);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 9bb4a49..ad2d4eb 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -57,7 +57,13 @@
     QUERY_DEFAULT_PRE_PROCESSING,
     SET_EFFECT_ENABLED,
     IS_STREAM_ACTIVE_REMOTELY,
-    IS_OFFLOAD_SUPPORTED
+    IS_OFFLOAD_SUPPORTED,
+    LIST_AUDIO_PORTS,
+    GET_AUDIO_PORT,
+    CREATE_AUDIO_PATCH,
+    RELEASE_AUDIO_PATCH,
+    LIST_AUDIO_PATCHES,
+    SET_AUDIO_PORT_CONFIG
 };
 
 class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
@@ -390,7 +396,134 @@
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         data.write(&info, sizeof(audio_offload_info_t));
         remote()->transact(IS_OFFLOAD_SUPPORTED, data, &reply);
-        return reply.readInt32();    }
+        return reply.readInt32();
+    }
+
+    virtual status_t listAudioPorts(audio_port_role_t role,
+                                    audio_port_type_t type,
+                                    unsigned int *num_ports,
+                                    struct audio_port *ports,
+                                    unsigned int *generation)
+    {
+        if (num_ports == NULL || (*num_ports != 0 && ports == NULL) ||
+                generation == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        unsigned int numPortsReq = (ports == NULL) ? 0 : *num_ports;
+        data.writeInt32(role);
+        data.writeInt32(type);
+        data.writeInt32(numPortsReq);
+        status_t status = remote()->transact(LIST_AUDIO_PORTS, data, &reply);
+        if (status == NO_ERROR) {
+            status = (status_t)reply.readInt32();
+            *num_ports = (unsigned int)reply.readInt32();
+        }
+        ALOGI("listAudioPorts() status %d got *num_ports %d", status, *num_ports);
+        if (status == NO_ERROR) {
+            if (numPortsReq > *num_ports) {
+                numPortsReq = *num_ports;
+            }
+            if (numPortsReq > 0) {
+                reply.read(ports, numPortsReq * sizeof(struct audio_port));
+            }
+            *generation = reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t getAudioPort(struct audio_port *port)
+    {
+        if (port == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(port, sizeof(struct audio_port));
+        status_t status = remote()->transact(GET_AUDIO_PORT, data, &reply);
+        if (status != NO_ERROR ||
+                (status = (status_t)reply.readInt32()) != NO_ERROR) {
+            return status;
+        }
+        reply.read(port, sizeof(struct audio_port));
+        return status;
+    }
+
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle)
+    {
+        if (patch == NULL || handle == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(patch, sizeof(struct audio_patch));
+        data.write(handle, sizeof(audio_patch_handle_t));
+        status_t status = remote()->transact(CREATE_AUDIO_PATCH, data, &reply);
+        if (status != NO_ERROR ||
+                (status = (status_t)reply.readInt32()) != NO_ERROR) {
+            return status;
+        }
+        reply.read(handle, sizeof(audio_patch_handle_t));
+        return status;
+    }
+
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&handle, sizeof(audio_patch_handle_t));
+        status_t status = remote()->transact(RELEASE_AUDIO_PATCH, data, &reply);
+        if (status != NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches,
+                                      unsigned int *generation)
+    {
+        if (num_patches == NULL || (*num_patches != 0 && patches == NULL) ||
+                generation == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        unsigned int numPatchesReq = (patches == NULL) ? 0 : *num_patches;
+        data.writeInt32(numPatchesReq);
+        status_t status = remote()->transact(LIST_AUDIO_PATCHES, data, &reply);
+        if (status == NO_ERROR) {
+            status = (status_t)reply.readInt32();
+            *num_patches = (unsigned int)reply.readInt32();
+        }
+        if (status == NO_ERROR) {
+            if (numPatchesReq > *num_patches) {
+                numPatchesReq = *num_patches;
+            }
+            if (numPatchesReq > 0) {
+                reply.read(patches, numPatchesReq * sizeof(struct audio_patch));
+            }
+            *generation = reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config)
+    {
+        if (config == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(config, sizeof(struct audio_port_config));
+        status_t status = remote()->transact(SET_AUDIO_PORT_CONFIG, data, &reply);
+        if (status != NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -687,6 +820,97 @@
             return NO_ERROR;
         }
 
+        case LIST_AUDIO_PORTS: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_port_role_t role = (audio_port_role_t)data.readInt32();
+            audio_port_type_t type = (audio_port_type_t)data.readInt32();
+            unsigned int numPortsReq = data.readInt32();
+            unsigned int numPorts = numPortsReq;
+            unsigned int generation;
+            struct audio_port *ports =
+                    (struct audio_port *)calloc(numPortsReq, sizeof(struct audio_port));
+            status_t status = listAudioPorts(role, type, &numPorts, ports, &generation);
+            reply->writeInt32(status);
+            reply->writeInt32(numPorts);
+            ALOGI("LIST_AUDIO_PORTS status %d got numPorts %d", status, numPorts);
+
+            if (status == NO_ERROR) {
+                if (numPortsReq > numPorts) {
+                    numPortsReq = numPorts;
+                }
+                reply->write(ports, numPortsReq * sizeof(struct audio_port));
+                reply->writeInt32(generation);
+            }
+            free(ports);
+            return NO_ERROR;
+        }
+
+        case GET_AUDIO_PORT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            struct audio_port port;
+            data.read(&port, sizeof(struct audio_port));
+            status_t status = getAudioPort(&port);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&port, sizeof(struct audio_port));
+            }
+            return NO_ERROR;
+        }
+
+        case CREATE_AUDIO_PATCH: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            struct audio_patch patch;
+            data.read(&patch, sizeof(struct audio_patch));
+            audio_patch_handle_t handle;
+            data.read(&handle, sizeof(audio_patch_handle_t));
+            status_t status = createAudioPatch(&patch, &handle);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&handle, sizeof(audio_patch_handle_t));
+            }
+            return NO_ERROR;
+        }
+
+        case RELEASE_AUDIO_PATCH: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_patch_handle_t handle;
+            data.read(&handle, sizeof(audio_patch_handle_t));
+            status_t status = releaseAudioPatch(handle);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+
+        case LIST_AUDIO_PATCHES: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            unsigned int numPatchesReq = data.readInt32();
+            unsigned int numPatches = numPatchesReq;
+            unsigned int generation;
+            struct audio_patch *patches =
+                    (struct audio_patch *)calloc(numPatchesReq,
+                                                 sizeof(struct audio_patch));
+            status_t status = listAudioPatches(&numPatches, patches, &generation);
+            reply->writeInt32(status);
+            reply->writeInt32(numPatches);
+            if (status == NO_ERROR) {
+                if (numPatchesReq > numPatches) {
+                    numPatchesReq = numPatches;
+                }
+                reply->write(patches, numPatchesReq * sizeof(struct audio_patch));
+                reply->writeInt32(generation);
+            }
+            free(patches);
+            return NO_ERROR;
+        }
+
+        case SET_AUDIO_PORT_CONFIG: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            struct audio_port_config config;
+            data.read(&config, sizeof(struct audio_port_config));
+            status_t status = setAudioPortConfig(&config);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d8d939a..857e703 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1376,16 +1376,15 @@
 
             sp<NuPlayerDriver> driver = mDriver.promote();
             if (driver != NULL) {
+                // notify duration first, so that it's definitely set when
+                // the app received the "prepare complete" callback.
+                int64_t durationUs;
+                if (mSource->getDuration(&durationUs) == OK) {
+                    driver->notifyDuration(durationUs);
+                }
                 driver->notifyPrepareCompleted(err);
             }
 
-            int64_t durationUs;
-            if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
-                sp<NuPlayerDriver> driver = mDriver.promote();
-                if (driver != NULL) {
-                    driver->notifyDuration(durationUs);
-                }
-            }
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index e4850f0..280b5af 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -284,6 +284,10 @@
         case STATE_PREPARED:
         {
             mStartupSeekTimeUs = seekTimeUs;
+            // pretend that the seek completed. It will actually happen when starting playback.
+            // TODO: actually perform the seek here, so the player is ready to go at the new
+            // location
+            notifySeekComplete();
             break;
         }
 
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index bd2541f..2ac16c7 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -61,6 +61,8 @@
     virtual void onMessageReceived(const sp<AMessage> &msg);
 };
 
+typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
+
 struct AMediaCodec {
     sp<android::MediaCodec> mCodec;
     sp<ALooper> mLooper;
@@ -347,7 +349,7 @@
     return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
 }
 
-EXPORT
+//EXPORT
 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
     mData->mCallback = callback;
     mData->mCallbackUserData = userdata;
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 8d0a705..f7b6f64 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -29,6 +29,7 @@
     Tracks.cpp                  \
     Effects.cpp                 \
     AudioMixer.cpp.arm          \
+    PatchPanel.cpp
 
 LOCAL_SRC_FILES += StateQueue.cpp
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9bd0e9b..5b09d54 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -177,6 +177,7 @@
     if (doLog) {
         mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters", MemoryHeapBase::READ_ONLY);
     }
+
 #ifdef TEE_SINK
     (void) property_get("ro.debuggable", value, "0");
     int debuggable = atoi(value);
@@ -218,6 +219,8 @@
         }
     }
 
+    mPatchPanel = new PatchPanel(this);
+
     mMode = AUDIO_MODE_NORMAL;
 }
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d2ded9a..29dc6b2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -223,6 +223,27 @@
 
     virtual status_t setLowRamDevice(bool isLowRamDevice);
 
+    /* List available audio ports and their attributes */
+    virtual status_t listAudioPorts(unsigned int *num_ports,
+                                    struct audio_port *ports);
+
+    /* Get attributes for a given audio port */
+    virtual status_t getAudioPort(struct audio_port *port);
+
+    /* Create an audio patch between several source and sink ports */
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle);
+
+    /* Release an audio patch */
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle);
+
+    /* List existing audio patches */
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches);
+
+    /* Set audio port configuration */
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -397,6 +418,8 @@
 
 #include "Effects.h"
 
+#include "PatchPanel.h"
+
     // server side of the client's IAudioTrack
     class TrackHandle : public android::BnAudioTrack {
     public:
@@ -504,6 +527,8 @@
 
         const char *moduleName() const { return mModuleName; }
         audio_hw_device_t *hwDevice() const { return mHwDevice; }
+        uint32_t version() const { return mHwDevice->common.version; }
+
     private:
         const char * const mModuleName;
         audio_hw_device_t * const mHwDevice;
@@ -664,6 +689,8 @@
     bool    mIsLowRamDevice;
     bool    mIsDeviceTypeKnown;
     nsecs_t mGlobalEffectEnableTime;  // when a global effect was last enabled
+
+    sp<PatchPanel> mPatchPanel;
 };
 
 #undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 342364e..8d57451 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -34,6 +34,7 @@
 #include <system/audio.h>
 
 #include <audio_utils/primitives.h>
+#include <audio_utils/format.h>
 #include <common_time/local_clock.h>
 #include <common_time/cc_helper.h>
 
@@ -88,6 +89,103 @@
     }
 }
 
+template <typename T>
+T min(const T& a, const T& b)
+{
+    return a < b ? a : b;
+}
+
+AudioMixer::ReformatBufferProvider::ReformatBufferProvider(int32_t channels,
+        audio_format_t inputFormat, audio_format_t outputFormat) :
+        mTrackBufferProvider(NULL),
+        mChannels(channels),
+        mInputFormat(inputFormat),
+        mOutputFormat(outputFormat),
+        mInputFrameSize(channels * audio_bytes_per_sample(inputFormat)),
+        mOutputFrameSize(channels * audio_bytes_per_sample(outputFormat)),
+        mOutputData(NULL),
+        mOutputCount(0),
+        mConsumed(0)
+{
+    ALOGV("ReformatBufferProvider(%p)(%d, %#x, %#x)", this, channels, inputFormat, outputFormat);
+    if (requiresInternalBuffers()) {
+        mOutputCount = 256;
+        (void)posix_memalign(&mOutputData, 32, mOutputCount * mOutputFrameSize);
+    }
+    mBuffer.frameCount = 0;
+}
+
+AudioMixer::ReformatBufferProvider::~ReformatBufferProvider()
+{
+    ALOGV("~ReformatBufferProvider(%p)", this);
+    if (mBuffer.frameCount != 0) {
+        mTrackBufferProvider->releaseBuffer(&mBuffer);
+    }
+    free(mOutputData);
+}
+
+status_t AudioMixer::ReformatBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
+        int64_t pts) {
+    //ALOGV("ReformatBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
+    //        this, pBuffer, pBuffer->frameCount, pts);
+    if (!requiresInternalBuffers()) {
+        status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+        if (res == OK) {
+            memcpy_by_audio_format(pBuffer->raw, mOutputFormat, pBuffer->raw, mInputFormat,
+                    pBuffer->frameCount * mChannels);
+        }
+        return res;
+    }
+    if (mBuffer.frameCount == 0) {
+        mBuffer.frameCount = pBuffer->frameCount;
+        status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+        // TODO: Track down a bug in the upstream provider
+        // LOG_ALWAYS_FATAL_IF(res == OK && mBuffer.frameCount == 0,
+        //        "ReformatBufferProvider::getNextBuffer():"
+        //        " Invalid zero framecount returned from getNextBuffer()");
+        if (res != OK || mBuffer.frameCount == 0) {
+            pBuffer->raw = NULL;
+            pBuffer->frameCount = 0;
+            return res;
+        }
+    }
+    ALOG_ASSERT(mConsumed < mBuffer.frameCount);
+    size_t count = min(mOutputCount, mBuffer.frameCount - mConsumed);
+    count = min(count, pBuffer->frameCount);
+    pBuffer->raw = mOutputData;
+    pBuffer->frameCount = count;
+    //ALOGV("reformatting %d frames from %#x to %#x, %d chan",
+    //        pBuffer->frameCount, mInputFormat, mOutputFormat, mChannels);
+    memcpy_by_audio_format(pBuffer->raw, mOutputFormat,
+            (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize, mInputFormat,
+            pBuffer->frameCount * mChannels);
+    return OK;
+}
+
+void AudioMixer::ReformatBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
+    //ALOGV("ReformatBufferProvider(%p)::releaseBuffer(%p(%zu))",
+    //        this, pBuffer, pBuffer->frameCount);
+    if (!requiresInternalBuffers()) {
+        mTrackBufferProvider->releaseBuffer(pBuffer);
+        return;
+    }
+    // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
+    mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
+    if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
+        mConsumed = 0;
+        mTrackBufferProvider->releaseBuffer(&mBuffer);
+        // ALOG_ASSERT(mBuffer.frameCount == 0);
+    }
+    pBuffer->raw = NULL;
+    pBuffer->frameCount = 0;
+}
+
+void AudioMixer::ReformatBufferProvider::reset() {
+    if (mBuffer.frameCount != 0) {
+        mTrackBufferProvider->releaseBuffer(&mBuffer);
+    }
+    mConsumed = 0;
+}
 
 // ----------------------------------------------------------------------------
 bool AudioMixer::sIsMultichannelCapable = false;
@@ -181,7 +279,8 @@
         // t->frameCount
         t->channelCount = audio_channel_count_from_out_mask(channelMask);
         t->enabled = false;
-        t->format = 16;
+        ALOGV_IF(channelMask != AUDIO_CHANNEL_OUT_STEREO,
+                "Non-stereo channel mask: %d\n", channelMask);
         t->channelMask = channelMask;
         t->sessionId = sessionId;
         // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
@@ -196,9 +295,15 @@
         // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
         t->mainBuffer = NULL;
         t->auxBuffer = NULL;
+        t->mInputBufferProvider = NULL;
+        t->mReformatBufferProvider = NULL;
         t->downmixerBufferProvider = NULL;
         t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
         t->mFormat = format;
+        t->mMixerInFormat = AUDIO_FORMAT_PCM_16_BIT;
+        if (t->mFormat != t->mMixerInFormat) {
+            prepareTrackForReformat(t, n);
+        }
         status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
         if (status != OK) {
             ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
@@ -242,9 +347,9 @@
     if (pTrack->downmixerBufferProvider != NULL) {
         // this track had previously been configured with a downmixer, delete it
         ALOGV(" deleting old downmixer");
-        pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider;
         delete pTrack->downmixerBufferProvider;
         pTrack->downmixerBufferProvider = NULL;
+        reconfigureBufferProviders(pTrack);
     } else {
         ALOGV(" nothing to do, no downmixer to delete");
     }
@@ -338,21 +443,51 @@
     }// end of scope for local variables that are not used in goto label "noDownmixForActiveTrack"
 
     // initialization successful:
-    // - keep track of the real buffer provider in case it was set before
-    pDbp->mTrackBufferProvider = pTrack->bufferProvider;
-    // - we'll use the downmix effect integrated inside this
-    //    track's buffer provider, and we'll use it as the track's buffer provider
     pTrack->downmixerBufferProvider = pDbp;
-    pTrack->bufferProvider = pDbp;
-
+    reconfigureBufferProviders(pTrack);
     return NO_ERROR;
 
 noDownmixForActiveTrack:
     delete pDbp;
     pTrack->downmixerBufferProvider = NULL;
+    reconfigureBufferProviders(pTrack);
     return NO_INIT;
 }
 
+void AudioMixer::unprepareTrackForReformat(track_t* pTrack, int trackName __unused) {
+    ALOGV("AudioMixer::unprepareTrackForReformat(%d)", trackName);
+    if (pTrack->mReformatBufferProvider != NULL) {
+        delete pTrack->mReformatBufferProvider;
+        pTrack->mReformatBufferProvider = NULL;
+        reconfigureBufferProviders(pTrack);
+    }
+}
+
+status_t AudioMixer::prepareTrackForReformat(track_t* pTrack, int trackName)
+{
+    ALOGV("AudioMixer::prepareTrackForReformat(%d) with format %#x", trackName, pTrack->mFormat);
+    // discard the previous reformatter if there was one
+     unprepareTrackForReformat(pTrack, trackName);
+     pTrack->mReformatBufferProvider = new ReformatBufferProvider(
+             audio_channel_count_from_out_mask(pTrack->channelMask),
+             pTrack->mFormat, pTrack->mMixerInFormat);
+     reconfigureBufferProviders(pTrack);
+     return NO_ERROR;
+}
+
+void AudioMixer::reconfigureBufferProviders(track_t* pTrack)
+{
+    pTrack->bufferProvider = pTrack->mInputBufferProvider;
+    if (pTrack->mReformatBufferProvider) {
+        pTrack->mReformatBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
+        pTrack->bufferProvider = pTrack->mReformatBufferProvider;
+    }
+    if (pTrack->downmixerBufferProvider) {
+        pTrack->downmixerBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
+        pTrack->bufferProvider = pTrack->downmixerBufferProvider;
+    }
+}
+
 void AudioMixer::deleteTrackName(int name)
 {
     ALOGV("AudioMixer::deleteTrackName(%d)", name);
@@ -369,6 +504,8 @@
     track.resampler = NULL;
     // delete the downmixer
     unprepareTrackForDownmix(&mState.tracks[name], name);
+    // delete the reformatter
+    unprepareTrackForReformat(&mState.tracks[name], name);
 
     mTrackNames &= ~(1<<name);
 }
@@ -440,9 +577,20 @@
                 invalidateState(1 << name);
             }
             break;
-        case FORMAT:
-            ALOG_ASSERT(valueInt == AUDIO_FORMAT_PCM_16_BIT);
-            break;
+        case FORMAT: {
+            audio_format_t format = static_cast<audio_format_t>(valueInt);
+            if (track.mFormat != format) {
+                ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
+                track.mFormat = format;
+                ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
+                //if (track.mFormat != track.mMixerInFormat)
+                {
+                    ALOGD("Reformatting!");
+                    prepareTrackForReformat(&track, name);
+                }
+                invalidateState(1 << name);
+            }
+            } break;
         // FIXME do we want to support setting the downmix type from AudioFlinger?
         //         for a specific track? or per mixer?
         /* case DOWNMIX_TYPE:
@@ -555,8 +703,9 @@
                 } else {
                     quality = AudioResampler::DEFAULT_QUALITY;
                 }
+                const int bits = mMixerInFormat == AUDIO_FORMAT_PCM_16_BIT ? 16 : /* FLOAT */ 32;
                 resampler = AudioResampler::create(
-                        format,
+                        bits,
                         // the resampler sees the number of channels after the downmixer, if any
                         (int) (downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount),
                         devSampleRate, quality);
@@ -601,21 +750,13 @@
     name -= TRACK0;
     ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
 
-    if (mState.tracks[name].downmixerBufferProvider != NULL) {
-        // update required?
-        if (mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider != bufferProvider) {
-            ALOGV("AudioMixer::setBufferProvider(%p) for downmix", bufferProvider);
-            // setting the buffer provider for a track that gets downmixed consists in:
-            //  1/ setting the buffer provider to the "downmix / buffer provider" wrapper
-            //     so it's the one that gets called when the buffer provider is needed,
-            mState.tracks[name].bufferProvider = mState.tracks[name].downmixerBufferProvider;
-            //  2/ saving the buffer provider for the track so the wrapper can use it
-            //     when it downmixes.
-            mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider = bufferProvider;
-        }
-    } else {
-        mState.tracks[name].bufferProvider = bufferProvider;
+    if (mState.tracks[name].mReformatBufferProvider != NULL) {
+        mState.tracks[name].mReformatBufferProvider->reset();
+    } else if (mState.tracks[name].downmixerBufferProvider != NULL) {
     }
+
+    mState.tracks[name].mInputBufferProvider = bufferProvider;
+    reconfigureBufferProviders(&mState.tracks[name]);
 }
 
 
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 4a39f88..573ba96 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -126,7 +126,10 @@
     size_t      getUnreleasedFrames(int name) const;
 
     static inline bool isValidPcmTrackFormat(audio_format_t format) {
-        return format == AUDIO_FORMAT_PCM_16_BIT;
+        return format == AUDIO_FORMAT_PCM_16_BIT ||
+                format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
+                format == AUDIO_FORMAT_PCM_32_BIT ||
+                format == AUDIO_FORMAT_PCM_FLOAT;
     }
 
 private:
@@ -150,6 +153,7 @@
     struct state_t;
     struct track_t;
     class DownmixerBufferProvider;
+    class ReformatBufferProvider;
 
     typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp,
                            int32_t* aux);
@@ -177,7 +181,7 @@
         uint16_t    frameCount;
 
         uint8_t     channelCount;   // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
-        uint8_t     format;         // always 16
+        uint8_t     unused_padding; // formerly format, was always 16
         uint16_t    enabled;        // actually bool
         audio_channel_mask_t channelMask;
 
@@ -200,13 +204,19 @@
         int32_t*           auxBuffer;
 
         // 16-byte boundary
-
+        AudioBufferProvider*     mInputBufferProvider;    // 4 bytes
+        ReformatBufferProvider*  mReformatBufferProvider; // 4 bytes
         DownmixerBufferProvider* downmixerBufferProvider; // 4 bytes
 
         int32_t     sessionId;
 
+        // 16-byte boundary
         audio_format_t mMixerFormat;     // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
         audio_format_t mFormat;          // input track format
+        audio_format_t mMixerInFormat;   // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+                                         // each track must be converted to this format.
+
+        int32_t        mUnused[1];       // alignment padding
 
         // 16-byte boundary
 
@@ -245,6 +255,35 @@
         effect_config_t    mDownmixConfig;
     };
 
+    // AudioBufferProvider wrapper that reformats track to acceptable mixer input type
+    class ReformatBufferProvider : public AudioBufferProvider {
+    public:
+        ReformatBufferProvider(int32_t channels,
+                audio_format_t inputFormat, audio_format_t outputFormat);
+        virtual ~ReformatBufferProvider();
+
+        // overrides AudioBufferProvider methods
+        virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
+        virtual void releaseBuffer(Buffer* buffer);
+
+        void reset();
+        inline bool requiresInternalBuffers() {
+            return true; //mInputFrameSize < mOutputFrameSize;
+        }
+
+        AudioBufferProvider* mTrackBufferProvider;
+        int32_t              mChannels;
+        audio_format_t       mInputFormat;
+        audio_format_t       mOutputFormat;
+        size_t               mInputFrameSize;
+        size_t               mOutputFrameSize;
+        // (only) required for reformatting to a larger size.
+        AudioBufferProvider::Buffer mBuffer;
+        void*                mOutputData;
+        size_t               mOutputCount;
+        size_t               mConsumed;
+    };
+
     // bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc.
     uint32_t        mTrackNames;
 
@@ -272,6 +311,9 @@
     static status_t initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask);
     static status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
     static void unprepareTrackForDownmix(track_t* pTrack, int trackName);
+    static status_t prepareTrackForReformat(track_t* pTrack, int trackNum);
+    static void unprepareTrackForReformat(track_t* pTrack, int trackName);
+    static void reconfigureBufferProviders(track_t* pTrack);
 
     static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
             int32_t* aux);
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 3abe8fd..a4446a4 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -455,12 +455,13 @@
     const Constants& c(mConstants);
     const TC* const coefs = mConstants.mFirCoefs;
     TI* impulse = mInBuffer.getImpulse();
-    size_t inputIndex = mInputIndex;
+    size_t inputIndex = 0;
     uint32_t phaseFraction = mPhaseFraction;
     const uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;   // stereo output
-    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount) + (phaseFraction != 0);
+    ALOG_ASSERT(0 < inFrameCount && inFrameCount < (1U << 31));
     const uint32_t phaseWrapLimit = c.mL << c.mShift;
 
     // NOTE: be very careful when modifying the code here. register
@@ -474,11 +475,13 @@
         // buffer is empty, fetch a new one
         while (mBuffer.frameCount == 0) {
             mBuffer.frameCount = inFrameCount;
+            ALOG_ASSERT(inFrameCount > 0);
             provider->getNextBuffer(&mBuffer,
                     calculateOutputPTS(outputIndex / 2));
             if (mBuffer.raw == NULL) {
                 goto resample_exit;
             }
+            inFrameCount -= mBuffer.frameCount;
             if (phaseFraction >= phaseWrapLimit) { // read in data
                 mInBuffer.template readAdvance<CHANNELS>(
                         impulse, c.mHalfNumCoefs,
@@ -487,7 +490,7 @@
                 while (phaseFraction >= phaseWrapLimit) {
                     inputIndex++;
                     if (inputIndex >= mBuffer.frameCount) {
-                        inputIndex -= mBuffer.frameCount;
+                        inputIndex = 0;
                         provider->releaseBuffer(&mBuffer);
                         break;
                     }
@@ -535,15 +538,22 @@
 done:
         // often arrives here when input buffer runs out
         if (inputIndex >= frameCount) {
-            inputIndex -= frameCount;
+            inputIndex = 0;
             provider->releaseBuffer(&mBuffer);
-            // mBuffer.frameCount MUST be zero here.
+            ALOG_ASSERT(mBuffer.frameCount == 0);
         }
     }
 
 resample_exit:
+    // Release frames to avoid the count being inaccurate for pts timing.
+    // TODO: Avoid this extra check by making fetch count exact. This is tricky
+    // due to the overfetching mechanism which loads unnecessarily when
+    // mBuffer.frameCount == 0.
+    if (inputIndex) {
+        mBuffer.frameCount = inputIndex;
+        provider->releaseBuffer(&mBuffer);
+    }
     mInBuffer.setImpulse(impulse);
-    mInputIndex = inputIndex;
     mPhaseFraction = phaseFraction;
 }
 
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 7e15bef..c840418 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -52,8 +52,8 @@
     outputSink(NULL),
     outputSinkGen(0),
     mixer(NULL),
-    mixBuffer(NULL),
-    mixBufferState(UNDEFINED),
+    mMixerBuffer(NULL),
+    mMixerBufferState(UNDEFINED),
     format(Format_Invalid),
     sampleRate(0),
     fastTracksGen(0),
@@ -108,7 +108,7 @@
 void FastMixer::onExit()
 {
     delete mixer;
-    delete[] mixBuffer;
+    delete[] mMixerBuffer;
 }
 
 bool FastMixer::isSubClassCommand(FastThreadState::Command command)
@@ -154,14 +154,14 @@
         // FIXME to avoid priority inversion, don't delete here
         delete mixer;
         mixer = NULL;
-        delete[] mixBuffer;
-        mixBuffer = NULL;
+        delete[] mMixerBuffer;
+        mMixerBuffer = NULL;
         if (frameCount > 0 && sampleRate > 0) {
             // FIXME new may block for unbounded time at internal mutex of the heap
             //       implementation; it would be better to have normal mixer allocate for us
             //       to avoid blocking here and to prevent possible priority inversion
             mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
-            mixBuffer = new short[frameCount * FCC_2];
+            mMixerBuffer = new short[frameCount * FCC_2];
             periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
             underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
             overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
@@ -174,7 +174,7 @@
             forceNs = 0;
             warmupNs = 0;
         }
-        mixBufferState = UNDEFINED;
+        mMixerBufferState = UNDEFINED;
 #if !LOG_NDEBUG
         for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
             fastTrackNames[i] = -1;
@@ -192,7 +192,7 @@
     const unsigned currentTrackMask = current->mTrackMask;
     dumpState->mTrackMask = currentTrackMask;
     if (current->mFastTracksGen != fastTracksGen) {
-        ALOG_ASSERT(mixBuffer != NULL);
+        ALOG_ASSERT(mMixerBuffer != NULL);
         int name;
 
         // process removed tracks first to avoid running out of track names
@@ -229,8 +229,10 @@
                 fastTrackNames[i] = name;
                 mixer->setBufferProvider(name, bufferProvider);
                 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
-                        (void *) mixBuffer);
+                        (void *) mMixerBuffer);
                 // newly allocated track names default to full scale volume
+                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+                        (void *)(uintptr_t)fastTrack->mFormat);
                 mixer->enable(name);
             }
             generations[i] = fastTrack->mGeneration;
@@ -259,6 +261,8 @@
                     }
                     mixer->setParameter(name, AudioMixer::RESAMPLE,
                             AudioMixer::REMOVE, NULL);
+                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+                            (void *)(uintptr_t)fastTrack->mFormat);
                     mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
                             (void *)(uintptr_t) fastTrack->mChannelMask);
                     // already enabled
@@ -281,7 +285,7 @@
     const size_t frameCount = current->mFrameCount;
 
     if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) {
-        ALOG_ASSERT(mixBuffer != NULL);
+        ALOG_ASSERT(mMixerBuffer != NULL);
         // for each track, update volume and check for underrun
         unsigned currentTrackMask = current->mTrackMask;
         while (currentTrackMask != 0) {
@@ -358,26 +362,26 @@
 
         // process() is CPU-bound
         mixer->process(pts);
-        mixBufferState = MIXED;
-    } else if (mixBufferState == MIXED) {
-        mixBufferState = UNDEFINED;
+        mMixerBufferState = MIXED;
+    } else if (mMixerBufferState == MIXED) {
+        mMixerBufferState = UNDEFINED;
     }
     //bool didFullWrite = false;    // dumpsys could display a count of partial writes
-    if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) {
-        if (mixBufferState == UNDEFINED) {
-            memset(mixBuffer, 0, frameCount * FCC_2 * sizeof(short));
-            mixBufferState = ZEROED;
+    if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mMixerBuffer != NULL)) {
+        if (mMixerBufferState == UNDEFINED) {
+            memset(mMixerBuffer, 0, frameCount * FCC_2 * sizeof(short));
+            mMixerBufferState = ZEROED;
         }
         // if non-NULL, then duplicate write() to this non-blocking sink
         NBAIO_Sink* teeSink;
         if ((teeSink = current->mTeeSink) != NULL) {
-            (void) teeSink->write(mixBuffer, frameCount);
+            (void) teeSink->write(mMixerBuffer, frameCount);
         }
         // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
         //       but this code should be modified to handle both non-blocking and blocking sinks
         dumpState->mWriteSequence++;
         ATRACE_BEGIN("write");
-        ssize_t framesWritten = outputSink->write(mixBuffer, frameCount);
+        ssize_t framesWritten = outputSink->write(mMixerBuffer, frameCount);
         ATRACE_END();
         dumpState->mWriteSequence++;
         if (framesWritten >= 0) {
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index db89ef4..db3e2c9 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -61,8 +61,8 @@
     NBAIO_Sink *outputSink;
     int outputSinkGen;
     AudioMixer* mixer;
-    short *mixBuffer;
-    enum {UNDEFINED, MIXED, ZEROED} mixBufferState;
+    short *mMixerBuffer;
+    enum {UNDEFINED, MIXED, ZEROED} mMixerBufferState;
     NBAIO_Format format;
     unsigned sampleRate;
     int fastTracksGen;
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
new file mode 100644
index 0000000..eee74b3
--- /dev/null
+++ b/services/audioflinger/PatchPanel.cpp
@@ -0,0 +1,409 @@
+/*
+**
+** Copyright 2014, 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 "AudioFlinger::PatchPanel"
+//#define LOG_NDEBUG 0
+
+#include "Configuration.h"
+#include <utils/Log.h>
+#include <audio_utils/primitives.h>
+
+#include "AudioFlinger.h"
+#include "ServiceUtilities.h"
+#include <media/AudioParameter.h>
+
+// ----------------------------------------------------------------------------
+
+// Note: the following macro is used for extremely verbose logging message.  In
+// order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to
+// 0; but one side effect of this is to turn all LOGV's as well.  Some messages
+// are so verbose that we want to suppress them even when we have ALOG_ASSERT
+// turned on.  Do not uncomment the #def below unless you really know what you
+// are doing and want to see all of the extremely verbose messages.
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+namespace android {
+
+/* List connected audio ports and their attributes */
+status_t AudioFlinger::listAudioPorts(unsigned int *num_ports,
+                                struct audio_port *ports)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPatchPanel != 0) {
+        return mPatchPanel->listAudioPorts(num_ports, ports);
+    }
+    return NO_INIT;
+}
+
+/* Get supported attributes for a given audio port */
+status_t AudioFlinger::getAudioPort(struct audio_port *port)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPatchPanel != 0) {
+        return mPatchPanel->getAudioPort(port);
+    }
+    return NO_INIT;
+}
+
+
+/* Connect a patch between several source and sink ports */
+status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch,
+                                   audio_patch_handle_t *handle)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPatchPanel != 0) {
+        return mPatchPanel->createAudioPatch(patch, handle);
+    }
+    return NO_INIT;
+}
+
+/* Disconnect a patch */
+status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPatchPanel != 0) {
+        return mPatchPanel->releaseAudioPatch(handle);
+    }
+    return NO_INIT;
+}
+
+
+/* List connected audio ports and they attributes */
+status_t AudioFlinger::listAudioPatches(unsigned int *num_patches,
+                                  struct audio_patch *patches)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPatchPanel != 0) {
+        return mPatchPanel->listAudioPatches(num_patches, patches);
+    }
+    return NO_INIT;
+}
+
+/* Set audio port configuration */
+status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPatchPanel != 0) {
+        return mPatchPanel->setAudioPortConfig(config);
+    }
+    return NO_INIT;
+}
+
+
+AudioFlinger::PatchPanel::PatchPanel(const sp<AudioFlinger>& audioFlinger)
+                                   : mAudioFlinger(audioFlinger)
+{
+}
+
+AudioFlinger::PatchPanel::~PatchPanel()
+{
+}
+
+/* List connected audio ports and their attributes */
+status_t AudioFlinger::PatchPanel::listAudioPorts(unsigned int *num_ports __unused,
+                                struct audio_port *ports __unused)
+{
+    ALOGV("listAudioPorts");
+    return NO_ERROR;
+}
+
+/* Get supported attributes for a given audio port */
+status_t AudioFlinger::PatchPanel::getAudioPort(struct audio_port *port __unused)
+{
+    ALOGV("getAudioPort");
+    return NO_ERROR;
+}
+
+
+/* Connect a patch between several source and sink ports */
+status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch,
+                                   audio_patch_handle_t *handle)
+{
+    ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d",
+          patch->num_sources, patch->num_sinks, *handle);
+    status_t status = NO_ERROR;
+
+    audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
+
+    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
+    if (audioflinger == 0) {
+        return NO_INIT;
+    }
+    if (handle == NULL || patch == NULL) {
+        return BAD_VALUE;
+    }
+    // limit number of sources to 1 for now
+    if (patch->num_sources == 0 || patch->num_sources > 1 ||
+            patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
+        return BAD_VALUE;
+    }
+
+    for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) {
+        if (*handle == mPatches[index]->mHandle) {
+            ALOGV("createAudioPatch() removing patch handle %d", *handle);
+            halHandle = mPatches[index]->mHalHandle;
+            mPatches.removeAt(index);
+            break;
+        }
+    }
+
+    switch (patch->sources[0].type) {
+        case AUDIO_PORT_TYPE_DEVICE: {
+            // limit number of sinks to 1 for now
+            if (patch->num_sinks > 1) {
+                return BAD_VALUE;
+            }
+            audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module;
+            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+            if (index < 0) {
+                ALOGW("createAudioPatch() bad src hw module %d", src_module);
+                return BAD_VALUE;
+            }
+            for (unsigned int i = 0; i < patch->num_sinks; i++) {
+                // limit to connections between devices and output streams
+                if (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX) {
+                    ALOGW("createAudioPatch() invalid sink type %d for device source",
+                          patch->sinks[i].type);
+                    return BAD_VALUE;
+                }
+                // limit to connections between sinks and sources on same HW module
+                if (patch->sinks[i].ext.mix.hw_module != src_module) {
+                    ALOGW("createAudioPatch() cannot connect source on module %d to"
+                            "sink on module %d", src_module, patch->sinks[i].ext.mix.hw_module);
+                    return BAD_VALUE;
+                }
+            }
+
+            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+            if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+                if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
+                    sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+                                                                    patch->sinks[0].ext.mix.handle);
+                    if (thread == 0) {
+                        ALOGW("createAudioPatch() bad capture I/O handle %d",
+                                                                  patch->sinks[0].ext.mix.handle);
+                        return BAD_VALUE;
+                    }
+                    status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+                } else {
+                    audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
+                    status = hwDevice->create_audio_patch(hwDevice,
+                                                           patch->num_sources,
+                                                           patch->sources,
+                                                           patch->num_sinks,
+                                                           patch->sinks,
+                                                           &halHandle);
+                }
+            } else {
+                sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+                                                                    patch->sinks[0].ext.mix.handle);
+                if (thread == 0) {
+                    ALOGW("createAudioPatch() bad capture I/O handle %d",
+                                                                  patch->sinks[0].ext.mix.handle);
+                    return BAD_VALUE;
+                }
+                AudioParameter param;
+                param.addInt(String8(AudioParameter::keyRouting),
+                             (int)patch->sources[0].ext.device.type);
+                param.addInt(String8(AudioParameter::keyInputSource),
+                                                     (int)patch->sinks[0].ext.mix.usecase.source);
+
+                ALOGW("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
+                                                                      param.toString().string());
+                status = thread->setParameters(param.toString());
+            }
+        } break;
+        case AUDIO_PORT_TYPE_MIX: {
+            audio_module_handle_t src_module =  patch->sources[0].ext.mix.hw_module;
+            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+            if (index < 0) {
+                ALOGW("createAudioPatch() bad src hw module %d", src_module);
+                return BAD_VALUE;
+            }
+            // limit to connections between devices and output streams
+            for (unsigned int i = 0; i < patch->num_sinks; i++) {
+                if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
+                    ALOGW("createAudioPatch() invalid sink type %d for bus source",
+                          patch->sinks[i].type);
+                    return BAD_VALUE;
+                }
+                // limit to connections between sinks and sources on same HW module
+                if (patch->sinks[i].ext.device.hw_module != src_module) {
+                    return BAD_VALUE;
+                }
+            }
+            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+            sp<ThreadBase> thread =
+                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
+            if (thread == 0) {
+                ALOGW("createAudioPatch() bad playback I/O handle %d",
+                          patch->sources[0].ext.mix.handle);
+                return BAD_VALUE;
+            }
+            if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+                status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+            } else {
+                audio_devices_t type = AUDIO_DEVICE_NONE;
+                for (unsigned int i = 0; i < patch->num_sinks; i++) {
+                    type |= patch->sinks[i].ext.device.type;
+                }
+                AudioParameter param;
+                param.addInt(String8(AudioParameter::keyRouting), (int)type);
+                status = thread->setParameters(param.toString());
+            }
+
+        } break;
+        default:
+            return BAD_VALUE;
+    }
+    ALOGV("createAudioPatch() status %d", status);
+    if (status == NO_ERROR) {
+        *handle = audioflinger->nextUniqueId();
+        Patch *newPatch = new Patch(patch);
+        newPatch->mHandle = *handle;
+        newPatch->mHalHandle = halHandle;
+        mPatches.add(newPatch);
+        ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
+    }
+    return status;
+}
+
+/* Disconnect a patch */
+status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
+{
+    ALOGV("releaseAudioPatch handle %d", handle);
+    status_t status = NO_ERROR;
+    size_t index;
+
+    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
+    if (audioflinger == 0) {
+        return NO_INIT;
+    }
+
+    for (index = 0; index < mPatches.size(); index++) {
+        if (handle == mPatches[index]->mHandle) {
+            break;
+        }
+    }
+    if (index == mPatches.size()) {
+        return BAD_VALUE;
+    }
+
+    struct audio_patch *patch = &mPatches[index]->mAudioPatch;
+
+    switch (patch->sources[0].type) {
+        case AUDIO_PORT_TYPE_DEVICE: {
+            audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module;
+            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+            if (index < 0) {
+                ALOGW("releaseAudioPatch() bad src hw module %d", src_module);
+                status = BAD_VALUE;
+                break;
+            }
+            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+            if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+                if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
+                    sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+                                                                    patch->sinks[0].ext.mix.handle);
+                    if (thread == 0) {
+                        ALOGW("createAudioPatch() bad capture I/O handle %d",
+                                                                  patch->sinks[0].ext.mix.handle);
+                        status = BAD_VALUE;
+                        break;
+                    }
+                    status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle);
+                } else {
+                    audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
+                    status = hwDevice->release_audio_patch(hwDevice, mPatches[index]->mHalHandle);
+                }
+            } else {
+                sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+                                                                    patch->sinks[0].ext.mix.handle);
+                if (thread == 0) {
+                    ALOGW("releaseAudioPatch() bad capture I/O handle %d",
+                                                                  patch->sinks[0].ext.mix.handle);
+                    status = BAD_VALUE;
+                    break;
+                }
+                AudioParameter param;
+                param.addInt(String8(AudioParameter::keyRouting), 0);
+                ALOGW("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
+                                                                      param.toString().string());
+                status = thread->setParameters(param.toString());
+            }
+        } break;
+        case AUDIO_PORT_TYPE_MIX: {
+            audio_module_handle_t src_module =  patch->sources[0].ext.mix.hw_module;
+            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+            if (index < 0) {
+                ALOGW("releaseAudioPatch() bad src hw module %d", src_module);
+                status = BAD_VALUE;
+                break;
+            }
+            sp<ThreadBase> thread =
+                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
+            if (thread == 0) {
+                ALOGW("releaseAudioPatch() bad playback I/O handle %d",
+                                                              patch->sources[0].ext.mix.handle);
+                status = BAD_VALUE;
+                break;
+            }
+            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+            if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+                status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle);
+            } else {
+                AudioParameter param;
+                param.addInt(String8(AudioParameter::keyRouting), (int)0);
+                status = thread->setParameters(param.toString());
+            }
+        } break;
+        default:
+            status = BAD_VALUE;
+            break;
+    }
+
+    delete (mPatches[index]);
+    mPatches.removeAt(index);
+    return status;
+}
+
+
+/* List connected audio ports and they attributes */
+status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
+                                  struct audio_patch *patches __unused)
+{
+    ALOGV("listAudioPatches");
+    return NO_ERROR;
+}
+
+/* Set audio port configuration */
+status_t AudioFlinger::PatchPanel::setAudioPortConfig(
+        const struct audio_port_config *config __unused)
+{
+    ALOGV("setAudioPortConfig");
+    return NO_ERROR;
+}
+
+
+
+}; // namespace android
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
new file mode 100644
index 0000000..7f78621
--- /dev/null
+++ b/services/audioflinger/PatchPanel.h
@@ -0,0 +1,60 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef INCLUDING_FROM_AUDIOFLINGER_H
+    #error This header file should only be included from AudioFlinger.h
+#endif
+
+class PatchPanel : public RefBase {
+public:
+    PatchPanel(const sp<AudioFlinger>& audioFlinger);
+    virtual ~PatchPanel();
+
+    /* List connected audio ports and their attributes */
+    status_t listAudioPorts(unsigned int *num_ports,
+                                    struct audio_port *ports);
+
+    /* Get supported attributes for a given audio port */
+    status_t getAudioPort(struct audio_port *port);
+
+    /* Create a patch between several source and sink ports */
+    status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle);
+
+    /* Release a patch */
+    status_t releaseAudioPatch(audio_patch_handle_t handle);
+
+    /* List connected audio devices and they attributes */
+    status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches);
+
+    /* Set audio port configuration */
+    status_t setAudioPortConfig(const struct audio_port_config *config);
+
+    class Patch {
+    public:
+        Patch(const struct audio_patch *patch) :
+            mAudioPatch(*patch), mHandle(0), mHalHandle(0) {}
+
+        struct audio_patch mAudioPatch;
+        audio_patch_handle_t mHandle;
+        audio_patch_handle_t mHalHandle;
+    };
+private:
+    const wp<AudioFlinger>  mAudioFlinger;
+    SortedVector <Patch *> mPatches;
+};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 7843387..576350e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -142,8 +142,17 @@
 // FIXME It would be better for client to tell AudioFlinger the value of N,
 // so AudioFlinger could allocate the right amount of memory.
 // See the client's minBufCount and mNotificationFramesAct calculations for details.
+
+// This is the default value, if not specified by property.
 static const int kFastTrackMultiplier = 2;
 
+// The minimum and maximum allowed values
+static const int kFastTrackMultiplierMin = 1;
+static const int kFastTrackMultiplierMax = 2;
+
+// The actual value to use, which can be specified per-device via property af.fast_track_multiplier.
+static int sFastTrackMultiplier = kFastTrackMultiplier;
+
 // See Thread::readOnlyHeap().
 // Initially this heap is used to allocate client buffers for "fast" AudioRecord.
 // Eventually it will be the single buffer that FastCapture writes into via HAL read(),
@@ -152,6 +161,22 @@
 
 // ----------------------------------------------------------------------------
 
+static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT;
+
+static void sFastTrackMultiplierInit()
+{
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("af.fast_track_multiplier", value, NULL) > 0) {
+        char *endptr;
+        unsigned long ul = strtoul(value, &endptr, 0);
+        if (*endptr == '\0' && kFastTrackMultiplierMin <= ul && ul <= kFastTrackMultiplierMax) {
+            sFastTrackMultiplier = (int) ul;
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+
 #ifdef ADD_BATTERY_DATA
 // To collect the amplifier usage
 static void addBatteryData(uint32_t params) {
@@ -401,6 +426,30 @@
     return sendConfigEvent_l(configEvent);
 }
 
+status_t AudioFlinger::ThreadBase::sendCreateAudioPatchConfigEvent(
+                                                        const struct audio_patch *patch,
+                                                        audio_patch_handle_t *handle)
+{
+    Mutex::Autolock _l(mLock);
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new CreateAudioPatchConfigEvent(*patch, *handle);
+    status_t status = sendConfigEvent_l(configEvent);
+    if (status == NO_ERROR) {
+        CreateAudioPatchConfigEventData *data =
+                                        (CreateAudioPatchConfigEventData *)configEvent->mData.get();
+        *handle = data->mHandle;
+    }
+    return status;
+}
+
+status_t AudioFlinger::ThreadBase::sendReleaseAudioPatchConfigEvent(
+                                                                const audio_patch_handle_t handle)
+{
+    Mutex::Autolock _l(mLock);
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new ReleaseAudioPatchConfigEvent(handle);
+    return sendConfigEvent_l(configEvent);
+}
+
+
 // post condition: mConfigEvents.isEmpty()
 void AudioFlinger::ThreadBase::processConfigEvents_l()
 {
@@ -431,6 +480,16 @@
                 configChanged = true;
             }
         } break;
+        case CFG_EVENT_CREATE_AUDIO_PATCH: {
+            CreateAudioPatchConfigEventData *data =
+                                            (CreateAudioPatchConfigEventData *)event->mData.get();
+            event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
+        } break;
+        case CFG_EVENT_RELEASE_AUDIO_PATCH: {
+            ReleaseAudioPatchConfigEventData *data =
+                                            (ReleaseAudioPatchConfigEventData *)event->mData.get();
+            event->mStatus = releaseAudioPatch_l(data->mHandle);
+        } break;
         default:
             ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
             break;
@@ -1321,7 +1380,12 @@
         ) {
         // if frameCount not specified, then it defaults to fast mixer (HAL) frame count
         if (frameCount == 0) {
-            frameCount = mFrameCount * kFastTrackMultiplier;
+            // read the fast track multiplier property the first time it is needed
+            int ok = pthread_once(&sFastTrackMultiplierOnce, sFastTrackMultiplierInit);
+            if (ok != 0) {
+                ALOGE("%s pthread_once failed: %d", __func__, ok);
+            }
+            frameCount = mFrameCount * sFastTrackMultiplier;
         }
         ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
                 frameCount, mFrameCount);
@@ -2593,6 +2657,47 @@
     }
     return INVALID_OPERATION;
 }
+
+status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_patch *patch,
+                                                          audio_patch_handle_t *handle)
+{
+    status_t status = NO_ERROR;
+    if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        // store new device and send to effects
+        audio_devices_t type = AUDIO_DEVICE_NONE;
+        for (unsigned int i = 0; i < patch->num_sinks; i++) {
+            type |= patch->sinks[i].ext.device.type;
+        }
+        mOutDevice = type;
+        for (size_t i = 0; i < mEffectChains.size(); i++) {
+            mEffectChains[i]->setDevice_l(mOutDevice);
+        }
+
+        audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice();
+        status = hwDevice->create_audio_patch(hwDevice,
+                                               patch->num_sources,
+                                               patch->sources,
+                                               patch->num_sinks,
+                                               patch->sinks,
+                                               handle);
+    } else {
+        ALOG_ASSERT(false, "createAudioPatch_l() called on a pre 3.0 HAL");
+    }
+    return status;
+}
+
+status_t AudioFlinger::PlaybackThread::releaseAudioPatch_l(const audio_patch_handle_t handle)
+{
+    status_t status = NO_ERROR;
+    if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice();
+        status = hwDevice->release_audio_patch(hwDevice, handle);
+    } else {
+        ALOG_ASSERT(false, "releaseAudioPatch_l() called on a pre 3.0 HAL");
+    }
+    return status;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
@@ -5748,4 +5853,61 @@
     return 0;
 }
 
+status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch *patch,
+                                                          audio_patch_handle_t *handle)
+{
+    status_t status = NO_ERROR;
+    if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        // store new device and send to effects
+        mInDevice = patch->sources[0].ext.device.type;
+        for (size_t i = 0; i < mEffectChains.size(); i++) {
+            mEffectChains[i]->setDevice_l(mInDevice);
+        }
+
+        // disable AEC and NS if the device is a BT SCO headset supporting those
+        // pre processings
+        if (mTracks.size() > 0) {
+            bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+                                mAudioFlinger->btNrecIsOff();
+            for (size_t i = 0; i < mTracks.size(); i++) {
+                sp<RecordTrack> track = mTracks[i];
+                setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
+                setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
+            }
+        }
+
+        // store new source and send to effects
+        if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) {
+            mAudioSource = patch->sinks[0].ext.mix.usecase.source;
+            for (size_t i = 0; i < mEffectChains.size(); i++) {
+                mEffectChains[i]->setAudioSource_l(mAudioSource);
+            }
+        }
+
+        audio_hw_device_t *hwDevice = mInput->audioHwDev->hwDevice();
+        status = hwDevice->create_audio_patch(hwDevice,
+                                               patch->num_sources,
+                                               patch->sources,
+                                               patch->num_sinks,
+                                               patch->sinks,
+                                               handle);
+    } else {
+        ALOG_ASSERT(false, "createAudioPatch_l() called on a pre 3.0 HAL");
+    }
+    return status;
+}
+
+status_t AudioFlinger::RecordThread::releaseAudioPatch_l(const audio_patch_handle_t handle)
+{
+    status_t status = NO_ERROR;
+    if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        audio_hw_device_t *hwDevice = mInput->audioHwDev->hwDevice();
+        status = hwDevice->release_audio_patch(hwDevice, handle);
+    } else {
+        ALOG_ASSERT(false, "releaseAudioPatch_l() called on a pre 3.0 HAL");
+    }
+    return status;
+}
+
+
 }; // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 44008e5..8c9943c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -48,6 +48,8 @@
         CFG_EVENT_IO,
         CFG_EVENT_PRIO,
         CFG_EVENT_SET_PARAMETER,
+        CFG_EVENT_CREATE_AUDIO_PATCH,
+        CFG_EVENT_RELEASE_AUDIO_PATCH,
     };
 
     class ConfigEventData: public RefBase {
@@ -161,6 +163,52 @@
         virtual ~SetParameterConfigEvent() {}
     };
 
+    class CreateAudioPatchConfigEventData : public ConfigEventData {
+    public:
+        CreateAudioPatchConfigEventData(const struct audio_patch patch,
+                                        audio_patch_handle_t handle) :
+            mPatch(patch), mHandle(handle) {}
+
+        virtual  void dump(char *buffer, size_t size) {
+            snprintf(buffer, size, "Patch handle: %u\n", mHandle);
+        }
+
+        const struct audio_patch mPatch;
+        audio_patch_handle_t mHandle;
+    };
+
+    class CreateAudioPatchConfigEvent : public ConfigEvent {
+    public:
+        CreateAudioPatchConfigEvent(const struct audio_patch patch,
+                                    audio_patch_handle_t handle) :
+            ConfigEvent(CFG_EVENT_CREATE_AUDIO_PATCH) {
+            mData = new CreateAudioPatchConfigEventData(patch, handle);
+            mWaitStatus = true;
+        }
+        virtual ~CreateAudioPatchConfigEvent() {}
+    };
+
+    class ReleaseAudioPatchConfigEventData : public ConfigEventData {
+    public:
+        ReleaseAudioPatchConfigEventData(const audio_patch_handle_t handle) :
+            mHandle(handle) {}
+
+        virtual  void dump(char *buffer, size_t size) {
+            snprintf(buffer, size, "Patch handle: %u\n", mHandle);
+        }
+
+        audio_patch_handle_t mHandle;
+    };
+
+    class ReleaseAudioPatchConfigEvent : public ConfigEvent {
+    public:
+        ReleaseAudioPatchConfigEvent(const audio_patch_handle_t handle) :
+            ConfigEvent(CFG_EVENT_RELEASE_AUDIO_PATCH) {
+            mData = new ReleaseAudioPatchConfigEventData(handle);
+            mWaitStatus = true;
+        }
+        virtual ~ReleaseAudioPatchConfigEvent() {}
+    };
 
     class PMDeathRecipient : public IBinder::DeathRecipient {
     public:
@@ -209,8 +257,15 @@
                 void        sendIoConfigEvent_l(int event, int param = 0);
                 void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
                 status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair);
+                status_t    sendCreateAudioPatchConfigEvent(const struct audio_patch *patch,
+                                                            audio_patch_handle_t *handle);
+                status_t    sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle);
                 void        processConfigEvents_l();
     virtual     void        cacheParameters_l() = 0;
+    virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
+                                               audio_patch_handle_t *handle) = 0;
+    virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
+
 
                 // see note at declaration of mStandby, mOutDevice and mInDevice
                 bool        standby() const { return mStandby; }
@@ -644,6 +699,10 @@
 
     virtual     uint32_t    correctLatency_l(uint32_t latency) const;
 
+    virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
+                                   audio_patch_handle_t *handle);
+    virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
+
 private:
 
     friend class AudioFlinger;      // for numerous
@@ -1035,6 +1094,9 @@
     virtual void        cacheParameters_l() {}
     virtual String8     getParameters(const String8& keys);
     virtual void        audioConfigChanged(int event, int param = 0);
+    virtual status_t    createAudioPatch_l(const struct audio_patch *patch,
+                                           audio_patch_handle_t *handle);
+    virtual status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
             void        readInputParameters_l();
     virtual uint32_t    getInputFramesLost();
 
diff --git a/services/audiopolicy/AudioPolicyClientImpl.cpp b/services/audiopolicy/AudioPolicyClientImpl.cpp
index 44c47c3..8225e36 100644
--- a/services/audiopolicy/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/AudioPolicyClientImpl.cpp
@@ -182,6 +182,17 @@
     return af->moveEffects(session, src_output, dst_output);
 }
 
+status_t AudioPolicyService::AudioPolicyClient::createAudioPatch(const struct audio_patch *patch,
+                                                                  audio_patch_handle_t *handle,
+                                                                  int delayMs)
+{
+    return mAudioPolicyService->clientCreateAudioPatch(patch, handle, delayMs);
+}
 
+status_t AudioPolicyService::AudioPolicyClient::releaseAudioPatch(audio_patch_handle_t handle,
+                                                                  int delayMs)
+{
+    return mAudioPolicyService->clientReleaseAudioPatch(handle, delayMs);
+}
 
 }; // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 66260e3..bb2deb6 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -246,6 +246,15 @@
                                      audio_io_handle_t srcOutput,
                                      audio_io_handle_t dstOutput) = 0;
 
+    /* Create a patch between several source and sink ports */
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle,
+                                       int delayMs) = 0;
+
+    /* Release a patch */
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
+                                       int delayMs) = 0;
+
 };
 
 extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
index c57c4fa..7cd253b 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -463,5 +463,43 @@
     return mAudioPolicyManager->isOffloadSupported(info);
 }
 
+status_t AudioPolicyService::listAudioPorts(audio_port_role_t role __unused,
+                                            audio_port_type_t type __unused,
+                                            unsigned int *num_ports,
+                                            struct audio_port *ports __unused,
+                                            unsigned int *generation __unused)
+{
+    *num_ports = 0;
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getAudioPort(struct audio_port *port __unused)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::createAudioPatch(const struct audio_patch *patch __unused,
+        audio_patch_handle_t *handle __unused)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::releaseAudioPatch(audio_patch_handle_t handle __unused)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::listAudioPatches(unsigned int *num_patches,
+        struct audio_patch *patches __unused,
+        unsigned int *generation __unused)
+{
+    *num_patches = 0;
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::setAudioPortConfig(const struct audio_port_config *config __unused)
+{
+    return INVALID_OPERATION;
+}
 
 }; // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
index bb62ab3..0bf4982 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
@@ -485,5 +485,43 @@
     return mpAudioPolicy->is_offload_supported(mpAudioPolicy, &info);
 }
 
+status_t AudioPolicyService::listAudioPorts(audio_port_role_t role __unused,
+                                            audio_port_type_t type __unused,
+                                            unsigned int *num_ports,
+                                            struct audio_port *ports __unused,
+                                            unsigned int *generation __unused)
+{
+    *num_ports = 0;
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getAudioPort(struct audio_port *port __unused)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::createAudioPatch(const struct audio_patch *patch __unused,
+        audio_patch_handle_t *handle __unused)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::releaseAudioPatch(audio_patch_handle_t handle __unused)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::listAudioPatches(unsigned int *num_patches,
+        struct audio_patch *patches __unused,
+        unsigned int *generation __unused)
+{
+    *num_patches = 0;
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::setAudioPortConfig(const struct audio_port_config *config __unused)
+{
+    return INVALID_OPERATION;
+}
 
 }; // namespace android
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index bd9b15a..db0f57d 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -100,6 +100,7 @@
     STRING_TO_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_LINE),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_SPDIF),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
 };
 
 const StringToEnum sFlagNameToEnumTable[] = {
@@ -267,7 +268,7 @@
             // also force a device 0 for the two outputs it is duplicated to which may override
             // a valid device selection on those outputs.
             setOutputDevice(mOutputs.keyAt(i),
-                            getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+                            getNewOutputDevice(mOutputs.keyAt(i), true /*fromCache*/),
                             !mOutputs.valueAt(i)->isDuplicated(),
                             0);
         }
@@ -419,7 +420,7 @@
     }
 
     // check for device and output changes triggered by new phone state
-    newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+    newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
     checkA2dpSuspend();
     checkOutputForAllStrategies();
     updateDevicesAndOutputs();
@@ -544,7 +545,7 @@
     updateDevicesAndOutputs();
     for (size_t i = 0; i < mOutputs.size(); i++) {
         audio_io_handle_t output = mOutputs.keyAt(i);
-        audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+        audio_devices_t newDevice = getNewOutputDevice(output, true /*fromCache*/);
         setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
         if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
             applyStreamVolumes(output, newDevice, 0, true);
@@ -553,16 +554,7 @@
 
     audio_io_handle_t activeInput = getActiveInput();
     if (activeInput != 0) {
-        AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
-        audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
-        if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
-            ALOGV("setForceUse() changing device from %x to %x for input %d",
-                    inputDesc->mDevice, newDevice, activeInput);
-            inputDesc->mDevice = newDevice;
-            AudioParameter param = AudioParameter();
-            param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
-            mpClientInterface->setParameters(activeInput, param.toString());
-        }
+        setInputDevice(activeInput, getNewInputDevice(activeInput));
     }
 
 }
@@ -579,7 +571,7 @@
 
 // Find a direct output profile compatible with the parameters passed, even if the input flags do
 // not explicitly request a direct output
-AudioPolicyManager::IOProfile *AudioPolicyManager::getProfileForDirectOutput(
+sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getProfileForDirectOutput(
                                                                audio_devices_t device,
                                                                uint32_t samplingRate,
                                                                audio_format_t format,
@@ -591,7 +583,7 @@
             continue;
         }
         for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
-            IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+            sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
             bool found = false;
             if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                 if (profile->isCompatibleProfile(device, samplingRate, format,
@@ -676,7 +668,7 @@
     // 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.
-    IOProfile *profile = NULL;
+    sp<IOProfile> profile;
     if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
             !isNonOffloadableEffectEnabled()) {
         profile = getProfileForDirectOutput(device,
@@ -686,7 +678,7 @@
                                            (audio_output_flags_t)flags);
     }
 
-    if (profile != NULL) {
+    if (profile != 0) {
         AudioOutputDescriptor *outputDesc = NULL;
 
         for (size_t i = 0; i < mOutputs.size(); i++) {
@@ -705,7 +697,7 @@
         }
         // close direct output if currently open and configured with different parameters
         if (outputDesc != NULL) {
-            closeOutput(outputDesc->mId);
+            closeOutput(outputDesc->mIoHandle);
         }
         outputDesc = new AudioOutputDescriptor(profile);
         outputDesc->mDevice = device;
@@ -837,7 +829,7 @@
     outputDesc->changeRefCount(stream, 1);
 
     if (outputDesc->mRefCount[stream] == 1) {
-        audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+        audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
         routing_strategy strategy = getStrategy(stream);
         bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
                             (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
@@ -910,7 +902,7 @@
         // store time at which the stream was stopped - see isStreamActive()
         if (outputDesc->mRefCount[stream] == 0) {
             outputDesc->mStopTime[stream] = systemTime();
-            audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+            audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
             // delay the device switch by twice the latency because stopOutput() is executed when
             // the track stop() command is received and at that time the audio track buffer can
             // still contain data that needs to be drained. The latency only covers the audio HAL
@@ -928,7 +920,7 @@
                         outputDesc->sharesHwModuleWith(desc) &&
                         (newDevice != desc->device())) {
                     setOutputDevice(curOutput,
-                                    getNewDevice(curOutput, false /*fromCache*/),
+                                    getNewOutputDevice(curOutput, false /*fromCache*/),
                                     true,
                                     outputDesc->mLatency*2);
                 }
@@ -1018,11 +1010,11 @@
         break;
     }
 
-    IOProfile *profile = getInputProfile(device,
+    sp<IOProfile> profile = getInputProfile(device,
                                          samplingRate,
                                          format,
                                          channelMask);
-    if (profile == NULL) {
+    if (profile == 0) {
         ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d, "
                 "channelMask %04x",
                 device, samplingRate, format, channelMask);
@@ -1095,10 +1087,7 @@
         }
     }
 
-    audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
-    if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
-        inputDesc->mDevice = newDevice;
-    }
+    setInputDevice(input, getNewInputDevice(input), true /* force */);
 
     // automatically enable the remote submix output when input is started
     if (audio_is_remote_submix_device(inputDesc->mDevice)) {
@@ -1106,17 +1095,8 @@
                 AUDIO_POLICY_DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
     }
 
-    AudioParameter param = AudioParameter();
-    param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
-
-    int aliasSource = (inputDesc->mInputSource == AUDIO_SOURCE_HOTWORD) ?
-                                        AUDIO_SOURCE_VOICE_RECOGNITION : inputDesc->mInputSource;
-
-    param.addInt(String8(AudioParameter::keyInputSource), aliasSource);
     ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
 
-    mpClientInterface->setParameters(input, param.toString());
-
     inputDesc->mRefCount = 1;
     return NO_ERROR;
 }
@@ -1141,9 +1121,7 @@
                     AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
         }
 
-        AudioParameter param = AudioParameter();
-        param.addInt(String8(AudioParameter::keyRouting), 0);
-        mpClientInterface->setParameters(input, param.toString());
+        resetInputDevice(input);
         inputDesc->mRefCount = 0;
         return NO_ERROR;
     }
@@ -1608,13 +1586,13 @@
 
     // See if there is a profile to support this.
     // AUDIO_DEVICE_NONE
-    IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
+    sp<IOProfile> profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
                                             offloadInfo.sample_rate,
                                             offloadInfo.format,
                                             offloadInfo.channel_mask,
                                             AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
-    ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT ");
-    return (profile != NULL);
+    ALOGV("isOffloadSupported() profile %sfound", profile != 0 ? "" : "NOT ");
+    return (profile != 0);
 }
 
 // ----------------------------------------------------------------------------
@@ -1671,7 +1649,7 @@
         // This also validates mAvailableOutputDevices list
         for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
         {
-            const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
+            const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
 
             if (outProfile->mSupportedDevices.isEmpty()) {
                 ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
@@ -1683,7 +1661,7 @@
                     ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
                 AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
 
-                outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mType & profileTypes);
+                outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mDeviceType & profileTypes);
                 audio_io_handle_t output = mpClientInterface->openOutput(
                                                 outProfile->mModule->mHandle,
                                                 &outputDesc->mDevice,
@@ -1699,7 +1677,7 @@
                     delete outputDesc;
                 } else {
                     for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
-                        audio_devices_t type = outProfile->mSupportedDevices[k]->mType;
+                        audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
                         ssize_t index =
                                 mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
                         // give a valid ID to an attached device once confirmed it is reachable
@@ -1722,7 +1700,7 @@
         // mAvailableInputDevices list
         for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
         {
-            const IOProfile *inProfile = mHwModules[i]->mInputProfiles[j];
+            const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
 
             if (inProfile->mSupportedDevices.isEmpty()) {
                 ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
@@ -1734,7 +1712,7 @@
                 AudioInputDescriptor *inputDesc = new AudioInputDescriptor(inProfile);
 
                 inputDesc->mInputSource = AUDIO_SOURCE_MIC;
-                inputDesc->mDevice = inProfile->mSupportedDevices[0]->mType;
+                inputDesc->mDevice = inProfile->mSupportedDevices[0]->mDeviceType;
                 audio_io_handle_t input = mpClientInterface->openInput(
                                                     inProfile->mModule->mHandle,
                                                     &inputDesc->mDevice,
@@ -1744,7 +1722,7 @@
 
                 if (input != 0) {
                     for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
-                        audio_devices_t type = inProfile->mSupportedDevices[k]->mType;
+                        audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType;
                         ssize_t index =
                                 mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
                         // give a valid ID to an attached device once confirmed it is reachable
@@ -1765,7 +1743,7 @@
     // make sure all attached devices have been allocated a unique ID
     for (size_t i = 0; i  < mAvailableOutputDevices.size();) {
         if (mAvailableOutputDevices[i]->mId == 0) {
-            ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mType);
+            ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mDeviceType);
             mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
             continue;
         }
@@ -1773,7 +1751,7 @@
     }
     for (size_t i = 0; i  < mAvailableInputDevices.size();) {
         if (mAvailableInputDevices[i]->mId == 0) {
-            ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mType);
+            ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mDeviceType);
             mAvailableInputDevices.remove(mAvailableInputDevices[i]);
             continue;
         }
@@ -1781,7 +1759,7 @@
     }
     // make sure default device is reachable
     if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
-        ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mType);
+        ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mDeviceType);
     }
 
     ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
@@ -1990,16 +1968,18 @@
 
 // ---
 
-void AudioPolicyManager::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc)
+void AudioPolicyManager::addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc)
 {
-    outputDesc->mId = id;
-    mOutputs.add(id, outputDesc);
+    outputDesc->mIoHandle = output;
+    outputDesc->mId = nextUniqueId();
+    mOutputs.add(output, outputDesc);
 }
 
-void AudioPolicyManager::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc)
+void AudioPolicyManager::addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc)
 {
-    inputDesc->mId = id;
-    mInputs.add(id, inputDesc);
+    inputDesc->mIoHandle = input;
+    inputDesc->mId = nextUniqueId();
+    mInputs.add(input, inputDesc);
 }
 
 String8 AudioPolicyManager::addressToParameter(audio_devices_t device, const String8 address)
@@ -2027,7 +2007,7 @@
             }
         }
         // then look for output profiles that can be routed to this device
-        SortedVector<IOProfile *> profiles;
+        SortedVector< sp<IOProfile> > profiles;
         for (size_t i = 0; i < mHwModules.size(); i++)
         {
             if (mHwModules[i]->mHandle == 0) {
@@ -2050,7 +2030,7 @@
         // open outputs for matching profiles if needed. Direct outputs are also opened to
         // query for dynamic parameters and will be closed later by setDeviceConnectionState()
         for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
-            IOProfile *profile = profiles[profile_index];
+            sp<IOProfile> profile = profiles[profile_index];
 
             // nothing to do if one output is already opened for this profile
             size_t j;
@@ -2096,7 +2076,7 @@
                               reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
-                        loadSamplingRates(value + 1, profile);
+                        profile->loadSamplingRates(value + 1);
                     }
                 }
                 if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
@@ -2106,7 +2086,7 @@
                               reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
-                        loadFormats(value + 1, profile);
+                        profile->loadFormats(value + 1);
                     }
                 }
                 if (profile->mChannelMasks[0] == 0) {
@@ -2116,7 +2096,7 @@
                               reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
-                        loadOutChannels(value + 1, profile);
+                        profile->loadOutChannels(value + 1);
                     }
                 }
                 if (((profile->mSamplingRates[0] == 0) &&
@@ -2211,7 +2191,7 @@
             }
             for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
             {
-                IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+                sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
                 if (profile->mSupportedDevices.types() & device) {
                     ALOGV("checkOutputsForDevice(): "
                             "clearing direct output profile %zu on module %zu", j, i);
@@ -2251,7 +2231,7 @@
         }
 
         // then look for input profiles that can be routed to this device
-        SortedVector<IOProfile *> profiles;
+        SortedVector< sp<IOProfile> > profiles;
         for (size_t module_idx = 0; module_idx < mHwModules.size(); module_idx++)
         {
             if (mHwModules[module_idx]->mHandle == 0) {
@@ -2279,7 +2259,7 @@
         // query for dynamic parameters and will be closed later by setDeviceConnectionState()
         for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
 
-            IOProfile *profile = profiles[profile_index];
+            sp<IOProfile> profile = profiles[profile_index];
             // nothing to do if one input is already opened for this profile
             size_t input_index;
             for (input_index = 0; input_index < mInputs.size(); input_index++) {
@@ -2317,7 +2297,7 @@
                               reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
-                        loadSamplingRates(value + 1, profile);
+                        profile->loadSamplingRates(value + 1);
                     }
                 }
                 if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
@@ -2326,7 +2306,7 @@
                     ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
-                        loadFormats(value + 1, profile);
+                        profile->loadFormats(value + 1);
                     }
                 }
                 if (profile->mChannelMasks[0] == 0) {
@@ -2336,7 +2316,7 @@
                               reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
-                        loadInChannels(value + 1, profile);
+                        profile->loadInChannels(value + 1);
                     }
                 }
                 if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
@@ -2386,7 +2366,7 @@
             for (size_t profile_index = 0;
                  profile_index < mHwModules[module_index]->mInputProfiles.size();
                  profile_index++) {
-                IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index];
+                sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index];
                 if (profile->mSupportedDevices.types() & device) {
                     ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d",
                           profile_index, module_index);
@@ -2605,7 +2585,7 @@
     }
 }
 
-audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache)
+audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, bool fromCache)
 {
     audio_devices_t device = AUDIO_DEVICE_NONE;
 
@@ -2638,7 +2618,16 @@
         device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
     }
 
-    ALOGV("getNewDevice() selected device %x", device);
+    ALOGV("getNewOutputDevice() selected device %x", device);
+    return device;
+}
+
+audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input)
+{
+    AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+    audio_devices_t device = getDeviceForInputSource(inputDesc->mInputSource);
+
+    ALOGV("getNewInputDevice() selected device %x", device);
     return device;
 }
 
@@ -2784,7 +2773,7 @@
             }
             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_EARPIECE;
             if (device) break;
-            device = mDefaultOutputDevice->mType;
+            device = mDefaultOutputDevice->mDeviceType;
             if (device == AUDIO_DEVICE_NONE) {
                 ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
             }
@@ -2813,7 +2802,7 @@
             }
             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
             if (device) break;
-            device = mDefaultOutputDevice->mType;
+            device = mDefaultOutputDevice->mDeviceType;
             if (device == AUDIO_DEVICE_NONE) {
                 ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
             }
@@ -2895,7 +2884,7 @@
         // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
         device |= device2;
         if (device) break;
-        device = mDefaultOutputDevice->mType;
+        device = mDefaultOutputDevice->mDeviceType;
         if (device == AUDIO_DEVICE_NONE) {
             ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
         }
@@ -2981,9 +2970,9 @@
         }
         for (size_t i = 0; i < NUM_STRATEGIES; i++) {
             if (outputDesc->isStrategyActive((routing_strategy)i)) {
-                setStrategyMute((routing_strategy)i, true, outputDesc->mId);
+                setStrategyMute((routing_strategy)i, true, outputDesc->mIoHandle);
                 // do tempMute unmute after twice the mute wait time
-                setStrategyMute((routing_strategy)i, false, outputDesc->mId,
+                setStrategyMute((routing_strategy)i, false, outputDesc->mIoHandle,
                                 muteWaitMs *2, device);
             }
         }
@@ -3009,8 +2998,8 @@
     uint32_t muteWaitMs;
 
     if (outputDesc->isDuplicated()) {
-        muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
-        muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+        muteWaitMs = setOutputDevice(outputDesc->mOutput1->mIoHandle, device, force, delayMs);
+        muteWaitMs += setOutputDevice(outputDesc->mOutput2->mIoHandle, device, force, delayMs);
         return muteWaitMs;
     }
     // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
@@ -3042,9 +3031,34 @@
     }
 
     ALOGV("setOutputDevice() changing device");
+
     // do the routing
-    param.addInt(String8(AudioParameter::keyRouting), (int)device);
-    mpClientInterface->setParameters(output, param.toString(), delayMs);
+    if (device == AUDIO_DEVICE_NONE) {
+        resetOutputDevice(output, delayMs);
+    } else {
+        DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+        if (!deviceList.isEmpty()) {
+            struct audio_patch patch;
+            outputDesc->toAudioPortConfig(&patch.sources[0]);
+            patch.num_sources = 1;
+            patch.num_sinks = 0;
+            for (size_t i = 0; i < deviceList.size() && i < AUDIO_PATCH_PORTS_MAX; i++) {
+                deviceList.itemAt(i)->toAudioPortConfig(&patch.sinks[i]);
+                patch.sinks[i].ext.device.hw_module = patch.sources[0].ext.mix.hw_module;
+                patch.num_sinks++;
+            }
+            audio_patch_handle_t patchHandle = outputDesc->mPatchHandle;
+            status_t status = mpClientInterface->createAudioPatch(&patch,
+                                                                  &patchHandle,
+                                                                  delayMs);
+            ALOGV("setOutputDevice() createAudioPatch returned %d patchHandle %d"
+                    "num_sources %d num_sinks %d",
+                                       status, patchHandle, patch.num_sources, patch.num_sinks);
+            if (status == NO_ERROR) {
+                outputDesc->mPatchHandle = patchHandle;
+            }
+        }
+    }
 
     // update stream volumes according to new device
     applyStreamVolumes(output, device, delayMs);
@@ -3052,7 +3066,65 @@
     return muteWaitMs;
 }
 
-AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices_t device,
+status_t AudioPolicyManager::resetOutputDevice(audio_io_handle_t output,
+                                               int delayMs)
+{
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    if (outputDesc->mPatchHandle == 0) {
+        return INVALID_OPERATION;
+    }
+    status_t status = mpClientInterface->releaseAudioPatch(outputDesc->mPatchHandle, delayMs);
+    ALOGV("resetOutputDevice() releaseAudioPatch returned %d", status);
+    outputDesc->mPatchHandle = 0;
+    return status;
+}
+
+status_t AudioPolicyManager::setInputDevice(audio_io_handle_t input,
+                                            audio_devices_t device,
+                                            bool force)
+{
+    status_t status = NO_ERROR;
+
+    AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+    if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) {
+        inputDesc->mDevice = device;
+
+        DeviceVector deviceList = mAvailableInputDevices.getDevicesFromType(device);
+        if (!deviceList.isEmpty()) {
+            struct audio_patch patch;
+            inputDesc->toAudioPortConfig(&patch.sinks[0]);
+            patch.num_sinks = 1;
+            //only one input device for now
+            deviceList.itemAt(0)->toAudioPortConfig(&patch.sources[0]);
+            patch.sources[0].ext.device.hw_module = patch.sinks[0].ext.mix.hw_module;
+            patch.num_sources = 1;
+            audio_patch_handle_t patchHandle = inputDesc->mPatchHandle;
+            status_t status = mpClientInterface->createAudioPatch(&patch,
+                                                                  &patchHandle,
+                                                                  0);
+            ALOGV("setInputDevice() createAudioPatch returned %d patchHandle %d",
+                                                                          status, patchHandle);
+            if (status == NO_ERROR) {
+                inputDesc->mPatchHandle = patchHandle;
+            }
+        }
+    }
+    return status;
+}
+
+status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input)
+{
+    AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+    if (inputDesc->mPatchHandle == 0) {
+        return INVALID_OPERATION;
+    }
+    status_t status = mpClientInterface->releaseAudioPatch(inputDesc->mPatchHandle, 0);
+    ALOGV("resetInputDevice() releaseAudioPatch returned %d", status);
+    inputDesc->mPatchHandle = 0;
+    return status;
+}
+
+sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
                                                    uint32_t samplingRate,
                                                    audio_format_t format,
                                                    audio_channel_mask_t channelMask)
@@ -3067,7 +3139,7 @@
         }
         for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
         {
-            IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+            sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j];
             // profile->log();
             if (profile->isCompatibleProfile(device, samplingRate, format,
                                              channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
@@ -3093,6 +3165,12 @@
 
     case AUDIO_SOURCE_DEFAULT:
     case AUDIO_SOURCE_MIC:
+    if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+        device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+        break;
+    }
+    // FALL THROUGH
+
     case AUDIO_SOURCE_VOICE_RECOGNITION:
     case AUDIO_SOURCE_HOTWORD:
     case AUDIO_SOURCE_VOICE_COMMUNICATION:
@@ -3648,10 +3726,10 @@
 // --- AudioOutputDescriptor class implementation
 
 AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor(
-        const IOProfile *profile)
-    : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
+        const sp<IOProfile>& profile)
+    : mId(0), mIoHandle(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
       mChannelMask(0), mLatency(0),
-    mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
+    mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0),
     mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
 {
     // clear usage count for all stream types
@@ -3770,6 +3848,32 @@
     return false;
 }
 
+void AudioPolicyManager::AudioOutputDescriptor::toAudioPortConfig(
+                                                        struct audio_port_config *config) const
+{
+    config->id = mId;
+    config->role = AUDIO_PORT_ROLE_SOURCE;
+    config->type = AUDIO_PORT_TYPE_MIX;
+    config->sample_rate = mSamplingRate;
+    config->channel_mask = mChannelMask;
+    config->format = mFormat;
+    config->gain.index = -1;
+    config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+                            AUDIO_PORT_CONFIG_FORMAT;
+    config->ext.mix.hw_module = mProfile->mModule->mHandle;
+    config->ext.mix.handle = mIoHandle;
+    config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
+}
+
+void AudioPolicyManager::AudioOutputDescriptor::toAudioPort(
+                                                    struct audio_port *port) const
+{
+    mProfile->toAudioPort(port);
+    port->id = mId;
+    port->ext.mix.handle = mIoHandle;
+    port->ext.mix.latency_class =
+            mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL;
+}
 
 status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd)
 {
@@ -3803,9 +3907,10 @@
 
 // --- AudioInputDescriptor class implementation
 
-AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
-    : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
-      mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
+AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
+    : mId(0), mIoHandle(0), mSamplingRate(0),
+      mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+      mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0),
       mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile)
 {
     if (profile != NULL) {
@@ -3815,6 +3920,33 @@
     }
 }
 
+void AudioPolicyManager::AudioInputDescriptor::toAudioPortConfig(
+                                                        struct audio_port_config *config) const
+{
+    config->id = mId;
+    config->role = AUDIO_PORT_ROLE_SINK;
+    config->type = AUDIO_PORT_TYPE_MIX;
+    config->sample_rate = mSamplingRate;
+    config->channel_mask = mChannelMask;
+    config->format = mFormat;
+    config->gain.index = -1;
+    config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+                          AUDIO_PORT_CONFIG_FORMAT;
+    config->ext.mix.hw_module = mProfile->mModule->mHandle;
+    config->ext.mix.handle = mIoHandle;
+    config->ext.mix.usecase.source = (mInputSource == AUDIO_SOURCE_HOTWORD) ?
+                                                    AUDIO_SOURCE_VOICE_RECOGNITION : mInputSource;
+}
+
+void AudioPolicyManager::AudioInputDescriptor::toAudioPort(
+                                                    struct audio_port *port) const
+{
+    mProfile->toAudioPort(port);
+    port->id = mId;
+    port->ext.mix.handle = mIoHandle;
+    port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
+}
+
 status_t AudioPolicyManager::AudioInputDescriptor::dump(int fd)
 {
     const size_t SIZE = 256;
@@ -3897,7 +4029,7 @@
     return NO_ERROR;
 }
 
-// --- IOProfile class implementation
+// --- HwModule class implementation
 
 AudioPolicyManager::HwModule::HwModule(const char *name)
     : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0)
@@ -3908,11 +4040,9 @@
 {
     for (size_t i = 0; i < mOutputProfiles.size(); i++) {
         mOutputProfiles[i]->mSupportedDevices.clear();
-        delete mOutputProfiles[i];
     }
     for (size_t i = 0; i < mInputProfiles.size(); i++) {
         mInputProfiles[i]->mSupportedDevices.clear();
-        delete mInputProfiles[i];
     }
     free((void *)mName);
 }
@@ -3946,8 +4076,129 @@
     }
 }
 
-AudioPolicyManager::IOProfile::IOProfile(HwModule *module)
-    : mFlags((audio_output_flags_t)0), mModule(module)
+// --- AudioPort class implementation
+
+void AudioPolicyManager::AudioPort::toAudioPort(struct audio_port *port) const
+{
+    port->role = mRole;
+    port->type = mType;
+    unsigned int i;
+    for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
+        port->sample_rates[i] = mSamplingRates[i];
+    }
+    port->num_sample_rates = i;
+    for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
+        port->channel_masks[i] = mChannelMasks[i];
+    }
+    port->num_channel_masks = i;
+    for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
+        port->formats[i] = mFormats[i];
+    }
+    port->num_formats = i;
+    port->num_gains = 0;
+}
+
+
+void AudioPolicyManager::AudioPort::loadSamplingRates(char *name)
+{
+    char *str = strtok(name, "|");
+
+    // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
+    // rates should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        mSamplingRates.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        uint32_t rate = atoi(str);
+        if (rate != 0) {
+            ALOGV("loadSamplingRates() adding rate %d", rate);
+            mSamplingRates.add(rate);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManager::AudioPort::loadFormats(char *name)
+{
+    char *str = strtok(name, "|");
+
+    // by convention, "0' in the first entry in mFormats indicates the supported formats
+    // should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        mFormats.add(AUDIO_FORMAT_DEFAULT);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
+                                                             ARRAY_SIZE(sFormatNameToEnumTable),
+                                                             str);
+        if (format != AUDIO_FORMAT_DEFAULT) {
+            mFormats.add(format);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManager::AudioPort::loadInChannels(char *name)
+{
+    const char *str = strtok(name, "|");
+
+    ALOGV("loadInChannels() %s", name);
+
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        mChannelMasks.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_channel_mask_t channelMask =
+                (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
+                                                   ARRAY_SIZE(sInChannelsNameToEnumTable),
+                                                   str);
+        if (channelMask != 0) {
+            ALOGV("loadInChannels() adding channelMask %04x", channelMask);
+            mChannelMasks.add(channelMask);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManager::AudioPort::loadOutChannels(char *name)
+{
+    const char *str = strtok(name, "|");
+
+    ALOGV("loadOutChannels() %s", name);
+
+    // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
+    // masks should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        mChannelMasks.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_channel_mask_t channelMask =
+                (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
+                                                   ARRAY_SIZE(sOutChannelsNameToEnumTable),
+                                                   str);
+        if (channelMask != 0) {
+            mChannelMasks.add(channelMask);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+// --- IOProfile class implementation
+
+AudioPolicyManager::IOProfile::IOProfile(audio_port_role_t role, HwModule *module)
+    : AudioPort(AUDIO_PORT_TYPE_MIX, role, module), mFlags((audio_output_flags_t)0)
 {
 }
 
@@ -4083,7 +4334,7 @@
     // - are of the same type (a device type cannot be AUDIO_DEVICE_NONE)
     // - have the same address or one device does not specify the address
     // - have the same channel mask or one device does not specify the channel mask
-    return (mType == other->mType) &&
+    return (mDeviceType == other->mDeviceType) &&
            (mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) &&
            (mChannelMask == 0 || other->mChannelMask == 0 ||
                 mChannelMask == other->mChannelMask);
@@ -4091,11 +4342,11 @@
 
 void AudioPolicyManager::DeviceVector::refreshTypes()
 {
-    mTypes = AUDIO_DEVICE_NONE;
+    mDeviceTypes = AUDIO_DEVICE_NONE;
     for(size_t i = 0; i < size(); i++) {
-        mTypes |= itemAt(i)->mType;
+        mDeviceTypes |= itemAt(i)->mDeviceType;
     }
-    ALOGV("DeviceVector::refreshTypes() mTypes %08x", mTypes);
+    ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
 }
 
 ssize_t AudioPolicyManager::DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
@@ -4118,7 +4369,7 @@
             refreshTypes();
         }
     } else {
-        ALOGW("DeviceVector::add device %08x already in", item->mType);
+        ALOGW("DeviceVector::add device %08x already in", item->mDeviceType);
         ret = -1;
     }
     return ret;
@@ -4130,7 +4381,7 @@
     ssize_t ret = indexOf(item);
 
     if (ret < 0) {
-        ALOGW("DeviceVector::remove device %08x not in", item->mType);
+        ALOGW("DeviceVector::remove device %08x not in", item->mDeviceType);
     } else {
         ret = SortedVector::removeAt(ret);
         if (ret >= 0) {
@@ -4155,6 +4406,61 @@
     }
 }
 
+sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDevice(
+                                                        audio_devices_t type, String8 address) const
+{
+    sp<DeviceDescriptor> device;
+    for (size_t i = 0; i < size(); i++) {
+        if (itemAt(i)->mDeviceType == type) {
+            device = itemAt(i);
+            if (itemAt(i)->mAddress = address) {
+                break;
+            }
+        }
+    }
+    ALOGV("DeviceVector::getDevice() for type %d address %s found %p",
+          type, address.string(), device.get());
+    return device;
+}
+
+AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromType(
+                                                                        audio_devices_t type) const
+{
+    DeviceVector devices;
+    for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
+        if (itemAt(i)->mDeviceType & type & ~AUDIO_DEVICE_BIT_IN) {
+            devices.add(itemAt(i));
+            type &= ~itemAt(i)->mDeviceType;
+            ALOGV("DeviceVector::getDevicesFromType() for type %x found %p",
+                  itemAt(i)->mDeviceType, itemAt(i).get());
+        }
+    }
+    return devices;
+}
+
+void AudioPolicyManager::DeviceDescriptor::toAudioPortConfig(struct audio_port_config *config) const
+{
+    config->id = mId;
+    config->role = audio_is_output_device(mDeviceType) ?
+                        AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+    config->type = AUDIO_PORT_TYPE_DEVICE;
+    config->sample_rate = 0;
+    config->channel_mask = mChannelMask;
+    config->format = AUDIO_FORMAT_DEFAULT;
+    config->config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK;
+    config->gain.index = -1;
+    config->ext.device.type = mDeviceType;
+    strncpy(config->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
+}
+
+void AudioPolicyManager::DeviceDescriptor::toAudioPort(struct audio_port *port) const
+{
+    AudioPort::toAudioPort(port);
+    port->id = mId;
+    port->ext.device.type = mDeviceType;
+    strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
+}
+
 void AudioPolicyManager::DeviceDescriptor::dumpHeader(int fd, int spaces)
 {
     const size_t SIZE = 256;
@@ -4174,7 +4480,7 @@
                          spaces, "",
                          enumToString(sDeviceNameToEnumTable,
                                       ARRAY_SIZE(sDeviceNameToEnumTable),
-                                      mType),
+                                      mDeviceType),
                          mId, mChannelMask, mAddress.string());
     write(fd, buffer, strlen(buffer));
 
@@ -4225,115 +4531,19 @@
     return device;
 }
 
-void AudioPolicyManager::loadSamplingRates(char *name, IOProfile *profile)
-{
-    char *str = strtok(name, "|");
-
-    // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
-    // rates should be read from the output stream after it is opened for the first time
-    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
-        profile->mSamplingRates.add(0);
-        return;
-    }
-
-    while (str != NULL) {
-        uint32_t rate = atoi(str);
-        if (rate != 0) {
-            ALOGV("loadSamplingRates() adding rate %d", rate);
-            profile->mSamplingRates.add(rate);
-        }
-        str = strtok(NULL, "|");
-    }
-    return;
-}
-
-void AudioPolicyManager::loadFormats(char *name, IOProfile *profile)
-{
-    char *str = strtok(name, "|");
-
-    // by convention, "0' in the first entry in mFormats indicates the supported formats
-    // should be read from the output stream after it is opened for the first time
-    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
-        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
-        return;
-    }
-
-    while (str != NULL) {
-        audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
-                                                             ARRAY_SIZE(sFormatNameToEnumTable),
-                                                             str);
-        if (format != AUDIO_FORMAT_DEFAULT) {
-            profile->mFormats.add(format);
-        }
-        str = strtok(NULL, "|");
-    }
-    return;
-}
-
-void AudioPolicyManager::loadInChannels(char *name, IOProfile *profile)
-{
-    const char *str = strtok(name, "|");
-
-    ALOGV("loadInChannels() %s", name);
-
-    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
-        profile->mChannelMasks.add(0);
-        return;
-    }
-
-    while (str != NULL) {
-        audio_channel_mask_t channelMask =
-                (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
-                                                   ARRAY_SIZE(sInChannelsNameToEnumTable),
-                                                   str);
-        if (channelMask != 0) {
-            ALOGV("loadInChannels() adding channelMask %04x", channelMask);
-            profile->mChannelMasks.add(channelMask);
-        }
-        str = strtok(NULL, "|");
-    }
-    return;
-}
-
-void AudioPolicyManager::loadOutChannels(char *name, IOProfile *profile)
-{
-    const char *str = strtok(name, "|");
-
-    ALOGV("loadOutChannels() %s", name);
-
-    // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
-    // masks should be read from the output stream after it is opened for the first time
-    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
-        profile->mChannelMasks.add(0);
-        return;
-    }
-
-    while (str != NULL) {
-        audio_channel_mask_t channelMask =
-                (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
-                                                   ARRAY_SIZE(sOutChannelsNameToEnumTable),
-                                                   str);
-        if (channelMask != 0) {
-            profile->mChannelMasks.add(channelMask);
-        }
-        str = strtok(NULL, "|");
-    }
-    return;
-}
-
 status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module)
 {
     cnode *node = root->first_child;
 
-    IOProfile *profile = new IOProfile(module);
+    sp<IOProfile> profile = new IOProfile(AUDIO_PORT_ROLE_SINK, module);
 
     while (node) {
         if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
-            loadSamplingRates((char *)node->value, profile);
+            profile->loadSamplingRates((char *)node->value);
         } else if (strcmp(node->name, FORMATS_TAG) == 0) {
-            loadFormats((char *)node->value, profile);
+            profile->loadFormats((char *)node->value);
         } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
-            loadInChannels((char *)node->value, profile);
+            profile->loadInChannels((char *)node->value);
         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
             profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
         }
@@ -4358,7 +4568,6 @@
         module->mInputProfiles.add(profile);
         return NO_ERROR;
     } else {
-        delete profile;
         return BAD_VALUE;
     }
 }
@@ -4367,15 +4576,15 @@
 {
     cnode *node = root->first_child;
 
-    IOProfile *profile = new IOProfile(module);
+    sp<IOProfile> profile = new IOProfile(AUDIO_PORT_ROLE_SOURCE, module);
 
     while (node) {
         if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
-            loadSamplingRates((char *)node->value, profile);
+            profile->loadSamplingRates((char *)node->value);
         } else if (strcmp(node->name, FORMATS_TAG) == 0) {
-            loadFormats((char *)node->value, profile);
+            profile->loadFormats((char *)node->value);
         } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
-            loadOutChannels((char *)node->value, profile);
+            profile->loadOutChannels((char *)node->value);
         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
             profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
         } else if (strcmp(node->name, FLAGS_TAG) == 0) {
@@ -4402,7 +4611,6 @@
         module->mOutputProfiles.add(profile);
         return NO_ERROR;
     } else {
-        delete profile;
         return BAD_VALUE;
     }
 }
@@ -4480,7 +4688,7 @@
             } else {
                 ALOGW("loadGlobalConfig() default device not specified");
             }
-            ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mType);
+            ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mDeviceType);
         } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
             mAvailableInputDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
             ALOGV("loadGlobalConfig() Available InputDevices %08x", mAvailableInputDevices.types());
@@ -4519,14 +4727,14 @@
 void AudioPolicyManager::defaultAudioPolicyConfig(void)
 {
     HwModule *module;
-    IOProfile *profile;
+    sp<IOProfile> profile;
     sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
     mAvailableOutputDevices.add(mDefaultOutputDevice);
     mAvailableInputDevices.add(defaultInputDevice);
 
     module = new HwModule("primary");
 
-    profile = new IOProfile(module);
+    profile = new IOProfile(AUDIO_PORT_ROLE_SOURCE, module);
     profile->mSamplingRates.add(44100);
     profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
     profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
@@ -4534,7 +4742,7 @@
     profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
     module->mOutputProfiles.add(profile);
 
-    profile = new IOProfile(module);
+    profile = new IOProfile(AUDIO_PORT_ROLE_SINK, module);
     profile->mSamplingRates.add(8000);
     profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
     profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index f00fa8a..905a3c8 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -175,47 +175,6 @@
 
         class IOProfile;
 
-        class DeviceDescriptor: public RefBase
-        {
-        public:
-            DeviceDescriptor(audio_devices_t type, String8 address,
-                             audio_channel_mask_t channelMask) :
-                                 mType(type), mAddress(address),
-                                 mChannelMask(channelMask), mId(0) {}
-
-            DeviceDescriptor(audio_devices_t type) :
-                                 mType(type), mAddress(""),
-                                 mChannelMask(0), mId(0) {}
-
-            status_t dump(int fd, int spaces) const;
-            static void dumpHeader(int fd, int spaces);
-
-            bool equals(const sp<DeviceDescriptor>& other) const;
-
-            audio_devices_t mType;
-            String8 mAddress;
-            audio_channel_mask_t mChannelMask;
-            uint32_t mId;
-        };
-
-        class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
-        {
-        public:
-            DeviceVector() : SortedVector(), mTypes(AUDIO_DEVICE_NONE) {}
-
-            ssize_t         add(const sp<DeviceDescriptor>& item);
-            ssize_t         remove(const sp<DeviceDescriptor>& item);
-            ssize_t         indexOf(const sp<DeviceDescriptor>& item) const;
-
-            audio_devices_t types() const { return mTypes; }
-
-            void loadDevicesFromType(audio_devices_t types);
-
-        private:
-            void refreshTypes();
-            audio_devices_t mTypes;
-        };
-
         class HwModule {
         public:
                     HwModule(const char *name);
@@ -225,8 +184,88 @@
 
             const char *const mName; // base name of the audio HW module (primary, a2dp ...)
             audio_module_handle_t mHandle;
-            Vector <IOProfile *> mOutputProfiles; // output profiles exposed by this module
-            Vector <IOProfile *> mInputProfiles;  // input profiles exposed by this module
+            Vector < sp<IOProfile> > mOutputProfiles; // output profiles exposed by this module
+            Vector < sp<IOProfile> > mInputProfiles;  // input profiles exposed by this module
+        };
+
+        class AudioPort: public RefBase
+        {
+        public:
+            AudioPort(audio_port_type_t type, audio_port_role_t role, HwModule *module) :
+                mType(type), mRole(role), mModule(module) {}
+            virtual ~AudioPort() {}
+
+            virtual void toAudioPort(struct audio_port *port) const;
+
+            void loadSamplingRates(char *name);
+            void loadFormats(char *name);
+            void loadOutChannels(char *name);
+            void loadInChannels(char *name);
+
+            audio_port_type_t        mType;
+            audio_port_role_t        mRole;
+            // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
+            // indicates the supported parameters should be read from the output stream
+            // after it is opened for the first time
+            Vector <uint32_t> mSamplingRates; // supported sampling rates
+            Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
+            Vector <audio_format_t> mFormats; // supported audio formats
+            HwModule *mModule;                     // audio HW module exposing this I/O stream
+        };
+
+
+        class DeviceDescriptor: public AudioPort
+        {
+        public:
+            DeviceDescriptor(audio_devices_t type, String8 address,
+                             audio_channel_mask_t channelMask) :
+                                 AudioPort(AUDIO_PORT_TYPE_DEVICE,
+                                           audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+                                                                          AUDIO_PORT_ROLE_SOURCE,
+                                         NULL),
+                                 mDeviceType(type), mAddress(address),
+                                 mChannelMask(channelMask), mId(0) {}
+
+            DeviceDescriptor(audio_devices_t type) :
+                                AudioPort(AUDIO_PORT_TYPE_DEVICE,
+                                          audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+                                                                         AUDIO_PORT_ROLE_SOURCE,
+                                        NULL),
+                                mDeviceType(type), mAddress(""),
+                                mChannelMask(0), mId(0) {}
+            virtual ~DeviceDescriptor() {}
+
+            bool equals(const sp<DeviceDescriptor>& other) const;
+            void toAudioPortConfig(struct audio_port_config *config) const;
+            virtual void toAudioPort(struct audio_port *port) const;
+
+            status_t dump(int fd, int spaces) const;
+            static void dumpHeader(int fd, int spaces);
+
+            audio_devices_t mDeviceType;
+            String8 mAddress;
+            audio_channel_mask_t mChannelMask;
+            audio_port_handle_t mId;
+        };
+
+        class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
+        {
+        public:
+            DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
+
+            ssize_t         add(const sp<DeviceDescriptor>& item);
+            ssize_t         remove(const sp<DeviceDescriptor>& item);
+            ssize_t         indexOf(const sp<DeviceDescriptor>& item) const;
+
+            audio_devices_t types() const { return mDeviceTypes; }
+
+            void loadDevicesFromType(audio_devices_t types);
+            sp<DeviceDescriptor> getDevice(audio_devices_t type, String8 address) const;
+            DeviceVector getDevicesFromType(audio_devices_t types) const;
+
+        private:
+            void refreshTypes();
+            audio_devices_t mDeviceTypes;
         };
 
         // the IOProfile class describes the capabilities of an output or input stream.
@@ -234,11 +273,11 @@
         // It is used by the policy manager to determine if an output or input is suitable for
         // a given use case,  open/close it accordingly and connect/disconnect audio tracks
         // to/from it.
-        class IOProfile
+        class IOProfile : public AudioPort
         {
         public:
-            IOProfile(HwModule *module);
-            ~IOProfile();
+            IOProfile(audio_port_role_t role, HwModule *module);
+            virtual ~IOProfile();
 
             bool isCompatibleProfile(audio_devices_t device,
                                      uint32_t samplingRate,
@@ -249,17 +288,10 @@
             void dump(int fd);
             void log();
 
-            // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
-            // indicates the supported parameters should be read from the output stream
-            // after it is opened for the first time
-            Vector <uint32_t> mSamplingRates; // supported sampling rates
-            Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
-            Vector <audio_format_t> mFormats; // supported audio formats
             DeviceVector  mSupportedDevices; // supported devices
                                              // (devices this output can be routed to)
             audio_output_flags_t mFlags; // attribute flags (e.g primary output,
                                                 // direct output...). For outputs only.
-            HwModule *mModule;                     // audio HW module exposing this I/O stream
         };
 
         // default volume curve
@@ -284,7 +316,7 @@
         class AudioOutputDescriptor
         {
         public:
-            AudioOutputDescriptor(const IOProfile *profile);
+            AudioOutputDescriptor(const sp<IOProfile>& profile);
 
             status_t    dump(int fd);
 
@@ -303,20 +335,25 @@
                              uint32_t inPastMs = 0,
                              nsecs_t sysTime = 0) const;
 
-            audio_io_handle_t mId;              // output handle
+            void toAudioPortConfig(struct audio_port_config *config) const;
+            void toAudioPort(struct audio_port *port) const;
+
+            audio_port_handle_t mId;
+            audio_io_handle_t mIoHandle;              // output handle
             uint32_t mSamplingRate;             //
             audio_format_t mFormat;             //
             audio_channel_mask_t mChannelMask;     // output configuration
             uint32_t mLatency;                  //
             audio_output_flags_t mFlags;   //
             audio_devices_t mDevice;                   // current device this output is routed to
+            audio_patch_handle_t mPatchHandle;
             uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
             nsecs_t mStopTime[AUDIO_STREAM_CNT];
             AudioOutputDescriptor *mOutput1;    // used by duplicated outputs: first output
             AudioOutputDescriptor *mOutput2;    // used by duplicated outputs: second output
             float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume
             int mMuteCount[AUDIO_STREAM_CNT];     // mute request counter
-            const IOProfile *mProfile;          // I/O profile this output derives from
+            const sp<IOProfile> mProfile;          // I/O profile this output derives from
             bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
                                                 // device selection. See checkDeviceMuteStrategies()
             uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
@@ -327,18 +364,23 @@
         class AudioInputDescriptor
         {
         public:
-            AudioInputDescriptor(const IOProfile *profile);
+            AudioInputDescriptor(const sp<IOProfile>& profile);
 
             status_t    dump(int fd);
 
-            audio_io_handle_t mId;                      // input handle
+            audio_port_handle_t mId;
+            audio_io_handle_t mIoHandle;              // input handle
             uint32_t mSamplingRate;                     //
             audio_format_t mFormat;                     // input configuration
             audio_channel_mask_t mChannelMask;             //
             audio_devices_t mDevice;                    // current device this input is routed to
+            audio_patch_handle_t mPatchHandle;
             uint32_t mRefCount;                         // number of AudioRecord clients using this output
             audio_source_t mInputSource;                // input source selected by application (mediarecorder.h)
-            const IOProfile *mProfile;                  // I/O profile this output derives from
+            const sp<IOProfile> mProfile;                  // I/O profile this output derives from
+
+            void toAudioPortConfig(struct audio_port_config *config) const;
+            void toAudioPort(struct audio_port *port) const;
         };
 
         // stream descriptor used for volume control
@@ -372,8 +414,8 @@
             bool mEnabled;              // enabled state: CPU load being used or not
         };
 
-        void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc);
-        void addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc);
+        void addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc);
+        void addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc);
 
         // return the strategy corresponding to a given stream type
         static routing_strategy getStrategy(audio_stream_type_t stream);
@@ -398,6 +440,12 @@
                              audio_devices_t device,
                              bool force = false,
                              int delayMs = 0);
+        status_t resetOutputDevice(audio_io_handle_t output,
+                                   int delayMs = 0);
+        status_t setInputDevice(audio_io_handle_t input,
+                                audio_devices_t device,
+                                bool force = false);
+        status_t resetInputDevice(audio_io_handle_t input);
 
         // select input device corresponding to requested audio source
         virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource);
@@ -484,16 +532,18 @@
         // must be called every time a condition that affects the device choice for a given output is
         // changed: connected device, phone state, force use, output start, output stop..
         // see getDeviceForStrategy() for the use of fromCache parameter
+        audio_devices_t getNewOutputDevice(audio_io_handle_t output, bool fromCache);
 
-        audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
         // updates cache of device used by all strategies (mDeviceForStrategy[])
         // must be called every time a condition that affects the device choice for a given strategy is
         // changed: connected device, phone state, force use...
         // cached values are used by getDeviceForStrategy() if parameter fromCache is true.
          // Must be called after checkOutputForAllStrategies()
-
         void updateDevicesAndOutputs();
 
+        // selects the most appropriate device on input for current state
+        audio_devices_t getNewInputDevice(audio_io_handle_t input);
+
         virtual uint32_t getMaxEffectsCpuLoad();
         virtual uint32_t getMaxEffectsMemory();
 #ifdef AUDIO_POLICY_TEST
@@ -525,11 +575,11 @@
 
         audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
                                        audio_output_flags_t flags);
-        IOProfile *getInputProfile(audio_devices_t device,
+        sp<IOProfile> getInputProfile(audio_devices_t device,
                                    uint32_t samplingRate,
                                    audio_format_t format,
                                    audio_channel_mask_t channelMask);
-        IOProfile *getProfileForDirectOutput(audio_devices_t device,
+        sp<IOProfile> getProfileForDirectOutput(audio_devices_t device,
                                                        uint32_t samplingRate,
                                                        audio_format_t format,
                                                        audio_channel_mask_t channelMask,
@@ -551,10 +601,6 @@
         static bool stringToBool(const char *value);
         static audio_output_flags_t parseFlagNames(char *name);
         static audio_devices_t parseDeviceNames(char *name);
-        void loadSamplingRates(char *name, IOProfile *profile);
-        void loadFormats(char *name, IOProfile *profile);
-        void loadOutChannels(char *name, IOProfile *profile);
-        void loadInChannels(char *name, IOProfile *profile);
         status_t loadOutput(cnode *root,  HwModule *module);
         status_t loadInput(cnode *root,  HwModule *module);
         void loadHwModule(cnode *root);
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 4e9a2f0..ea573a4 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -150,6 +150,19 @@
 #endif
 }
 
+status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
+                                                audio_patch_handle_t *handle,
+                                                int delayMs)
+{
+    return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
+}
+
+status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
+                                                 int delayMs)
+{
+    return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
+}
+
 
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
@@ -357,6 +370,26 @@
                     svc->doReleaseOutput(data->mIO);
                     mLock.lock();
                     }break;
+                case CREATE_AUDIO_PATCH: {
+                    CreateAudioPatchData *data = (CreateAudioPatchData *)command->mParam.get();
+                    ALOGV("AudioCommandThread() processing create audio patch");
+                    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+                    if (af == 0) {
+                        command->mStatus = PERMISSION_DENIED;
+                    } else {
+                        command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
+                    }
+                    } break;
+                case RELEASE_AUDIO_PATCH: {
+                    ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mParam.get();
+                    ALOGV("AudioCommandThread() processing release audio patch");
+                    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+                    if (af == 0) {
+                        command->mStatus = PERMISSION_DENIED;
+                    } else {
+                        command->mStatus = af->releaseAudioPatch(data->mHandle);
+                    }
+                    } break;
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                 }
@@ -516,6 +549,41 @@
     sendCommand(command);
 }
 
+status_t AudioPolicyService::AudioCommandThread::createAudioPatchCommand(
+                                                const struct audio_patch *patch,
+                                                audio_patch_handle_t *handle,
+                                                int delayMs)
+{
+    status_t status = NO_ERROR;
+
+    sp<AudioCommand> command = new AudioCommand();
+    command->mCommand = CREATE_AUDIO_PATCH;
+    CreateAudioPatchData *data = new CreateAudioPatchData();
+    data->mPatch = *patch;
+    data->mHandle = *handle;
+    command->mParam = data;
+    command->mWaitStatus = true;
+    ALOGV("AudioCommandThread() adding create patch delay %d", delayMs);
+    status = sendCommand(command, delayMs);
+    if (status == NO_ERROR) {
+        *handle = data->mHandle;
+    }
+    return status;
+}
+
+status_t AudioPolicyService::AudioCommandThread::releaseAudioPatchCommand(audio_patch_handle_t handle,
+                                                 int delayMs)
+{
+    sp<AudioCommand> command = new AudioCommand();
+    command->mCommand = RELEASE_AUDIO_PATCH;
+    ReleaseAudioPatchData *data = new ReleaseAudioPatchData();
+    data->mHandle = handle;
+    command->mParam = data;
+    command->mWaitStatus = true;
+    ALOGV("AudioCommandThread() adding release patch delay %d", delayMs);
+    return sendCommand(command, delayMs);
+}
+
 status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
 {
     {
@@ -534,6 +602,7 @@
     return command->mStatus;
 }
 
+
 // insertCommand_l() must be called with mLock held
 void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& command, int delayMs)
 {
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 26037e4..9f88b1e 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -140,11 +140,31 @@
     virtual status_t setVoiceVolume(float volume, int delayMs = 0);
     virtual bool isOffloadSupported(const audio_offload_info_t &config);
 
+    virtual status_t listAudioPorts(audio_port_role_t role,
+                                    audio_port_type_t type,
+                                    unsigned int *num_ports,
+                                    struct audio_port *ports,
+                                    unsigned int *generation);
+    virtual status_t getAudioPort(struct audio_port *port);
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle);
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle);
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches,
+                                      unsigned int *generation);
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+
             status_t doStopOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   int session = 0);
             void doReleaseOutput(audio_io_handle_t output);
 
+            status_t clientCreateAudioPatch(const struct audio_patch *patch,
+                                      audio_patch_handle_t *handle,
+                                      int delayMs);
+            status_t clientReleaseAudioPatch(audio_patch_handle_t handle,
+                                             int delayMs);
+
 private:
                         AudioPolicyService() ANDROID_API;
     virtual             ~AudioPolicyService();
@@ -169,7 +189,9 @@
             SET_PARAMETERS,
             SET_VOICE_VOLUME,
             STOP_OUTPUT,
-            RELEASE_OUTPUT
+            RELEASE_OUTPUT,
+            CREATE_AUDIO_PATCH,
+            RELEASE_AUDIO_PATCH,
         };
 
         AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -196,6 +218,13 @@
                     void        releaseOutputCommand(audio_io_handle_t output);
                     status_t    sendCommand(sp<AudioCommand>& command, int delayMs = 0);
                     void        insertCommand_l(sp<AudioCommand>& command, int delayMs = 0);
+                    status_t    createAudioPatchCommand(const struct audio_patch *patch,
+                                                        audio_patch_handle_t *handle,
+                                                        int delayMs);
+                    status_t    releaseAudioPatchCommand(audio_patch_handle_t handle,
+                                                         int delayMs);
+
+                    void        insertCommand_l(AudioCommand *command, int delayMs = 0);
 
     private:
         class AudioCommandData;
@@ -261,6 +290,17 @@
             audio_io_handle_t mIO;
         };
 
+        class CreateAudioPatchData : public AudioCommandData {
+        public:
+            struct audio_patch mPatch;
+            audio_patch_handle_t mHandle;
+        };
+
+        class ReleaseAudioPatchData : public AudioCommandData {
+        public:
+            audio_patch_handle_t mHandle;
+        };
+
         Mutex   mLock;
         Condition mWaitWorkCV;
         Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -405,6 +445,15 @@
                                          audio_io_handle_t srcOutput,
                                          audio_io_handle_t dstOutput);
 
+        /* Create a patch between several source and sink ports */
+        virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                           audio_patch_handle_t *handle,
+                                           int delayMs);
+
+        /* Release a patch */
+        virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
+                                           int delayMs);
+
      private:
         AudioPolicyService *mAudioPolicyService;
     };