Merge "soundtrigger: Add support for HAL V2.1"
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
index d689e25..0196a0c 100644
--- a/include/media/MmapStreamInterface.h
+++ b/include/media/MmapStreamInterface.h
@@ -52,6 +52,9 @@
      * \param[in,out] deviceId audio device the stream should preferably be routed to/from
      *                       Requested as input,
      *                       Actual as output
+     * \param[in,out] sessionId audio sessionId for the stream
+     *                       Requested as input, may be AUDIO_SESSION_ALLOCATE
+     *                       Actual as output
      * \param[in] callback the MmapStreamCallback interface used by AudioFlinger to notify
      *                     condition changes affecting the stream operation
      * \param[out] interface the MmapStreamInterface interface controlling the created stream
@@ -66,6 +69,7 @@
                                            audio_config_base_t *config,
                                            const AudioClient& client,
                                            audio_port_handle_t *deviceId,
+                                           audio_session_t *sessionId,
                                            const sp<MmapStreamCallback>& callback,
                                            sp<MmapStreamInterface>& interface,
                                            audio_port_handle_t *handle);
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index b3e069d..5da8114 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -123,7 +123,7 @@
     /**
      * No particular performance needs. Default.
      */
-            AAUDIO_PERFORMANCE_MODE_NONE = 10,
+    AAUDIO_PERFORMANCE_MODE_NONE = 10,
 
     /**
      * Extending battery life is most important.
@@ -131,12 +131,12 @@
      * This mode is not supported in input streams.
      * Mode NONE will be used if this is requested.
      */
-            AAUDIO_PERFORMANCE_MODE_POWER_SAVING,
+    AAUDIO_PERFORMANCE_MODE_POWER_SAVING,
 
     /**
      * Reducing latency is most important.
      */
-            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+    AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
 };
 typedef int32_t aaudio_performance_mode_t;
 
@@ -283,6 +283,25 @@
 };
 typedef int32_t aaudio_input_preset_t;
 
+enum {
+    /**
+     * Do not allocate a session ID.
+     * Effects cannot be used with this stream.
+     * Default.
+     */
+    AAUDIO_SESSION_ID_NONE = -1,
+
+    /**
+     * Allocate a session ID that can be used to attach and control
+     * effects using the Java AudioEffects API.
+     * Note that the use of this flag may result in higher latency.
+     *
+     * Note that this matches the value of AudioManager.AUDIO_SESSION_ID_GENERATE.
+     */
+    AAUDIO_SESSION_ID_ALLOCATE = 0,
+};
+typedef int32_t aaudio_session_id_t;
+
 typedef struct AAudioStreamStruct         AAudioStream;
 typedef struct AAudioStreamBuilderStruct  AAudioStreamBuilder;
 
@@ -499,6 +518,32 @@
 AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* builder,
                                                    aaudio_input_preset_t inputPreset);
 
+/** Set the requested session ID.
+ *
+ * The session ID can be used to associate a stream with effects processors.
+ * The effects are controlled using the Android AudioEffect Java API.
+ *
+ * The default, if you do not call this function, is AAUDIO_SESSION_ID_NONE.
+ *
+ * If set to AAUDIO_SESSION_ID_ALLOCATE then a session ID will be allocated
+ * when the stream is opened.
+ *
+ * The allocated session ID can be obtained by calling AAudioStream_getSessionId()
+ * and then used with this function when opening another stream.
+ * This allows effects to be shared between streams.
+ *
+ * Session IDs from AAudio can be used the Android Java APIs and vice versa.
+ * So a session ID from an AAudio stream can be passed to Java
+ * and effects applied using the Java AudioEffect API.
+ *
+ * Allocated session IDs will always be positive and nonzero.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param sessionId an allocated sessionID or AAUDIO_SESSION_ID_ALLOCATE
+ */
+AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* builder,
+                                                aaudio_session_id_t sessionId);
+
 /**
  * Return one of these values from the data callback function.
  */
@@ -996,6 +1041,28 @@
 AAUDIO_API int64_t AAudioStream_getFramesRead(AAudioStream* stream);
 
 /**
+ * Passes back the session ID associated with this stream.
+ *
+ * The session ID can be used to associate a stream with effects processors.
+ * The effects are controlled using the Android AudioEffect Java API.
+ *
+ * If AAudioStreamBuilder_setSessionId() was called with AAUDIO_SESSION_ID_ALLOCATE
+ * then a new session ID should be allocated once when the stream is opened.
+ *
+ * If AAudioStreamBuilder_setSessionId() was called with a previously allocated
+ * session ID then that value should be returned.
+ *
+ * If AAudioStreamBuilder_setSessionId() was not called then this function should
+ * return AAUDIO_SESSION_ID_NONE.
+ *
+ * The sessionID for a stream should not change once the stream has been opened.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return session ID or AAUDIO_SESSION_ID_NONE
+ */
+AAUDIO_API aaudio_session_id_t AAudioStream_getSessionId(AAudioStream* stream);
+
+/**
  * Passes back the time at which a particular frame was presented.
  * This can be used to synchronize audio with video or MIDI.
  * It can also be used to align a recorded stream with a playback stream.
diff --git a/media/libaaudio/libaaudio.map.txt b/media/libaaudio/libaaudio.map.txt
index 98fbb6f..cbf5921 100644
--- a/media/libaaudio/libaaudio.map.txt
+++ b/media/libaaudio/libaaudio.map.txt
@@ -20,6 +20,7 @@
     AAudioStreamBuilder_setUsage;       # introduced=28
     AAudioStreamBuilder_setContentType; # introduced=28
     AAudioStreamBuilder_setInputPreset; # introduced=28
+    AAudioStreamBuilder_setSessionId;   # introduced=28
     AAudioStreamBuilder_openStream;
     AAudioStreamBuilder_delete;
     AAudioStream_close;
@@ -50,6 +51,7 @@
     AAudioStream_getInputPreset; # introduced=28
     AAudioStream_getFramesWritten;
     AAudioStream_getFramesRead;
+    AAudioStream_getSessionId;   # introduced=28
     AAudioStream_getTimestamp;
     AAudioStream_isMMapUsed;
   local:
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 97672a0..959db61 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -56,6 +56,8 @@
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32((int32_t) getInputPreset());
     if (status != NO_ERROR) goto error;
+    status = parcel->writeInt32(getSessionId());
+    if (status != NO_ERROR) goto error;
     return NO_ERROR;
 error:
     ALOGE("AAudioStreamConfiguration.writeToParcel(): write failed = %d", status);
@@ -94,6 +96,9 @@
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
     setInputPreset((aaudio_input_preset_t) value);
+    status = parcel->readInt32(&value);
+    if (status != NO_ERROR) goto error;
+    setSessionId(value);
     return NO_ERROR;
 error:
     ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 5856ec3..4980e97 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -133,6 +133,7 @@
     setSampleRate(configurationOutput.getSampleRate());
     setSamplesPerFrame(configurationOutput.getSamplesPerFrame());
     setDeviceId(configurationOutput.getDeviceId());
+    setSessionId(configurationOutput.getSessionId());
     setSharingMode(configurationOutput.getSharingMode());
 
     setUsage(configurationOutput.getUsage());
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 9e5ca8e..df0db79 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -196,12 +196,19 @@
 }
 
 AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
-                                                        int32_t frames)
+                                                              int32_t frames)
 {
     AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
     streamBuilder->setBufferCapacity(frames);
 }
 
+AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* builder,
+                                                 aaudio_session_id_t sessionId)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    streamBuilder->setSessionId(sessionId);
+}
+
 AAUDIO_API void AAudioStreamBuilder_setDataCallback(AAudioStreamBuilder* builder,
                                                     AAudioStream_dataCallback callback,
                                                     void *userData)
@@ -483,6 +490,12 @@
     return audioStream->getInputPreset();
 }
 
+AAUDIO_API int32_t AAudioStream_getSessionId(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getSessionId();
+}
+
 AAUDIO_API int64_t AAudioStream_getFramesWritten(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 23c4eb8..9645ea8 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -38,6 +38,7 @@
     mSamplesPerFrame = other.mSamplesPerFrame;
     mSampleRate      = other.mSampleRate;
     mDeviceId        = other.mDeviceId;
+    mSessionId       = other.mSessionId;
     mSharingMode     = other.mSharingMode;
     mAudioFormat     = other.mAudioFormat;
     mDirection       = other.mDirection;
@@ -59,6 +60,15 @@
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
+    // All Session ID values are legal.
+    switch (mSessionId) {
+        case AAUDIO_SESSION_ID_NONE:
+        case AAUDIO_SESSION_ID_ALLOCATE:
+            break;
+        default:
+            break;
+    }
+
     switch (mSharingMode) {
         case AAUDIO_SHARING_MODE_EXCLUSIVE:
         case AAUDIO_SHARING_MODE_SHARED:
@@ -154,6 +164,7 @@
 
 void AAudioStreamParameters::dump() const {
     ALOGD("mDeviceId        = %6d", mDeviceId);
+    ALOGD("mSessionId       = %6d", mSessionId);
     ALOGD("mSampleRate      = %6d", mSampleRate);
     ALOGD("mSamplesPerFrame = %6d", mSamplesPerFrame);
     ALOGD("mSharingMode     = %6d", (int)mSharingMode);
@@ -164,4 +175,3 @@
     ALOGD("mContentType     = %6d", mContentType);
     ALOGD("mInputPreset     = %6d", mInputPreset);
 }
-
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index 0c173f5..ce5dacd 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -112,6 +112,14 @@
         mInputPreset = inputPreset;
     }
 
+    aaudio_session_id_t getSessionId() const {
+        return mSessionId;
+    }
+
+    void setSessionId(aaudio_session_id_t sessionId) {
+        mSessionId = sessionId;
+    }
+
     int32_t calculateBytesPerFrame() const {
         return getSamplesPerFrame() * AAudioConvert_formatToSizeInBytes(getFormat());
     }
@@ -137,6 +145,7 @@
     aaudio_content_type_t      mContentType     = AAUDIO_UNSPECIFIED;
     aaudio_input_preset_t      mInputPreset     = AAUDIO_UNSPECIFIED;
     int32_t                    mBufferCapacity  = AAUDIO_UNSPECIFIED;
+    aaudio_session_id_t        mSessionId       = AAUDIO_SESSION_ID_NONE;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 1b2ca39..82c0667 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -108,8 +108,10 @@
           mSampleRate, mSamplesPerFrame, mFormat,
           AudioStream_convertSharingModeToShortText(mSharingMode),
           (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
-    ALOGI("open() device = %d, perfMode = %d, callback: %s with frames = %d",
-          mDeviceId, mPerformanceMode,
+    ALOGI("open() device = %d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
+          mDeviceId,
+          mSessionId,
+          mPerformanceMode,
           (isDataCallbackSet() ? "ON" : "OFF"),
           mFramesPerDataCallback);
     ALOGI("open() usage = %d, contentType = %d, inputPreset = %d",
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 21fa595..42b585f 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -216,6 +216,10 @@
         return mInputPreset;
     }
 
+    int32_t getSessionId() const {
+        return mSessionId;
+    }
+
     /**
      * This is only valid after setSamplesPerFrame() and setFormat() have been called.
      */
@@ -455,10 +459,15 @@
         mDeviceId = deviceId;
     }
 
+    void setSessionId(int32_t sessionId) {
+        mSessionId = sessionId;
+    }
+
     std::atomic<bool>    mCallbackEnabled{false};
 
     float                mDuckAndMuteVolume = 1.0f;
 
+
 protected:
 
     void setPeriodNanoseconds(int64_t periodNanoseconds) {
@@ -505,10 +514,13 @@
     aaudio_format_t             mFormat = AAUDIO_FORMAT_UNSPECIFIED;
     aaudio_stream_state_t       mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
     aaudio_performance_mode_t   mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
+
     aaudio_usage_t              mUsage           = AAUDIO_USAGE_MEDIA;
     aaudio_content_type_t       mContentType     = AAUDIO_CONTENT_TYPE_MUSIC;
     aaudio_input_preset_t       mInputPreset     = AAUDIO_INPUT_PRESET_GENERIC;
 
+    int32_t                     mSessionId = AAUDIO_UNSPECIFIED;
+
     // callback ----------------------------------
 
     AAudioStream_dataCallback   mDataCallbackProc = nullptr;  // external callback functions
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index f7cb8d6..293a6a8 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -141,6 +141,13 @@
     // TODO Support other performance settings in MMAP mode.
     // Disable MMAP if low latency not requested.
     if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) {
+        ALOGD("build() MMAP not available because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not used.");
+        allowMMap = false;
+    }
+
+    // SessionID and Effects are only supported in Legacy mode.
+    if (getSessionId() != AAUDIO_SESSION_ID_NONE) {
+        ALOGD("build() MMAP not available because sessionId used.");
         allowMMap = false;
     }
 
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 5f4ab9b..61a0f8a 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -117,6 +117,9 @@
             .tags = ""
     };
 
+    aaudio_session_id_t requestedSessionId = builder.getSessionId();
+    audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
     mAudioRecord = new AudioRecord(
             mOpPackageName // const String16& opPackageName TODO does not compile
             );
@@ -130,7 +133,7 @@
             callbackData,
             notificationFrames,
             false /*threadCanCallJava*/,
-            AUDIO_SESSION_ALLOCATE,
+            sessionId,
             streamTransferType,
             flags,
             AUDIO_UID_INVALID, // DEFAULT uid
@@ -189,6 +192,13 @@
 
     setState(AAUDIO_STREAM_STATE_OPEN);
     setDeviceId(mAudioRecord->getRoutedDeviceId());
+
+    aaudio_session_id_t actualSessionId =
+            (requestedSessionId == AAUDIO_SESSION_ID_NONE)
+            ? AAUDIO_SESSION_ID_NONE
+            : (aaudio_session_id_t) mAudioRecord->getSessionId();
+    setSessionId(actualSessionId);
+
     mAudioRecord->addAudioDeviceCallback(mDeviceCallback);
 
     return AAUDIO_OK;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 17a8d52..52c7822 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -134,6 +134,11 @@
             .tags = ""
     };
 
+    static_assert(AAUDIO_UNSPECIFIED == AUDIO_SESSION_ALLOCATE, "Session IDs should match");
+
+    aaudio_session_id_t requestedSessionId = builder.getSessionId();
+    audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
     mAudioTrack = new AudioTrack();
     mAudioTrack->set(
             AUDIO_STREAM_DEFAULT,  // ignored because we pass attributes below
@@ -147,7 +152,7 @@
             notificationFrames,
             0,       // DEFAULT sharedBuffer*/,
             false,   // DEFAULT threadCanCallJava
-            AUDIO_SESSION_ALLOCATE,
+            sessionId,
             streamTransferType,
             NULL,    // DEFAULT audio_offload_info_t
             AUDIO_UID_INVALID, // DEFAULT uid
@@ -193,6 +198,13 @@
 
     setState(AAUDIO_STREAM_STATE_OPEN);
     setDeviceId(mAudioTrack->getRoutedDeviceId());
+
+    aaudio_session_id_t actualSessionId =
+            (requestedSessionId == AAUDIO_SESSION_ID_NONE)
+            ? AAUDIO_SESSION_ID_NONE
+            : (aaudio_session_id_t) mAudioTrack->getSessionId();
+    setSessionId(actualSessionId);
+
     mAudioTrack->addAudioDeviceCallback(mDeviceCallback);
 
     // Update performance mode based on the actual stream flags.
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index c6adf33..2bee6e3 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -250,6 +250,13 @@
     return result;
 }
 
+audio_session_t AAudioConvert_aaudioToAndroidSessionId(aaudio_session_id_t sessionId) {
+    // If not a valid sessionId then convert to a safe value of AUDIO_SESSION_ALLOCATE.
+    return (sessionId < AAUDIO_SESSION_ID_MIN)
+           ? AUDIO_SESSION_ALLOCATE
+           : (audio_session_t) sessionId;
+}
+
 audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_format_t aaudioFormat) {
     audio_format_t androidFormat;
     switch (aaudioFormat) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index f2347f5..0c59f6d 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -27,6 +27,9 @@
 
 #include "aaudio/AAudio.h"
 
+
+constexpr aaudio_session_id_t AAUDIO_SESSION_ID_MIN = 1; // must be positive
+
 /**
  * Convert an AAudio result into the closest matching Android status.
  */
@@ -38,6 +41,13 @@
 aaudio_result_t AAudioConvert_androidToAAudioResult(android::status_t status);
 
 /**
+ * Convert an aaudio_session_id_t to a value that is safe to pass to AudioFlinger.
+ * @param sessionId
+ * @return safe value
+ */
+audio_session_t AAudioConvert_aaudioToAndroidSessionId(aaudio_session_id_t sessionId);
+
+/**
  * Convert an array of floats to an array of int16_t.
  *
  * @param source
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 33718fc..45d417f 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -113,6 +113,18 @@
 }
 
 cc_test {
+    name: "test_session_id",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_session_id.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
     name: "test_aaudio_monkey",
     defaults: ["libaaudio_tests_defaults"],
     srcs: ["test_aaudio_monkey.cpp"],
diff --git a/media/libaaudio/tests/test_session_id.cpp b/media/libaaudio/tests/test_session_id.cpp
new file mode 100644
index 0000000..d9072af
--- /dev/null
+++ b/media/libaaudio/tests/test_session_id.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// Test AAudio SessionId, which is used to associate Effects with a stream
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+#include <gtest/gtest.h>
+
+constexpr int64_t kNanosPerSecond = 1000000000;
+constexpr int kNumFrames = 256;
+constexpr int kChannelCount = 2;
+
+// Test AAUDIO_SESSION_ID_NONE default
+static void checkSessionIdNone(aaudio_performance_mode_t perfMode) {
+
+    float *buffer = new float[kNumFrames * kChannelCount];
+
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+
+    AAudioStream *aaudioStream1 = nullptr;
+    int32_t       sessionId1 = 0;
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
+
+    // Request stream properties.
+    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream1));
+
+    // Since we did not request or specify a SessionID, we should get NONE
+    sessionId1 = AAudioStream_getSessionId(aaudioStream1);
+    ASSERT_EQ(AAUDIO_SESSION_ID_NONE, sessionId1);
+
+    ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream1));
+
+    ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream1, buffer, kNumFrames, kNanosPerSecond));
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream1));
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream1));
+    delete[] buffer;
+    AAudioStreamBuilder_delete(aaudioBuilder);
+}
+
+TEST(test_session_id, aaudio_session_id_none_perfnone) {
+    checkSessionIdNone(AAUDIO_PERFORMANCE_MODE_NONE);
+}
+
+TEST(test_session_id, aaudio_session_id_none_lowlat) {
+    checkSessionIdNone(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
+
+// Test AAUDIO_SESSION_ID_ALLOCATE
+static void checkSessionIdAllocate(aaudio_performance_mode_t perfMode,
+                                   aaudio_direction_t direction) {
+
+    float *buffer = new float[kNumFrames * kChannelCount];
+
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+
+    AAudioStream *aaudioStream1 = nullptr;
+    int32_t       sessionId1 = 0;
+    AAudioStream *aaudioStream2 = nullptr;
+    int32_t       sessionId2 = 0;
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
+
+    // Request stream properties.
+    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
+    // This stream could be input or output.
+    AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
+
+    // Ask AAudio to allocate a Session ID.
+    AAudioStreamBuilder_setSessionId(aaudioBuilder, AAUDIO_SESSION_ID_ALLOCATE);
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream1));
+
+    // Get the allocated ID from the stream.
+    sessionId1 = AAudioStream_getSessionId(aaudioStream1);
+    ASSERT_LT(0, sessionId1); // Must be positive.
+
+    ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream1));
+
+    if (direction == AAUDIO_DIRECTION_INPUT) {
+        ASSERT_EQ(kNumFrames, AAudioStream_read(aaudioStream1,
+                                                buffer, kNumFrames, kNanosPerSecond));
+    } else {
+        ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream1,
+                                         buffer, kNumFrames, kNanosPerSecond));
+    }
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream1));
+
+    // Now open a second stream using the same session ID. ==================
+    AAudioStreamBuilder_setSessionId(aaudioBuilder, sessionId1);
+
+    // Reverse direction for second stream.
+    aaudio_direction_t otherDirection = (direction == AAUDIO_DIRECTION_OUTPUT)
+                                        ? AAUDIO_DIRECTION_INPUT
+                                        : AAUDIO_DIRECTION_OUTPUT;
+    AAudioStreamBuilder_setDirection(aaudioBuilder, otherDirection);
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream2));
+
+    // Get the allocated ID from the stream.
+    // It should match the ID that we set it to in the builder.
+    sessionId2 = AAudioStream_getSessionId(aaudioStream2);
+    ASSERT_EQ(sessionId1, sessionId2);
+
+    ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream2));
+
+    if (otherDirection == AAUDIO_DIRECTION_INPUT) {
+        ASSERT_EQ(kNumFrames, AAudioStream_read(aaudioStream2,
+                                                 buffer, kNumFrames, kNanosPerSecond));
+    } else {
+        ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream2,
+                                                 buffer, kNumFrames, kNanosPerSecond));
+    }
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream2));
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream2));
+
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream1));
+    delete[] buffer;
+    AAudioStreamBuilder_delete(aaudioBuilder);
+}
+
+TEST(test_session_id, aaudio_session_id_alloc_perfnone_in) {
+    checkSessionIdAllocate(AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_DIRECTION_INPUT);
+}
+TEST(test_session_id, aaudio_session_id_alloc_perfnone_out) {
+    checkSessionIdAllocate(AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_DIRECTION_OUTPUT);
+}
+
+TEST(test_session_id, aaudio_session_id_alloc_lowlat_in) {
+    checkSessionIdAllocate(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_DIRECTION_INPUT);
+}
+TEST(test_session_id, aaudio_session_id_alloc_lowlat_out) {
+    checkSessionIdAllocate(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_DIRECTION_OUTPUT);
+}
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index a777663..bbf87f0 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -146,9 +146,14 @@
     MediaExtractor::ExtractorDef def;
     void *libHandle;
     String8 libPath;
+    String8 uuidString;
 
     ExtractorPlugin(MediaExtractor::ExtractorDef definition, void *handle, String8 &path)
-        : def(definition), libHandle(handle), libPath(path) { }
+        : def(definition), libHandle(handle), libPath(path) {
+        for (size_t i = 0; i < sizeof MediaExtractor::ExtractorDef::extractor_uuid; i++) {
+            uuidString.appendFormat("%02x", def.extractor_uuid.b[i]);
+        }
+    }
     ~ExtractorPlugin() {
         if (libHandle != nullptr) {
             ALOGV("closing handle for %s %d", libPath.c_str(), def.extractor_version);
@@ -307,4 +312,20 @@
     gPluginsRegistered = true;
 }
 
+status_t MediaExtractorFactory::dump(int fd, const Vector<String16>&) {
+    Mutex::Autolock autoLock(gPluginMutex);
+    String8 out;
+    out.append("Available extractors:\n");
+    for (auto it = gPlugins->begin(); it != gPlugins->end(); ++it) {
+        out.appendFormat("  %25s: uuid(%s), version(%u), path(%s)\n",
+                (*it)->def.extractor_name,
+                (*it)->uuidString.c_str(),
+                (*it)->def.extractor_version,
+                (*it)->libPath.c_str());
+    }
+    write(fd, out.string(), out.size());
+    return OK;
+}
+
+
 }  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index 7fddf80..55654f1 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -41,6 +41,7 @@
     static sp<IMediaExtractor> CreateFromService(
             const sp<DataSource> &source, const char *mime = NULL);
     static void LoadPlugins(const ::std::string& apkPath);
+    static status_t dump(int fd, const Vector<String16>& args);
 
 private:
     static Mutex gPluginMutex;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4d5e094..2a2f6fc 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -262,6 +262,7 @@
                                              audio_config_base_t *config,
                                              const AudioClient& client,
                                              audio_port_handle_t *deviceId,
+                                             audio_session_t *sessionId,
                                              const sp<MmapStreamCallback>& callback,
                                              sp<MmapStreamInterface>& interface,
                                              audio_port_handle_t *handle)
@@ -274,7 +275,8 @@
     status_t ret = NO_INIT;
     if (af != 0) {
         ret = af->openMmapStream(
-                direction, attr, config, client, deviceId, callback, interface, handle);
+                direction, attr, config, client, deviceId,
+                sessionId, callback, interface, handle);
     }
     return ret;
 }
@@ -284,6 +286,7 @@
                                       audio_config_base_t *config,
                                       const AudioClient& client,
                                       audio_port_handle_t *deviceId,
+                                      audio_session_t *sessionId,
                                       const sp<MmapStreamCallback>& callback,
                                       sp<MmapStreamInterface>& interface,
                                       audio_port_handle_t *handle)
@@ -292,8 +295,10 @@
     if (ret != NO_ERROR) {
         return ret;
     }
-
-    audio_session_t sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+    audio_session_t actualSessionId = *sessionId;
+    if (actualSessionId == AUDIO_SESSION_ALLOCATE) {
+        actualSessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+    }
     audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
     audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -303,7 +308,7 @@
         fullConfig.channel_mask = config->channel_mask;
         fullConfig.format = config->format;
         ret = AudioSystem::getOutputForAttr(attr, &io,
-                                            sessionId,
+                                            actualSessionId,
                                             &streamType, client.clientUid,
                                             &fullConfig,
                                             (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
@@ -311,7 +316,7 @@
                                             deviceId, &portId);
     } else {
         ret = AudioSystem::getInputForAttr(attr, &io,
-                                              sessionId,
+                                              actualSessionId,
                                               client.clientPid,
                                               client.clientUid,
                                               config,
@@ -326,13 +331,14 @@
     sp<MmapThread> thread = mMmapThreads.valueFor(io);
     if (thread != 0) {
         interface = new MmapThreadHandle(thread);
-        thread->configure(attr, streamType, sessionId, callback, *deviceId, portId);
+        thread->configure(attr, streamType, actualSessionId, callback, *deviceId, portId);
         *handle = portId;
+        *sessionId = actualSessionId;
     } else {
         if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
-            AudioSystem::releaseOutput(io, streamType, sessionId);
+            AudioSystem::releaseOutput(io, streamType, actualSessionId);
         } else {
-            AudioSystem::releaseInput(io, sessionId);
+            AudioSystem::releaseInput(io, actualSessionId);
         }
         ret = NO_INIT;
     }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index bc73ffd..5a64f0b 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -271,6 +271,7 @@
                             audio_config_base_t *config,
                             const AudioClient& client,
                             audio_port_handle_t *deviceId,
+                            audio_session_t *sessionId,
                             const sp<MmapStreamCallback>& callback,
                             sp<MmapStreamInterface>& interface,
                             audio_port_handle_t *handle);
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
index 6e0f2b6..ede8e3f 100644
--- a/services/audioflinger/Configuration.h
+++ b/services/audioflinger/Configuration.h
@@ -47,6 +47,9 @@
 #ifdef FLOAT_EFFECT_CHAIN
 // define FLOAT_AUX to process aux effect buffers in float (FLOAT_EFFECT_CHAIN must be defined)
 #define FLOAT_AUX
+
+// define MULTICHANNEL_EFFECT_CHAIN to allow multichannel effects (FLOAT_EFFECT_CHAIN defined)
+#define MULTICHANNEL_EFFECT_CHAIN
 #endif
 
 #endif // ANDROID_AUDIOFLINGER_CONFIGURATION_H
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index b4ff0d6..b13e551 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -26,6 +26,7 @@
 #include <system/audio_effects/effect_aec.h>
 #include <system/audio_effects/effect_ns.h>
 #include <system/audio_effects/effect_visualizer.h>
+#include <audio_utils/channels.h>
 #include <audio_utils/primitives.h>
 #include <media/AudioEffect.h>
 #include <media/audiohal/EffectHalInterface.h>
@@ -292,7 +293,6 @@
         return;
     }
 
-    // TODO: Implement multichannel effects; here outChannelCount == FCC_2 == 2
     const uint32_t inChannelCount =
             audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
     const uint32_t outChannelCount =
@@ -342,6 +342,7 @@
         if (isProcessImplemented()) {
             if (auxType) {
                 // We overwrite the aux input buffer here and clear after processing.
+                // aux input is always mono.
 #ifdef FLOAT_EFFECT_CHAIN
                 if (mSupportsFloat) {
 #ifndef FLOAT_AUX
@@ -371,6 +372,28 @@
                 }
             }
 #ifdef FLOAT_EFFECT_CHAIN
+            sp<EffectBufferHalInterface> inBuffer = mInBuffer;
+            sp<EffectBufferHalInterface> outBuffer = mOutBuffer;
+
+            if (!auxType && mInChannelCountRequested != inChannelCount) {
+                adjust_channels(
+                        inBuffer->audioBuffer()->f32, mInChannelCountRequested,
+                        mInConversionBuffer->audioBuffer()->f32, inChannelCount,
+                        sizeof(float),
+                        sizeof(float)
+                        * mInChannelCountRequested * mConfig.inputCfg.buffer.frameCount);
+                inBuffer = mInConversionBuffer;
+            }
+            if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE
+                    && mOutChannelCountRequested != outChannelCount) {
+                adjust_selected_channels(
+                        outBuffer->audioBuffer()->f32, mOutChannelCountRequested,
+                        mOutConversionBuffer->audioBuffer()->f32, outChannelCount,
+                        sizeof(float),
+                        sizeof(float)
+                        * mOutChannelCountRequested * mConfig.outputCfg.buffer.frameCount);
+                outBuffer = mOutConversionBuffer;
+            }
             if (!mSupportsFloat) { // convert input to int16_t as effect doesn't support float.
                 if (!auxType) {
                     if (mInConversionBuffer.get() == nullptr) {
@@ -379,8 +402,9 @@
                     }
                     memcpy_to_i16_from_float(
                             mInConversionBuffer->audioBuffer()->s16,
-                            mInBuffer->audioBuffer()->f32,
+                            inBuffer->audioBuffer()->f32,
                             inChannelCount * mConfig.inputCfg.buffer.frameCount);
+                    inBuffer = mInConversionBuffer;
                 }
                 if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
                     if (mOutConversionBuffer.get() == nullptr) {
@@ -389,21 +413,30 @@
                     }
                     memcpy_to_i16_from_float(
                             mOutConversionBuffer->audioBuffer()->s16,
-                            mOutBuffer->audioBuffer()->f32,
+                            outBuffer->audioBuffer()->f32,
                             outChannelCount * mConfig.outputCfg.buffer.frameCount);
+                    outBuffer = mOutConversionBuffer;
                 }
             }
 #endif
-
             ret = mEffectInterface->process();
-
 #ifdef FLOAT_EFFECT_CHAIN
             if (!mSupportsFloat) { // convert output int16_t back to float.
+                sp<EffectBufferHalInterface> target =
+                        mOutChannelCountRequested != outChannelCount
+                        ? mOutConversionBuffer : mOutBuffer;
+
                 memcpy_to_float_from_i16(
-                        mOutBuffer->audioBuffer()->f32,
+                        target->audioBuffer()->f32,
                         mOutConversionBuffer->audioBuffer()->s16,
                         outChannelCount * mConfig.outputCfg.buffer.frameCount);
             }
+            if (mOutChannelCountRequested != outChannelCount) {
+                adjust_selected_channels(mOutConversionBuffer->audioBuffer()->f32, outChannelCount,
+                        mOutBuffer->audioBuffer()->f32, mOutChannelCountRequested,
+                        sizeof(float),
+                        sizeof(float) * outChannelCount * mConfig.outputCfg.buffer.frameCount);
+            }
 #endif
         } else {
 #ifdef FLOAT_EFFECT_CHAIN
@@ -476,15 +509,28 @@
     }
 
     // TODO: handle configuration of effects replacing track process
+    // TODO: handle configuration of input (record) SW effects above the HAL,
+    // similar to output EFFECT_FLAG_TYPE_INSERT/REPLACE,
+    // in which case input channel masks should be used here.
     channelMask = thread->channelMask();
+    mConfig.inputCfg.channels = channelMask;
     mConfig.outputCfg.channels = channelMask;
 
     if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-        mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO;
-        mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
-        ALOGV("Overriding auxiliary effect input as MONO and output as STEREO");
+        if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_MONO) {
+            mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO;
+            ALOGV("Overriding auxiliary effect input channels %#x as MONO",
+                    mConfig.inputCfg.channels);
+        }
+#ifndef MULTICHANNEL_EFFECT_CHAIN
+        if (mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) {
+            mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+            ALOGV("Overriding auxiliary effect output channels %#x as STEREO",
+                    mConfig.outputCfg.channels);
+        }
+#endif
     } else {
-        mConfig.inputCfg.channels = channelMask;
+#ifndef MULTICHANNEL_EFFECT_CHAIN
         // TODO: Update this logic when multichannel effects are implemented.
         // For offloaded tracks consider mono output as stereo for proper effect initialization
         if (channelMask == AUDIO_CHANNEL_OUT_MONO) {
@@ -492,7 +538,12 @@
             mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
             ALOGV("Overriding effect input and output as STEREO");
         }
+#endif
     }
+    mInChannelCountRequested =
+            audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
+    mOutChannelCountRequested =
+            audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
 
     mConfig.inputCfg.format = EFFECT_BUFFER_FORMAT;
     mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
@@ -530,28 +581,58 @@
     status_t cmdStatus;
     size = sizeof(int);
     status = mEffectInterface->command(EFFECT_CMD_SET_CONFIG,
-                                       sizeof(effect_config_t),
+                                       sizeof(mConfig),
                                        &mConfig,
                                        &size,
                                        &cmdStatus);
     if (status == NO_ERROR) {
         status = cmdStatus;
-#ifdef FLOAT_EFFECT_CHAIN
-        mSupportsFloat = true;
-#endif
     }
-#ifdef FLOAT_EFFECT_CHAIN
-    else {
-        ALOGV("EFFECT_CMD_SET_CONFIG failed with float format, retry with int16_t.");
-        mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
-        mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+
+#ifdef MULTICHANNEL_EFFECT_CHAIN
+    if (status != NO_ERROR &&
+            (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
+                    || mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO)) {
+        // Older effects may require exact STEREO position mask.
+        if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) {
+            ALOGV("Overriding effect input channels %#x as STEREO", mConfig.inputCfg.channels);
+            mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+        }
+        if (mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) {
+            ALOGV("Overriding effect output channels %#x as STEREO", mConfig.outputCfg.channels);
+            mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+        }
+        size = sizeof(int);
         status = mEffectInterface->command(EFFECT_CMD_SET_CONFIG,
-                                           sizeof(effect_config_t),
+                                           sizeof(mConfig),
                                            &mConfig,
                                            &size,
                                            &cmdStatus);
         if (status == NO_ERROR) {
             status = cmdStatus;
+        }
+    }
+#endif
+
+#ifdef FLOAT_EFFECT_CHAIN
+    if (status == NO_ERROR) {
+        mSupportsFloat = true;
+    }
+
+    if (status != NO_ERROR) {
+        ALOGV("EFFECT_CMD_SET_CONFIG failed with float format, retry with int16_t.");
+        mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+        mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+        size = sizeof(int);
+        status = mEffectInterface->command(EFFECT_CMD_SET_CONFIG,
+                                           sizeof(mConfig),
+                                           &mConfig,
+                                           &size,
+                                           &cmdStatus);
+        if (status == NO_ERROR) {
+            status = cmdStatus;
+        }
+        if (status == NO_ERROR) {
             mSupportsFloat = false;
             ALOGVV("config worked with 16 bit");
         } else {
@@ -929,11 +1010,15 @@
     // the original buffer) when the output buffer is identical to the input buffer,
     // but we don't optimize for it here.
     const bool auxType = (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY;
-    if (!auxType && !mSupportsFloat && mInBuffer.get() != nullptr) {
+    const uint32_t inChannelCount =
+            audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
+    const bool formatMismatch = !mSupportsFloat || mInChannelCountRequested != inChannelCount;
+    if (!auxType && formatMismatch && mInBuffer.get() != nullptr) {
         // we need to translate - create hidl shared buffer and intercept
         const size_t inFrameCount = mConfig.inputCfg.buffer.frameCount;
-        const int inChannels = audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
-        const size_t size = inChannels * inFrameCount * sizeof(int16_t);
+        // Use FCC_2 in case mInChannelCountRequested is mono and the effect is stereo.
+        const uint32_t inChannels = std::max((uint32_t)FCC_2, mInChannelCountRequested);
+        const size_t size = inChannels * inFrameCount * std::max(sizeof(int16_t), sizeof(float));
 
         ALOGV("%s: setInBuffer updating for inChannels:%d inFrameCount:%zu total size:%zu",
                 __func__, inChannels, inFrameCount, size);
@@ -970,10 +1055,14 @@
 #ifdef FLOAT_EFFECT_CHAIN
     // Note: Any effect that does not accumulate does not need mOutConversionBuffer and
     // can do in-place conversion from int16_t to float.  We don't optimize here.
-    if (!mSupportsFloat && mOutBuffer.get() != nullptr) {
+    const uint32_t outChannelCount =
+            audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
+    const bool formatMismatch = !mSupportsFloat || mOutChannelCountRequested != outChannelCount;
+    if (formatMismatch && mOutBuffer.get() != nullptr) {
         const size_t outFrameCount = mConfig.outputCfg.buffer.frameCount;
-        const int outChannels = audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
-        const size_t size = outChannels * outFrameCount * sizeof(int16_t);
+        // Use FCC_2 in case mOutChannelCountRequested is mono and the effect is stereo.
+        const uint32_t outChannels = std::max((uint32_t)FCC_2, mOutChannelCountRequested);
+        const size_t size = outChannels * outFrameCount * std::max(sizeof(int16_t), sizeof(float));
 
         ALOGV("%s: setOutBuffer updating for outChannels:%d outFrameCount:%zu total size:%zu",
                 __func__, outChannels, outFrameCount, size);
@@ -1813,14 +1902,8 @@
     if (mInBuffer == NULL) {
         return;
     }
-    // TODO: This will change in the future, depending on multichannel
-    // and sample format changes for effects.
-    // Currently effects processing is only available for stereo, AUDIO_FORMAT_PCM_16_BIT
-    // (4 bytes frame size)
-
     const size_t frameSize =
-            audio_bytes_per_sample(EFFECT_BUFFER_FORMAT)
-            * std::min((uint32_t)FCC_2, thread->channelCount());
+            audio_bytes_per_sample(EFFECT_BUFFER_FORMAT) * thread->channelCount();
 
     memset(mInBuffer->audioBuffer()->raw, 0, thread->frameCount() * frameSize);
     mInBuffer->commit();
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index eea3208..2327bb9 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -173,6 +173,8 @@
     bool    mSupportsFloat;         // effect supports float processing
     sp<EffectBufferHalInterface> mInConversionBuffer;  // Buffers for HAL conversion if needed.
     sp<EffectBufferHalInterface> mOutConversionBuffer;
+    uint32_t mInChannelCountRequested;
+    uint32_t mOutChannelCountRequested;
 #endif
 };
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d5def48..3a41ac8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1176,6 +1176,7 @@
 
     switch (mType) {
     case MIXER: {
+#ifndef MULTICHANNEL_EFFECT_CHAIN
         // Reject any effect on mixer multichannel sinks.
         // TODO: fix both format and multichannel issues with effects.
         if (mChannelCount != FCC_2) {
@@ -1183,6 +1184,7 @@
                     " thread %s", desc->name, mChannelCount, mThreadName);
             return BAD_VALUE;
         }
+#endif
         audio_output_flags_t flags = mOutput->flags;
         if (hasFastMixer() || (flags & AUDIO_OUTPUT_FLAG_FAST)) {
             if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
@@ -1229,6 +1231,7 @@
                 desc->name, mThreadName);
         return BAD_VALUE;
     case DUPLICATING:
+#ifndef MULTICHANNEL_EFFECT_CHAIN
         // Reject any effect on mixer multichannel sinks.
         // TODO: fix both format and multichannel issues with effects.
         if (mChannelCount != FCC_2) {
@@ -1236,6 +1239,7 @@
                     " on DUPLICATING thread %s", desc->name, mChannelCount, mThreadName);
             return BAD_VALUE;
         }
+#endif
         if ((sessionId == AUDIO_SESSION_OUTPUT_STAGE) || (sessionId == AUDIO_SESSION_OUTPUT_MIX)) {
             ALOGW("checkEffectCompatibility_l(): global effect %s on DUPLICATING"
                     " thread %s", desc->name, mThreadName);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 68730a5..33f31e0 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2123,7 +2123,10 @@
                                                   audio_devices_t device)
 {
 
-    if ((index < mVolumeCurves->getVolumeIndexMin(stream)) ||
+    // VOICE_CALL stream has minVolumeIndex > 0  but can be muted directly by an
+    // app that has MODIFY_PHONE_STATE permission.
+    if (((index < mVolumeCurves->getVolumeIndexMin(stream)) &&
+            !(stream == AUDIO_STREAM_VOICE_CALL && index == 0)) ||
             (index > mVolumeCurves->getVolumeIndexMax(stream))) {
         return BAD_VALUE;
     }
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 0dc1fce..f0f44f5 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -56,7 +56,7 @@
 }
 
 status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
-    return dumpExtractors(fd, args);
+    return MediaExtractorFactory::dump(fd, args) || dumpExtractors(fd, args);
 }
 
 status_t MediaExtractorService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index b0c3771..7b8d817 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -102,8 +102,8 @@
         }
     }
 
-    ALOGV("findExclusiveEndpoint_l(), found %p for device = %d",
-          endpoint.get(), configuration.getDeviceId());
+    ALOGV("findExclusiveEndpoint_l(), found %p for device = %d, sessionId = %d",
+          endpoint.get(), configuration.getDeviceId(), configuration.getSessionId());
     return endpoint;
 }
 
@@ -118,8 +118,8 @@
         }
     }
 
-    ALOGV("findSharedEndpoint_l(), found %p for device = %d",
-          endpoint.get(), configuration.getDeviceId());
+    ALOGV("findSharedEndpoint_l(), found %p for device = %d, sessionId = %d",
+          endpoint.get(), configuration.getDeviceId(), configuration.getSessionId());
     return endpoint;
 }
 
@@ -151,19 +151,17 @@
         return nullptr;
     } else {
         sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP();
-        ALOGD("openEndpoint(),created MMAP %p", endpointMMap.get());
+        ALOGD("openExclusiveEndpoint(), no match so try to open MMAP %p for dev %d",
+              endpointMMap.get(), configuration.getDeviceId());
         endpoint = endpointMMap;
 
         aaudio_result_t result = endpoint->open(request);
         if (result != AAUDIO_OK) {
-            ALOGE("openEndpoint(), open failed");
+            ALOGE("openExclusiveEndpoint(), open failed");
             endpoint.clear();
         } else {
             mExclusiveStreams.push_back(endpointMMap);
         }
-
-        ALOGD("openEndpoint(), created %p for device = %d",
-              endpoint.get(), configuration.getDeviceId());
     }
 
     if (endpoint.get() != nullptr) {
@@ -209,7 +207,7 @@
                 mSharedStreams.push_back(endpoint);
             }
         }
-        ALOGD("openSharedEndpoint(), created %p for device = %d, dir = %d",
+        ALOGD("openSharedEndpoint(), created %p, requested device = %d, dir = %d",
               endpoint.get(), configuration.getDeviceId(), (int)direction);
         IPCThreadState::self()->restoreCallingIdentity(token);
     }
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 32c8454..f6aeb5a 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -47,7 +47,7 @@
     std::string dump() const;
 
     /**
-     * Find a service endpoint for the given deviceId and direction.
+     * Find a service endpoint for the given deviceId, sessionId and direction.
      * If an endpoint does not already exist then try to create one.
      *
      * @param audioService
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 01e9c6f..33439fc 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -64,6 +64,7 @@
     result << "    ContentType:          " << getContentType() << "\n";
     result << "    InputPreset:          " << getInputPreset() << "\n";
     result << "    Reference Count:      " << mOpenCount << "\n";
+    result << "    Session Id:           " << getSessionId() << "\n";
     result << "    Connected:            " << mConnected.load() << "\n";
     result << "    Registered Streams:" << "\n";
     result << AAudioServiceStreamShared::dumpHeader() << "\n";
@@ -113,6 +114,10 @@
         configuration.getDeviceId() != getDeviceId()) {
         return false;
     }
+    if (configuration.getSessionId() != AAUDIO_SESSION_ID_ALLOCATE &&
+        configuration.getSessionId() != getSessionId()) {
+        return false;
+    }
     if (configuration.getSampleRate() != AAUDIO_UNSPECIFIED &&
         configuration.getSampleRate() != getSampleRate()) {
         return false;
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 541be20..db01c88 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -144,12 +144,16 @@
             ? MmapStreamInterface::DIRECTION_OUTPUT
             : MmapStreamInterface::DIRECTION_INPUT;
 
+    aaudio_session_id_t requestedSessionId = getSessionId();
+    audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
     // Open HAL stream. Set mMmapStream
     status_t status = MmapStreamInterface::openMmapStream(streamDirection,
                                                           &attributes,
                                                           &config,
                                                           mMmapClient,
                                                           &deviceId,
+                                                          &sessionId,
                                                           this, // callback
                                                           mMmapStream,
                                                           &mPortHandle);
@@ -165,6 +169,17 @@
     }
     setDeviceId(deviceId);
 
+    if (sessionId == AUDIO_SESSION_ALLOCATE) {
+        ALOGW("open() - openMmapStream() failed to set sessionId");
+    }
+
+    aaudio_session_id_t actualSessionId =
+            (requestedSessionId == AAUDIO_SESSION_ID_NONE)
+            ? AAUDIO_SESSION_ID_NONE
+            : (aaudio_session_id_t) sessionId;
+    setSessionId(actualSessionId);
+    ALOGD("open() deviceId = %d, sessionId = %d", getDeviceId(), getSessionId());
+
     // Create MMAP/NOIRQ buffer.
     int32_t minSizeFrames = getBufferCapacity();
     if (minSizeFrames <= 0) { // zero will get rejected
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 2de537a..584efe5 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -77,6 +77,8 @@
     setSampleRate(mStreamInternal->getSampleRate());
     setSamplesPerFrame(mStreamInternal->getSamplesPerFrame());
     setDeviceId(mStreamInternal->getDeviceId());
+    setSessionId(mStreamInternal->getSessionId());
+    ALOGD("open() deviceId = %d, sessionId = %d", getDeviceId(), getSessionId());
     mFramesPerBurst = mStreamInternal->getFramesPerBurst();
 
     return result;