Spatializer: add output changed method on native callback

Add onOutputChanged() method to INativeSpatializerCallback
indicating when the output stream the Spatializer is attached to
changes.

Test: run and enable/disable spatial audio
Bug: 202723925
Change-Id: I5f7c5e0038f1c9235ee6fcdd0b56b7f2af07e01a
diff --git a/media/libaudioclient/aidl/android/media/INativeSpatializerCallback.aidl b/media/libaudioclient/aidl/android/media/INativeSpatializerCallback.aidl
index 0e9634c..88b8108 100644
--- a/media/libaudioclient/aidl/android/media/INativeSpatializerCallback.aidl
+++ b/media/libaudioclient/aidl/android/media/INativeSpatializerCallback.aidl
@@ -31,4 +31,9 @@
      * (e.g. when the spatializer is enabled or disabled)
      */
     void onLevelChanged(SpatializationLevel level);
+
+    /** Called when the output stream the Spatializer is attached to changes.
+     * Indicates the IO Handle of the new output.
+     */
+    void onOutputChanged(int output);
 }
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 502a8d0..0fdbe20 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -627,6 +627,9 @@
 
 status_t Spatializer::attachOutput(audio_io_handle_t output) {
     std::shared_ptr<SpatializerPoseController> poseController;
+    bool outputChanged = false;
+    sp<media::INativeSpatializerCallback> callback;
+
     {
         std::lock_guard lock(mLock);
         ALOGV("%s output %d mOutput %d", __func__, (int)output, (int)mOutput);
@@ -654,6 +657,7 @@
                              std::vector<SpatializerHeadTrackingMode>{mActualHeadTrackingMode});
 
         mEngine->setEnabled(true);
+        outputChanged = mOutput != output;
         mOutput = output;
 
         if (mSupportsHeadTracking) {
@@ -668,26 +672,42 @@
             mPoseController->setDisplayOrientation(mDisplayOrientation);
             poseController = mPoseController;
         }
+        callback = mSpatializerCallback;
     }
     if (poseController != nullptr) {
         poseController->waitUntilCalculated();
     }
+
+    if (outputChanged && callback != nullptr) {
+        callback->onOutputChanged(output);
+    }
+
     return NO_ERROR;
 }
 
 audio_io_handle_t Spatializer::detachOutput() {
-    std::lock_guard lock(mLock);
-    ALOGV("%s mOutput %d", __func__, (int)mOutput);
     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-    if (mOutput == AUDIO_IO_HANDLE_NONE) {
-        return output;
+    sp<media::INativeSpatializerCallback> callback;
+
+    {
+        std::lock_guard lock(mLock);
+        ALOGV("%s mOutput %d", __func__, (int)mOutput);
+        if (mOutput == AUDIO_IO_HANDLE_NONE) {
+            return output;
+        }
+        // remove FX instance
+        mEngine->setEnabled(false);
+        mEngine.clear();
+        output = mOutput;
+        mOutput = AUDIO_IO_HANDLE_NONE;
+        mPoseController.reset();
+
+        callback = mSpatializerCallback;
     }
-    // remove FX instance
-    mEngine->setEnabled(false);
-    mEngine.clear();
-    output = mOutput;
-    mOutput = AUDIO_IO_HANDLE_NONE;
-    mPoseController.reset();
+
+    if (callback != nullptr) {
+        callback->onOutputChanged(AUDIO_IO_HANDLE_NONE);
+    }
     return output;
 }