Merge "Clean up USE_NEON to make it easier to disable NEON for benchmarking" into nyc-dev
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
index e6ca225..531b548 100644
--- a/include/media/AudioTimestamp.h
+++ b/include/media/AudioTimestamp.h
@@ -79,7 +79,7 @@
 
     // Returns the best timestamp as judged from the closest-to-hw stage in the
     // pipeline with a valid timestamp.
-    int getBestTimestamp(int64_t *position, int64_t *time, int timebase) {
+    status_t getBestTimestamp(int64_t *position, int64_t *time, int timebase) const {
         if (position == nullptr || time == nullptr
                 || timebase < 0 || timebase >= TIMEBASE_MAX) {
             return BAD_VALUE;
@@ -97,6 +97,20 @@
         return INVALID_OPERATION;
     }
 
+    status_t getBestTimestamp(AudioTimestamp *timestamp) const {
+        if (timestamp == nullptr) {
+            return BAD_VALUE;
+        }
+        int64_t position, time;
+        if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC) == OK) {
+            timestamp->mPosition = position;
+            timestamp->mTime.tv_sec = time / 1000000000;
+            timestamp->mTime.tv_nsec = time - timestamp->mTime.tv_sec * 1000000000LL;
+            return OK;
+        }
+        return INVALID_OPERATION;
+    }
+
     // convert fields to a printable string
     std::string toString() {
         std::stringstream ss;
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
index 1420120..f7586a7 100644
--- a/include/media/IMediaSource.h
+++ b/include/media/IMediaSource.h
@@ -26,6 +26,7 @@
 struct MediaSource;
 class MetaData;
 class MediaBuffer;
+class MediaBufferGroup;
 
 class IMediaSource : public IInterface {
 public:
@@ -112,6 +113,8 @@
 class BnMediaSource: public BnInterface<IMediaSource>
 {
 public:
+    BnMediaSource();
+
     virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                 uint32_t flags = 0);
 
@@ -122,6 +125,12 @@
     virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) {
         return ERROR_UNSUPPORTED;
     }
+
+protected:
+    virtual ~BnMediaSource();
+
+private:
+    MediaBufferGroup *mGroup;
 };
 
 
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index 1e0c7d4..18b80e3 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -48,6 +48,9 @@
 
 class MediaBuffer : public MediaBufferBase {
 public:
+    // allocations larger than or equal to this will use shared memory.
+    static const size_t kSharedMemThreshold = 64 * 1024;
+
     // The underlying data remains the responsibility of the caller!
     MediaBuffer(void *data, size_t size);
 
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index a006f7f..7ca3fa1 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -39,7 +39,11 @@
     // The returned buffer will have a reference count of 1.
     // If nonBlocking is true and a buffer is not immediately available,
     // buffer is set to NULL and it returns WOULD_BLOCK.
-    status_t acquire_buffer(MediaBuffer **buffer, bool nonBlocking = false);
+    // If requestedSize is 0, any free MediaBuffer will be returned.
+    // If requestedSize is > 0, the returned MediaBuffer should have buffer
+    // size of at least requstedSize.
+    status_t acquire_buffer(
+            MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
 
 protected:
     virtual void signalBufferReturned(MediaBuffer *buffer);
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 2270c85..aa9e98c 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -315,6 +315,19 @@
     // See documentation for AudioTrack.setBufferSizeInFrames()
     size_t      setBufferSizeInFrames(size_t requestedSize);
 
+    status_t    getTimestamp(ExtendedTimestamp *timestamp) {
+        if (timestamp == nullptr) {
+            return BAD_VALUE;
+        }
+        (void) mTimestampObserver.poll(mTimestamp);
+        *timestamp = mTimestamp;
+        return OK;
+    }
+
+    void        clearTimestamp() {
+        mTimestamp.clear();
+    }
+
 protected:
     // This is set by AudioTrack.setBufferSizeInFrames().
     // A write will not fill the buffer above this limit.
@@ -322,6 +335,12 @@
 
 private:
     Modulo<uint32_t> mEpoch;
+
+    // The shared buffer contents referred to by the timestamp observer
+    // is initialized when the server proxy created.  A local zero timestamp
+    // is initialized by the client constructor.
+    ExtendedTimestampQueue::Observer mTimestampObserver;
+    ExtendedTimestamp mTimestamp; // initialized by constructor
 };
 
 // ----------------------------------------------------------------------------
@@ -333,7 +352,9 @@
             size_t frameSize, bool clientInServer = false)
         : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/,
           clientInServer),
-          mPlaybackRateMutator(&cblk->mPlaybackRateQueue) { }
+          mPlaybackRateMutator(&cblk->mPlaybackRateQueue) {
+    }
+
     virtual ~AudioTrackClientProxy() { }
 
     // No barriers on the following operations, so the ordering of loads/stores
@@ -431,23 +452,9 @@
     AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
             size_t frameSize)
         : ClientProxy(cblk, buffers, frameCount, frameSize,
-            false /*isOut*/, false /*clientInServer*/)
-        , mTimestampObserver(&cblk->mExtendedTimestampQueue) { }
+            false /*isOut*/, false /*clientInServer*/) { }
     ~AudioRecordClientProxy() { }
 
-    status_t    getTimestamp(ExtendedTimestamp *timestamp) {
-        if (timestamp == nullptr) {
-            return BAD_VALUE;
-        }
-        (void) mTimestampObserver.poll(mTimestamp);
-        *timestamp = mTimestamp;
-        return OK;
-    }
-
-    void        clearTimestamp() {
-        mTimestamp.clear();
-    }
-
     // Advances the client read pointer to the server write head pointer
     // effectively flushing the client read buffer. The effect is
     // instantaneous. Returns the number of frames flushed.
@@ -457,13 +464,6 @@
         android_atomic_release_store(rear, &mCblk->u.mStreaming.mFront);
         return (Modulo<int32_t>(rear) - front).unsignedValue();
     }
-
-private:
-    // The shared buffer contents referred to by the timestamp observer
-    // is initialized when the server proxy created.  A local zero timestamp
-    // is initialized by the client constructor.
-    ExtendedTimestampQueue::Observer mTimestampObserver;
-    ExtendedTimestamp mTimestamp; // initialized by constructor
 };
 
 // ----------------------------------------------------------------------------
@@ -509,10 +509,20 @@
     //  buffer->mRaw is NULL.
     virtual void        releaseBuffer(Buffer* buffer);
 
+    // Return the total number of frames that AudioFlinger has obtained and released
+    virtual int64_t     framesReleased() const { return mReleased; }
+
+    // Expose timestamp to client proxy. Should only be called by a single thread.
+    virtual void        setTimestamp(const ExtendedTimestamp &timestamp) {
+        mTimestampMutator.push(timestamp);
+    }
+
 protected:
     size_t      mAvailToClient; // estimated frames available to client prior to releaseBuffer()
     int32_t     mFlush;         // our copy of cblk->u.mStreaming.mFlush, for streaming output only
     int64_t     mReleased;      // our copy of cblk->mServer, at 64 bit resolution
+
+    ExtendedTimestampQueue::Mutator mTimestampMutator;
 };
 
 // Proxy used by AudioFlinger for servicing AudioTrack
@@ -556,9 +566,6 @@
     // and thus which resulted in an underrun.
     virtual uint32_t    getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
 
-    // Return the total number of frames that AudioFlinger has obtained and released
-    virtual size_t      framesReleased() const { return mReleased; }
-
     // Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
     AudioPlaybackRate getPlaybackRate();
 
@@ -611,20 +618,10 @@
 public:
     AudioRecordServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
             size_t frameSize, bool clientInServer)
-        : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer)
-        , mTimestampMutator(&cblk->mExtendedTimestampQueue) { }
+        : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer) { }
 
-    // Return the total number of frames that AudioFlinger has obtained and released
-    virtual int64_t     framesReleased() const { return mReleased; }
-
-    // Expose timestamp to client proxy. Should only be called by a single thread.
-    virtual void        setExtendedTimestamp(const ExtendedTimestamp &timestamp) {
-                            mTimestampMutator.push(timestamp);
-                        }
 protected:
     virtual ~AudioRecordServerProxy() { }
-
-    ExtendedTimestampQueue::Mutator       mTimestampMutator;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index b2a5f14..33dcc57 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -528,12 +528,14 @@
         mTimestampStartupGlitchReported = false;
         mRetrogradeMotionReported = false;
 
-        // If previousState == STATE_STOPPED, we reactivate markers (mMarkerPosition != 0)
+        // If previousState == STATE_STOPPED, we clear the timestamp so that it
+        // needs a new server push. We also reactivate markers (mMarkerPosition != 0)
         // as the position is reset to 0. This is legacy behavior. This is not done
         // in stop() to avoid a race condition where the last marker event is issued twice.
         // Note: the if is technically unnecessary because previousState == STATE_FLUSHED
         // is only for streaming tracks, and mMarkerReached is already set to false.
         if (previousState == STATE_STOPPED) {
+            mProxy->clearTimestamp(); // need new server push for valid timestamp
             mMarkerReached = false;
         }
 
@@ -2169,11 +2171,6 @@
     // Set false here to cover all the error return cases.
     mPreviousTimestampValid = false;
 
-    // FIXME not implemented for fast tracks; should use proxy and SSQ
-    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
-        return INVALID_OPERATION;
-    }
-
     switch (mState) {
     case STATE_ACTIVE:
     case STATE_PAUSED:
@@ -2203,7 +2200,22 @@
 
     // The presented frame count must always lag behind the consumed frame count.
     // To avoid a race, read the presented frames first.  This ensures that presented <= consumed.
-    status_t status = mAudioTrack->getTimestamp(timestamp);
+
+    status_t status;
+    if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
+        // use Binder to get timestamp
+        status = mAudioTrack->getTimestamp(timestamp);
+    } else {
+        // read timestamp from shared memory
+        ExtendedTimestamp ets;
+        status = mProxy->getTimestamp(&ets);
+        if (status == OK) {
+            status = ets.getBestTimestamp(&timestamp);
+        }
+        if (status == INVALID_OPERATION) {
+            status = WOULD_BLOCK;
+        }
+    }
     if (status != NO_ERROR) {
         ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
         return status;
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 988386e..1d15495 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -69,6 +69,7 @@
     : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer)
     , mBufferSizeInFrames(frameCount)
     , mEpoch(0)
+    , mTimestampObserver(&cblk->mExtendedTimestampQueue)
 {
 }
 
@@ -598,6 +599,7 @@
         size_t frameSize, bool isOut, bool clientInServer)
     : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
       mAvailToClient(0), mFlush(0), mReleased(0)
+    , mTimestampMutator(&cblk->mExtendedTimestampQueue)
 {
 }
 
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index fc9a123..b988c46 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -25,6 +25,7 @@
 #include <binder/Parcel.h>
 #include <media/IMediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 
@@ -47,8 +48,9 @@
 
 class RemoteMediaBufferReleaser : public BBinder {
 public:
-    RemoteMediaBufferReleaser(MediaBuffer *buf) {
+    RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
         mBuf = buf;
+        mOwner = owner;
     }
     ~RemoteMediaBufferReleaser() {
         if (mBuf) {
@@ -70,6 +72,10 @@
     }
 private:
     MediaBuffer *mBuf;
+    // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
+    // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
+    // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
+    sp<BnMediaSource> mOwner;
 };
 
 
@@ -207,6 +213,15 @@
 #undef LOG_TAG
 #define LOG_TAG "BnMediaSource"
 
+BnMediaSource::BnMediaSource()
+    : mGroup(NULL) {
+}
+
+BnMediaSource::~BnMediaSource() {
+    delete mGroup;
+    mGroup = NULL;
+}
+
 status_t BnMediaSource::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -263,17 +278,45 @@
                 size_t usedSize = buf->range_length();
                 // even if we're using shared memory, we might not want to use it, since for small
                 // sizes it's faster to copy data through the Binder transaction
-                if (buf->mMemory != NULL && usedSize >= 64 * 1024) {
-                    ALOGV("buffer is using shared memory: %zu", usedSize);
+                // On the other hand, if the data size is large enough, it's better to use shared
+                // memory. When data is too large, binder can't handle it.
+                if (usedSize >= MediaBuffer::kSharedMemThreshold) {
+                    ALOGV("use shared memory: %zu", usedSize);
+
+                    MediaBuffer *transferBuf = buf;
+                    size_t offset = buf->range_offset();
+                    if (transferBuf->mMemory == NULL) {
+                        if (mGroup == NULL) {
+                            mGroup = new MediaBufferGroup;
+                            size_t allocateSize = usedSize;
+                            if (usedSize < SIZE_MAX / 3) {
+                                allocateSize = usedSize * 3 / 2;
+                            }
+                            mGroup->add_buffer(new MediaBuffer(allocateSize));
+                        }
+
+                        ret = mGroup->acquire_buffer(
+                                &transferBuf, false /* nonBlocking */, usedSize);
+                        if (ret != OK || transferBuf == NULL || transferBuf->mMemory == NULL) {
+                            ALOGW("failed to acquire shared memory, ret %d", ret);
+                            reply->writeInt32(NULL_BUFFER);
+                            return NO_ERROR;
+                        }
+                        memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
+                                buf->range_length());
+                        offset = 0;
+                    }
+
                     reply->writeInt32(SHARED_BUFFER);
-                    RemoteMediaBufferReleaser *wrapper = new RemoteMediaBufferReleaser(buf);
+                    RemoteMediaBufferReleaser *wrapper =
+                        new RemoteMediaBufferReleaser(transferBuf, this);
                     reply->writeStrongBinder(wrapper);
-                    reply->writeStrongBinder(IInterface::asBinder(buf->mMemory));
-                    reply->writeInt32(buf->range_offset());
+                    reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
+                    reply->writeInt32(offset);
                     reply->writeInt32(usedSize);
                     buf->meta_data()->writeToParcel(*reply);
                 } else {
-                    // buffer is not in shared memory, or is small: copy it
+                    // buffer is small: copy it
                     if (buf->mMemory != NULL) {
                         ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
                     }
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 9a7dff6..bd398aa 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -447,7 +447,7 @@
         remote()->transact(CONFIGURE_VIDEO_TUNNEL_MODE, data, &reply);
 
         status_t err = reply.readInt32();
-        if (sidebandHandle) {
+        if (err == OK && sidebandHandle) {
             *sidebandHandle = (native_handle_t *)reply.readNativeHandle();
         }
         return err;
@@ -863,9 +863,13 @@
             OMX_U32 port_index = data.readInt32();
 
             sp<IGraphicBufferProducer> bufferProducer;
-            MetadataBufferType type;
+            MetadataBufferType type = kMetadataBufferTypeInvalid;
             status_t err = createInputSurface(node, port_index, &bufferProducer, &type);
 
+            if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
+                android_errorWriteLog(0x534e4554, "26324358");
+            }
+
             reply->writeInt32(type);
             reply->writeInt32(err);
 
@@ -906,11 +910,16 @@
                     interface_cast<IGraphicBufferConsumer>(data.readStrongBinder());
 
             MetadataBufferType type = kMetadataBufferTypeInvalid;
+
             status_t err = INVALID_OPERATION;
             if (bufferConsumer == NULL) {
                 ALOGE("b/26392700");
             } else {
                 err = setInputSurface(node, port_index, bufferConsumer, &type);
+
+                if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
+                   android_errorWriteLog(0x534e4554, "26324358");
+                }
             }
 
             reply->writeInt32(type);
@@ -938,8 +947,13 @@
             OMX_U32 port_index = data.readInt32();
             OMX_BOOL enable = (OMX_BOOL)data.readInt32();
 
-            MetadataBufferType type;
+            MetadataBufferType type = kMetadataBufferTypeInvalid;
             status_t err = storeMetaDataInBuffers(node, port_index, enable, &type);
+
+            if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
+                android_errorWriteLog(0x534e4554, "26324358");
+            }
+
             reply->writeInt32(type);
             reply->writeInt32(err);
 
@@ -976,7 +990,9 @@
             status_t err = configureVideoTunnelMode(
                     node, port_index, tunneled, audio_hw_sync, &sideband_handle);
             reply->writeInt32(err);
-            reply->writeNativeHandle(sideband_handle);
+            if(err == OK){
+                reply->writeNativeHandle(sideband_handle);
+            }
 
             return NO_ERROR;
         }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index fd4ed58..68e02e7 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -29,7 +29,6 @@
         MPEG4Extractor.cpp                \
         MPEG4Writer.cpp                   \
         MediaAdapter.cpp                  \
-        MediaBufferGroup.cpp              \
         MediaClock.cpp                    \
         MediaCodec.cpp                    \
         MediaCodecList.cpp                \
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
deleted file mode 100644
index 6ac6d4a..0000000
--- a/media/libstagefright/MediaBufferGroup.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MediaBufferGroup"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-
-namespace android {
-
-MediaBufferGroup::MediaBufferGroup()
-    : mFirstBuffer(NULL),
-      mLastBuffer(NULL) {
-}
-
-MediaBufferGroup::~MediaBufferGroup() {
-    MediaBuffer *next;
-    for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
-         buffer = next) {
-        next = buffer->nextBuffer();
-
-        CHECK_EQ(buffer->refcount(), 0);
-
-        buffer->setObserver(NULL);
-        buffer->release();
-    }
-}
-
-void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
-    Mutex::Autolock autoLock(mLock);
-
-    buffer->setObserver(this);
-
-    if (mLastBuffer) {
-        mLastBuffer->setNextBuffer(buffer);
-    } else {
-        mFirstBuffer = buffer;
-    }
-
-    mLastBuffer = buffer;
-}
-
-status_t MediaBufferGroup::acquire_buffer(
-        MediaBuffer **out, bool nonBlocking) {
-    Mutex::Autolock autoLock(mLock);
-
-    for (;;) {
-        for (MediaBuffer *buffer = mFirstBuffer;
-             buffer != NULL; buffer = buffer->nextBuffer()) {
-            if (buffer->refcount() == 0) {
-                buffer->add_ref();
-                buffer->reset();
-
-                *out = buffer;
-                goto exit;
-            }
-        }
-
-        if (nonBlocking) {
-            *out = NULL;
-            return WOULD_BLOCK;
-        }
-
-        // All buffers are in use. Block until one of them is returned to us.
-        mCondition.wait(mLock);
-    }
-
-exit:
-    return OK;
-}
-
-void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
-    Mutex::Autolock autoLock(mLock);
-    mCondition.signal();
-}
-
-}  // namespace android
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index e17534f..711601f 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -16,6 +16,7 @@
     AStringUtils.cpp              \
     AWakeLock.cpp                 \
     MediaBuffer.cpp               \
+    MediaBufferGroup.cpp          \
     MetaData.cpp                  \
     ParsedMessage.cpp             \
     base64.cpp                    \
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index d83a351..fa8e241 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -30,9 +30,6 @@
 
 namespace android {
 
-// allocations larger than this will use shared memory
-static const size_t kSharedMemThreshold = 64 * 1024;
-
 MediaBuffer::MediaBuffer(void *data, size_t size)
     : mObserver(NULL),
       mNextBuffer(NULL),
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
new file mode 100644
index 0000000..9022324
--- /dev/null
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaBufferGroup"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+
+namespace android {
+
+MediaBufferGroup::MediaBufferGroup()
+    : mFirstBuffer(NULL),
+      mLastBuffer(NULL) {
+}
+
+MediaBufferGroup::~MediaBufferGroup() {
+    MediaBuffer *next;
+    for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
+         buffer = next) {
+        next = buffer->nextBuffer();
+
+        CHECK_EQ(buffer->refcount(), 0);
+
+        buffer->setObserver(NULL);
+        buffer->release();
+    }
+}
+
+void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    buffer->setObserver(this);
+
+    if (mLastBuffer) {
+        mLastBuffer->setNextBuffer(buffer);
+    } else {
+        mFirstBuffer = buffer;
+    }
+
+    mLastBuffer = buffer;
+}
+
+status_t MediaBufferGroup::acquire_buffer(
+        MediaBuffer **out, bool nonBlocking, size_t requestedSize) {
+    Mutex::Autolock autoLock(mLock);
+
+    for (;;) {
+        MediaBuffer *freeBuffer = NULL;
+        MediaBuffer *freeBufferPrevious = NULL;
+        MediaBuffer *buffer = NULL;
+        MediaBuffer *bufferPrevious = NULL;
+        size_t smallest = requestedSize;
+        for (buffer = mFirstBuffer;
+             buffer != NULL; buffer = buffer->nextBuffer()) {
+            if (buffer->refcount() == 0) {
+               if (buffer->size() >= requestedSize) {
+                   break;
+               } else if (buffer->size() < smallest) {
+                   freeBuffer = buffer;
+                   freeBufferPrevious = bufferPrevious;
+               }
+            }
+            bufferPrevious = buffer;
+        }
+
+        if (buffer == NULL && freeBuffer != NULL) {
+            ALOGV("allocate new buffer, requested size %zu vs available %zu",
+                    requestedSize, freeBuffer->size());
+            size_t allocateSize = requestedSize;
+            if (requestedSize < SIZE_MAX / 3) {
+                allocateSize = requestedSize * 3 / 2;
+            }
+            MediaBuffer *newBuffer = new MediaBuffer(allocateSize);
+            newBuffer->setObserver(this);
+            if (freeBuffer == mFirstBuffer) {
+                mFirstBuffer = newBuffer;
+            }
+            if (freeBuffer == mLastBuffer) {
+                mLastBuffer = newBuffer;
+            }
+            newBuffer->setNextBuffer(freeBuffer->nextBuffer());
+            if (freeBufferPrevious != NULL) {
+                freeBufferPrevious->setNextBuffer(newBuffer);
+            }
+            freeBuffer->setObserver(NULL);
+            freeBuffer->release();
+
+            buffer = newBuffer;
+        }
+
+        if (buffer != NULL) {
+            buffer->add_ref();
+            buffer->reset();
+
+            *out = buffer;
+            goto exit;
+        }
+
+        if (nonBlocking) {
+            *out = NULL;
+            return WOULD_BLOCK;
+        }
+
+        // All buffers are in use. Block until one of them is returned to us.
+        mCondition.wait(mLock);
+    }
+
+exit:
+    return OK;
+}
+
+void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
+    Mutex::Autolock autoLock(mLock);
+    mCondition.signal();
+}
+
+}  // namespace android
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index ee99a26..979143c 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -23,6 +23,7 @@
 	libmediaplayerservice \
 	libutils \
 	libbinder \
+	libicuuc \
 
 LOCAL_STATIC_LIBRARIES := \
         libicuandroid_utils \
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index e006e89..e9dede9 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -26,6 +26,7 @@
 
 // from LOCAL_C_INCLUDES
 #include "CameraService.h"
+#include "IcuUtils.h"
 #include "MediaPlayerService.h"
 #include "ResourceManagerService.h"
 
@@ -38,6 +39,7 @@
     sp<ProcessState> proc(ProcessState::self());
     sp<IServiceManager> sm(defaultServiceManager());
     ALOGI("ServiceManager: %p", sm.get());
+    InitializeIcuOrDie();
     MediaPlayerService::instantiate();
     ResourceManagerService::instantiate();
     registerExtensions();
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 7c20478..4f8b413 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -29,7 +29,8 @@
 #include "AudioResamplerDyn.h"
 
 #ifdef __arm__
-    #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
+    // bug 13102576
+    //#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
 #endif
 
 namespace android {
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index c81bbf9..fe3cc53 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -89,6 +89,7 @@
     // ExtendedAudioBufferProvider interface
     virtual size_t framesReady() const;
     virtual size_t framesReleased() const;
+    virtual void onTimestamp(const AudioTimestamp &timestamp);
 
     bool isPausing() const { return mState == PAUSING; }
     bool isPaused() const { return mState == PAUSED; }
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 5f70479..6f84af1 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -76,8 +76,6 @@
             // be dropped and therefore not read by the application.
             sp<SyncEvent>                       mSyncStartEvent;
 
-            AudioRecordServerProxy             *mAudioRecordServerProxy;
-
             // number of captured frames to drop after the start sync event has been received.
             // when < 0, maximum frames to drop before starting capture even if sync event is
             // not received
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 5aff394..4807400 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6157,7 +6157,7 @@
 
             // update frame information and push timestamp out
             activeTrack->updateTrackFrameInfo(
-                    activeTrack->mAudioRecordServerProxy->framesReleased(),
+                    activeTrack->mServerProxy->framesReleased(),
                     mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER],
                     mSampleRate, mTimestamp);
         }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b719046..536581c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -596,6 +596,20 @@
     return mAudioTrackServerProxy->framesReleased();
 }
 
+void AudioFlinger::PlaybackThread::Track::onTimestamp(const AudioTimestamp &timestamp)
+{
+    // This call comes from a FastTrack and should be kept lockless.
+    // The server side frames are already translated to client frames.
+
+    ExtendedTimestamp ets;
+    ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
+            timestamp.mTime.tv_sec * 1000000000LL + timestamp.mTime.tv_nsec;
+    ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = timestamp.mPosition;
+
+    // Caution, this doesn't set the timebase for BOOTTIME properly, but is ignored right now.
+    mAudioTrackServerProxy->setTimestamp(ets);
+}
+
 // Don't call for fast tracks; the framesReady() could result in priority inversion
 bool AudioFlinger::PlaybackThread::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) {
@@ -1438,9 +1452,8 @@
         return;
     }
 
-    mAudioRecordServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
+    mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
             mFrameSize, !isExternalTrack());
-    mServerProxy = mAudioRecordServerProxy;
 
     mResamplerBufferProvider = new ResamplerBufferProvider(this);
 
@@ -1594,7 +1607,7 @@
             local.mPosition[i] = relativeTrackFrames + trackFramesReleased;
         }
     }
-    mAudioRecordServerProxy->setExtendedTimestamp(local);
+    mServerProxy->setTimestamp(local);
 }
 
 AudioFlinger::RecordThread::PatchRecord::PatchRecord(RecordThread *recordThread,
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 4dcc6b2..dd3f144 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -67,16 +67,6 @@
         API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
     } input_type_t;
 
-   enum {
-        API_INPUT_CONCURRENCY_NONE = 0,
-        API_INPUT_CONCURRENCY_CALL = (1 << 0),      // Concurrency with a call
-        API_INPUT_CONCURRENCY_CAPTURE = (1 << 1),   // Concurrency with another capture
-
-        API_INPUT_CONCURRENCY_ALL = (API_INPUT_CONCURRENCY_CALL | API_INPUT_CONCURRENCY_CAPTURE),
-   };
-
-   typedef uint32_t concurrency_type__mask_t;
-
 public:
     virtual ~AudioPolicyInterface() {}
     //
@@ -150,8 +140,7 @@
                                      input_type_t *inputType) = 0;
     // indicates to the audio policy manager that the input starts being used.
     virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session,
-                                concurrency_type__mask_t *concurrency) = 0;
+                                audio_session_t session) = 0;
     // indicates to the audio policy manager that the input stops being used.
     virtual status_t stopInput(audio_io_handle_t input,
                                audio_session_t session) = 0;
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 18acb23..d9e7212 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -30,9 +30,9 @@
 
 /**
  * A device mask for all audio input devices that are considered "virtual" when evaluating
- * active inputs in getActiveInputs()
+ * active inputs in getActiveInput()
  */
-#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  (AUDIO_DEVICE_IN_REMOTE_SUBMIX)
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_FM_TUNER)
 
 
 /**
@@ -89,44 +89,6 @@
             ((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));
 }
 
-/**
- * Returns the priority of a given audio source for capture. The priority is used when more than one
- * capture session is active on a given input stream to determine which session drives routing and
- * effect configuration.
- *
- * @param[in] inputSource to consider. Valid sources are:
- * - AUDIO_SOURCE_VOICE_COMMUNICATION
- * - AUDIO_SOURCE_CAMCORDER
- * - AUDIO_SOURCE_MIC
- * - AUDIO_SOURCE_FM_TUNER
- * - AUDIO_SOURCE_VOICE_RECOGNITION
- * - AUDIO_SOURCE_HOTWORD
- *
- * @return the corresponding input source priority or 0 if priority is irrelevant for this source.
- *      This happens when the specified source cannot share a given input stream (e.g remote submix)
- *      The higher the value, the higher the priority.
- */
-static inline int32_t source_priority(audio_source_t inputSource)
-{
-    switch (inputSource) {
-    case AUDIO_SOURCE_VOICE_COMMUNICATION:
-        return 6;
-    case AUDIO_SOURCE_CAMCORDER:
-        return 5;
-    case AUDIO_SOURCE_MIC:
-        return 4;
-    case AUDIO_SOURCE_FM_TUNER:
-        return 3;
-    case AUDIO_SOURCE_VOICE_RECOGNITION:
-        return 2;
-    case AUDIO_SOURCE_HOTWORD:
-        return 1;
-    default:
-        break;
-    }
-    return 0;
-}
-
 /* Indicates if audio formats are equivalent when considering a match between
  * audio HAL supported formats and client requested formats
  */
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 282bece..77c0d07 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -63,9 +63,7 @@
                              const sp<AudioSession>& audioSession);
     status_t removeAudioSession(audio_session_t session);
     sp<AudioSession> getAudioSession(audio_session_t session) const;
-    AudioSessionCollection getAudioSessions(bool activeOnly) const;
-    size_t getAudioSessionCount(bool activeOnly) const;
-    audio_source_t getHighestPrioritySource(bool activeOnly) const;
+    AudioSessionCollection getActiveAudioSessions() const;
 
 private:
     audio_port_handle_t           mId;
@@ -95,7 +93,7 @@
      * Only considers inputs from physical devices (e.g. main mic, headset mic) when
      * ignoreVirtualInputs is true.
      */
-    Vector<sp <AudioInputDescriptor> > getActiveInputs(bool ignoreVirtualInputs = true);
+    audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
 
     audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index e19a8ee..5958f4f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -165,10 +165,6 @@
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                                    const struct audio_port_config *srcConfig = NULL) const = 0;
     virtual sp<AudioPort> getAudioPort() const = 0;
-    virtual bool hasSameHwModuleAs(const sp<AudioPortConfig>& other) const {
-        return (other != 0) &&
-                (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
-    }
     uint32_t mSamplingRate;
     audio_format_t mFormat;
     audio_channel_mask_t mChannelMask;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 648cc00..576822c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -85,10 +85,8 @@
     uint32_t getOpenCount() const;
 
     AudioSessionCollection getActiveSessions() const;
-    size_t getActiveSessionCount() const;
     bool hasActiveSession() const;
     bool isSourceActive(audio_source_t source) const;
-    audio_source_t getHighestPrioritySource(bool activeOnly) const;
 
     status_t dump(int fd, int spaces) const;
 };
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 38d7ad5..9b6469c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -132,12 +132,6 @@
     return mSessions.isSourceActive(source);
 }
 
-audio_source_t AudioInputDescriptor::getHighestPrioritySource(bool activeOnly) const
-{
-
-    return mSessions.getHighestPrioritySource(activeOnly);
-}
-
 bool AudioInputDescriptor::isSoundTrigger() const {
     // sound trigger and non sound trigger sessions are not mixed
     // on a given input
@@ -149,22 +143,9 @@
     return mSessions.valueFor(session);
 }
 
-AudioSessionCollection AudioInputDescriptor::getAudioSessions(bool activeOnly) const
+AudioSessionCollection AudioInputDescriptor::getActiveAudioSessions() const
 {
-    if (activeOnly) {
-        return mSessions.getActiveSessions();
-    } else {
-        return mSessions;
-    }
-}
-
-size_t AudioInputDescriptor::getAudioSessionCount(bool activeOnly) const
-{
-    if (activeOnly) {
-        return mSessions.getActiveSessionCount();
-    } else {
-        return mSessions.size();
-    }
+    return mSessions.getActiveSessions();
 }
 
 status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
@@ -235,19 +216,17 @@
     return count;
 }
 
-Vector<sp <AudioInputDescriptor> > AudioInputCollection::getActiveInputs(bool ignoreVirtualInputs)
+audio_io_handle_t AudioInputCollection::getActiveInput(bool ignoreVirtualInputs)
 {
-    Vector<sp <AudioInputDescriptor> > activeInputs;
-
     for (size_t i = 0; i < size(); i++) {
         const sp<AudioInputDescriptor>  inputDescriptor = valueAt(i);
         if ((inputDescriptor->isActive())
                 && (!ignoreVirtualInputs ||
                     !is_virtual_input_device(inputDescriptor->mDevice))) {
-            activeInputs.add(inputDescriptor);
+            return keyAt(i);
         }
     }
-    return activeInputs;
+    return 0;
 }
 
 audio_devices_t AudioInputCollection::getSupportedDevices(audio_io_handle_t handle) const
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index f5927ab..5d0f03f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -81,7 +81,7 @@
         return sharesHwModuleWith(outputDesc->subOutput1()) ||
                     sharesHwModuleWith(outputDesc->subOutput2());
     } else {
-        return hasSameHwModuleAs(outputDesc);
+        return (getModuleHandle() == outputDesc->getModuleHandle());
     }
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index 306ed28..597c029 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -18,7 +18,6 @@
 //#define LOG_NDEBUG 0
 
 #include <AudioPolicyInterface.h>
-#include "policy.h"
 #include "AudioSession.h"
 #include "AudioGain.h"
 #include "TypeConverter.h"
@@ -186,20 +185,9 @@
     return activeSessions;
 }
 
-size_t AudioSessionCollection::getActiveSessionCount() const
-{
-    size_t activeCount = 0;
-    for (size_t i = 0; i < size(); i++) {
-        if (valueAt(i)->activeCount() != 0) {
-            activeCount++;
-        }
-    }
-    return activeCount;
-}
-
 bool AudioSessionCollection::hasActiveSession() const
 {
-    return getActiveSessionCount() != 0;
+    return getActiveSessions().size() != 0;
 }
 
 bool AudioSessionCollection::isSourceActive(audio_source_t source) const
@@ -219,24 +207,6 @@
     return false;
 }
 
-audio_source_t AudioSessionCollection::getHighestPrioritySource(bool activeOnly) const
-{
-    audio_source_t source = AUDIO_SOURCE_DEFAULT;
-    int32_t priority = -1;
-
-    for (size_t i = 0; i < size(); i++) {
-        const sp<AudioSession>  audioSession = valueAt(i);
-        if (activeOnly && audioSession->activeCount() == 0) {
-            continue;
-        }
-        int32_t curPriority = source_priority(audioSession->inputSource());
-        if (curPriority > priority) {
-            priority = curPriority;
-            source = audioSession->inputSource();
-        }
-    }
-    return source;
-}
 
 status_t AudioSessionCollection::dump(int fd, int spaces) const
 {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index bf68d46..758673b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -420,17 +420,15 @@
         // FIXME: would be better to refine to only inputs whose profile connects to the
         // call TX device but this information is not in the audio patch and logic here must be
         // symmetric to the one in startInput()
-        Vector<sp <AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
-        for (size_t i = 0; i < activeInputs.size(); i++) {
-            sp<AudioInputDescriptor> activeDesc = activeInputs[i];
-            if (activeDesc->hasSameHwModuleAs(txSourceDeviceDesc)) {
-                AudioSessionCollection activeSessions =
-                        activeDesc->getAudioSessions(true /*activeOnly*/);
-                for (size_t j = 0; j < activeSessions.size(); j++) {
-                    audio_session_t activeSession = activeSessions.keyAt(j);
-                    stopInput(activeDesc->mIoHandle, activeSession);
-                    releaseInput(activeDesc->mIoHandle, activeSession);
-                }
+        audio_io_handle_t activeInput = mInputs.getActiveInput();
+        if (activeInput != 0) {
+            sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
+            if (activeDesc->getModuleHandle() == txSourceDeviceDesc->getModuleHandle()) {
+                //FIXME: consider all active sessions
+                AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
+                audio_session_t activeSession = activeSessions.keyAt(0);
+                stopInput(activeInput, activeSession);
+                releaseInput(activeInput, activeSession);
             }
         }
 
@@ -596,16 +594,15 @@
         }
     }
 
-    Vector<sp <AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
-    for (size_t i = 0; i < activeInputs.size(); i++) {
-        sp<AudioInputDescriptor> activeDesc = activeInputs[i];
-        audio_devices_t newDevice = getNewInputDevice(activeDesc);
+    audio_io_handle_t activeInput = mInputs.getActiveInput();
+    if (activeInput != 0) {
+        sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
+        audio_devices_t newDevice = getNewInputDevice(activeInput);
         // Force new input selection if the new device can not be reached via current input
-        if (activeDesc->mProfile->getSupportedDevices().types() &
-                (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
-            setInputDevice(activeDesc->mIoHandle, newDevice);
+        if (activeDesc->mProfile->getSupportedDevices().types() & (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
+            setInputDevice(activeInput, newDevice);
         } else {
-            closeInput(activeDesc->mIoHandle);
+            closeInput(activeInput);
         }
     }
 }
@@ -1358,7 +1355,6 @@
 
     *input = AUDIO_IO_HANDLE_NONE;
     *inputType = API_INPUT_INVALID;
-
     audio_devices_t device;
     // handle legacy remote submix case where the address was not always specified
     String8 address = String8("");
@@ -1496,22 +1492,14 @@
                                                               isSoundTrigger,
                                                               policyMix, mpClientInterface);
 
-
+// TODO enable input reuse
+#if 0
     // reuse an open input if possible
     for (size_t i = 0; i < mInputs.size(); i++) {
         sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
-        // reuse input if:
-        // - it shares the same profile
-        //      AND
-        // - it is not a reroute submix input
-        //      AND
-        // - it is: not used for sound trigger
-        //                OR
-        //          used for sound trigger and all clients use the same session ID
-        //
-        if ((profile == desc->mProfile) &&
-            (isSoundTrigger == desc->isSoundTrigger()) &&
-            !is_virtual_input_device(device)) {
+        // reuse input if it shares the same profile and same sound trigger attribute
+        if (profile == desc->mProfile &&
+            isSoundTrigger == desc->isSoundTrigger()) {
 
             sp<AudioSession> as = desc->getAudioSession(session);
             if (as != 0) {
@@ -1521,33 +1509,16 @@
                 } else {
                     ALOGW("getInputForDevice() record with different attributes"
                           " exists for session %d", session);
-                    break;
+                    return input;
                 }
-            } else if (isSoundTrigger) {
-                break;
-            }
-            // force close input if current source is now the highest priority request on this input
-            // and current input properties are not exactly as requested.
-            if ((desc->mSamplingRate != samplingRate ||
-                    desc->mChannelMask != channelMask ||
-                    !audio_formats_match(desc->mFormat, format)) &&
-                    (source_priority(desc->getHighestPrioritySource(false /*activeOnly*/)) <
-                     source_priority(inputSource))) {
-                ALOGV("%s: ", __FUNCTION__);
-                AudioSessionCollection sessions = desc->getAudioSessions(false /*activeOnly*/);
-                for (size_t j = 0; j < sessions.size(); j++) {
-                    audio_session_t currentSession = sessions.keyAt(j);
-                    stopInput(desc->mIoHandle, currentSession);
-                    releaseInput(desc->mIoHandle, currentSession);
-                }
-                break;
             } else {
                 desc->addAudioSession(session, audioSession);
-                ALOGV("%s: reusing input %d", __FUNCTION__, mInputs.keyAt(i));
-                return mInputs.keyAt(i);
             }
+            ALOGV("getInputForDevice() reusing input %d", mInputs.keyAt(i));
+            return mInputs.keyAt(i);
         }
     }
+#endif
 
     audio_config_t config = AUDIO_CONFIG_INITIALIZER;
     config.sample_rate = profileSamplingRate;
@@ -1590,50 +1561,10 @@
     return input;
 }
 
-bool AudioPolicyManager::isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
-        const sp<AudioSession>& audioSession)
-{
-    // Do not allow capture if an active voice call is using a software patch and
-    // the call TX source device is on the same HW module.
-    // FIXME: would be better to refine to only inputs whose profile connects to the
-    // call TX device but this information is not in the audio patch
-    if (mCallTxPatch != 0 &&
-        inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
-        return false;
-    }
-
-    // starting concurrent capture is enabled if:
-    // 1) capturing for re-routing
-    // 2) capturing for HOTWORD source
-    // 3) capturing for FM TUNER source
-    // 3) All other active captures are either for re-routing or HOTWORD
-
-    if (is_virtual_input_device(inputDesc->mDevice) ||
-            audioSession->inputSource() == AUDIO_SOURCE_HOTWORD ||
-            audioSession->inputSource() == AUDIO_SOURCE_FM_TUNER) {
-        return true;
-    }
-
-    Vector< sp<AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
-    for (size_t i = 0; i <  activeInputs.size(); i++) {
-        sp<AudioInputDescriptor> activeInput = activeInputs[i];
-        if ((activeInput->inputSource() != AUDIO_SOURCE_HOTWORD) &&
-                (activeInput->inputSource() != AUDIO_SOURCE_FM_TUNER) &&
-                !is_virtual_input_device(activeInput->mDevice)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-
 status_t AudioPolicyManager::startInput(audio_io_handle_t input,
-                                        audio_session_t session,
-                                        concurrency_type__mask_t *concurrency)
+                                        audio_session_t session)
 {
     ALOGV("startInput() input %d", input);
-    *concurrency = API_INPUT_CONCURRENCY_NONE;
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
         ALOGW("startInput() unknown input %d", input);
@@ -1647,62 +1578,81 @@
         return BAD_VALUE;
     }
 
-    if (!isConcurentCaptureAllowed(inputDesc, audioSession)) {
-        ALOGW("startInput(%d) failed: other input already started", input);
-        return INVALID_OPERATION;
-    }
+    // virtual input devices are compatible with other input devices
+    if (!is_virtual_input_device(inputDesc->mDevice)) {
 
-    if (isInCall()) {
-        *concurrency |= API_INPUT_CONCURRENCY_CALL;
-    }
-    if (mInputs.activeInputsCount() != 0) {
-        *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
-    }
+        // for a non-virtual input device, check if there is another (non-virtual) active input
+        audio_io_handle_t activeInput = mInputs.getActiveInput();
+        if (activeInput != 0 && activeInput != input) {
 
-    // increment activity count before calling getNewInputDevice() below as only active sessions
-    // are considered for device selection
-    audioSession->changeActiveCount(1);
+            // If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
+            // otherwise the active input continues and the new input cannot be started.
+            sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
+            if ((activeDesc->inputSource() == AUDIO_SOURCE_HOTWORD) &&
+                    !activeDesc->hasPreemptedSession(session)) {
+                ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
+                //FIXME: consider all active sessions
+                AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
+                audio_session_t activeSession = activeSessions.keyAt(0);
+                SortedVector<audio_session_t> sessions =
+                                           activeDesc->getPreemptedSessions();
+                sessions.add(activeSession);
+                inputDesc->setPreemptedSessions(sessions);
+                stopInput(activeInput, activeSession);
+                releaseInput(activeInput, activeSession);
+            } else {
+                ALOGE("startInput(%d) failed: other input %d already started", input, activeInput);
+                return INVALID_OPERATION;
+            }
+        }
+
+        // Do not allow capture if an active voice call is using a software patch and
+        // the call TX source device is on the same HW module.
+        // FIXME: would be better to refine to only inputs whose profile connects to the
+        // call TX device but this information is not in the audio patch
+        if (mCallTxPatch != 0 &&
+            inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
+            return INVALID_OPERATION;
+        }
+    }
 
     // Routing?
     mInputRoutes.incRouteActivity(session);
 
-    if (audioSession->activeCount() == 1 || mInputRoutes.hasRouteChanged(session)) {
+    if (!inputDesc->isActive() || mInputRoutes.hasRouteChanged(session)) {
+        // if input maps to a dynamic policy with an activity listener, notify of state change
+        if ((inputDesc->mPolicyMix != NULL)
+                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
+                    MIX_STATE_MIXING);
+        }
 
-        setInputDevice(input, getNewInputDevice(inputDesc), true /* force */);
+        if (mInputs.activeInputsCount() == 0) {
+            SoundTrigger::setCaptureState(true);
+        }
+        setInputDevice(input, getNewInputDevice(input), true /* force */);
 
-        if (inputDesc->getAudioSessionCount(true/*activeOnly*/) == 1) {
-            // if input maps to a dynamic policy with an activity listener, notify of state change
-            if ((inputDesc->mPolicyMix != NULL)
-                    && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-                mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
-                        MIX_STATE_MIXING);
+        // automatically enable the remote submix output when input is started if not
+        // used by a policy mix of type MIX_TYPE_RECORDERS
+        // For remote submix (a virtual device), we open only one input per capture request.
+        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+            String8 address = String8("");
+            if (inputDesc->mPolicyMix == NULL) {
+                address = String8("0");
+            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+                address = inputDesc->mPolicyMix->mRegistrationId;
             }
-
-            if (mInputs.activeInputsCount() == 0) {
-                SoundTrigger::setCaptureState(true);
-            }
-
-            // automatically enable the remote submix output when input is started if not
-            // used by a policy mix of type MIX_TYPE_RECORDERS
-            // For remote submix (a virtual device), we open only one input per capture request.
-            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
-                String8 address = String8("");
-                if (inputDesc->mPolicyMix == NULL) {
-                    address = String8("0");
-                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                    address = inputDesc->mPolicyMix->mRegistrationId;
-                }
-                if (address != "") {
-                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                            AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-                            address, "remote-submix");
-                }
+            if (address != "") {
+                setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                        AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                        address, "remote-submix");
             }
         }
     }
 
     ALOGV("AudioPolicyManager::startInput() input source = %d", audioSession->inputSource());
 
+    audioSession->changeActiveCount(1);
     return NO_ERROR;
 }
 
@@ -1733,41 +1683,36 @@
     // Routing?
     mInputRoutes.decRouteActivity(session);
 
-    if (audioSession->activeCount() == 0) {
-
-        if (inputDesc->isActive()) {
-            setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
-        } else {
-            // if input maps to a dynamic policy with an activity listener, notify of state change
-            if ((inputDesc->mPolicyMix != NULL)
-                    && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-                mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
-                        MIX_STATE_IDLE);
-            }
-
-            // automatically disable the remote submix output when input is stopped if not
-            // used by a policy mix of type MIX_TYPE_RECORDERS
-            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
-                String8 address = String8("");
-                if (inputDesc->mPolicyMix == NULL) {
-                    address = String8("0");
-                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                    address = inputDesc->mPolicyMix->mRegistrationId;
-                }
-                if (address != "") {
-                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                             AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                             address, "remote-submix");
-                }
-            }
-
-            resetInputDevice(input);
-
-            if (mInputs.activeInputsCount() == 0) {
-                SoundTrigger::setCaptureState(false);
-            }
-            inputDesc->clearPreemptedSessions();
+    if (!inputDesc->isActive()) {
+        // if input maps to a dynamic policy with an activity listener, notify of state change
+        if ((inputDesc->mPolicyMix != NULL)
+                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
+                    MIX_STATE_IDLE);
         }
+
+        // automatically disable the remote submix output when input is stopped if not
+        // used by a policy mix of type MIX_TYPE_RECORDERS
+        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+            String8 address = String8("");
+            if (inputDesc->mPolicyMix == NULL) {
+                address = String8("0");
+            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+                address = inputDesc->mPolicyMix->mRegistrationId;
+            }
+            if (address != "") {
+                setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                                         AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                                         address, "remote-submix");
+            }
+        }
+
+        resetInputDevice(input);
+
+        if (mInputs.activeInputsCount() == 0) {
+            SoundTrigger::setCaptureState(false);
+        }
+        inputDesc->clearPreemptedSessions();
     }
     return NO_ERROR;
 }
@@ -2539,7 +2484,7 @@
                 // create a software bridge in PatchPanel if:
                 // - source and sink devices are on differnt HW modules OR
                 // - audio HAL version is < 3.0
-                if (!srcDeviceDesc->hasSameHwModuleAs(sinkDeviceDesc) ||
+                if ((srcDeviceDesc->getModuleHandle() != sinkDeviceDesc->getModuleHandle()) ||
                         (srcDeviceDesc->mModule->getHalVersion() < AUDIO_DEVICE_API_VERSION_3_0)) {
                     // support only one sink device for now to simplify output selection logic
                     if (patch->num_sinks > 1) {
@@ -2639,7 +2584,7 @@
                 return BAD_VALUE;
             }
             setInputDevice(inputDesc->mIoHandle,
-                           getNewInputDevice(inputDesc),
+                           getNewInputDevice(inputDesc->mIoHandle),
                            true,
                            NULL);
         } else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
@@ -4265,9 +4210,9 @@
     return device;
 }
 
-audio_devices_t AudioPolicyManager::getNewInputDevice(const sp<AudioInputDescriptor>& inputDesc)
+audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input)
 {
-    audio_devices_t device = AUDIO_DEVICE_NONE;
+    sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
 
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
     if (index >= 0) {
@@ -4279,12 +4224,7 @@
         }
     }
 
-    audio_source_t source = inputDesc->getHighestPrioritySource(true /*activeOnly*/);
-    if (isInCall()) {
-        device = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
-    } else if (source != AUDIO_SOURCE_DEFAULT) {
-        device = getDeviceAndMixForInputSource(source);
-    }
+    audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->inputSource());
 
     return device;
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 1b1a9b4..fb9b46b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -139,8 +139,7 @@
 
         // indicates to the audio policy manager that the input starts being used.
         virtual status_t startInput(audio_io_handle_t input,
-                                    audio_session_t session,
-                                    concurrency_type__mask_t *concurrency);
+                                    audio_session_t session);
 
         // indicates to the audio policy manager that the input stops being used.
         virtual status_t stopInput(audio_io_handle_t input,
@@ -406,7 +405,7 @@
         void updateDevicesAndOutputs();
 
         // selects the most appropriate device on input for current state
-        audio_devices_t getNewInputDevice(const sp<AudioInputDescriptor>& inputDesc);
+        audio_devices_t getNewInputDevice(audio_io_handle_t input);
 
         virtual uint32_t getMaxEffectsCpuLoad()
         {
@@ -506,8 +505,6 @@
 
         void clearAudioSources(uid_t uid);
 
-        bool isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
-                const sp<AudioSession>& audioSession);
 
         uid_t mUidCached;
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 9a28137..ce77814 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -57,11 +57,11 @@
     }
     mInputSources.clear();
 
-    for (i = 0; i < mInputSessions.size(); i++) {
-        mInputSessions.valueAt(i)->mEffects.clear();
-        delete mInputSessions.valueAt(i);
+    for (i = 0; i < mInputs.size(); i++) {
+        mInputs.valueAt(i)->mEffects.clear();
+        delete mInputs.valueAt(i);
     }
-    mInputSessions.clear();
+    mInputs.clear();
 
     // release audio output processing resources
     for (i = 0; i < mOutputStreams.size(); i++) {
@@ -79,7 +79,7 @@
 
 status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
                              audio_source_t inputSource,
-                             audio_session_t audioSession)
+                             int audioSession)
 {
     status_t status = NO_ERROR;
 
@@ -93,19 +93,19 @@
         ALOGV("addInputEffects(): no processing needs to be attached to this source");
         return status;
     }
-    ssize_t idx = mInputSessions.indexOfKey(audioSession);
-    EffectVector *sessionDesc;
+    ssize_t idx = mInputs.indexOfKey(input);
+    EffectVector *inputDesc;
     if (idx < 0) {
-        sessionDesc = new EffectVector(audioSession);
-        mInputSessions.add(audioSession, sessionDesc);
+        inputDesc = new EffectVector(audioSession);
+        mInputs.add(input, inputDesc);
     } else {
         // EffectVector is existing and we just need to increase ref count
-        sessionDesc = mInputSessions.valueAt(idx);
+        inputDesc = mInputs.valueAt(idx);
     }
-    sessionDesc->mRefCount++;
+    inputDesc->mRefCount++;
 
-    ALOGV("addInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
-    if (sessionDesc->mRefCount == 1) {
+    ALOGV("addInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount);
+    if (inputDesc->mRefCount == 1) {
         Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
         for (size_t i = 0; i < effects.size(); i++) {
             EffectDesc *effect = effects[i];
@@ -123,37 +123,36 @@
             }
             ALOGV("addInputEffects(): added Fx %s on source: %d",
                   effect->mName, (int32_t)aliasSource);
-            sessionDesc->mEffects.add(fx);
+            inputDesc->mEffects.add(fx);
         }
-        sessionDesc->setProcessorEnabled(true);
+        inputDesc->setProcessorEnabled(true);
     }
     return status;
 }
 
 
-status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input,
-                                                 audio_session_t audioSession)
+status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input)
 {
     status_t status = NO_ERROR;
 
     Mutex::Autolock _l(mLock);
-    ssize_t index = mInputSessions.indexOfKey(audioSession);
+    ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
         return status;
     }
-    EffectVector *sessionDesc = mInputSessions.valueAt(index);
-    sessionDesc->mRefCount--;
-    ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
-    if (sessionDesc->mRefCount == 0) {
-        sessionDesc->setProcessorEnabled(false);
-        delete sessionDesc;
-        mInputSessions.removeItemsAt(index);
+    EffectVector *inputDesc = mInputs.valueAt(index);
+    inputDesc->mRefCount--;
+    ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount);
+    if (inputDesc->mRefCount == 0) {
+        inputDesc->setProcessorEnabled(false);
+        delete inputDesc;
+        mInputs.removeItemsAt(index);
         ALOGV("releaseInputEffects(): all effects released");
     }
     return status;
 }
 
-status_t AudioPolicyEffects::queryDefaultInputEffects(audio_session_t audioSession,
+status_t AudioPolicyEffects::queryDefaultInputEffects(int audioSession,
                                                       effect_descriptor_t *descriptors,
                                                       uint32_t *count)
 {
@@ -161,16 +160,16 @@
 
     Mutex::Autolock _l(mLock);
     size_t index;
-    for (index = 0; index < mInputSessions.size(); index++) {
-        if (mInputSessions.valueAt(index)->mSessionId == audioSession) {
+    for (index = 0; index < mInputs.size(); index++) {
+        if (mInputs.valueAt(index)->mSessionId == audioSession) {
             break;
         }
     }
-    if (index == mInputSessions.size()) {
+    if (index == mInputs.size()) {
         *count = 0;
         return BAD_VALUE;
     }
-    Vector< sp<AudioEffect> > effects = mInputSessions.valueAt(index)->mEffects;
+    Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects;
 
     for (size_t i = 0; i < effects.size(); i++) {
         effect_descriptor_t desc = effects[i]->descriptor();
@@ -186,7 +185,7 @@
 }
 
 
-status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(audio_session_t audioSession,
+status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(int audioSession,
                          effect_descriptor_t *descriptors,
                          uint32_t *count)
 {
@@ -221,7 +220,7 @@
 
 status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
                          audio_stream_type_t stream,
-                         audio_session_t audioSession)
+                         int audioSession)
 {
     status_t status = NO_ERROR;
 
@@ -276,7 +275,7 @@
 
 status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output,
                          audio_stream_type_t stream,
-                         audio_session_t audioSession)
+                         int audioSession)
 {
     status_t status = NO_ERROR;
     (void) output; // argument not used for now
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index f302167..266a45e 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -51,7 +51,7 @@
 
     // Return a list of effect descriptors for default input effects
     // associated with audioSession
-    status_t queryDefaultInputEffects(audio_session_t audioSession,
+    status_t queryDefaultInputEffects(int audioSession,
                              effect_descriptor_t *descriptors,
                              uint32_t *count);
 
@@ -59,16 +59,15 @@
     // Effects are attached depending on the audio_source_t
     status_t addInputEffects(audio_io_handle_t input,
                              audio_source_t inputSource,
-                             audio_session_t audioSession);
+                             int audioSession);
 
     // Add all input effects associated to this input
-    status_t releaseInputEffects(audio_io_handle_t input,
-                                 audio_session_t audioSession);
+    status_t releaseInputEffects(audio_io_handle_t input);
 
 
     // Return a list of effect descriptors for default output effects
     // associated with audioSession
-    status_t queryDefaultOutputSessionEffects(audio_session_t audioSession,
+    status_t queryDefaultOutputSessionEffects(int audioSession,
                              effect_descriptor_t *descriptors,
                              uint32_t *count);
 
@@ -76,12 +75,12 @@
     // Effects are attached depending on the audio_stream_type_t
     status_t addOutputSessionEffects(audio_io_handle_t output,
                              audio_stream_type_t stream,
-                             audio_session_t audioSession);
+                             int audioSession);
 
     // release all output effects associated with this output stream and audiosession
     status_t releaseOutputSessionEffects(audio_io_handle_t output,
                              audio_stream_type_t stream,
-                             audio_session_t audioSession);
+                             int audioSession);
 
 private:
 
@@ -179,17 +178,17 @@
                          size_t *curSize,
                          size_t *totSize);
 
-    // protects access to mInputSources, mInputSessions, mOutputStreams, mOutputSessions
+    // protects access to mInputSources, mInputs, mOutputStreams, mOutputSessions
     Mutex mLock;
     // Automatic input effects are configured per audio_source_t
     KeyedVector< audio_source_t, EffectDescVector* > mInputSources;
     // Automatic input effects are unique for audio_io_handle_t
-    KeyedVector< audio_session_t, EffectVector* > mInputSessions;
+    KeyedVector< audio_io_handle_t, EffectVector* > mInputs;
 
     // Automatic output effects are organized per audio_stream_type_t
     KeyedVector< audio_stream_type_t, EffectDescVector* > mOutputStreams;
     // Automatic output effects are unique for audiosession ID
-    KeyedVector< audio_session_t, EffectVector* > mOutputSessions;
+    KeyedVector< int32_t, EffectVector* > mOutputSessions;
 };
 
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index ae5cf3d..c7486a5 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -349,23 +349,8 @@
         return NO_INIT;
     }
     Mutex::Autolock _l(mLock);
-    AudioPolicyInterface::concurrency_type__mask_t concurrency;
-    status_t status = mAudioPolicyManager->startInput(input, session, &concurrency);
 
-    if (status == NO_ERROR) {
-        LOG_ALWAYS_FATAL_IF(concurrency & ~AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL,
-                            "startInput(): invalid concurrency type %d", (int)concurrency);
-
-        // enforce permission (if any) required for each type of concurrency
-        if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_CALL) {
-            //TODO: check incall capture permission
-        }
-        if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_CAPTURE) {
-            //TODO: check concurrent capture permission
-        }
-    }
-
-    return status;
+    return mAudioPolicyManager->startInput(input, session);
 }
 
 status_t AudioPolicyService::stopInput(audio_io_handle_t input,
@@ -393,7 +378,7 @@
     }
     if (audioPolicyEffects != 0) {
         // release audio processors from the input
-        status_t status = audioPolicyEffects->releaseInputEffects(input, session);
+        status_t status = audioPolicyEffects->releaseInputEffects(input);
         if(status != NO_ERROR) {
             ALOGW("Failed to release effects on input %d", input);
         }
@@ -566,8 +551,7 @@
         *count = 0;
         return NO_INIT;
     }
-    return audioPolicyEffects->queryDefaultInputEffects(
-            (audio_session_t)audioSession, descriptors, count);
+    return audioPolicyEffects->queryDefaultInputEffects(audioSession, descriptors, count);
 }
 
 bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 42719f6..08b2a3b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -306,7 +306,7 @@
 }
 
 void AudioPolicyService::releaseInput(audio_io_handle_t input,
-                                      audio_session_t session)
+                                      audio_session_t session __unused)
 {
     if (mpAudioPolicy == NULL) {
         return;
@@ -320,7 +320,7 @@
     }
     if (audioPolicyEffects != 0) {
         // release audio processors from the input
-        status_t status = audioPolicyEffects->releaseInputEffects(input, session);
+        status_t status = audioPolicyEffects->releaseInputEffects(input);
         if(status != NO_ERROR) {
             ALOGW("Failed to release effects on input %d", input);
         }
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
index 66522cc..5bbd4e3 100644
--- a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
@@ -31,6 +31,7 @@
 sched_setscheduler: 1
 gettid: 1
 rt_sigprocmask: 1
+sched_yield: 1
 
 # for attaching to debuggerd on process crash
 sigaction: 1
diff --git a/services/radio/Android.mk b/services/radio/Android.mk
index 9ee5666..6aae31d 100644
--- a/services/radio/Android.mk
+++ b/services/radio/Android.mk
@@ -31,6 +31,8 @@
     libradio \
     libradio_metadata
 
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
 LOCAL_MODULE:= libradioservice
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/radio/RadioRegions.h b/services/radio/RadioRegions.h
index 3335b8a..d40ee83 100644
--- a/services/radio/RadioRegions.h
+++ b/services/radio/RadioRegions.h
@@ -67,11 +67,14 @@
             1,
             {RADIO_BAND_SPACING_FM_ITU1},
             {
-            RADIO_DEEMPHASIS_50,
-            true,
-            RADIO_RDS_WORLD,
-            true,
-            true,
+                {
+                RADIO_DEEMPHASIS_50,
+                true,
+                RADIO_RDS_WORLD,
+                true,
+                true,
+                true,
+                }
             }
         }
     },
@@ -85,11 +88,14 @@
             1,
             {RADIO_BAND_SPACING_FM_ITU2},
             {
-            RADIO_DEEMPHASIS_75,
-            true,
-            RADIO_RDS_US,
-            true,
-            true,
+                {
+                RADIO_DEEMPHASIS_75,
+                true,
+                RADIO_RDS_US,
+                true,
+                true,
+                true,
+                }
             }
         }
     },
@@ -103,11 +109,14 @@
             1,
             {RADIO_BAND_SPACING_FM_JAPAN},
             {
-            RADIO_DEEMPHASIS_50,
-            true,
-            RADIO_RDS_WORLD,
-            true,
-            true,
+                {
+                RADIO_DEEMPHASIS_50,
+                true,
+                RADIO_RDS_WORLD,
+                true,
+                true,
+                true,
+                }
             }
         }
     },
@@ -121,11 +130,14 @@
             1,
             {RADIO_BAND_SPACING_FM_ITU1},
             {
-            RADIO_DEEMPHASIS_75,
-            true,
-            RADIO_RDS_WORLD,
-            true,
-            true,
+                {
+                RADIO_DEEMPHASIS_75,
+                true,
+                RADIO_RDS_WORLD,
+                true,
+                true,
+                true,
+                }
             }
         }
     },
@@ -139,11 +151,14 @@
             1,
             {RADIO_BAND_SPACING_FM_OIRT},
             {
-            RADIO_DEEMPHASIS_50,
-            true,
-            RADIO_RDS_WORLD,
-            true,
-            true,
+                {
+                RADIO_DEEMPHASIS_50,
+                true,
+                RADIO_RDS_WORLD,
+                true,
+                true,
+                true,
+                }
             }
         }
     },
@@ -157,11 +172,14 @@
             1,
             {RADIO_BAND_SPACING_FM_ITU2},
             {
-            RADIO_DEEMPHASIS_75,
-            true,
-            RADIO_RDS_US,
-            true,
-            true,
+                {
+                RADIO_DEEMPHASIS_75,
+                true,
+                RADIO_RDS_US,
+                true,
+                true,
+                true,
+                }
             }
         }
     },
diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp
index 57697f3..5a3f750 100644
--- a/services/radio/RadioService.cpp
+++ b/services/radio/RadioService.cpp
@@ -735,7 +735,7 @@
         }
     } else {
         mConfig = *config;
-        status == INVALID_OPERATION;
+        status = INVALID_OPERATION;
     }
 
     return status;
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index c891fd6..66310b5 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -544,19 +544,39 @@
     AutoMutex lock(mLock);
 
     if (mModels.size() >= mDescriptor.properties.max_sound_models) {
+        /* Make space for a keyphrase sound model by first trying to swap out a previously loaded
+         * keyphrase sound model, or if needed, another sound model. This decision would optimally
+         * happen in SoundTriggerHelper, but is happening here because state tracking isn't good
+         * enough in SoundTriggerHelper to ensure that state is consistent between it and the HAL,
+         * nor does sufficient error handling exist to recover from inconsistencies.
+         * Once that exists:
+         * TODO: we should return an error instead of unloading a previous sound model here.
+         */
         if (mModels.size() == 0) {
             return INVALID_OPERATION;
         }
-        ALOGW("loadSoundModel() max number of models exceeded %d making room for a new one",
-              mDescriptor.properties.max_sound_models);
-        unloadSoundModel_l(mModels.valueAt(0)->mHandle);
+        if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+            ALOGW("loadSoundModel() max number of models exceeded %d making room for a new one",
+                  mDescriptor.properties.max_sound_models);
+            sound_model_handle_t unload_handle = mModels.valueAt(0)->mHandle;
+            for (size_t i = 0; i < mModels.size(); i++) {
+                if (mModels.valueAt(i)->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
+                    unload_handle = mModels.keyAt(i);
+                    break;
+                }
+            }
+            unloadSoundModel_l(unload_handle);
+        } else {
+            ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
+                  mDescriptor.properties.max_sound_models);
+            return INVALID_OPERATION;
+        }
     }
 
-    status_t status = mHwDevice->load_sound_model(mHwDevice,
-                                                  sound_model,
+    status_t status = mHwDevice->load_sound_model(mHwDevice, sound_model,
                                                   SoundTriggerHwService::soundModelCallback,
-                                                  this,
-                                                  handle);
+                                                  this, handle);
+
     if (status != NO_ERROR) {
         return status;
     }