Merge "Move AudioMMapPolicy* from android.media to a.m.audio.common SAIDL"
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 74b099c..9e3a823 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -100,8 +100,10 @@
         ASSERT_NE(mLinearPool, nullptr);
 
         std::vector<std::unique_ptr<C2Param>> queried;
-        mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
-        ASSERT_GT(queried.size(), 0);
+        c2_status_t c2err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+                                              C2_DONT_BLOCK, &queried);
+        ASSERT_EQ(c2err, C2_OK) << "Query media type failed";
+        ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
 
         mMime = ((C2PortMediaTypeSetting::input*)queried[0].get())->m.value;
 
@@ -277,24 +279,20 @@
     };
     std::vector<std::unique_ptr<C2Param>> inParams;
     c2_status_t status = component->query({}, indices, C2_DONT_BLOCK, &inParams);
-    if (status != C2_OK && inParams.size() == 0) {
-        ALOGE("Query media type failed => %d", status);
-        ASSERT_TRUE(false);
-    } else {
-        size_t offset = sizeof(C2Param);
-        for (size_t i = 0; i < inParams.size(); ++i) {
-            C2Param* param = inParams[i].get();
-            bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
-        }
-        if (mime.find("3gpp") != std::string::npos) {
-            ASSERT_EQ(bitStreamInfo[0], 8000);
-            ASSERT_EQ(bitStreamInfo[1], 1);
-        } else if (mime.find("amr-wb") != std::string::npos) {
-            ASSERT_EQ(bitStreamInfo[0], 16000);
-            ASSERT_EQ(bitStreamInfo[1], 1);
-        } else if (mime.find("gsm") != std::string::npos) {
-            ASSERT_EQ(bitStreamInfo[0], 8000);
-        }
+    ASSERT_EQ(status, C2_OK) << "Query sample rate and channel count info failed";
+    ASSERT_EQ(inParams.size(), indices.size()) << "Size of the vector returned is invalid";
+
+    bitStreamInfo[0] = C2StreamSampleRateInfo::output::From(inParams[0].get())->value;
+    bitStreamInfo[1] = C2StreamChannelCountInfo::output::From(inParams[1].get())->value;
+    if (mime.find("3gpp") != std::string::npos) {
+        ASSERT_EQ(bitStreamInfo[0], 8000);
+        ASSERT_EQ(bitStreamInfo[1], 1);
+    } else if (mime.find("amr-wb") != std::string::npos) {
+        ASSERT_EQ(bitStreamInfo[0], 16000);
+        ASSERT_EQ(bitStreamInfo[1], 1);
+    } else if (mime.find("gsm") != std::string::npos) {
+        ASSERT_EQ(bitStreamInfo[0], 8000);
+        ASSERT_EQ(bitStreamInfo[1], 1);
     }
 }
 
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index 1dc037a..bd7ec0d 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -73,9 +73,10 @@
         ASSERT_NE(mLinearPool, nullptr);
 
         std::vector<std::unique_ptr<C2Param>> queried;
-        mComponent->query({}, {C2PortMediaTypeSetting::output::PARAM_TYPE}, C2_DONT_BLOCK,
-                          &queried);
-        ASSERT_GT(queried.size(), 0);
+        c2_status_t c2err = mComponent->query({}, {C2PortMediaTypeSetting::output::PARAM_TYPE},
+                                              C2_DONT_BLOCK, &queried);
+        ASSERT_EQ(c2err, C2_OK) << "Query media type failed";
+        ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
 
         mMime = ((C2PortMediaTypeSetting::output*)queried[0].get())->m.value;
         mEos = false;
@@ -84,16 +85,10 @@
         mEncoderFrameSize = 0;
         mWorkResult = C2_OK;
         mOutputSize = 0u;
-        getInputMaxBufSize();
-
-        c2_status_t status = getChannelCount(&mNumChannels);
-        ASSERT_EQ(status, C2_OK) << "Unable to get supported channel count";
-
-        status = getSampleRate(&mSampleRate);
-        ASSERT_EQ(status, C2_OK) << "Unable to get supported sample rate";
-
-        status = getSamplesPerFrame(mNumChannels, &mSamplesPerFrame);
-        ASSERT_EQ(status, C2_OK) << "Unable to get supported number of samples per frame";
+        ASSERT_NO_FATAL_FAILURE(getInputMaxBufSize());
+        ASSERT_NO_FATAL_FAILURE(getChannelCount(&mNumChannels));
+        ASSERT_NO_FATAL_FAILURE(getSampleRate(&mSampleRate));
+        ASSERT_NO_FATAL_FAILURE(getSamplesPerFrame(mNumChannels, &mSamplesPerFrame));
 
         getFile(mNumChannels, mSampleRate);
     }
@@ -109,9 +104,9 @@
     // Get the test parameters from GetParam call.
     virtual void getParams() {}
 
-    c2_status_t getChannelCount(int32_t* nChannels);
-    c2_status_t getSampleRate(int32_t* nSampleRate);
-    c2_status_t getSamplesPerFrame(int32_t nChannels, int32_t* samplesPerFrame);
+    void getChannelCount(int32_t* nChannels);
+    void getSampleRate(int32_t* nSampleRate);
+    void getSamplesPerFrame(int32_t nChannels, int32_t* samplesPerFrame);
 
     void getFile(int32_t channelCount, int32_t sampleRate);
 
@@ -175,21 +170,13 @@
 
     // In encoder components, fetch the size of input buffer allocated
     void getInputMaxBufSize() {
-        int32_t bitStreamInfo[1] = {0};
         std::vector<std::unique_ptr<C2Param>> inParams;
         c2_status_t status = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
                                                C2_DONT_BLOCK, &inParams);
-        if (status != C2_OK && inParams.size() == 0) {
-            ALOGE("Query MaxBufferSizeInfo failed => %d", status);
-            ASSERT_TRUE(false);
-        } else {
-            size_t offset = sizeof(C2Param);
-            for (size_t i = 0; i < inParams.size(); ++i) {
-                C2Param* param = inParams[i].get();
-                bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
-            }
-        }
-        mInputMaxBufSize = bitStreamInfo[0];
+        ASSERT_EQ(status, C2_OK) << "Query max buffer size info failed";
+        ASSERT_EQ(inParams.size(), 1) << "Size of the vector returned is invalid";
+
+        mInputMaxBufSize = C2StreamMaxBufferSizeInfo::input::From(inParams[0].get())->value;
     }
 };
 
@@ -245,17 +232,15 @@
     return false;
 }
 
-c2_status_t Codec2AudioEncHidlTestBase::getChannelCount(int32_t* nChannels) {
+void Codec2AudioEncHidlTestBase::getChannelCount(int32_t* nChannels) {
     std::unique_ptr<C2StreamChannelCountInfo::input> channelCount =
             std::make_unique<C2StreamChannelCountInfo::input>();
     std::vector<C2FieldSupportedValuesQuery> validValueInfos = {
             C2FieldSupportedValuesQuery::Current(
                     C2ParamField(channelCount.get(), &C2StreamChannelCountInfo::value))};
     c2_status_t c2err = mComponent->querySupportedValues(validValueInfos, C2_DONT_BLOCK);
-    if (c2err != C2_OK || validValueInfos.size() != 1u) {
-        ALOGE("querySupportedValues_vb failed for channelCount");
-        return c2err;
-    }
+    ASSERT_EQ(c2err, C2_OK) << "Query channel count info failed";
+    ASSERT_EQ(validValueInfos.size(), 1) << "Size of the vector returned is invalid";
 
     // setting default value of channelCount
     *nChannels = 1;
@@ -282,48 +267,45 @@
             break;
         }
         default:
+            ASSERT_TRUE(false) << "Unsupported type: " << c2FSV.type;
             break;
     }
-    return C2_OK;
+    return;
 }
-c2_status_t Codec2AudioEncHidlTestBase::getSampleRate(int32_t* nSampleRate) {
+void Codec2AudioEncHidlTestBase::getSampleRate(int32_t* nSampleRate) {
     // Use the default sample rate for mComponents
     std::vector<std::unique_ptr<C2Param>> queried;
     c2_status_t c2err = mComponent->query({}, {C2StreamSampleRateInfo::input::PARAM_TYPE},
                                           C2_DONT_BLOCK, &queried);
-    if (c2err != C2_OK || queried.size() == 0) return c2err;
+    ASSERT_EQ(c2err, C2_OK) << "Query sample rate info failed";
+    ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
 
-    size_t offset = sizeof(C2Param);
-    C2Param* param = queried[0].get();
-    *nSampleRate = *(int32_t*)((uint8_t*)param + offset);
-
-    return C2_OK;
+    *nSampleRate = C2StreamSampleRateInfo::input::From(queried[0].get())->value;
+    return;
 }
 
-c2_status_t Codec2AudioEncHidlTestBase::getSamplesPerFrame(int32_t nChannels,
-                                                           int32_t* samplesPerFrame) {
+void Codec2AudioEncHidlTestBase::getSamplesPerFrame(int32_t nChannels, int32_t* samplesPerFrame) {
     std::vector<std::unique_ptr<C2Param>> queried;
     c2_status_t c2err = mComponent->query({}, {C2StreamAudioFrameSizeInfo::input::PARAM_TYPE},
                                           C2_DONT_BLOCK, &queried);
-    size_t offset = sizeof(C2Param);
-    if (c2err == C2_OK && queried.size()) {
-        C2Param* param = queried[0].get();
-        mEncoderFrameSize = *(uint32_t*)((uint8_t*)param + offset);
+
+    if (c2err == C2_OK && queried.size() == 1) {
+        mEncoderFrameSize = C2StreamAudioFrameSizeInfo::input::From(queried[0].get())->value;
         if (mEncoderFrameSize) {
             *samplesPerFrame = mEncoderFrameSize;
-            return C2_OK;
+            return;
         }
     }
 
     c2err = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE}, C2_DONT_BLOCK,
                               &queried);
-    if (c2err != C2_OK || queried.size() == 0) return c2err;
+    ASSERT_EQ(c2err, C2_OK) << "Query max buffer size info failed";
+    ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
 
-    C2Param* param = queried[0].get();
-    uint32_t maxInputSize = *(uint32_t*)((uint8_t*)param + offset);
+    uint32_t maxInputSize = C2StreamMaxBufferSizeInfo::input::From(queried[0].get())->value;
     *samplesPerFrame = std::min((maxInputSize / (nChannels * 2)), kMaxSamplesPerFrame);
 
-    return C2_OK;
+    return;
 }
 
 // LookUpTable of clips and metadata for component testing
@@ -619,12 +601,11 @@
         std::vector<std::unique_ptr<C2Param>> inParams;
         c2_status_t c2_status = mComponent->query({}, {C2StreamChannelCountInfo::input::PARAM_TYPE},
                                                   C2_DONT_BLOCK, &inParams);
-        ASSERT_TRUE(!c2_status && inParams.size())
-                << "Query configured channelCount failed => %d" << c2_status;
+        ASSERT_EQ(c2_status, C2_OK) << "Query channel count info failed";
+        ASSERT_EQ(inParams.size(), 1) << "Size of the vector returned is invalid";
 
-        size_t offset = sizeof(C2Param);
-        C2Param* param = inParams[0].get();
-        int32_t channelCount = *(int32_t*)((uint8_t*)param + offset);
+        int32_t channelCount = C2StreamChannelCountInfo::input::From(inParams[0].get())->value;
+
         if (channelCount != nChannels) {
             std::cout << "[   WARN   ] Test Skipped for ChannelCount " << nChannels << "\n";
             continue;
@@ -708,13 +689,11 @@
         std::vector<std::unique_ptr<C2Param>> inParams;
         c2_status_t c2_status = mComponent->query({}, {C2StreamSampleRateInfo::input::PARAM_TYPE},
                                                   C2_DONT_BLOCK, &inParams);
+        ASSERT_EQ(c2_status, C2_OK) << "Query sample rate info failed";
+        ASSERT_EQ(inParams.size(), 1) << "Size of the vector returned is invalid";
 
-        ASSERT_TRUE(!c2_status && inParams.size())
-                << "Query configured SampleRate failed => %d" << c2_status;
-        size_t offset = sizeof(C2Param);
-        C2Param* param = inParams[0].get();
-        int32_t configuredSampleRate = *(int32_t*)((uint8_t*)param + offset);
-
+        int32_t configuredSampleRate =
+                C2StreamSampleRateInfo::input::From(inParams[0].get())->value;
         if (configuredSampleRate != nSampleRate) {
             std::cout << "[   WARN   ] Test Skipped for SampleRate " << nSampleRate << "\n";
             continue;
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 95a4674..67873fa 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -123,8 +123,10 @@
         ASSERT_NE(mLinearPool, nullptr);
 
         std::vector<std::unique_ptr<C2Param>> queried;
-        mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
-        ASSERT_GT(queried.size(), 0);
+        c2_status_t c2err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+                                              C2_DONT_BLOCK, &queried);
+        ASSERT_EQ(c2err, C2_OK) << "Query media type failed";
+        ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
 
         mMime = ((C2PortMediaTypeSetting::input*)queried[0].get())->m.value;
         mEos = false;
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index a6507e7..8305feb 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -74,9 +74,10 @@
         ASSERT_NE(mGraphicPool, nullptr);
 
         std::vector<std::unique_ptr<C2Param>> queried;
-        mComponent->query({}, {C2PortMediaTypeSetting::output::PARAM_TYPE}, C2_DONT_BLOCK,
-                          &queried);
-        ASSERT_GT(queried.size(), 0);
+        c2_status_t c2err = mComponent->query({}, {C2PortMediaTypeSetting::output::PARAM_TYPE},
+                                              C2_DONT_BLOCK, &queried);
+        ASSERT_EQ(c2err, C2_OK) << "Query media type failed";
+        ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
 
         mMime = ((C2PortMediaTypeSetting::output*)queried[0].get())->m.value;
         std::cout << "mime : " << mMime << "\n";
@@ -531,9 +532,17 @@
                   << " resetting num BFrames to 0\n";
         mConfigBPictures = false;
     } else {
-        size_t offset = sizeof(C2Param);
-        C2Param* param = inParams[0].get();
-        int32_t numBFrames = *(int32_t*)((uint8_t*)param + offset);
+        int32_t numBFrames = 0;
+        C2StreamGopTuning::output* gop = C2StreamGopTuning::output::From(inParams[0].get());
+        if (gop && gop->flexCount() >= 1) {
+            for (size_t i = 0; i < gop->flexCount(); ++i) {
+                const C2GopLayerStruct& layer = gop->m.values[i];
+                if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME)) {
+                    numBFrames = layer.count;
+                    break;
+                }
+            }
+        }
 
         if (!numBFrames) {
             std::cout << "[   WARN   ] Bframe not supported for " << mComponentName
@@ -817,6 +826,10 @@
 TEST_P(Codec2VideoEncHidlTest, AdaptiveBitrateTest) {
     description("Encodes input file for different bitrates");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
+    if (mMime != "video/avc" && mMime != "video/hevc" && mMime != "video/x-vnd.on2.vp8" &&
+        mMime != "video/x-vnd.on2.vp9") {
+        GTEST_SKIP() << "AdaptiveBitrateTest is enabled only for avc, hevc, vp8 and vp9 encoders";
+    }
 
     std::ifstream eleStream;
     eleStream.open(mInputFile, std::ifstream::binary);
diff --git a/media/libaudioclient/aidl/android/media/ISpatializer.aidl b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
index 6355b46..b871238 100644
--- a/media/libaudioclient/aidl/android/media/ISpatializer.aidl
+++ b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
@@ -50,9 +50,15 @@
     /** Gets the selected spatialization level (see SpatializationLevel.aidl) */
     SpatializationLevel getLevel();
 
+    /** Reports if the spatializer engine supports head tracking or not.
+     * This is a pre condition independent of the fact that a head tracking sensor is
+     * registered or not.
+     */
+    boolean isHeadTrackingSupported();
+
     /** Reports the list of supported head tracking modes (see SpatializerHeadTrackingMode.aidl).
      * The list can be empty if the spatializer implementation does not support head tracking or if
-     * no head tracking device is connected.
+     * no head tracking sensor is registered (see setHeadSensor() and setScreenSensor()).
      */
     SpatializerHeadTrackingMode[] getSupportedHeadTrackingModes();
 
@@ -113,4 +119,20 @@
      */
     void registerHeadTrackingCallback(@nullable ISpatializerHeadTrackingCallback callback);
 
+    /**
+     * Sets a parameter to the spatializer engine. Used by effect implementor for vendor
+     * specific configuration.
+     */
+     void setParameter(int key, in byte[] value);
+
+    /**
+     * Gets a parameter from the spatializer engine. Used by effect implementor for vendor
+     * specific configuration.
+     */
+     void getParameter(int key, inout byte[] value);
+
+    /**
+     * Gets the io handle of the output stream the spatializer is connected to.
+     */
+     int getOutput();
 }
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index 2988c67..ab6a8b6 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -328,7 +328,9 @@
     DO_CHANNEL_POSITION(21);
     DO_CHANNEL_POSITION(22);
     DO_CHANNEL_POSITION(23);
-    static_assert(FCC_LIMIT <= FCC_24); // Note: this may need to change.
+    DO_CHANNEL_POSITION(24);
+    DO_CHANNEL_POSITION(25);
+    static_assert(FCC_LIMIT <= FCC_26); // Note: this may need to change.
 #pragma pop_macro("DO_CHANNEL_POSITION")
 }
 
@@ -346,6 +348,8 @@
         [7] = AUDIO_CHANNEL_OUT_6POINT1,
         [8] = AUDIO_CHANNEL_OUT_7POINT1,
         [12] = AUDIO_CHANNEL_OUT_7POINT1POINT4,
+        [14] = AUDIO_CHANNEL_OUT_9POINT1POINT4,
+        [16] = AUDIO_CHANNEL_OUT_9POINT1POINT6,
         [24] = AUDIO_CHANNEL_OUT_22POINT2,
     };
     return channelCount < std::size(canonical) ? canonical[channelCount] : AUDIO_CHANNEL_NONE;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 87964d1..a75e427 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -65,6 +65,7 @@
 #include <system/audio_effects/effect_ns.h>
 #include <system/audio_effects/effect_aec.h>
 #include <system/audio_effects/effect_hapticgenerator.h>
+#include <system/audio_effects/effect_spatializer.h>
 
 #include <audio_utils/primitives.h>
 
@@ -3791,6 +3792,15 @@
             goto Exit;
         }
 
+        // Only audio policy service can create a spatializer effect
+        if ((memcmp(&descOut.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) &&
+            (callingUid != AID_AUDIOSERVER || currentPid != getpid())) {
+            ALOGW("%s: attempt to create a spatializer effect from uid/pid %d/%d",
+                    __func__, callingUid, currentPid);
+            lStatus = PERMISSION_DENIED;
+            goto Exit;
+        }
+
         if (io == AUDIO_IO_HANDLE_NONE && sessionId == AUDIO_SESSION_OUTPUT_MIX) {
             // if the output returned by getOutputForEffect() is removed before we lock the
             // mutex below, the call to checkPlaybackThread_l(io) below will detect it
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c158620..ab9d2f1 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1343,6 +1343,13 @@
         return BAD_VALUE;
     }
 
+    if (memcmp(&desc->type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0
+            && mType != SPATIALIZER) {
+        ALOGW("%s: attempt to create a spatializer effect on a thread of type %d",
+                __func__, mType);
+        return BAD_VALUE;
+    }
+
     switch (mType) {
     case MIXER: {
 #ifndef MULTICHANNEL_EFFECT_CHAIN
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 28d267c..0773f27 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -58,12 +58,6 @@
        if (!_tmp.ok()) return aidl_utils::binderStatusFromStatusT(_tmp.error()); \
        std::move(_tmp.value()); })
 
-#define RETURN_IF_BINDER_ERROR(x)      \
-    {                                  \
-        binder::Status _tmp = (x);     \
-        if (!_tmp.isOk()) return _tmp; \
-    }
-
 // ---------------------------------------------------------------------------
 
 class Spatializer::EngineCallbackHandler : public AHandler {
@@ -332,6 +326,16 @@
     return Status::ok();
 }
 
+Status Spatializer::isHeadTrackingSupported(bool *supports) {
+    ALOGV("%s mSupportsHeadTracking %d", __func__, mSupportsHeadTracking);
+    if (supports == nullptr) {
+        return binderStatusFromStatusT(BAD_VALUE);
+    }
+    std::lock_guard lock(mLock);
+    *supports = mSupportsHeadTracking;
+    return Status::ok();
+}
+
 Status Spatializer::getSupportedHeadTrackingModes(
         std::vector<SpatializerHeadTrackingMode>* modes) {
     std::lock_guard lock(mLock);
@@ -485,6 +489,10 @@
     if (mPoseController != nullptr) {
         mPoseController->setDisplayOrientation(mDisplayOrientation);
     }
+    if (mEngine != nullptr) {
+        setEffectParameter_l(
+            SPATIALIZER_PARAM_DISPLAY_ORIENTATION, std::vector<float>{physicalToLogicalAngle});
+    }
     return Status::ok();
 }
 
@@ -517,6 +525,42 @@
     return Status::ok();
 }
 
+Status Spatializer::setParameter(int key, const std::vector<unsigned char>& value) {
+    ALOGV("%s key %d", __func__, key);
+    std::lock_guard lock(mLock);
+    status_t status = INVALID_OPERATION;
+    if (mEngine != nullptr) {
+        status = setEffectParameter_l(key, value);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+Status Spatializer::getParameter(int key, std::vector<unsigned char> *value) {
+    ALOGV("%s key %d value size %d", __func__, key,
+          (value != nullptr ? (int)value->size() : -1));
+    if (value == nullptr) {
+        binderStatusFromStatusT(BAD_VALUE);
+    }
+    std::lock_guard lock(mLock);
+    status_t status = INVALID_OPERATION;
+    if (mEngine != nullptr) {
+        ALOGV("%s key %d mEngine %p", __func__, key, mEngine.get());
+        status = getEffectParameter_l(key, value);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+Status Spatializer::getOutput(int *output) {
+    ALOGV("%s", __func__);
+    if (output == nullptr) {
+        binderStatusFromStatusT(BAD_VALUE);
+    }
+    std::lock_guard lock(mLock);
+    *output = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_io_handle_t_int32_t(mOutput));
+    ALOGV("%s got output %d", __func__, *output);
+    return Status::ok();
+}
+
 // SpatializerPoseController::Listener
 void Spatializer::onHeadToStagePose(const Pose3f& headToStage) {
     ALOGV("%s", __func__);
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 61daf01..136a467 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -100,6 +100,7 @@
     binder::Status getSupportedLevels(std::vector<media::SpatializationLevel>* levels) override;
     binder::Status setLevel(media::SpatializationLevel level) override;
     binder::Status getLevel(media::SpatializationLevel *level) override;
+    binder::Status isHeadTrackingSupported(bool *supports);
     binder::Status getSupportedHeadTrackingModes(
             std::vector<media::SpatializerHeadTrackingMode>* modes) override;
     binder::Status setDesiredHeadTrackingMode(
@@ -115,6 +116,9 @@
     binder::Status getSupportedModes(std::vector<media::SpatializationMode>* modes) override;
     binder::Status registerHeadTrackingCallback(
         const sp<media::ISpatializerHeadTrackingCallback>& callback) override;
+    binder::Status setParameter(int key, const std::vector<unsigned char>& value) override;
+    binder::Status getParameter(int key, std::vector<unsigned char> *value) override;
+    binder::Status getOutput(int *output);
 
     /** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
     virtual void binderDied(const wp<IBinder>& who);
@@ -209,6 +213,7 @@
         if (numParams > kMaxEffectParamValues) {
             return BAD_VALUE;
         }
+        (*values).clear();
         std::copy(&params[0], &params[numParams], back_inserter(*values));
         return NO_ERROR;
     }
@@ -229,7 +234,46 @@
         *(uint32_t *)p->data = type;
         memcpy((uint32_t *)p->data + 1, values.data(), sizeof(T) * values.size());
 
-        return mEngine->setParameter(p);
+        status_t status = mEngine->setParameter(p);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        if (p->status != NO_ERROR) {
+            return p->status;
+        }
+        return NO_ERROR;
+    }
+
+    /**
+     * Get a parameter from spatializer engine by calling getParameter on AudioEffect object.
+     * It is possible to read more than one value of type T according to the parameter type
+     * by specifying values vector size.
+     */
+    template<typename T>
+    status_t getEffectParameter_l(uint32_t type, std::vector<T> *values) REQUIRES(mLock) {
+        static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
+
+        uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values->size()];
+        effect_param_t *p = (effect_param_t *)cmd;
+        p->psize = sizeof(uint32_t);
+        p->vsize = sizeof(T) * values->size();
+        *(uint32_t *)p->data = type;
+
+        status_t status = mEngine->getParameter(p);
+
+        if (status != NO_ERROR) {
+            return status;
+        }
+        if (p->status != NO_ERROR) {
+            return p->status;
+        }
+
+        int numValues = std::min(p->vsize / sizeof(T), values->size());
+        (*values).clear();
+        T *retValues = (T *)((uint8_t *)p->data + sizeof(uint32_t));
+        std::copy(&retValues[0], &retValues[numValues], back_inserter(*values));
+
+        return NO_ERROR;
     }
 
     void postFramesProcessedMsg(int frames);