Merge "RTSP: append track URL to base URL" into mnc-dev
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index 0029aec..0d04760 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -142,8 +142,13 @@
         CHECK_EQ(err, (status_t)OK);
 
         ssize_t newTrackIndex = muxer->addTrack(format);
-        CHECK_GE(newTrackIndex, 0);
-        trackIndexMap.add(i, newTrackIndex);
+        if (newTrackIndex < 0) {
+            fprintf(stderr, "%s track (%d) unsupported by muxer\n",
+                    isAudio ? "audio" : "video",
+                    i);
+        } else {
+            trackIndexMap.add(i, newTrackIndex);
+        }
     }
 
     int64_t muxerStartTimeUs = ALooper::GetNowUs();
@@ -162,7 +167,12 @@
             ALOGV("saw input eos, err %d", err);
             sawInputEOS = true;
             break;
+        } else if (trackIndexMap.indexOfKey(trackIndex) < 0) {
+            // ALOGV("skipping input from unsupported track %zu", trackIndex);
+            extractor->advance();
+            continue;
         } else {
+            // ALOGV("reading sample from track index %zu\n", trackIndex);
             err = extractor->readSampleData(newBuffer);
             CHECK_EQ(err, (status_t)OK);
 
diff --git a/include/media/AudioIoDescriptor.h b/include/media/AudioIoDescriptor.h
index 2437901..c94b738 100644
--- a/include/media/AudioIoDescriptor.h
+++ b/include/media/AudioIoDescriptor.h
@@ -33,12 +33,31 @@
 class AudioIoDescriptor : public RefBase {
 public:
     AudioIoDescriptor() :
+        mIoHandle(AUDIO_IO_HANDLE_NONE),
         mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(AUDIO_CHANNEL_NONE),
-        mFrameCount(0), mLatency(0) {}
+        mFrameCount(0), mLatency(0)
+    {
+        memset(&mPatch, 0, sizeof(struct audio_patch));
+    }
 
     virtual ~AudioIoDescriptor() {}
 
+    audio_port_handle_t getDeviceId() {
+        if (mPatch.num_sources != 0 && mPatch.num_sinks != 0) {
+            if (mPatch.sources[0].type == AUDIO_PORT_TYPE_MIX) {
+                // this is an output mix
+                // FIXME: the API only returns the first device in case of multiple device selection
+                return mPatch.sinks[0].id;
+            } else {
+                // this is an input mix
+                return mPatch.sources[0].id;
+            }
+        }
+        return AUDIO_PORT_HANDLE_NONE;
+    }
+
     audio_io_handle_t mIoHandle;
+    struct audio_patch mPatch;
     uint32_t mSamplingRate;
     audio_format_t mFormat;
     audio_channel_mask_t mChannelMask;
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index b743c11..c4c7b0e 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -178,6 +178,8 @@
                                     int sessionId = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
+                                    int uid = -1,
+                                    pid_t pid = -1,
                                     const audio_attributes_t* pAttributes = NULL);
 
     /* Terminates the AudioRecord and unregisters it from AudioFlinger.
@@ -214,6 +216,8 @@
                             int sessionId = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
+                            int uid = -1,
+                            pid_t pid = -1,
                             const audio_attributes_t* pAttributes = NULL);
 
     /* Result of constructing the AudioRecord. This must be checked for successful initialization
@@ -390,6 +394,39 @@
      * TODO Document this method.
      */
             audio_port_handle_t getInputDevice();
+
+     /* Returns the ID of the audio device actually used by the input to which this AudioRecord
+      * is attached.
+      * A value of AUDIO_PORT_HANDLE_NONE indicates the AudioRecord is not attached to any input.
+      *
+      * Parameters:
+      *  none.
+      */
+     audio_port_handle_t getRoutedDeviceId();
+
+    /* Add an AudioDeviceCallback. The caller will be notified when the audio device
+     * to which this AudioRecord is routed is updated.
+     * Replaces any previously installed callback.
+     * Parameters:
+     *  callback:  The callback interface
+     * Returns NO_ERROR if successful.
+     *         INVALID_OPERATION if the same callback is already installed.
+     *         NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
+     *         BAD_VALUE if the callback is NULL
+     */
+            status_t addAudioDeviceCallback(
+                    const sp<AudioSystem::AudioDeviceCallback>& callback);
+
+    /* remove an AudioDeviceCallback.
+     * Parameters:
+     *  callback:  The callback interface
+     * Returns NO_ERROR if successful.
+     *         INVALID_OPERATION if the callback is not installed
+     *         BAD_VALUE if the callback is NULL
+     */
+            status_t removeAudioDeviceCallback(
+                    const sp<AudioSystem::AudioDeviceCallback>& callback);
+
 private:
     /* If nonContig is non-NULL, it is an output parameter that will be set to the number of
      * additional non-contiguous frames that are predicted to be available immediately,
@@ -577,11 +614,14 @@
 
     sp<DeathNotifier>       mDeathNotifier;
     uint32_t                mSequence;              // incremented for each new IAudioRecord attempt
+    int                     mClientUid;
+    pid_t                   mClientPid;
     audio_attributes_t      mAttributes;
 
     // For Device Selection API
     //  a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing.
     audio_port_handle_t    mSelectedDeviceId;
+    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
 };
 
 }; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 0cbcdb1..3241e9c 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -332,8 +332,26 @@
 
     };
 
-    static status_t addAudioPortCallback(const sp<AudioPortCallback>& callBack);
-    static status_t removeAudioPortCallback(const sp<AudioPortCallback>& callBack);
+    static status_t addAudioPortCallback(const sp<AudioPortCallback>& callback);
+    static status_t removeAudioPortCallback(const sp<AudioPortCallback>& callback);
+
+    class AudioDeviceCallback : public RefBase
+    {
+    public:
+
+                AudioDeviceCallback() {}
+        virtual ~AudioDeviceCallback() {}
+
+        virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                         audio_port_handle_t deviceId) = 0;
+    };
+
+    static status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+                                           audio_io_handle_t audioIo);
+    static status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+                                              audio_io_handle_t audioIo);
+
+    static audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
 
 private:
 
@@ -359,10 +377,20 @@
         // values for output/input parameters up-to-date in client process
         virtual void ioConfigChanged(audio_io_config_event event,
                                      const sp<AudioIoDescriptor>& ioDesc);
+
+
+        status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+                                               audio_io_handle_t audioIo);
+        status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+                                           audio_io_handle_t audioIo);
+
+        audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
+
     private:
         Mutex                               mLock;
-        DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors;
-
+        DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> >   mIoDescriptors;
+        DefaultKeyedVector<audio_io_handle_t, Vector < sp<AudioDeviceCallback> > >
+                                                                        mAudioDeviceCallbacks;
         // cached values for recording getInputBufferSize() queries
         size_t                              mInBuffSize;    // zero indicates cache is invalid
         uint32_t                            mInSamplingRate;
@@ -377,8 +405,8 @@
         AudioPolicyServiceClient() {
         }
 
-        status_t addAudioPortCallback(const sp<AudioPortCallback>& callBack);
-        status_t removeAudioPortCallback(const sp<AudioPortCallback>& callBack);
+        status_t addAudioPortCallback(const sp<AudioPortCallback>& callback);
+        status_t removeAudioPortCallback(const sp<AudioPortCallback>& callback);
 
         // DeathRecipient
         virtual void binderDied(const wp<IBinder>& who);
@@ -393,6 +421,9 @@
         Vector <sp <AudioPortCallback> >    mAudioPortCallbacks;
     };
 
+    static const sp<AudioFlingerClient> getAudioFlingerClient();
+    static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle);
+
     static sp<AudioFlingerClient> gAudioFlingerClient;
     static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient;
     friend class AudioFlingerClient;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 0ccd19e..458f4b4 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -510,7 +510,7 @@
      */
             status_t    setOutputDevice(audio_port_handle_t deviceId);
 
-    /* Returns the ID of the audio device used for output of this AudioTrack.
+    /* Returns the ID of the audio device selected for this AudioTrack.
      * A value of AUDIO_PORT_HANDLE_NONE indicates default (AudioPolicyManager) routing.
      *
      * Parameters:
@@ -518,6 +518,15 @@
      */
      audio_port_handle_t getOutputDevice();
 
+     /* Returns the ID of the audio device actually used by the output to which this AudioTrack is
+      * attached.
+      * A value of AUDIO_PORT_HANDLE_NONE indicates the audio track is not attached to any output.
+      *
+      * Parameters:
+      *  none.
+      */
+     audio_port_handle_t getRoutedDeviceId();
+
     /* Returns the unique session ID associated with this track.
      *
      * Parameters:
@@ -664,6 +673,28 @@
      */
             status_t    getTimestamp(AudioTimestamp& timestamp);
 
+    /* Add an AudioDeviceCallback. The caller will be notified when the audio device to which this
+     * AudioTrack is routed is updated.
+     * Replaces any previously installed callback.
+     * Parameters:
+     *  callback:  The callback interface
+     * Returns NO_ERROR if successful.
+     *         INVALID_OPERATION if the same callback is already installed.
+     *         NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
+     *         BAD_VALUE if the callback is NULL
+     */
+            status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+
+    /* remove an AudioDeviceCallback.
+     * Parameters:
+     *  callback:  The callback interface
+     * Returns NO_ERROR if successful.
+     *         INVALID_OPERATION if the callback is not installed
+     *         BAD_VALUE if the callback is NULL
+     */
+            status_t removeAudioDeviceCallback(
+                    const sp<AudioSystem::AudioDeviceCallback>& callback);
+
 protected:
     /* copying audio tracks is not allowed */
                         AudioTrack(const AudioTrack& other);
@@ -885,6 +916,8 @@
     uint32_t                mSequence;              // incremented for each new IAudioTrack attempt
     int                     mClientUid;
     pid_t                   mClientPid;
+
+    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
 };
 
 class TimedAudioTrack : public AudioTrack
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 046345c..3f7fd09 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -89,6 +89,7 @@
                                 size_t *pFrameCount,
                                 track_flags_t *flags,
                                 pid_t tid,  // -1 means unused, otherwise must be valid non-0
+                                int clientUid,
                                 int *sessionId,
                                 size_t *notificationFrames,
                                 sp<IMemory>& cblk,
diff --git a/include/media/stagefright/MediaSync.h b/include/media/stagefright/MediaSync.h
index a349986..d1d634d 100644
--- a/include/media/stagefright/MediaSync.h
+++ b/include/media/stagefright/MediaSync.h
@@ -75,11 +75,11 @@
 
     // Called when MediaSync is used to render video. It should be called
     // before createInputSurface().
-    status_t configureSurface(const sp<IGraphicBufferProducer> &output);
+    status_t setSurface(const sp<IGraphicBufferProducer> &output);
 
     // Called when audio track is used as media clock source. It should be
     // called before updateQueuedAudioData().
-    status_t configureAudioTrack(const sp<AudioTrack> &audioTrack);
+    status_t setAudioTrack(const sp<AudioTrack> &audioTrack);
 
     // Create a surface for client to render video frames. This is the surface
     // on which the client should render video frames. Those video frames will
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 23015c0..3868f13 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -85,6 +85,8 @@
         int sessionId,
         transfer_type transferType,
         audio_input_flags_t flags,
+        int uid,
+        pid_t pid,
         const audio_attributes_t* pAttributes)
     : mStatus(NO_INIT),
       mOpPackageName(opPackageName),
@@ -96,7 +98,7 @@
 {
     mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
             notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
-            pAttributes);
+            uid, pid, pAttributes);
 }
 
 AudioRecord::~AudioRecord()
@@ -112,6 +114,10 @@
             mAudioRecordThread->requestExitAndWait();
             mAudioRecordThread.clear();
         }
+        // No lock here: worst case we remove a NULL callback which will be a nop
+        if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
+            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+        }
         IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
         mAudioRecord.clear();
         mCblkMemory.clear();
@@ -136,12 +142,15 @@
         int sessionId,
         transfer_type transferType,
         audio_input_flags_t flags,
+        int uid,
+        pid_t pid,
         const audio_attributes_t* pAttributes)
 {
     ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
-          "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s",
+          "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s "
+          "uid %d, pid %d",
           inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
-          sessionId, transferType, flags, String8(mOpPackageName).string());
+          sessionId, transferType, flags, String8(mOpPackageName).string(), uid, pid);
 
     switch (transferType) {
     case TRANSFER_DEFAULT:
@@ -228,6 +237,19 @@
     }
     ALOGV("set(): mSessionId %d", mSessionId);
 
+    int callingpid = IPCThreadState::self()->getCallingPid();
+    int mypid = getpid();
+    if (uid == -1 || (callingpid != mypid)) {
+        mClientUid = IPCThreadState::self()->getCallingUid();
+    } else {
+        mClientUid = uid;
+    }
+    if (pid == -1 || (callingpid != mypid)) {
+        mClientPid = callingpid;
+    } else {
+        mClientPid = pid;
+    }
+
     mFlags = flags;
     mCbf = cbf;
 
@@ -286,6 +308,8 @@
     mNewPosition = mProxy->getPosition() + mUpdatePeriod;
     int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
 
+    mActive = true;
+
     status_t status = NO_ERROR;
     if (!(flags & CBLK_INVALID)) {
         status = mAudioRecord->start(event, triggerSession);
@@ -298,9 +322,9 @@
     }
 
     if (status != NO_ERROR) {
+        mActive = false;
         ALOGE("start() status %d", status);
     } else {
-        mActive = true;
         sp<AudioRecordThread> t = mAudioRecordThread;
         if (t != 0) {
             t->resume();
@@ -425,6 +449,11 @@
     AutoMutex lock(mLock);
     if (mSelectedDeviceId != deviceId) {
         mSelectedDeviceId = deviceId;
+        // stop capture so that audio policy manager does not reject the new instance start request
+        // as only one capture can be active at a time.
+        if (mAudioRecord != 0 && mActive) {
+            mAudioRecord->stop();
+        }
         android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
     }
     return NO_ERROR;
@@ -435,6 +464,14 @@
     return mSelectedDeviceId;
 }
 
+audio_port_handle_t AudioRecord::getRoutedDeviceId() {
+    AutoMutex lock(mLock);
+    if (mInput == AUDIO_IO_HANDLE_NONE) {
+        return AUDIO_PORT_HANDLE_NONE;
+    }
+    return AudioSystem::getDeviceIdForIo(mInput);
+}
+
 // -------------------------------------------------------------------------
 
 // must be called with mLock held
@@ -478,6 +515,10 @@
         }
     }
 
+    if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
+        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+    }
+
     audio_io_handle_t input;
     status_t status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                         (audio_session_t)mSessionId,
@@ -513,6 +554,7 @@
                                                        &temp,
                                                        &trackFlags,
                                                        tid,
+                                                       mClientUid,
                                                        &mSessionId,
                                                        &notificationFrames,
                                                        iMem,
@@ -609,6 +651,10 @@
     mDeathNotifier = new DeathNotifier(this);
     IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
 
+    if (mDeviceCallback != 0) {
+        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
+    }
+
     return NO_ERROR;
     }
 
@@ -1054,6 +1100,48 @@
     return result;
 }
 
+status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
+{
+    if (callback == 0) {
+        ALOGW("%s adding NULL callback!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    AutoMutex lock(mLock);
+    if (mDeviceCallback == callback) {
+        ALOGW("%s adding same callback!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    status_t status = NO_ERROR;
+    if (mInput != AUDIO_IO_HANDLE_NONE) {
+        if (mDeviceCallback != 0) {
+            ALOGW("%s callback already present!", __FUNCTION__);
+            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+        }
+        status = AudioSystem::addAudioDeviceCallback(callback, mInput);
+    }
+    mDeviceCallback = callback;
+    return status;
+}
+
+status_t AudioRecord::removeAudioDeviceCallback(
+        const sp<AudioSystem::AudioDeviceCallback>& callback)
+{
+    if (callback == 0) {
+        ALOGW("%s removing NULL callback!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    AutoMutex lock(mLock);
+    if (mDeviceCallback != callback) {
+        ALOGW("%s removing different callback!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if (mInput != AUDIO_IO_HANDLE_NONE) {
+        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+    }
+    mDeviceCallback = 0;
+    return NO_ERROR;
+}
+
 // =========================================================================
 
 void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 85ed2b1..4c2e77b 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -76,6 +76,25 @@
     return af;
 }
 
+const sp<AudioSystem::AudioFlingerClient> AudioSystem::getAudioFlingerClient()
+{
+    // calling get_audio_flinger() will initialize gAudioFlingerClient if needed
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return 0;
+    Mutex::Autolock _l(gLock);
+    return gAudioFlingerClient;
+}
+
+sp<AudioIoDescriptor> AudioSystem::getIoDescriptor(audio_io_handle_t ioHandle)
+{
+    sp<AudioIoDescriptor> desc;
+    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
+    if (afc != 0) {
+        desc = afc->getIoDescriptor(ioHandle);
+    }
+    return desc;
+}
+
 /* static */ status_t AudioSystem::checkAudioFlinger()
 {
     if (defaultServiceManager()->checkService(String16("media.audio_flinger")) != 0) {
@@ -249,9 +268,7 @@
 {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
-
-    LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0);
-    sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output);
+    sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output);
     if (outputDesc == 0) {
         ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output);
         *samplingRate = af->sampleRate(output);
@@ -290,9 +307,7 @@
 {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
-
-    LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0);
-    sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output);
+    sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output);
     if (outputDesc == 0) {
         *frameCount = af->frameCount(output);
     } else {
@@ -329,9 +344,7 @@
 {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
-
-    LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0);
-    sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output);
+    sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output);
     if (outputDesc == 0) {
         *latency = af->latency(output);
     } else {
@@ -346,10 +359,11 @@
 status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
         audio_channel_mask_t channelMask, size_t* buffSize)
 {
-    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
-    if (af == 0) return PERMISSION_DENIED;
-    LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0);
-    return gAudioFlingerClient->getInputBufferSize(sampleRate, format, channelMask, buffSize);
+    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
+    if (afc == 0) {
+        return NO_INIT;
+    }
+    return afc->getInputBufferSize(sampleRate, format, channelMask, buffSize);
 }
 
 status_t AudioSystem::setVoiceVolume(float value)
@@ -446,47 +460,77 @@
 
     if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
 
-    Mutex::Autolock _l(mLock);
+    audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+    Vector < sp<AudioDeviceCallback> > callbacks;
 
-    switch (event) {
-    case AUDIO_OUTPUT_OPENED:
-    case AUDIO_INPUT_OPENED: {
-        if (getIoDescriptor(ioDesc->mIoHandle) != 0) {
-            ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle);
-            break;
-        }
-        mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
-        ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
-                "frameCount %zu", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
-                ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
-                ioDesc->mFrameCount);
-        } break;
-    case AUDIO_OUTPUT_CLOSED:
-    case AUDIO_INPUT_CLOSED: {
-        if (getIoDescriptor(ioDesc->mIoHandle) == 0) {
-            ALOGW("ioConfigChanged() closing unknown %s %d",
+    {
+        Mutex::Autolock _l(mLock);
+
+        switch (event) {
+        case AUDIO_OUTPUT_OPENED:
+        case AUDIO_INPUT_OPENED: {
+            if (getIoDescriptor(ioDesc->mIoHandle) != 0) {
+                ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle);
+                break;
+            }
+            mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
+
+            if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
+                deviceId = ioDesc->getDeviceId();
+                ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+                if (ioIndex >= 0) {
+                    callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                }
+            }
+            ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
+                    "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
+                    ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
+                    ioDesc->mFrameCount, ioDesc->getDeviceId());
+            } break;
+        case AUDIO_OUTPUT_CLOSED:
+        case AUDIO_INPUT_CLOSED: {
+            if (getIoDescriptor(ioDesc->mIoHandle) == 0) {
+                ALOGW("ioConfigChanged() closing unknown %s %d",
+                      event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle);
+                break;
+            }
+            ALOGV("ioConfigChanged() %s %d closed",
                   event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle);
-            break;
-        }
-        ALOGV("ioConfigChanged() %s %d closed", event == AUDIO_OUTPUT_CLOSED ? "output" : "input",
-                ioDesc->mIoHandle);
 
-        mIoDescriptors.removeItem(ioDesc->mIoHandle);
+            mIoDescriptors.removeItem(ioDesc->mIoHandle);
+            mAudioDeviceCallbacks.removeItem(ioDesc->mIoHandle);
+            } break;
+
+        case AUDIO_OUTPUT_CONFIG_CHANGED:
+        case AUDIO_INPUT_CONFIG_CHANGED: {
+            sp<AudioIoDescriptor> oldDesc = getIoDescriptor(ioDesc->mIoHandle);
+            if (oldDesc == 0) {
+                ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle);
+                break;
+            }
+
+            deviceId = oldDesc->getDeviceId();
+            mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
+
+            if (deviceId != ioDesc->getDeviceId()) {
+                deviceId = ioDesc->getDeviceId();
+                ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+                if (ioIndex >= 0) {
+                    callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                }
+            }
+            ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x "
+                    "channel mask %#x frameCount %zu deviceId %d",
+                    event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input",
+                    ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat,
+                    ioDesc->mChannelMask, ioDesc->mFrameCount, ioDesc->getDeviceId());
+
         } break;
-
-    case AUDIO_OUTPUT_CONFIG_CHANGED:
-    case AUDIO_INPUT_CONFIG_CHANGED: {
-        if (getIoDescriptor(ioDesc->mIoHandle) == 0) {
-            ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle);
-            break;
         }
-        mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
-        ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x "
-                "channel mask %#x frameCount %zu",
-                event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input",
-                ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat,
-                ioDesc->mChannelMask, ioDesc->mFrameCount);
-    } break;
+    }
+    // callbacks.size() != 0 =>  ioDesc->mIoHandle and deviceId are valid
+    for (size_t i = 0; i < callbacks.size(); i++) {
+        callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
     }
 }
 
@@ -532,7 +576,56 @@
     return desc;
 }
 
-/*static*/ void AudioSystem::setErrorCallback(audio_error_callback cb)
+status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
+        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+{
+    Mutex::Autolock _l(mLock);
+    Vector < sp<AudioDeviceCallback> > callbacks;
+    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
+    if (ioIndex >= 0) {
+        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+    }
+
+    for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
+        if (callbacks[cbIndex] == callback) {
+            return INVALID_OPERATION;
+        }
+    }
+    callbacks.add(callback);
+
+    mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
+    return NO_ERROR;
+}
+
+status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
+        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+{
+    Mutex::Autolock _l(mLock);
+    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
+    if (ioIndex < 0) {
+        return INVALID_OPERATION;
+    }
+    Vector < sp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+
+    size_t cbIndex;
+    for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
+        if (callbacks[cbIndex] == callback) {
+            break;
+        }
+    }
+    if (cbIndex == callbacks.size()) {
+        return INVALID_OPERATION;
+    }
+    callbacks.removeAt(cbIndex);
+    if (callbacks.size() != 0) {
+        mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
+    } else {
+        mAudioDeviceCallbacks.removeItem(audioIo);
+    }
+    return NO_ERROR;
+}
+
+/* static */ void AudioSystem::setErrorCallback(audio_error_callback cb)
 {
     Mutex::Autolock _l(gLock);
     gAudioErrorCallback = cb;
@@ -864,11 +957,11 @@
 {
     // called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances
     ALOGV("clearAudioConfigCache()");
-    if (gAudioFlingerClient != 0) {
-        gAudioFlingerClient->clearIoCache();
-    }
     {
         Mutex::Autolock _l(gLock);
+        if (gAudioFlingerClient != 0) {
+            gAudioFlingerClient->clearIoCache();
+        }
         gAudioFlinger.clear();
     }
     {
@@ -934,7 +1027,7 @@
     return aps->setAudioPortConfig(config);
 }
 
-status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callBack)
+status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callback)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
@@ -943,11 +1036,11 @@
     if (gAudioPolicyServiceClient == 0) {
         return NO_INIT;
     }
-    return gAudioPolicyServiceClient->addAudioPortCallback(callBack);
+    return gAudioPolicyServiceClient->addAudioPortCallback(callback);
 }
 
 /*static*/
-status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callBack)
+status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callback)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
@@ -956,7 +1049,38 @@
     if (gAudioPolicyServiceClient == 0) {
         return NO_INIT;
     }
-    return gAudioPolicyServiceClient->removeAudioPortCallback(callBack);
+    return gAudioPolicyServiceClient->removeAudioPortCallback(callback);
+}
+
+status_t AudioSystem::addAudioDeviceCallback(
+        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+{
+    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
+    if (afc == 0) {
+        return NO_INIT;
+    }
+    return afc->addAudioDeviceCallback(callback, audioIo);
+}
+
+status_t AudioSystem::removeAudioDeviceCallback(
+        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+{
+    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
+    if (afc == 0) {
+        return NO_INIT;
+    }
+    return afc->removeAudioDeviceCallback(callback, audioIo);
+}
+
+audio_port_handle_t AudioSystem::getDeviceIdForIo(audio_io_handle_t audioIo)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    const sp<AudioIoDescriptor> desc = getIoDescriptor(audioIo);
+    if (desc == 0) {
+        return AUDIO_PORT_HANDLE_NONE;
+    }
+    return desc->getDeviceId();
 }
 
 status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session,
@@ -1008,25 +1132,25 @@
 // ---------------------------------------------------------------------------
 
 status_t AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
-        const sp<AudioPortCallback>& callBack)
+        const sp<AudioPortCallback>& callback)
 {
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
-        if (mAudioPortCallbacks[i] == callBack) {
+        if (mAudioPortCallbacks[i] == callback) {
             return INVALID_OPERATION;
         }
     }
-    mAudioPortCallbacks.add(callBack);
+    mAudioPortCallbacks.add(callback);
     return NO_ERROR;
 }
 
 status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback(
-        const sp<AudioPortCallback>& callBack)
+        const sp<AudioPortCallback>& callback)
 {
     Mutex::Autolock _l(mLock);
     size_t i;
     for (i = 0; i < mAudioPortCallbacks.size(); i++) {
-        if (mAudioPortCallbacks[i] == callBack) {
+        if (mAudioPortCallbacks[i] == callback) {
             break;
         }
     }
@@ -1037,6 +1161,7 @@
     return NO_ERROR;
 }
 
+
 void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate()
 {
     Mutex::Autolock _l(mLock);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index bb47d3e..db316b0 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -234,6 +234,10 @@
             mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
+        // No lock here: worst case we remove a NULL callback which will be a nop
+        if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
+            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+        }
         IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
         mAudioTrack.clear();
         mCblkMemory.clear();
@@ -1042,6 +1046,14 @@
     return mSelectedDeviceId;
 }
 
+audio_port_handle_t AudioTrack::getRoutedDeviceId() {
+    AutoMutex lock(mLock);
+    if (mOutput == AUDIO_IO_HANDLE_NONE) {
+        return AUDIO_PORT_HANDLE_NONE;
+    }
+    return AudioSystem::getDeviceIdForIo(mOutput);
+}
+
 status_t AudioTrack::attachAuxEffect(int effectId)
 {
     AutoMutex lock(mLock);
@@ -1071,6 +1083,9 @@
         return NO_INIT;
     }
 
+    if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
+        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+    }
     audio_io_handle_t output;
     audio_stream_type_t streamType = mStreamType;
     audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
@@ -1375,6 +1390,10 @@
     mDeathNotifier = new DeathNotifier(this);
     IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
 
+    if (mDeviceCallback != 0) {
+        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mOutput);
+    }
+
     return NO_ERROR;
     }
 
@@ -2308,6 +2327,48 @@
     return mProxy->getUnderrunFrames();
 }
 
+status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
+{
+    if (callback == 0) {
+        ALOGW("%s adding NULL callback!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    AutoMutex lock(mLock);
+    if (mDeviceCallback == callback) {
+        ALOGW("%s adding same callback!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    status_t status = NO_ERROR;
+    if (mOutput != AUDIO_IO_HANDLE_NONE) {
+        if (mDeviceCallback != 0) {
+            ALOGW("%s callback already present!", __FUNCTION__);
+            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+        }
+        status = AudioSystem::addAudioDeviceCallback(callback, mOutput);
+    }
+    mDeviceCallback = callback;
+    return status;
+}
+
+status_t AudioTrack::removeAudioDeviceCallback(
+        const sp<AudioSystem::AudioDeviceCallback>& callback)
+{
+    if (callback == 0) {
+        ALOGW("%s removing NULL callback!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    AutoMutex lock(mLock);
+    if (mDeviceCallback != callback) {
+        ALOGW("%s removing different callback!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if (mOutput != AUDIO_IO_HANDLE_NONE) {
+        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+    }
+    mDeviceCallback = 0;
+    return NO_ERROR;
+}
+
 // =========================================================================
 
 void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index d48532e..d722fe9 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -178,6 +178,7 @@
                                 size_t *pFrameCount,
                                 track_flags_t *flags,
                                 pid_t tid,
+                                int clientUid,
                                 int *sessionId,
                                 size_t *notificationFrames,
                                 sp<IMemory>& cblk,
@@ -197,6 +198,7 @@
         track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
         data.writeInt32(lFlags);
         data.writeInt32((int32_t) tid);
+        data.writeInt32((int32_t) clientUid);
         int lSessionId = AUDIO_SESSION_ALLOCATE;
         if (sessionId != NULL) {
             lSessionId = *sessionId;
@@ -958,6 +960,7 @@
             size_t frameCount = data.readInt64();
             track_flags_t flags = (track_flags_t) data.readInt32();
             pid_t tid = (pid_t) data.readInt32();
+            int clientUid = data.readInt32();
             int sessionId = data.readInt32();
             size_t notificationFrames = data.readInt64();
             sp<IMemory> cblk;
@@ -965,7 +968,7 @@
             status_t status;
             sp<IAudioRecord> record = openRecord(input,
                     sampleRate, format, channelMask, opPackageName, &frameCount, &flags, tid,
-                    &sessionId, &notificationFrames, cblk, buffers, &status);
+                    clientUid, &sessionId, &notificationFrames, cblk, buffers, &status);
             LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR));
             reply->writeInt64(frameCount);
             reply->writeInt32(flags);
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index a622241..3429d36 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -45,6 +45,7 @@
         data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
         data.writeInt32(event);
         data.writeInt32((int32_t)ioDesc->mIoHandle);
+        data.write(&ioDesc->mPatch, sizeof(struct audio_patch));
         data.writeInt32(ioDesc->mSamplingRate);
         data.writeInt32(ioDesc->mFormat);
         data.writeInt32(ioDesc->mChannelMask);
@@ -67,6 +68,7 @@
             audio_io_config_event event = (audio_io_config_event)data.readInt32();
             sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
             ioDesc->mIoHandle = (audio_io_handle_t) data.readInt32();
+            data.read(&ioDesc->mPatch, sizeof(struct audio_patch));
             ioDesc->mSamplingRate = data.readInt32();
             ioDesc->mFormat = (audio_format_t) data.readInt32();
             ioDesc->mChannelMask = (audio_channel_mask_t) data.readInt32();
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 9246a7c..2f440fe 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -142,7 +142,7 @@
 
         ssize_t result = reply.readInt32();
 
-        if (result >= ERROR_DRM_VENDOR_MIN && result <= ERROR_DRM_VENDOR_MAX) {
+        if (isCryptoError(result)) {
             errorDetailMsg->setTo(reply.readCString());
         }
 
@@ -319,8 +319,7 @@
 
             reply->writeInt32(result);
 
-            if (result >= ERROR_DRM_VENDOR_MIN
-                && result <= ERROR_DRM_VENDOR_MAX) {
+            if (isCryptoError(result)) {
                 reply->writeCString(errorDetailMsg.c_str());
             }
 
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
index 2ff7658..09137ef 100644
--- a/media/libmedia/IMediaHTTPConnection.cpp
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -24,6 +24,7 @@
 #include <binder/Parcel.h>
 #include <utils/String8.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -106,11 +107,18 @@
             return UNKNOWN_ERROR;
         }
 
-        int32_t len = reply.readInt32();
+        size_t len = reply.readInt32();
 
-        if (len > 0) {
-            memcpy(buffer, mMemory->pointer(), len);
+        if (len > size) {
+            ALOGE("requested %zu, got %zu", size, len);
+            return ERROR_OUT_OF_RANGE;
         }
+        if (len > mMemory->size()) {
+            ALOGE("got %zu, but memory has %zu", len, mMemory->size());
+            return ERROR_OUT_OF_RANGE;
+        }
+
+        memcpy(buffer, mMemory->pointer(), len);
 
         return len;
     }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 9963353..a118dec 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -423,7 +423,19 @@
     CHECK(format->findInt32("type", &trackType));
 
     AString mime;
-    CHECK(format->findString("mime", &mime));
+    if (!format->findString("mime", &mime)) {
+        // Java MediaPlayer only uses mimetype for subtitle and timedtext tracks.
+        // If we can't find the mimetype here it means that we wouldn't be needing
+        // the mimetype on the Java end. We still write a placeholder mime to keep the
+        // (de)serialization logic simple.
+        if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
+            mime = "audio/";
+        } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
+            mime = "video/";
+        } else {
+            TRESPASS();
+        }
+    }
 
     AString lang;
     CHECK(format->findString("language", &lang));
@@ -704,9 +716,8 @@
             }
 
             if (mVideoDecoder != NULL) {
-                sp<MetaData> meta = getFileMeta();
-                int32_t rate;
-                if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
+                float rate = getFrameRate();
+                if (rate > 0) {
                     sp<AMessage> params = new AMessage();
                     params->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
                     mVideoDecoder->setParameters(params);
@@ -1265,10 +1276,8 @@
         return;
     }
 
-    sp<MetaData> meta = getFileMeta();
-    int32_t rate;
-    if (meta != NULL
-            && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
+    float rate = getFrameRate();
+    if (rate > 0) {
         mRenderer->setVideoFrameRate(rate);
     }
 
@@ -1426,9 +1435,8 @@
             format->setInt32("protected", true);
         }
 
-        sp<MetaData> meta = getFileMeta();
-        int32_t rate;
-        if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
+        float rate = getFrameRate();
+        if (rate > 0) {
             format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
         }
     }
@@ -1702,6 +1710,28 @@
     return mSource->getFileFormatMeta();
 }
 
+float NuPlayer::getFrameRate() {
+    sp<MetaData> meta = mSource->getFormatMeta(false /* audio */);
+    if (meta == NULL) {
+        return 0;
+    }
+    int32_t rate;
+    if (!meta->findInt32(kKeyFrameRate, &rate)) {
+        // fall back to try file meta
+        sp<MetaData> fileMeta = getFileMeta();
+        if (fileMeta == NULL) {
+            ALOGW("source has video meta but not file meta");
+            return -1;
+        }
+        int32_t fileMetaRate;
+        if (!fileMeta->findInt32(kKeyFrameRate, &fileMetaRate)) {
+            return -1;
+        }
+        return fileMetaRate;
+    }
+    return rate;
+}
+
 void NuPlayer::schedulePollDuration() {
     sp<AMessage> msg = new AMessage(kWhatPollDuration, this);
     msg->setInt32("generation", mPollDurationGeneration);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index fcf6841..6b7d71e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -80,6 +80,7 @@
     void getStats(int64_t *mNumFramesTotal, int64_t *mNumFramesDropped);
 
     sp<MetaData> getFileMeta();
+    float getFrameRate();
 
 protected:
     virtual ~NuPlayer();
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b7798d2..22395cc 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -4156,6 +4156,9 @@
         goto error;
     }
 
+    static_cast<Surface*>(mNativeWindow.get())
+            ->getIGraphicBufferProducer()->allowAllocation(true);
+
     err = mNativeWindow->query(mNativeWindow.get(),
             NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
     if (err != NO_ERROR) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index beb12ec..3bc22f2 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -94,6 +94,7 @@
     void addChunkOffset(off64_t offset);
     int32_t getTrackId() const { return mTrackId; }
     status_t dump(int fd, const Vector<String16>& args) const;
+    static const char *getFourCCForMime(const char *mime);
 
 private:
     enum {
@@ -426,6 +427,33 @@
     return OK;
 }
 
+// static
+const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) {
+    if (mime == NULL) {
+        return NULL;
+    }
+    if (!strncasecmp(mime, "audio/", 6)) {
+        if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
+            return "samr";
+        } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
+            return "sawb";
+        } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
+            return "mp4a";
+        }
+    } else if (!strncasecmp(mime, "video/", 6)) {
+        if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
+            return "mp4v";
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
+            return "s263";
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
+            return "avc1";
+        }
+    } else {
+        ALOGE("Track (%s) other than video or audio is not supported", mime);
+    }
+    return NULL;
+}
+
 status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
     Mutex::Autolock l(mLock);
     if (mStarted) {
@@ -441,14 +469,11 @@
 
     CHECK(source.get() != NULL);
 
-    // A track of type other than video or audio is not supported.
     const char *mime;
     source->getFormat()->findCString(kKeyMIMEType, &mime);
     bool isAudio = !strncasecmp(mime, "audio/", 6);
-    bool isVideo = !strncasecmp(mime, "video/", 6);
-    if (!isAudio && !isVideo) {
-        ALOGE("Track (%s) other than video or audio is not supported",
-            mime);
+    if (Track::getFourCCForMime(mime) == NULL) {
+        ALOGE("Unsupported mime '%s'", mime);
         return ERROR_UNSUPPORTED;
     }
 
@@ -2730,17 +2755,13 @@
     const char *mime;
     bool success = mMeta->findCString(kKeyMIMEType, &mime);
     CHECK(success);
-    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
-        mOwner->beginBox("mp4v");
-    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
-        mOwner->beginBox("s263");
-    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
-        mOwner->beginBox("avc1");
-    } else {
+    const char *fourcc = getFourCCForMime(mime);
+    if (fourcc == NULL) {
         ALOGE("Unknown mime type '%s'.", mime);
         CHECK(!"should not be here, unknown mime type.");
     }
 
+    mOwner->beginBox(fourcc);        // video format
     mOwner->writeInt32(0);           // reserved
     mOwner->writeInt16(0);           // reserved
     mOwner->writeInt16(1);           // data ref index
@@ -2784,14 +2805,8 @@
     const char *mime;
     bool success = mMeta->findCString(kKeyMIMEType, &mime);
     CHECK(success);
-    const char *fourcc = NULL;
-    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
-        fourcc = "samr";
-    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
-        fourcc = "sawb";
-    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
-        fourcc = "mp4a";
-    } else {
+    const char *fourcc = getFourCCForMime(mime);
+    if (fourcc == NULL) {
         ALOGE("Unknown mime type '%s'.", mime);
         CHECK(!"should not be here, unknown mime type.");
     }
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index ad4b7a3..97264fb 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -79,17 +79,17 @@
     }
 }
 
-status_t MediaSync::configureSurface(const sp<IGraphicBufferProducer> &output) {
+status_t MediaSync::setSurface(const sp<IGraphicBufferProducer> &output) {
     Mutex::Autolock lock(mMutex);
 
     // TODO: support suface change.
     if (mOutput != NULL) {
-        ALOGE("configureSurface: output surface has already been configured.");
+        ALOGE("setSurface: output surface has already been configured.");
         return INVALID_OPERATION;
     }
 
     if (output == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_VSYNC) {
-        ALOGE("configureSurface: output surface is used as sync source and cannot be removed.");
+        ALOGE("setSurface: output surface is used as sync source and cannot be removed.");
         return INVALID_OPERATION;
     }
 
@@ -103,7 +103,7 @@
                             true /* producerControlledByApp */,
                             &queueBufferOutput);
         if (status != NO_ERROR) {
-            ALOGE("configureSurface: failed to connect (%d)", status);
+            ALOGE("setSurface: failed to connect (%d)", status);
             return status;
         }
 
@@ -114,17 +114,17 @@
 }
 
 // |audioTrack| is used only for querying information.
-status_t MediaSync::configureAudioTrack(const sp<AudioTrack> &audioTrack) {
+status_t MediaSync::setAudioTrack(const sp<AudioTrack> &audioTrack) {
     Mutex::Autolock lock(mMutex);
 
     // TODO: support audio track change.
     if (mAudioTrack != NULL) {
-        ALOGE("configureAudioTrack: audioTrack has already been configured.");
+        ALOGE("setAudioTrack: audioTrack has already been configured.");
         return INVALID_OPERATION;
     }
 
     if (audioTrack == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_AUDIO) {
-        ALOGE("configureAudioTrack: audioTrack is used as sync source and cannot be removed.");
+        ALOGE("setAudioTrack: audioTrack is used as sync source and cannot be removed.");
         return INVALID_OPERATION;
     }
 
@@ -137,7 +137,7 @@
         }
         uint32_t nativeSampleRateInHz = audioTrack->getOriginalSampleRate();
         if (nativeSampleRateInHz <= 0) {
-            ALOGE("configureAudioTrack: native sample rate should be positive.");
+            ALOGE("setAudioTrack: native sample rate should be positive.");
             return BAD_VALUE;
         }
         mAudioTrack = audioTrack;
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index d577034..4297549 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -753,7 +753,9 @@
     oggpack_buffer bits;
     oggpack_readinit(&bits, &ref);
 
-    CHECK_EQ(oggpack_read(&bits, 8), type);
+    if (oggpack_read(&bits, 8) != type) {
+        return ERROR_MALFORMED;
+    }
     for (size_t i = 0; i < 6; ++i) {
         oggpack_read(&bits, 8);  // skip 'vorbis'
     }
@@ -761,7 +763,9 @@
     switch (type) {
         case 1:
         {
-            CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits));
+            if (0 != _vorbis_unpack_info(&mVi, &bits)) {
+                return ERROR_MALFORMED;
+            }
 
             mMeta->setData(kKeyVorbisInfo, 0, data, size);
             mMeta->setInt32(kKeySampleRate, mVi.rate);
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
old mode 100644
new mode 100755
index 06b2163..6afac74
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -625,7 +625,7 @@
         return errType;
     }
 
-    mStride = ALIGN16(mWidth);
+    mStride = mWidth;
 
     if (mInputDataIsMeta) {
         if (mConversionBuffer) {
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 970acf3..e654843 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -661,7 +661,8 @@
         BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
         OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
 
-        if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+        if ((inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) &&
+                inputBufferHeader->nFilledLen == 0) {
             inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
             inputBufferInfo->mOwnedByUs = false;
             notifyEmptyBufferDone(inputBufferHeader);
@@ -762,6 +763,9 @@
                        encoded_packet->data.frame.sz);
                 outputBufferInfo->mOwnedByUs = false;
                 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
+                if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                    outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+                }
                 notifyFillBufferDone(outputBufferHeader);
             }
         }
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 8f356b6..c559682 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -364,7 +364,7 @@
         } else {
             numFrames = vorbis_dsp_pcmout(
                     mState, (int16_t *)outHeader->pBuffer,
-                    kMaxNumSamplesPerBuffer);
+                    (kMaxNumSamplesPerBuffer / mVi->channels));
 
             if (numFrames < 0) {
                 ALOGE("vorbis_dsp_pcmout returned %d", numFrames);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index f31af7b..03c9a8a 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -29,6 +29,8 @@
 struct OMXMaster;
 class GraphicBufferSource;
 
+status_t StatusFromOMXError(OMX_ERRORTYPE err);
+
 struct OMXNodeInstance {
     OMXNodeInstance(
             OMX *owner, const sp<IOMXObserver> &observer, const char *name);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index b9e2f9c..876abb8 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -32,6 +32,7 @@
 
 #include "OMXMaster.h"
 
+#include <OMX_AsString.h>
 #include <OMX_Component.h>
 
 namespace android {
@@ -233,11 +234,11 @@
             instance, &handle);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("FAILED to allocate omx component '%s'", name);
+        ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
 
         instance->onGetHandleFailed();
 
-        return UNKNOWN_ERROR;
+        return StatusFromOMXError(err);
     }
 
     *node = makeNodeID(instance);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 5bc1972..04293d6 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -220,13 +220,15 @@
     return mNodeID;
 }
 
-static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
+status_t StatusFromOMXError(OMX_ERRORTYPE err) {
     switch (err) {
         case OMX_ErrorNone:
             return OK;
         case OMX_ErrorUnsupportedSetting:
         case OMX_ErrorUnsupportedIndex:
             return ERROR_UNSUPPORTED;
+        case OMX_ErrorInsufficientResources:
+            return NO_MEMORY;
         default:
             return UNKNOWN_ERROR;
     }
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index bd6889d..485e320 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1425,6 +1425,7 @@
         size_t *frameCount,
         IAudioFlinger::track_flags_t *flags,
         pid_t tid,
+        int clientUid,
         int *sessionId,
         size_t *notificationFrames,
         sp<IMemory>& cblk,
@@ -1494,8 +1495,7 @@
         // TODO: the uid should be passed in as a parameter to openRecord
         recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
                                                   frameCount, lSessionId, notificationFrames,
-                                                  IPCThreadState::self()->getCallingUid(),
-                                                  flags, tid, &lStatus);
+                                                  clientUid, flags, tid, &lStatus);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
 
         if (lStatus == NO_ERROR) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8085ec2..51b2610 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -124,6 +124,7 @@
                                 size_t *pFrameCount,
                                 IAudioFlinger::track_flags_t *flags,
                                 pid_t tid,
+                                int clientUid,
                                 int *sessionId,
                                 size_t *notificationFrames,
                                 sp<IMemory>& cblk,
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 8b8dd78..2c4d801 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -500,6 +500,7 @@
         // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this))
 {
+    memset(&mPatch, 0, sizeof(struct audio_patch));
 }
 
 AudioFlinger::ThreadBase::~ThreadBase()
@@ -1930,6 +1931,7 @@
     switch (event) {
     case AUDIO_OUTPUT_OPENED:
     case AUDIO_OUTPUT_CONFIG_CHANGED:
+        desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
         desc->mSamplingRate = mSampleRate;
         desc->mFormat = mFormat;
@@ -3002,6 +3004,7 @@
         mEffectChains[i]->setDevice_l(type);
     }
     mOutDevice = type;
+    mPatch = *patch;
 
     if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
         audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice();
@@ -3028,6 +3031,7 @@
                 param.toString().string());
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
+    sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
     return status;
 }
 
@@ -6727,6 +6731,7 @@
     switch (event) {
     case AUDIO_INPUT_OPENED:
     case AUDIO_INPUT_CONFIG_CHANGED:
+        desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
         desc->mSamplingRate = mSampleRate;
         desc->mFormat = mFormat;
@@ -6884,6 +6889,7 @@
 
     // store new device and send to effects
     mInDevice = patch->sources[0].ext.device.type;
+    mPatch = *patch;
     for (size_t i = 0; i < mEffectChains.size(); i++) {
         mEffectChains[i]->setDevice_l(mInDevice);
     }
@@ -6936,6 +6942,8 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
+    sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+
     return status;
 }
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8167bd1..0a5597f 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -426,6 +426,7 @@
                 bool                    mStandby;     // Whether thread is currently in standby.
                 audio_devices_t         mOutDevice;   // output device
                 audio_devices_t         mInDevice;    // input device
+                struct audio_patch      mPatch;
                 audio_source_t          mAudioSource;
 
                 const audio_io_handle_t mId;
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index a2327ee..e6a767f 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -60,7 +60,7 @@
  *
  * @return true if the device is a virtual one, false otherwise.
  */
-static bool is_virtual_input_device(audio_devices_t device)
+static inline bool is_virtual_input_device(audio_devices_t device)
 {
     if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
         device &= ~AUDIO_DEVICE_BIT_IN;
@@ -78,7 +78,7 @@
  *
  * @return true if the device needs distinguish on address, false otherwise..
  */
-static bool device_distinguishes_on_address(audio_devices_t device)
+static inline bool device_distinguishes_on_address(audio_devices_t device)
 {
     return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0);
 }
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index aa37eec..d1a2f4f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -29,7 +29,7 @@
 class DeviceDescriptor : public AudioPort, public AudioPortConfig
 {
 public:
-    DeviceDescriptor(const String8& name, audio_devices_t type);
+    DeviceDescriptor(audio_devices_t type);
 
     virtual ~DeviceDescriptor() {}
 
@@ -50,10 +50,9 @@
     status_t dump(int fd, int spaces, int index) const;
     void log() const;
 
+    String8 mTag;
     String8 mAddress;
 
-    static String8  emptyNameStr;
-
 private:
     audio_devices_t     mDeviceType;
     audio_port_handle_t mId;
@@ -73,12 +72,12 @@
     audio_devices_t types() const { return mDeviceTypes; }
 
     void loadDevicesFromType(audio_devices_t types);
-    void loadDevicesFromName(char *name, const DeviceVector& declaredDevices);
+    void loadDevicesFromTag(char *tag, const DeviceVector& declaredDevices);
 
     sp<DeviceDescriptor> getDevice(audio_devices_t type, String8 address) const;
     DeviceVector getDevicesFromType(audio_devices_t types) const;
     sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
-    sp<DeviceDescriptor> getDeviceFromName(const String8& name) const;
+    sp<DeviceDescriptor> getDeviceFromTag(const String8& tag) const;
     DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address) const;
 
     audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 9ab1d61..89ef045 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -218,7 +218,7 @@
     node = node->first_child;
     while (node) {
         if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
-            availableOutputDevices.loadDevicesFromName((char *)node->value,
+            availableOutputDevices.loadDevicesFromTag((char *)node->value,
                                                         declaredDevices);
             ALOGV("loadGlobalConfig() Attached Output Devices %08x",
                   availableOutputDevices.types());
@@ -228,13 +228,13 @@
                     ARRAY_SIZE(sDeviceTypeToEnumTable),
                     (char *)node->value);
             if (device != AUDIO_DEVICE_NONE) {
-                defaultOutputDevice = new DeviceDescriptor(String8("default-output"), device);
+                defaultOutputDevice = new DeviceDescriptor(device);
             } else {
                 ALOGW("loadGlobalConfig() default device not specified");
             }
             ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
         } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
-            availableInputDevices.loadDevicesFromName((char *)node->value,
+            availableInputDevices.loadDevicesFromTag((char *)node->value,
                                                        declaredDevices);
             ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
         } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 0715eea..797077a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -24,13 +24,11 @@
 
 namespace android {
 
-String8 DeviceDescriptor::emptyNameStr = String8("");
-
-DeviceDescriptor::DeviceDescriptor(const String8& name, audio_devices_t type) :
-    AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+    AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
               audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
                                              AUDIO_PORT_ROLE_SOURCE),
-    mAddress(""), mDeviceType(type), mId(0)
+    mTag(""), mAddress(""), mDeviceType(type), mId(0)
 {
 
 }
@@ -142,24 +140,21 @@
         uint32_t i = 31 - __builtin_clz(types);
         uint32_t type = 1 << i;
         types &= ~type;
-        add(new DeviceDescriptor(String8("device_type"), type | role_bit));
+        add(new DeviceDescriptor(type | role_bit));
     }
 }
 
-void DeviceVector::loadDevicesFromName(char *name,
+void DeviceVector::loadDevicesFromTag(char *tag,
                                        const DeviceVector& declaredDevices)
 {
-    char *devName = strtok(name, "|");
-    while (devName != NULL) {
-        if (strlen(devName) != 0) {
+    char *devTag = strtok(tag, "|");
+    while (devTag != NULL) {
+        if (strlen(devTag) != 0) {
             audio_devices_t type = ConfigParsingUtils::stringToEnum(sDeviceTypeToEnumTable,
                                  ARRAY_SIZE(sDeviceTypeToEnumTable),
-                                 devName);
+                                 devTag);
             if (type != AUDIO_DEVICE_NONE) {
-                devName = (char *)ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
-                                                           ARRAY_SIZE(sDeviceNameToEnumTable),
-                                                           type);
-                sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(devName), type);
+                sp<DeviceDescriptor> dev = new DeviceDescriptor(type);
                 if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
                         type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
                     dev->mAddress = String8("0");
@@ -167,13 +162,13 @@
                 add(dev);
             } else {
                 sp<DeviceDescriptor> deviceDesc =
-                        declaredDevices.getDeviceFromName(String8(devName));
+                        declaredDevices.getDeviceFromTag(String8(devTag));
                 if (deviceDesc != 0) {
                     add(deviceDesc);
                 }
             }
          }
-         devName = strtok(NULL, "|");
+         devTag = strtok(NULL, "|");
      }
 }
 
@@ -239,11 +234,11 @@
     return devices;
 }
 
-sp<DeviceDescriptor> DeviceVector::getDeviceFromName(const String8& name) const
+sp<DeviceDescriptor> DeviceVector::getDeviceFromTag(const String8& tag) const
 {
     sp<DeviceDescriptor> device;
     for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->mName == name) {
+        if (itemAt(i)->mTag == tag) {
             device = itemAt(i);
             break;
         }
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index e955447..7e2050b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -58,7 +58,7 @@
         } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
             profile->loadInChannels((char *)node->value);
         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
-            profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
+            profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
                                                            mDeclaredDevices);
         } else if (strcmp(node->name, FLAGS_TAG) == 0) {
             profile->mFlags = ConfigParsingUtils::parseInputFlagNames((char *)node->value);
@@ -105,7 +105,7 @@
         } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
             profile->loadOutChannels((char *)node->value);
         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
-            profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
+            profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
                                                            mDeclaredDevices);
         } else if (strcmp(node->name, FLAGS_TAG) == 0) {
             profile->mFlags = ConfigParsingUtils::parseOutputFlagNames((char *)node->value);
@@ -154,7 +154,8 @@
         ALOGW("loadDevice() bad type %08x", type);
         return BAD_VALUE;
     }
-    sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(String8(root->name), type);
+    sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type);
+    deviceDesc->mTag = String8(root->name);
 
     node = root->first_child;
     while (node) {
@@ -172,8 +173,8 @@
         node = node->next;
     }
 
-    ALOGV("loadDevice() adding device name %s type %08x address %s",
-          deviceDesc->mName.string(), type, deviceDesc->mAddress.string());
+    ALOGV("loadDevice() adding device tag %s type %08x address %s",
+          deviceDesc->mTag.string(), type, deviceDesc->mAddress.string());
 
     mDeclaredDevices.add(deviceDesc);
 
@@ -189,7 +190,7 @@
     profile->mChannelMasks.add(config->channel_mask);
     profile->mFormats.add(config->format);
 
-    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(name, device);
+    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
     devDesc->mAddress = address;
     profile->mSupportedDevices.add(devDesc);
 
@@ -220,7 +221,7 @@
     profile->mChannelMasks.add(config->channel_mask);
     profile->mFormats.add(config->format);
 
-    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(name, device);
+    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
     devDesc->mAddress = address;
     profile->mSupportedDevices.add(devDesc);
 
@@ -350,7 +351,8 @@
     }
 
     sp<DeviceDescriptor> devDesc =
-            new DeviceDescriptor(String8(device_name != NULL ? device_name : ""), device);
+            new DeviceDescriptor(device);
+    devDesc->mName = device_name;
     devDesc->mAddress = address;
     return devDesc;
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b7eed62..0c02d93 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2648,7 +2648,7 @@
     mUidCached = getuid();
     mpClientInterface = clientInterface;
 
-    mDefaultOutputDevice = new DeviceDescriptor(String8("Speaker"), AUDIO_DEVICE_OUT_SPEAKER);
+    mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
     if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE,
                  mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
                  mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
@@ -4738,7 +4738,7 @@
     sp<HwModule> module;
     sp<IOProfile> profile;
     sp<DeviceDescriptor> defaultInputDevice =
-                    new DeviceDescriptor(String8("builtin-mic"), AUDIO_DEVICE_IN_BUILTIN_MIC);
+                    new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
     mAvailableOutputDevices.add(mDefaultOutputDevice);
     mAvailableInputDevices.add(defaultInputDevice);
 
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index ac4d9a6..064ff71 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -36,12 +36,47 @@
         chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
         data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
         chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1);
-        controlModes.push(ANDROID_CONTROL_MODE_OFF);
         controlModes.push(ANDROID_CONTROL_MODE_AUTO);
         camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
         if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
             controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
         }
+
+        // Only advertise CONTROL_OFF mode if 3A manual controls are supported.
+        bool isManualAeSupported = false;
+        bool isManualAfSupported = false;
+        bool isManualAwbSupported = false;
+        entry = chars.find(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AE_MODE_OFF) {
+                    isManualAeSupported = true;
+                    break;
+                }
+            }
+        }
+        entry = chars.find(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AF_MODE_OFF) {
+                    isManualAfSupported = true;
+                    break;
+                }
+            }
+        }
+        entry = chars.find(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AWB_MODE_OFF) {
+                    isManualAwbSupported = true;
+                    break;
+                }
+            }
+        }
+        if (isManualAeSupported && isManualAfSupported && isManualAwbSupported) {
+            controlModes.push(ANDROID_CONTROL_MODE_OFF);
+        }
+
         chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes);
     }
     return;
@@ -86,7 +121,7 @@
         if (ret != 0) {
             return ret;
         }
-        int deviceVersion = cameraInfo.device_version;
+        int deviceVersion = rawInfo.device_version;
         if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
             // static_camera_characteristics is invalid
             *info = rawInfo;
diff --git a/soundtrigger/ISoundTriggerHwService.cpp b/soundtrigger/ISoundTriggerHwService.cpp
index 75f68b8..e14a771 100644
--- a/soundtrigger/ISoundTriggerHwService.cpp
+++ b/soundtrigger/ISoundTriggerHwService.cpp
@@ -40,6 +40,8 @@
     SET_CAPTURE_STATE,
 };
 
+#define MAX_ITEMS_PER_LIST 1024
+
 class BpSoundTriggerHwService: public BpInterface<ISoundTriggerHwService>
 {
 public:
@@ -116,10 +118,18 @@
         case LIST_MODULES: {
             CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
             unsigned int numModulesReq = data.readInt32();
+            if (numModulesReq > MAX_ITEMS_PER_LIST) {
+                numModulesReq = MAX_ITEMS_PER_LIST;
+            }
             unsigned int numModules = numModulesReq;
             struct sound_trigger_module_descriptor *modules =
                     (struct sound_trigger_module_descriptor *)calloc(numModulesReq,
                                                    sizeof(struct sound_trigger_module_descriptor));
+            if (modules == NULL) {
+                reply->writeInt32(NO_MEMORY);
+                reply->writeInt32(0);
+                return NO_ERROR;
+            }
             status_t status = listModules(modules, &numModules);
             reply->writeInt32(status);
             reply->writeInt32(numModules);