Add selectPresentation API to IAudioTrack

The Java AudioTrack interface has a setPresentation API. This
calls the setParameters API in IAudioTrack. However, this does
not eventuate into a call into the android.hardware.audio@4.0
IStreamOut selectPresentation API.

Add selectPresentation API to IAudioTrack and call down to the
android.hardware.audio@4.0 IStreamOut selectPresentation API.
Translate into calls to setParameters API for legacy HAL
interfaces.

Bug: 63901775
Test: compile
Change-Id: Id634a107f3f93ab18dc80d2bd0af67bda35e859f
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index df9aea6..8607ee1 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2452,13 +2452,8 @@
 status_t AudioTrack::selectPresentation(int presentationId, int programId)
 {
     AutoMutex lock(mLock);
-    AudioParameter param = AudioParameter();
-    param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
-    param.addInt(String8(AudioParameter::keyProgramId), programId);
-    ALOGV("%s(%d): PresentationId/ProgramId[%s]",
-            __func__, mId, param.toString().string());
-
-    return mAudioTrack->setParameters(param.toString());
+    ALOGV("%s(%d): PresentationId:%d ProgramId:%d", __func__, mId, presentationId, programId);
+    return mAudioTrack->selectPresentation(presentationId, programId);
 }
 
 VolumeShaper::Status AudioTrack::applyVolumeShaper(
diff --git a/media/libaudioclient/IAudioTrack.cpp b/media/libaudioclient/IAudioTrack.cpp
index adff057..83a568a 100644
--- a/media/libaudioclient/IAudioTrack.cpp
+++ b/media/libaudioclient/IAudioTrack.cpp
@@ -39,6 +39,7 @@
     PAUSE,
     ATTACH_AUX_EFFECT,
     SET_PARAMETERS,
+    SELECT_PRESENTATION,
     GET_TIMESTAMP,
     SIGNAL,
     APPLY_VOLUME_SHAPER,
@@ -127,6 +128,19 @@
         return status;
     }
 
+    /* Selects the presentation (if available) */
+    virtual status_t selectPresentation(int presentationId, int programId) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        data.writeInt32(presentationId);
+        data.writeInt32(programId);
+        status_t status = remote()->transact(SELECT_PRESENTATION, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        }
+        return status;
+    }
+
     virtual status_t getTimestamp(AudioTimestamp& timestamp) {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
@@ -239,6 +253,11 @@
             reply->writeInt32(setParameters(keyValuePairs));
             return NO_ERROR;
         } break;
+        case SELECT_PRESENTATION: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            reply->writeInt32(selectPresentation(data.readInt32(), data.readInt32()));
+            return NO_ERROR;
+        } break;
         case GET_TIMESTAMP: {
             CHECK_INTERFACE(IAudioTrack, data, reply);
             AudioTimestamp timestamp;
diff --git a/media/libaudioclient/include/media/IAudioTrack.h b/media/libaudioclient/include/media/IAudioTrack.h
index 94afe3c..06e786d 100644
--- a/media/libaudioclient/include/media/IAudioTrack.h
+++ b/media/libaudioclient/include/media/IAudioTrack.h
@@ -70,6 +70,9 @@
     /* Send parameters to the audio hardware */
     virtual status_t    setParameters(const String8& keyValuePairs) = 0;
 
+    /* Selects the presentation (if available) */
+    virtual status_t    selectPresentation(int presentationId, int programId) = 0;
+
     /* Return NO_ERROR if timestamp is valid.  timestamp is undefined otherwise. */
     virtual status_t    getTimestamp(AudioTimestamp& timestamp) = 0;
 
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index bfa80e8..5ac2d9a 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -20,6 +20,7 @@
 #include <android/hardware/audio/2.0/IStreamOutCallback.h>
 #include <android/hardware/audio/4.0/IStreamOutCallback.h>
 #include <hwbinder/IPCThreadState.h>
+#include <media/AudioParameter.h>
 #include <mediautils/SchedulingPolicyService.h>
 #include <utils/Log.h>
 
@@ -347,6 +348,24 @@
     return processReturn("setVolume", mStream->setVolume(left, right));
 }
 
+#if MAJOR_VERSION == 2
+status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
+    if (mStream == 0) return NO_INIT;
+    std::vector<ParameterValue> parameters;
+    String8 halParameters;
+    parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
+    parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
+    parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
+    return setParameters(halParameters);
+}
+#elif MAJOR_VERSION == 4
+status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("selectPresentation",
+            mStream->selectPresentation(presentationId, programId));
+}
+#endif
+
 status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
     if (mStream == 0) return NO_INIT;
     *written = 0;
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index 95ec7f1..74101d7 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -131,6 +131,9 @@
     // Use this method in situations where audio mixing is done in the hardware.
     virtual status_t setVolume(float left, float right);
 
+    // Selects the audio presentation (if available).
+    virtual status_t selectPresentation(int presentationId, int programId);
+
     // Write audio buffer to driver.
     virtual status_t write(const void *buffer, size_t bytes, size_t *written);
 
diff --git a/media/libaudiohal/impl/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
index b134f57..0aba7c1 100644
--- a/media/libaudiohal/impl/StreamHalLocal.cpp
+++ b/media/libaudiohal/impl/StreamHalLocal.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <hardware/audio.h>
+#include <media/AudioParameter.h>
 #include <utils/Log.h>
 
 #include "DeviceHalLocal.h"
@@ -138,6 +139,13 @@
     return mStream->set_volume(mStream, left, right);
 }
 
+status_t StreamOutHalLocal::selectPresentation(int presentationId, int programId) {
+    AudioParameter param;
+    param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
+    param.addInt(String8(AudioParameter::keyProgramId), programId);
+    return setParameters(param.toString());
+}
+
 status_t StreamOutHalLocal::write(const void *buffer, size_t bytes, size_t *written) {
     ssize_t writeResult = mStream->write(mStream, buffer, bytes);
     if (writeResult > 0) {
diff --git a/media/libaudiohal/impl/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
index cea4229..4fd1960 100644
--- a/media/libaudiohal/impl/StreamHalLocal.h
+++ b/media/libaudiohal/impl/StreamHalLocal.h
@@ -103,6 +103,9 @@
     // Use this method in situations where audio mixing is done in the hardware.
     virtual status_t setVolume(float left, float right);
 
+    // Selects the audio presentation (if available).
+    virtual status_t selectPresentation(int presentationId, int programId);
+
     // Write audio buffer to driver.
     virtual status_t write(const void *buffer, size_t bytes, size_t *written);
 
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index c969e28..bd71dc0 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -109,6 +109,9 @@
     // Use this method in situations where audio mixing is done in the hardware.
     virtual status_t setVolume(float left, float right) = 0;
 
+    // Selects the audio presentation (if available).
+    virtual status_t selectPresentation(int presentationId, int programId) = 0;
+
     // Write audio buffer to driver.
     virtual status_t write(const void *buffer, size_t bytes, size_t *written) = 0;
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index b6b3815..1b20693 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -553,6 +553,7 @@
         virtual void        pause();
         virtual status_t    attachAuxEffect(int effectId);
         virtual status_t    setParameters(const String8& keyValuePairs);
+        virtual status_t    selectPresentation(int presentationId, int programId);
         virtual media::VolumeShaper::Status applyVolumeShaper(
                 const sp<media::VolumeShaper::Configuration>& configuration,
                 const sp<media::VolumeShaper::Operation>& operation) override;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 53ea9a4..971f6a5 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -67,6 +67,7 @@
             bool        isStatic() const { return  mSharedBuffer.get() != nullptr; }
 
             status_t    setParameters(const String8& keyValuePairs);
+            status_t    selectPresentation(int presentationId, int programId);
             status_t    attachAuxEffect(int EffectId);
             void        setAuxBuffer(int EffectId, int32_t *buffer);
             int32_t     *auxBuffer() const { return mAuxBuffer; }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index f833cf7..cec0819 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2413,6 +2413,14 @@
     return String8();
 }
 
+status_t AudioFlinger::DirectOutputThread::selectPresentation(int presentationId, int programId) {
+    Mutex::Autolock _l(mLock);
+    if (mOutput == nullptr || mOutput->stream == nullptr) {
+        return NO_INIT;
+    }
+    return mOutput->stream->selectPresentation(presentationId, programId);
+}
+
 void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
     sp<AudioIoDescriptor> desc = new AudioIoDescriptor();
     ALOGV("PlaybackThread::ioConfigChanged, thread %p, event %d", this, event);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 49fc234..7f3ea0f 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1199,6 +1199,8 @@
                        audio_io_handle_t id, audio_devices_t device, bool systemReady);
     virtual                 ~DirectOutputThread();
 
+                status_t    selectPresentation(int presentationId, int programId);
+
     // Thread virtuals
 
     virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f2617ae..91a3286 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -326,6 +326,10 @@
     return mTrack->setParameters(keyValuePairs);
 }
 
+status_t AudioFlinger::TrackHandle::selectPresentation(int presentationId, int programId) {
+    return mTrack->selectPresentation(presentationId, programId);
+}
+
 VolumeShaper::Status AudioFlinger::TrackHandle::applyVolumeShaper(
         const sp<VolumeShaper::Configuration>& configuration,
         const sp<VolumeShaper::Operation>& operation) {
@@ -976,6 +980,19 @@
     }
 }
 
+status_t AudioFlinger::PlaybackThread::Track::selectPresentation(int presentationId,
+        int programId) {
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        ALOGE("thread is dead");
+        return FAILED_TRANSACTION;
+    } else if ((thread->type() == ThreadBase::DIRECT) || (thread->type() == ThreadBase::OFFLOAD)) {
+        DirectOutputThread *directOutputThread = static_cast<DirectOutputThread*>(thread.get());
+        return directOutputThread->selectPresentation(presentationId, programId);
+    }
+    return INVALID_OPERATION;
+}
+
 VolumeShaper::Status AudioFlinger::PlaybackThread::Track::applyVolumeShaper(
         const sp<VolumeShaper::Configuration>& configuration,
         const sp<VolumeShaper::Operation>& operation)