Merge "GenericSource: timed text support" into lmp-dev
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 142b7cb..42a03bb 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -32,6 +32,7 @@
 
 struct ABuffer;
 struct MemoryDealer;
+struct DescribeColorFormatParams;
 
 struct ACodec : public AHierarchicalStateMachine, public CodecBase {
     ACodec();
@@ -305,6 +306,8 @@
             OMX_ERRORTYPE error = OMX_ErrorUndefined,
             status_t internalError = UNKNOWN_ERROR);
 
+    static void describeDefaultColorFormat(DescribeColorFormatParams &describeParams);
+
     status_t requestIDRFrame();
     status_t setParameters(const sp<AMessage> &params);
 
diff --git a/include/media/stagefright/foundation/ABuffer.h b/include/media/stagefright/foundation/ABuffer.h
index 28f0aed..602f7ab 100644
--- a/include/media/stagefright/foundation/ABuffer.h
+++ b/include/media/stagefright/foundation/ABuffer.h
@@ -42,6 +42,9 @@
 
     void setRange(size_t offset, size_t size);
 
+    // create buffer from dup of some memory block
+    static sp<ABuffer> CreateAsCopy(const void *data, size_t capacity);
+
     void setInt32Data(int32_t data) { mInt32Data = data; }
     int32_t int32Data() const { return mInt32Data; }
 
diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp
index 9cea721..1b20e36 100644
--- a/media/img_utils/src/TiffEntry.cpp
+++ b/media/img_utils/src/TiffEntry.cpp
@@ -203,14 +203,20 @@
             }
             break;
         }
-        case FLOAT:
-        case DOUBLE: {
+        case FLOAT: {
             const float* typed_data = getData<float>();
             for (size_t i = 0; i < cappedCount; ++i) {
                 output.appendFormat("%f ", typed_data[i]);
             }
             break;
         }
+        case DOUBLE: {
+            const double* typed_data = getData<double>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%f ", typed_data[i]);
+            }
+            break;
+        }
         default: {
             output.append("unknown type ");
             break;
diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp
index d85289e..ac41734 100644
--- a/media/img_utils/src/TiffWriter.cpp
+++ b/media/img_utils/src/TiffWriter.cpp
@@ -66,10 +66,6 @@
         return BAD_VALUE;
     }
 
-    if (LOG_NDEBUG == 0) {
-        log();
-    }
-
     uint32_t totalSize = getTotalSize();
 
     KeyedVector<uint32_t, uint32_t> offsetVector;
@@ -104,7 +100,9 @@
         ifd = ifd->getNextIfd();
     }
 
-    log();
+    if (LOG_NDEBUG == 0) {
+        log();
+    }
 
     for (size_t i = 0; i < offVecSize; ++i) {
         uint32_t ifdKey = offsetVector.keyAt(i);
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index e9c5e8e..dacb144 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -62,18 +62,18 @@
 
 player_type MediaPlayerFactory::getDefaultPlayerType() {
     char value[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.use-nuplayer", value, NULL)
+    if (property_get("media.stagefright.use-awesome", value, NULL)
             && (!strcmp("1", value) || !strcasecmp("true", value))) {
-        return NU_PLAYER;
+        return STAGEFRIGHT_PLAYER;
     }
 
     // TODO: remove this EXPERIMENTAL developer settings property
-    if (property_get("persist.sys.media.use-nuplayer", value, NULL)
+    if (property_get("persist.sys.media.use-awesome", value, NULL)
             && !strcasecmp("true", value)) {
-        return NU_PLAYER;
+        return STAGEFRIGHT_PLAYER;
     }
 
-    return STAGEFRIGHT_PLAYER;
+    return NU_PLAYER;
 }
 
 status_t MediaPlayerFactory::registerFactory(IFactory* factory,
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b6cc742..1b1d7a9 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2709,6 +2709,83 @@
     }
 }
 
+// static
+void ACodec::describeDefaultColorFormat(DescribeColorFormatParams &params) {
+    MediaImage &image = params.sMediaImage;
+    memset(&image, 0, sizeof(image));
+
+    image.mType = MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN;
+    image.mNumPlanes = 0;
+
+    const OMX_COLOR_FORMATTYPE fmt = params.eColorFormat;
+    // we need stride and slice-height to be non-zero
+    if (params.nStride == 0 || params.nSliceHeight == 0) {
+        ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u",
+                fmt, fmt, params.nStride, params.nSliceHeight);
+        return;
+    }
+
+    image.mWidth = params.nFrameWidth;
+    image.mHeight = params.nFrameHeight;
+
+    // only supporting YUV420
+    if (fmt != OMX_COLOR_FormatYUV420Planar &&
+        fmt != OMX_COLOR_FormatYUV420PackedPlanar &&
+        fmt != OMX_COLOR_FormatYUV420SemiPlanar &&
+        fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar) {
+        ALOGW("do not know color format 0x%x = %d", fmt, fmt);
+        return;
+    }
+
+    // set-up YUV format
+    image.mType = MediaImage::MEDIA_IMAGE_TYPE_YUV;
+    image.mNumPlanes = 3;
+    image.mBitDepth = 8;
+    image.mPlane[image.Y].mOffset = 0;
+    image.mPlane[image.Y].mColInc = 1;
+    image.mPlane[image.Y].mRowInc = params.nStride;
+    image.mPlane[image.Y].mHorizSubsampling = 1;
+    image.mPlane[image.Y].mVertSubsampling = 1;
+
+    switch (fmt) {
+        case OMX_COLOR_FormatYUV420Planar: // used for YV12
+        case OMX_COLOR_FormatYUV420PackedPlanar:
+            image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
+            image.mPlane[image.U].mColInc = 1;
+            image.mPlane[image.U].mRowInc = params.nStride / 2;
+            image.mPlane[image.U].mHorizSubsampling = 2;
+            image.mPlane[image.U].mVertSubsampling = 2;
+
+            image.mPlane[image.V].mOffset = image.mPlane[image.U].mOffset
+                    + (params.nStride * params.nSliceHeight / 4);
+            image.mPlane[image.V].mColInc = 1;
+            image.mPlane[image.V].mRowInc = params.nStride / 2;
+            image.mPlane[image.V].mHorizSubsampling = 2;
+            image.mPlane[image.V].mVertSubsampling = 2;
+            break;
+
+        case OMX_COLOR_FormatYUV420SemiPlanar:
+            // FIXME: NV21 for sw-encoder, NV12 for decoder and hw-encoder
+        case OMX_COLOR_FormatYUV420PackedSemiPlanar:
+            // NV12
+            image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
+            image.mPlane[image.U].mColInc = 2;
+            image.mPlane[image.U].mRowInc = params.nStride;
+            image.mPlane[image.U].mHorizSubsampling = 2;
+            image.mPlane[image.U].mVertSubsampling = 2;
+
+            image.mPlane[image.V].mOffset = image.mPlane[image.U].mOffset + 1;
+            image.mPlane[image.V].mColInc = 2;
+            image.mPlane[image.V].mRowInc = params.nStride;
+            image.mPlane[image.V].mHorizSubsampling = 2;
+            image.mPlane[image.V].mVertSubsampling = 2;
+            break;
+
+        default:
+            TRESPASS();
+    }
+}
+
 status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
     // TODO: catch errors an return them instead of using CHECK
     OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -2736,6 +2813,33 @@
                     notify->setInt32("slice-height", videoDef->nSliceHeight);
                     notify->setInt32("color-format", videoDef->eColorFormat);
 
+
+                    DescribeColorFormatParams describeParams;
+                    InitOMXParams(&describeParams);
+                    describeParams.eColorFormat = videoDef->eColorFormat;
+                    describeParams.nFrameWidth = videoDef->nFrameWidth;
+                    describeParams.nFrameHeight = videoDef->nFrameHeight;
+                    describeParams.nStride = videoDef->nStride;
+                    describeParams.nSliceHeight = videoDef->nSliceHeight;
+
+                    OMX_INDEXTYPE describeColorFormatIndex;
+                    if (mOMX->getExtensionIndex(
+                            mNode, "OMX.google.android.index.describeColorFormat",
+                            &describeColorFormatIndex) ||
+                        mOMX->getParameter(
+                            mNode, describeColorFormatIndex,
+                            &describeParams, sizeof(describeParams))) {
+                        describeDefaultColorFormat(describeParams);
+                    }
+
+                    if (describeParams.sMediaImage.mType != MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN) {
+                        notify->setBuffer(
+                                "image-data",
+                                ABuffer::CreateAsCopy(
+                                        &describeParams.sMediaImage,
+                                        sizeof(describeParams.sMediaImage)));
+                    }
+
                     OMX_CONFIG_RECTTYPE rect;
                     InitOMXParams(&rect);
                     rect.nPortIndex = kPortIndexOutput;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 15e062e..e944766 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1948,6 +1948,18 @@
         Mutex::Autolock al(mBufferLock);
         info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat;
         info->mOwnedByClient = true;
+
+        // set image-data
+        if (info->mFormat != NULL) {
+            sp<ABuffer> imageData;
+            if (info->mFormat->findBuffer("image-data", &imageData)) {
+                info->mData->meta()->setBuffer("image-data", imageData);
+            }
+            int32_t left, top, right, bottom;
+            if (info->mFormat->findRect("crop", &left, &top, &right, &bottom)) {
+                info->mData->meta()->setRect("crop-rect", left, top, right, bottom);
+            }
+        }
     }
 
     return index;
diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp
index 6173db4..c93c7e8 100644
--- a/media/libstagefright/foundation/ABuffer.cpp
+++ b/media/libstagefright/foundation/ABuffer.cpp
@@ -40,6 +40,14 @@
       mOwnsData(false) {
 }
 
+// static
+sp<ABuffer> ABuffer::CreateAsCopy(const void *data, size_t capacity)
+{
+    sp<ABuffer> res = new ABuffer(capacity);
+    memcpy(res->data(), data, capacity);
+    return res;
+}
+
 ABuffer::~ABuffer() {
     if (mOwnsData) {
         if (mData != NULL) {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c3aafd9..c959b9f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -167,7 +167,7 @@
 // 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(),
 // and that all "fast" AudioRecord clients read from.  In either case, the size can be small.
-static const size_t kRecordThreadReadOnlyHeapSize = 0x1000;
+static const size_t kRecordThreadReadOnlyHeapSize = 0x2000;
 
 // ----------------------------------------------------------------------------
 
@@ -4862,8 +4862,8 @@
                 // or primary output sample rate is unknown, and capture sample rate is reasonable
                 ((primaryOutputSampleRate == 0) &&
                     ((mSampleRate == 44100 || mSampleRate == 48000)))) &&
-                // and the buffer size is < 10 ms
-                (mFrameCount * 1000) / mSampleRate < 10;
+                // and the buffer size is < 12 ms
+                (mFrameCount * 1000) / mSampleRate < 12;
         break;
     // case FastCapture_Dynamic:
     }
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 737cacd..c5248fe 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -30,6 +30,10 @@
 // A device mask for all audio output devices that are considered "remote" when evaluating
 // active output devices in isStreamActiveRemotely()
 #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL  AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+// A device mask for all audio input and output devices where matching inputs/outputs on device
+// type alone is not enough: the address must match too
+#define APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \
+                                            AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
 
 #include <inttypes.h>
 #include <math.h>
@@ -228,14 +232,6 @@
             }
             ALOGV("setDeviceConnectionState() connecting device %x", device);
 
-            if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) {
-                return INVALID_OPERATION;
-            }
-            // outputs should never be empty here
-            ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
-                    "checkOutputsForDevice() returned no outputs but status OK");
-            ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
-                  outputs.size());
             // register new device as available
             index = mAvailableOutputDevices.add(devDesc);
             if (index >= 0) {
@@ -248,6 +244,15 @@
                 return NO_MEMORY;
             }
 
+            if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) {
+                mAvailableOutputDevices.remove(devDesc);
+                return INVALID_OPERATION;
+            }
+            // outputs should never be empty here
+            ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
+                    "checkOutputsForDevice() returned no outputs but status OK");
+            ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
+                  outputs.size());
             break;
         // handle output device disconnection
         case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
@@ -261,8 +266,6 @@
             mAvailableOutputDevices.remove(devDesc);
 
             checkOutputsForDevice(device, state, outputs, address);
-            // not currently handling multiple simultaneous submixes: ignoring remote submix
-            //   case and address
             } break;
 
         default:
@@ -295,10 +298,13 @@
             // do not force device change on duplicated output because if device is 0, it will
             // also force a device 0 for the two outputs it is duplicated to which may override
             // a valid device selection on those outputs.
+            bool force = !mOutputs.valueAt(i)->isDuplicated()
+                    && (!deviceDistinguishesOnAddress(device)
+                            // always force when disconnecting (a non-duplicated device)
+                            || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
             setOutputDevice(mOutputs.keyAt(i),
                             getNewOutputDevice(mOutputs.keyAt(i), true /*fromCache*/),
-                            !mOutputs.valueAt(i)->isDuplicated(),
-                            0);
+                            force, 0);
         }
 
         mpClientInterface->onAudioPortListUpdate();
@@ -617,20 +623,10 @@
         }
         for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
             sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
-            bool found = false;
-            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
-                if (profile->isCompatibleProfile(device, samplingRate, format,
-                                           channelMask,
-                                           AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
-                    found = true;
-                }
-            } else {
-                if (profile->isCompatibleProfile(device, samplingRate, format,
-                                           channelMask,
-                                           AUDIO_OUTPUT_FLAG_DIRECT)) {
-                    found = true;
-                }
-            }
+            bool found = profile->isCompatibleProfile(device, samplingRate,
+                    NULL /*updatedSamplingRate*/, format, channelMask,
+                    flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ?
+                        AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT);
             if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) {
                 return profile;
             }
@@ -1895,6 +1891,7 @@
 
         if (!outputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
                                                        patch->sources[0].sample_rate,
+                                                     NULL,  // updatedSamplingRate
                                                      patch->sources[0].format,
                                                      patch->sources[0].channel_mask,
                                                      AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
@@ -1940,7 +1937,8 @@
             }
 
             if (!inputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
-                                                           patch->sinks[0].sample_rate,
+                                                         patch->sinks[0].sample_rate,
+                                                         NULL, /*updatedSampleRate*/
                                                          patch->sinks[0].format,
                                                          patch->sinks[0].channel_mask,
                                                          // FIXME for the parameter type,
@@ -2643,10 +2641,39 @@
 {
     if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
         return String8("a2dp_sink_address=")+address;
+    } else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+        return String8("mix=")+address;
     }
     return address;
 }
 
+void AudioPolicyManager::findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/,
+        const String8 address /*in*/,
+        SortedVector<audio_io_handle_t>& outputs /*out*/) {
+    // look for a match on the given address on the addresses of the outputs:
+    // find the address by finding the patch that maps to this output
+    ssize_t patchIdx = mAudioPatches.indexOfKey(desc->mPatchHandle);
+    //ALOGV("    inspecting output %d (patch %d) for supported device=0x%x",
+    //        outputIdx, patchIdx,  desc->mProfile->mSupportedDevices.types());
+    if (patchIdx >= 0) {
+        const sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patchIdx);
+        const int numSinks = patchDesc->mPatch.num_sinks;
+        for (ssize_t j=0; j < numSinks; j++) {
+            if (patchDesc->mPatch.sinks[j].type == AUDIO_PORT_TYPE_DEVICE) {
+                const char* patchAddr =
+                        patchDesc->mPatch.sinks[j].ext.device.address;
+                if (strncmp(patchAddr,
+                        address.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
+                    ALOGV("checkOutputsForDevice(): adding opened output %d on same address %s",
+                            desc->mIoHandle,  patchDesc->mPatch.sinks[j].ext.device.address);
+                    outputs.add(desc->mIoHandle);
+                    break;
+                }
+            }
+        }
+    }
+}
+
 status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
                                                        audio_policy_dev_state_t state,
                                                        SortedVector<audio_io_handle_t>& outputs,
@@ -2659,8 +2686,13 @@
         for (size_t i = 0; i < mOutputs.size(); i++) {
             desc = mOutputs.valueAt(i);
             if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices.types() & device)) {
-                ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
-                outputs.add(mOutputs.keyAt(i));
+                if (!deviceDistinguishesOnAddress(device)) {
+                    ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
+                    outputs.add(mOutputs.keyAt(i));
+                } else {
+                    ALOGV("  checking address match due to device 0x%x", device);
+                    findIoHandlesByAddress(desc, address, outputs);
+                }
             }
         }
         // then look for output profiles that can be routed to this device
@@ -2679,6 +2711,8 @@
             }
         }
 
+        ALOGV("  found %d profiles, %d outputs", profiles.size(), outputs.size());
+
         if (profiles.isEmpty() && outputs.isEmpty()) {
             ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
             return BAD_VALUE;
@@ -2691,13 +2725,13 @@
 
             // nothing to do if one output is already opened for this profile
             size_t j;
-            for (j = 0; j < mOutputs.size(); j++) {
-                desc = mOutputs.valueAt(j);
+            for (j = 0; j < outputs.size(); j++) {
+                desc = mOutputs.valueFor(outputs.itemAt(j));
                 if (!desc->isDuplicated() && desc->mProfile == profile) {
                     break;
                 }
             }
-            if (j != mOutputs.size()) {
+            if (j != outputs.size()) {
                 continue;
             }
 
@@ -2730,7 +2764,7 @@
                 if (profile->mSamplingRates[0] == 0) {
                     reply = mpClientInterface->getParameters(output,
                                             String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
-                    ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+                    ALOGV("checkOutputsForDevice() supported sampling rates %s",
                               reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
@@ -2740,7 +2774,7 @@
                 if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
                     reply = mpClientInterface->getParameters(output,
                                                    String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
-                    ALOGV("checkOutputsForDevice() direct output sup formats %s",
+                    ALOGV("checkOutputsForDevice() supported formats %s",
                               reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
@@ -2750,7 +2784,7 @@
                 if (profile->mChannelMasks[0] == 0) {
                     reply = mpClientInterface->getParameters(output,
                                                   String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
-                    ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+                    ALOGV("checkOutputsForDevice() supported channel masks %s",
                               reply.string());
                     value = strpbrk((char *)reply.string(), "=");
                     if (value != NULL) {
@@ -2763,7 +2797,7 @@
                          (profile->mFormats.size() < 2)) ||
                      ((profile->mChannelMasks[0] == 0) &&
                          (profile->mChannelMasks.size() < 2))) {
-                    ALOGW("checkOutputsForDevice() direct output missing param");
+                    ALOGW("checkOutputsForDevice() missing param");
                     mpClientInterface->closeOutput(output);
                     output = 0;
                 } else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 ||
@@ -2827,6 +2861,12 @@
                 profile_index--;
             } else {
                 outputs.add(output);
+                if (deviceDistinguishesOnAddress(device)) {
+                    ALOGV("checkOutputsForDevice(): setOutputDevice(dev=0x%x, addr=%s)",
+                            device, address.string());
+                    setOutputDevice(output, device, true/*force*/, 0/*delay*/,
+                            NULL/*patch handle*/, address.string());
+                }
                 ALOGV("checkOutputsForDevice(): adding output %d", output);
             }
         }
@@ -2839,11 +2879,17 @@
         // check if one opened output is not needed any more after disconnecting one device
         for (size_t i = 0; i < mOutputs.size(); i++) {
             desc = mOutputs.valueAt(i);
-            if (!desc->isDuplicated() &&
-                    !(desc->mProfile->mSupportedDevices.types() &
-                            mAvailableOutputDevices.types())) {
-                ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i));
-                outputs.add(mOutputs.keyAt(i));
+            if (!desc->isDuplicated()) {
+                if  (!(desc->mProfile->mSupportedDevices.types()
+                        & mAvailableOutputDevices.types())) {
+                    ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
+                            mOutputs.keyAt(i));
+                    outputs.add(mOutputs.keyAt(i));
+                } else if (deviceDistinguishesOnAddress(device) &&
+                        // exact match on device
+                        (desc->mProfile->mSupportedDevices.types() == device)) {
+                    findIoHandlesByAddress(desc, address, outputs);
+                }
             }
         }
         // Clear any profiles associated with the disconnected device.
@@ -3736,7 +3782,8 @@
                                              audio_devices_t device,
                                              bool force,
                                              int delayMs,
-                                             audio_patch_handle_t *patchHandle)
+                                             audio_patch_handle_t *patchHandle,
+                                             const char* address)
 {
     ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
     sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
@@ -3782,7 +3829,9 @@
     if (device == AUDIO_DEVICE_NONE) {
         resetOutputDevice(output, delayMs, NULL);
     } else {
-        DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+        DeviceVector deviceList = (address == NULL) ?
+                mAvailableOutputDevices.getDevicesFromType(device)
+                : mAvailableOutputDevices.getDevicesFromTypeAddr(device, String8(address));
         if (!deviceList.isEmpty()) {
             struct audio_patch patch;
             outputDesc->toAudioPortConfig(&patch.sources[0]);
@@ -3949,10 +3998,10 @@
 }
 
 sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
-                                                   uint32_t samplingRate,
+                                                   uint32_t& samplingRate,
                                                    audio_format_t format,
                                                    audio_channel_mask_t channelMask,
-                                                   audio_input_flags_t flags __unused)
+                                                   audio_input_flags_t flags)
 {
     // Choose an input profile based on the requested capture parameters: select the first available
     // profile supporting all requested parameters.
@@ -3966,8 +4015,9 @@
         {
             sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j];
             // profile->log();
-            if (profile->isCompatibleProfile(device, samplingRate, format,
-                                             channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
+            if (profile->isCompatibleProfile(device, samplingRate,
+                                             &samplingRate /*updatedSamplingRate*/,
+                                             format, channelMask, (audio_output_flags_t) flags)) {
                 return profile;
             }
         }
@@ -4046,6 +4096,10 @@
     return false;
 }
 
+bool AudioPolicyManager::deviceDistinguishesOnAddress(audio_devices_t device) {
+    return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL) != 0);
+}
+
 audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs)
 {
     for (size_t i = 0; i < mInputs.size(); i++) {
@@ -4566,13 +4620,13 @@
     }
     if (profile != NULL) {
         mAudioPort = profile;
+        mFlags = profile->mFlags;
         mSamplingRate = profile->pickSamplingRate();
         mFormat = profile->pickFormat();
         mChannelMask = profile->pickChannelMask();
         if (profile->mGains.size() > 0) {
             profile->mGains[0]->getDefaultConfig(&mGain);
         }
-        mFlags = profile->mFlags;
     }
 }
 
@@ -5269,7 +5323,7 @@
     }
 }
 
-status_t AudioPolicyManager::AudioPort::checkSamplingRate(uint32_t samplingRate) const
+status_t AudioPolicyManager::AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
 {
     for (size_t i = 0; i < mSamplingRates.size(); i ++) {
         if (mSamplingRates[i] == samplingRate) {
@@ -5279,9 +5333,68 @@
     return BAD_VALUE;
 }
 
-status_t AudioPolicyManager::AudioPort::checkChannelMask(audio_channel_mask_t channelMask) const
+status_t AudioPolicyManager::AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
+        uint32_t *updatedSamplingRate) const
 {
-    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+    // Search for the closest supported sampling rate that is above (preferred)
+    // or below (acceptable) the desired sampling rate, within a permitted ratio.
+    // The sampling rates do not need to be sorted in ascending order.
+    ssize_t maxBelow = -1;
+    ssize_t minAbove = -1;
+    uint32_t candidate;
+    for (size_t i = 0; i < mSamplingRates.size(); i++) {
+        candidate = mSamplingRates[i];
+        if (candidate == samplingRate) {
+            if (updatedSamplingRate != NULL) {
+                *updatedSamplingRate = candidate;
+            }
+            return NO_ERROR;
+        }
+        // candidate < desired
+        if (candidate < samplingRate) {
+            if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
+                maxBelow = i;
+            }
+        // candidate > desired
+        } else {
+            if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
+                minAbove = i;
+            }
+        }
+    }
+    // This uses hard-coded knowledge about AudioFlinger resampling ratios.
+    // TODO Move these assumptions out.
+    static const uint32_t kMaxDownSampleRatio = 6;  // beyond this aliasing occurs
+    static const uint32_t kMaxUpSampleRatio = 256;  // beyond this sample rate inaccuracies occur
+                                                    // due to approximation by an int32_t of the
+                                                    // phase increments
+    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+    if (minAbove >= 0) {
+        candidate = mSamplingRates[minAbove];
+        if (candidate / kMaxDownSampleRatio <= samplingRate) {
+            if (updatedSamplingRate != NULL) {
+                *updatedSamplingRate = candidate;
+            }
+            return NO_ERROR;
+        }
+    }
+    // But if we have to up-sample from a lower sampling rate, that's OK.
+    if (maxBelow >= 0) {
+        candidate = mSamplingRates[maxBelow];
+        if (candidate * kMaxUpSampleRatio >= samplingRate) {
+            if (updatedSamplingRate != NULL) {
+                *updatedSamplingRate = candidate;
+            }
+            return NO_ERROR;
+        }
+    }
+    // leave updatedSamplingRate unmodified
+    return BAD_VALUE;
+}
+
+status_t AudioPolicyManager::AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
+{
+    for (size_t i = 0; i < mChannelMasks.size(); i++) {
         if (mChannelMasks[i] == channelMask) {
             return NO_ERROR;
         }
@@ -5289,6 +5402,30 @@
     return BAD_VALUE;
 }
 
+status_t AudioPolicyManager::AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
+        const
+{
+    const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
+    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+        // FIXME Does not handle multi-channel automatic conversions yet
+        audio_channel_mask_t supported = mChannelMasks[i];
+        if (supported == channelMask) {
+            return NO_ERROR;
+        }
+        if (isRecordThread) {
+            // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix.
+            // FIXME Abstract this out to a table.
+            if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO)
+                    && channelMask == AUDIO_CHANNEL_IN_MONO) ||
+                (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+                    || channelMask == AUDIO_CHANNEL_IN_STEREO))) {
+                return NO_ERROR;
+            }
+        }
+    }
+    return BAD_VALUE;
+}
+
 status_t AudioPolicyManager::AudioPort::checkFormat(audio_format_t format) const
 {
     for (size_t i = 0; i < mFormats.size(); i ++) {
@@ -5409,7 +5546,7 @@
     // limit format otherwise
     if ((mType != AUDIO_PORT_TYPE_MIX) ||
             ((mRole == AUDIO_PORT_ROLE_SOURCE) &&
-             (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) == 0)))) {
+             (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) {
         bestFormat = AUDIO_FORMAT_INVALID;
     }
 
@@ -5623,14 +5760,14 @@
         goto exit;
     }
     if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-        status = mAudioPort->checkSamplingRate(config->sample_rate);
+        status = mAudioPort->checkExactSamplingRate(config->sample_rate);
         if (status != NO_ERROR) {
             goto exit;
         }
         mSamplingRate = config->sample_rate;
     }
     if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-        status = mAudioPort->checkChannelMask(config->channel_mask);
+        status = mAudioPort->checkExactChannelMask(config->channel_mask);
         if (status != NO_ERROR) {
             goto exit;
         }
@@ -5721,30 +5858,60 @@
 // get a valid a match
 bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device,
                                                             uint32_t samplingRate,
+                                                            uint32_t *updatedSamplingRate,
                                                             audio_format_t format,
                                                             audio_channel_mask_t channelMask,
                                                             audio_output_flags_t flags) const
 {
-    if (samplingRate == 0 || !audio_is_valid_format(format) || channelMask == 0) {
-         return false;
-     }
+    const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
+    const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
+    ALOG_ASSERT(isPlaybackThread != isRecordThread);
 
-     if ((mSupportedDevices.types() & device) != device) {
+    if ((mSupportedDevices.types() & device) != device) {
+        return false;
+    }
+
+    if (samplingRate == 0) {
          return false;
-     }
-     if ((mFlags & flags) != flags) {
+    }
+    uint32_t myUpdatedSamplingRate = samplingRate;
+    if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
          return false;
-     }
-     if (checkSamplingRate(samplingRate) != NO_ERROR) {
+    }
+    if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
+            NO_ERROR) {
          return false;
-     }
-     if (checkChannelMask(channelMask) != NO_ERROR) {
-         return false;
-     }
-     if (checkFormat(format) != NO_ERROR) {
-         return false;
-     }
-     return true;
+    }
+
+    if (!audio_is_valid_format(format) || checkFormat(format) != NO_ERROR) {
+        return false;
+    }
+
+    if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
+            checkExactChannelMask(channelMask) != NO_ERROR)) {
+        return false;
+    }
+    if (isRecordThread && (!audio_is_input_channel(channelMask) ||
+            checkCompatibleChannelMask(channelMask) != NO_ERROR)) {
+        return false;
+    }
+
+    if (isPlaybackThread && (mFlags & flags) != flags) {
+        return false;
+    }
+    // The only input flag that is allowed to be different is the fast flag.
+    // An existing fast stream is compatible with a normal track request.
+    // An existing normal stream is compatible with a fast track request,
+    // but the fast request will be denied by AudioFlinger and converted to normal track.
+    if (isRecordThread && (((audio_input_flags_t) mFlags ^ (audio_input_flags_t) flags) &
+            ~AUDIO_INPUT_FLAG_FAST)) {
+        return false;
+    }
+
+    if (updatedSamplingRate != NULL) {
+        *updatedSamplingRate = myUpdatedSamplingRate;
+    }
+    return true;
 }
 
 void AudioPolicyManager::IOProfile::dump(int fd)
@@ -5954,6 +6121,24 @@
     return devices;
 }
 
+AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromTypeAddr(
+        audio_devices_t type, String8 address) const
+{
+    DeviceVector devices;
+    //ALOGV("   looking for device=%x, addr=%s", type, address.string());
+    for (size_t i = 0; i < size(); i++) {
+        //ALOGV("     at i=%d: device=%x, addr=%s",
+        //        i, itemAt(i)->mDeviceType, itemAt(i)->mAddress.string());
+        if (itemAt(i)->mDeviceType == type) {
+            if (itemAt(i)->mAddress == address) {
+                //ALOGV("      found matching address %s", address.string());
+                devices.add(itemAt(i));
+            }
+        }
+    }
+    return devices;
+}
+
 sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDeviceFromName(
         const String8& name) const
 {
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index e9ec78e..62b3ce5 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -240,8 +240,15 @@
             void loadGain(cnode *root, int index);
             void loadGains(cnode *root);
 
-            status_t checkSamplingRate(uint32_t samplingRate) const;
-            status_t checkChannelMask(audio_channel_mask_t channelMask) const;
+            // searches for an exact match
+            status_t checkExactSamplingRate(uint32_t samplingRate) const;
+            // searches for a compatible match, and returns the best match via updatedSamplingRate
+            status_t checkCompatibleSamplingRate(uint32_t samplingRate,
+                    uint32_t *updatedSamplingRate) const;
+            // searches for an exact match
+            status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
+            // searches for a compatible match, currently implemented for input channel masks only
+            status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask) const;
             status_t checkFormat(audio_format_t format) const;
             status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
 
@@ -339,6 +346,8 @@
             DeviceVector getDevicesFromType(audio_devices_t types) const;
             sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
             sp<DeviceDescriptor> getDeviceFromName(const String8& name) const;
+            DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address)
+                    const;
 
         private:
             void refreshTypes();
@@ -356,8 +365,13 @@
             IOProfile(const String8& name, audio_port_role_t role, const sp<HwModule>& module);
             virtual ~IOProfile();
 
+            // This method is used for both output and input.
+            // If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
+            // For input, flags is interpreted as audio_input_flags_t.
+            // TODO: merge audio_output_flags_t and audio_input_flags_t.
             bool isCompatibleProfile(audio_devices_t device,
                                      uint32_t samplingRate,
+                                     uint32_t *updatedSamplingRate,
                                      audio_format_t format,
                                      audio_channel_mask_t channelMask,
                                      audio_output_flags_t flags) const;
@@ -534,7 +548,8 @@
                              audio_devices_t device,
                              bool force = false,
                              int delayMs = 0,
-                             audio_patch_handle_t *patchHandle = NULL);
+                             audio_patch_handle_t *patchHandle = NULL,
+                             const char* address = NULL);
         status_t resetOutputDevice(audio_io_handle_t output,
                                    int delayMs = 0,
                                    audio_patch_handle_t *patchHandle = NULL);
@@ -673,8 +688,9 @@
 
         audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
                                        audio_output_flags_t flags);
+        // samplingRate parameter is an in/out and so may be modified
         sp<IOProfile> getInputProfile(audio_devices_t device,
-                                   uint32_t samplingRate,
+                                   uint32_t& samplingRate,
                                    audio_format_t format,
                                    audio_channel_mask_t channelMask,
                                    audio_input_flags_t flags);
@@ -774,6 +790,15 @@
         //    routing of notifications
         void handleNotificationRoutingForStream(audio_stream_type_t stream);
         static bool isVirtualInputDevice(audio_devices_t device);
+        static bool deviceDistinguishesOnAddress(audio_devices_t device);
+        // find the outputs on a given output descriptor that have the given address.
+        // to be called on an AudioOutputDescriptor whose supported devices (as defined
+        //   in mProfile->mSupportedDevices) matches the device whose address is to be matched.
+        // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one
+        //   where addresses are used to distinguish between one connected device and another.
+        void findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/,
+                const String8 address /*in*/,
+                SortedVector<audio_io_handle_t>& outputs /*out*/);
         uint32_t nextUniqueId();
         uint32_t nextAudioPortGeneration();
         uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }