Add callback for codec format change.

When creating native audio track, a IAudioTrackCallback will be created
systematically. All callbacks will be cached in Threads and protected by
a lock. Whenever there is a callback event from audio HAL, it will
finally trigger callback to native audio track. Currently, there is only
one callback event, which is codec format change.

Bug: 150301890
Test: manual
Change-Id: I32293627ed923b17dd25f11f0ee0a0c35cd7c01f
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 3638d2c..65afc8d 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -51,6 +51,7 @@
         // AIDL files for audioclient interfaces
         // The headers for these interfaces will be available to any modules that
         // include libaudioclient, at the path "aidl/package/path/BnFoo.h"
+        ":libaudioclient_aidl_callback",
         ":libaudioclient_aidl_private",
         ":libaudioclient_aidl",
 
@@ -138,3 +139,12 @@
     ],
     path: "aidl",
 }
+
+// AIDL interface for audio track callback
+filegroup {
+    name: "libaudioclient_aidl_callback",
+    srcs: [
+        "aidl/android/media/IAudioTrackCallback.aidl",
+    ],
+    path: "aidl",
+}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index d5690fb..2f95886 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -217,7 +217,8 @@
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mAudioTrackCallback(new AudioTrackCallback())
 {
     mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
     mAttributes.usage = AUDIO_USAGE_UNKNOWN;
@@ -248,7 +249,8 @@
       mState(STATE_STOPPED),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
-      mPausedPosition(0)
+      mPausedPosition(0),
+      mAudioTrackCallback(new AudioTrackCallback())
 {
     mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
 
@@ -281,7 +283,8 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mAudioTrackCallback(new AudioTrackCallback())
 {
     mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
 
@@ -1527,6 +1530,7 @@
     input.notificationFrameCount = mNotificationFramesReq;
     input.selectedDeviceId = mSelectedDeviceId;
     input.sessionId = mSessionId;
+    input.audioTrackCallback = mAudioTrackCallback;
 
     IAudioFlinger::CreateTrackOutput output;
 
@@ -3376,4 +3380,23 @@
     mPausedNs = ns;
 }
 
+binder::Status AudioTrack::AudioTrackCallback::onCodecFormatChanged(
+        const std::vector<uint8_t>& audioMetadata)
+{
+    AutoMutex _l(mAudioTrackCbLock);
+    sp<media::IAudioTrackCallback> callback = mCallback.promote();
+    if (callback.get() != nullptr) {
+        callback->onCodecFormatChanged(audioMetadata);
+    } else {
+        mCallback.clear();
+    }
+    return binder::Status::ok();
+}
+
+void AudioTrack::AudioTrackCallback::setAudioTrackCallback(
+        const sp<media::IAudioTrackCallback> &callback) {
+    AutoMutex lock(mAudioTrackCbLock);
+    mCallback = callback;
+}
+
 } // namespace android
diff --git a/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl b/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl
new file mode 100644
index 0000000..21553b5
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+/**
+ * @hide
+ */
+interface IAudioTrackCallback {
+    oneway void onCodecFormatChanged(in byte[] audioMetadata);
+}
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 95cad0a..4adaaea 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -26,6 +26,9 @@
 #include <media/Modulo.h>
 #include <utils/threads.h>
 
+#include "android/media/BnAudioTrackCallback.h"
+#include "android/media/IAudioTrackCallback.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -885,8 +888,6 @@
             virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                              audio_port_handle_t deviceId);
 
-
-
     /* Obtain the pending duration in milliseconds for playback of pure PCM
      * (mixable without embedded timing) data remaining in AudioTrack.
      *
@@ -933,6 +934,10 @@
      */
             audio_port_handle_t getPortId() const { return mPortId; };
 
+            void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback) {
+                mAudioTrackCallback->setAudioTrackCallback(callback);
+            }
+
  protected:
     /* copying audio tracks is not allowed */
                         AudioTrack(const AudioTrack& other);
@@ -1254,6 +1259,18 @@
     };
     MediaMetrics mMediaMetrics;
     std::string mMetricsId;  // GUARDED_BY(mLock), could change in createTrack_l().
+
+private:
+    class AudioTrackCallback : public media::BnAudioTrackCallback {
+    public:
+        binder::Status onCodecFormatChanged(const std::vector<uint8_t>& audioMetadata) override;
+
+        void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback);
+    private:
+        Mutex mAudioTrackCbLock;
+        wp<media::IAudioTrackCallback> mCallback;
+    };
+    sp<AudioTrackCallback> mAudioTrackCallback;
 };
 
 }; // namespace android
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 8658cfa..f4ce5d7 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -40,6 +40,7 @@
 #include <vector>
 
 #include "android/media/IAudioRecord.h"
+#include "android/media/IAudioTrackCallback.h"
 
 namespace android {
 
@@ -83,6 +84,8 @@
             }
             notificationsPerBuffer = parcel->readInt32();
             speed = parcel->readFloat();
+            audioTrackCallback = interface_cast<media::IAudioTrackCallback>(
+                    parcel->readStrongBinder());
 
             /* input/output arguments*/
             (void)parcel->read(&flags, sizeof(audio_output_flags_t));
@@ -107,6 +110,7 @@
             }
             (void)parcel->writeInt32(notificationsPerBuffer);
             (void)parcel->writeFloat(speed);
+            (void)parcel->writeStrongBinder(IInterface::asBinder(audioTrackCallback));
 
             /* input/output arguments*/
             (void)parcel->write(&flags, sizeof(audio_output_flags_t));
@@ -125,6 +129,7 @@
         sp<IMemory> sharedBuffer;
         uint32_t notificationsPerBuffer;
         float speed;
+        sp<media::IAudioTrackCallback> audioTrackCallback;
 
         /* input/output */
         audio_output_flags_t flags;
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index c08dddb..2726e36 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -299,10 +299,17 @@
         if (mCallback.unsafe_get()) {
             processReturn("clearCallback", mStream->clearCallback());
         }
+#if MAJOR_VERSION >= 6
+        if (mEventCallback.unsafe_get() != nullptr) {
+            processReturn("setEventCallback",
+                    mStream->setEventCallback(nullptr));
+        }
+#endif
         processReturn("close", mStream->close());
         mStream.clear();
     }
     mCallback.clear();
+    mEventCallback.clear();
     hardware::IPCThreadState::self()->flushCommands();
     if (mEfGroup) {
         EventFlag::deleteEventFlag(&mEfGroup);
@@ -614,6 +621,50 @@
 }
 #endif
 
+#if MAJOR_VERSION < 6
+status_t StreamOutHalHidl::setEventCallback(
+        const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
+    // Codec format callback is supported starting from audio HAL V6.0
+    return INVALID_OPERATION;
+}
+#else
+
+#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
+
+namespace {
+
+struct StreamOutEventCallback : public IStreamOutEventCallback {
+    StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
+
+    // IStreamOutEventCallback implementation
+    Return<void> onCodecFormatChanged(
+            const android::hardware::hidl_vec<uint8_t>& audioMetadata)  override {
+        sp<StreamOutHalHidl> stream = mStream.promote();
+        if (stream != nullptr) {
+            std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
+            stream->onCodecFormatChanged(metadataBs);
+        }
+        return Void();
+    }
+
+  private:
+    wp<StreamOutHalHidl> mStream;
+};
+
+}  // namespace
+
+status_t StreamOutHalHidl::setEventCallback(
+        const sp<StreamOutHalInterfaceEventCallback>& callback) {
+    if (mStream == nullptr) return NO_INIT;
+    mEventCallback = callback;
+    status_t status = processReturn(
+            "setEventCallback",
+            mStream->setEventCallback(
+                    callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
+    return status;
+}
+#endif
+
 void StreamOutHalHidl::onWriteReady() {
     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
     if (callback == 0) return;
@@ -635,6 +686,13 @@
     callback->onError();
 }
 
+void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
+    sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.promote();
+    if (callback == nullptr) return;
+    ALOGV("asyncCodecFormatCallback %s", __func__);
+    callback->onCodecFormatChanged(metadataBs);
+}
+
 
 StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
         : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index f587889..88f8587 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -173,6 +173,11 @@
     void onDrainReady();
     void onError();
 
+    status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
+    // Methods used by StreamCodecFormatCallback (HIDL).
+    void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs);
+
   private:
     friend class DeviceHalHidl;
     typedef MessageQueue<WriteCommand, hardware::kSynchronizedReadWrite> CommandMQ;
@@ -180,6 +185,7 @@
     typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ;
 
     wp<StreamOutHalInterfaceCallback> mCallback;
+    wp<StreamOutHalInterfaceEventCallback> mEventCallback;
     sp<IStreamOut> mStream;
     std::unique_ptr<CommandMQ> mCommandMQ;
     std::unique_ptr<DataMQ> mDataMQ;
diff --git a/media/libaudiohal/impl/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
index 4818fd8..69be303 100644
--- a/media/libaudiohal/impl/StreamHalLocal.cpp
+++ b/media/libaudiohal/impl/StreamHalLocal.cpp
@@ -275,6 +275,43 @@
     return mStream->get_mmap_position(mStream, position);
 }
 
+status_t StreamOutHalLocal::setEventCallback(
+        const sp<StreamOutHalInterfaceEventCallback>& callback) {
+    if (mStream->set_event_callback == nullptr) {
+        return INVALID_OPERATION;
+    }
+    stream_event_callback_t asyncCallback =
+            callback == nullptr ? nullptr : StreamOutHalLocal::asyncEventCallback;
+    status_t result = mStream->set_event_callback(mStream, asyncCallback, this);
+    if (result == OK) {
+        mEventCallback = callback;
+    }
+    return result;
+}
+
+// static
+int StreamOutHalLocal::asyncEventCallback(
+        stream_event_callback_type_t event, void *param, void *cookie) {
+    // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
+    // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
+    // already running, because the destructor is invoked after the refcount has been atomically
+    // decremented.
+    wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
+    sp<StreamOutHalLocal> self = weakSelf.promote();
+    if (self == nullptr) return 0;
+    sp<StreamOutHalInterfaceEventCallback> callback = self->mEventCallback.promote();
+    if (callback.get() == nullptr) return 0;
+    switch (event) {
+        case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED:
+            callback->onCodecFormatChanged(std::basic_string<uint8_t>((uint8_t*)param));
+            break;
+        default:
+            ALOGW("%s unknown event %d", __func__, event);
+            break;
+    }
+    return 0;
+}
+
 StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
         : StreamHalLocal(&stream->common, device), mStream(stream) {
 }
diff --git a/media/libaudiohal/impl/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
index 34f2bd8..d17f9f3 100644
--- a/media/libaudiohal/impl/StreamHalLocal.h
+++ b/media/libaudiohal/impl/StreamHalLocal.h
@@ -156,9 +156,12 @@
     // Called when the metadata of the stream's source has been changed.
     status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
 
+    status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
   private:
     audio_stream_out_t *mStream;
     wp<StreamOutHalInterfaceCallback> mCallback;
+    wp<StreamOutHalInterfaceEventCallback> mEventCallback;
 
     friend class DeviceHalLocal;
 
@@ -168,6 +171,8 @@
     virtual ~StreamOutHalLocal();
 
     static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
+
+    static int asyncEventCallback(stream_event_callback_type_t event, void *param, void *cookie);
 };
 
 class StreamInHalLocal : public StreamInHalInterface, public StreamHalLocal {
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index 6c3b21c..e30cb72 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -101,6 +101,15 @@
     virtual ~StreamOutHalInterfaceCallback() {}
 };
 
+class StreamOutHalInterfaceEventCallback : public virtual RefBase {
+public:
+    virtual void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) = 0;
+
+protected:
+    StreamOutHalInterfaceEventCallback() {}
+    virtual ~StreamOutHalInterfaceEventCallback() {}
+};
+
 class StreamOutHalInterface : public virtual StreamHalInterface {
   public:
     // Return the audio hardware driver estimated latency in milliseconds.
@@ -157,6 +166,8 @@
      */
     virtual status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) = 0;
 
+    virtual status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) = 0;
+
   protected:
     virtual ~StreamOutHalInterface() {}
 };