audiopolicy: add Volume for attribute and callback native APIs

Change-Id: I259de42452d2802aa8dbd553f56040dea6995a93
Signed-off-by: François Gaffie <francois.gaffie@renault.com>

Bug: 124767636
Test: make
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 9b00a4d..d61188f 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -159,6 +159,19 @@
                                           int *index,
                                           audio_devices_t device) = 0;
 
+    virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int index,
+                                                 audio_devices_t device) = 0;
+    virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int &index,
+                                                 audio_devices_t device) = 0;
+
+    virtual status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                    int &index) = 0;
+
+    virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                    int &index) = 0;
+
     // return the strategy corresponding to a given stream type
     virtual uint32_t getStrategyForStream(audio_stream_type_t stream) = 0;
 
@@ -347,6 +360,8 @@
 
     virtual void onAudioPatchListUpdate() = 0;
 
+    virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags) = 0;
+
     virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use) = 0;
 
     virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 4540c4d..92aa189 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2498,6 +2498,107 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                         int index,
+                                                         audio_devices_t device)
+{
+    // Get Volume group matching the Audio Attributes
+    auto volumeGroup = mEngine->getVolumeGroupForAttributes(attr);
+    if (volumeGroup == VOLUME_GROUP_NONE) {
+        ALOGD("%s: could not find group matching with %s", __FUNCTION__, toString(attr).c_str());
+        return BAD_VALUE;
+    }
+    ALOGD("%s: FOUND group %d matching with %s", __FUNCTION__, volumeGroup, toString(attr).c_str());
+    return setVolumeGroupIndex(getVolumeCurves(attr), volumeGroup, index, device, attr);
+}
+
+status_t AudioPolicyManager::setVolumeGroupIndex(IVolumeCurves &curves, volume_group_t group,
+                                                 int index,
+                                                 audio_devices_t device,
+                                                 const audio_attributes_t /*attributes*/)
+{
+    ALOGVV("%s: group=%d", __func__, group);
+    status_t status = NO_ERROR;
+    setVolumeCurveIndex(group, index, device, curves);
+    // update volume on all outputs and streams matching the following:
+    // - The requested stream (or a stream matching for volume control) is active on the output
+    // - The device (or devices) selected by the engine for this stream includes
+    // the requested device
+    // - For non default requested device, currently selected device on the output is either the
+    // requested device or one of the devices selected by the engine for this stream
+    // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
+    // no specific device volume value exists for currently selected device.
+    // @TODO
+    mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
+    return status;
+}
+
+status_t AudioPolicyManager::setVolumeCurveIndex(volume_group_t volumeGroup,
+                                                 int index,
+                                                 audio_devices_t device,
+                                                 IVolumeCurves &volumeCurves)
+{
+    // VOICE_CALL stream has minVolumeIndex > 0  but can be muted directly by an
+    // app that has MODIFY_PHONE_STATE permission.
+    // If voice is member of the volume group, it will contaminate all the member of this group
+    auto streams = mEngine->getStreamTypesForVolumeGroup(volumeGroup);
+    if (((index < volumeCurves.getVolumeIndexMin()) && !(hasVoiceStream(streams) && index == 0)) ||
+            (index > volumeCurves.getVolumeIndexMax())) {
+        ALOGD("%s: wrong index %d min=%d max=%d", __FUNCTION__, index,
+              volumeCurves.getVolumeIndexMin(), volumeCurves.getVolumeIndexMax());
+        return BAD_VALUE;
+    }
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+
+    // Force max volume if stream cannot be muted
+    if (!volumeCurves.canBeMuted()) index = volumeCurves.getVolumeIndexMax();
+
+    ALOGD("%s device %08x, index %d", __FUNCTION__ , device, index);
+    volumeCurves.addCurrentVolumeIndex(device, index);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                         int &index,
+                                                         audio_devices_t device)
+{
+    // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
+    // stream by the engine.
+    if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
+        device = mEngine->getOutputDevicesForAttributes(attr, nullptr, true /*fromCache*/).types();
+    }
+    return getVolumeIndex(getVolumeCurves(attr), index, device);
+}
+
+status_t AudioPolicyManager::getVolumeIndex(const IVolumeCurves &curves,
+                                            int &index,
+                                            audio_devices_t device) const
+{
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+    device = Volume::getDeviceForVolume(device);
+    index = curves.getVolumeIndex(device);
+    ALOGV("%s: device %08x index %d", __FUNCTION__, device, index);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMinVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                            int &index)
+{
+    index = getVolumeCurves(attr).getVolumeIndexMin();
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMaxVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                            int &index)
+{
+    index = getVolumeCurves(attr).getVolumeIndexMax();
+    return NO_ERROR;
+}
+
 audio_io_handle_t AudioPolicyManager::selectOutputForMusicEffects()
 {
     // select one output among several suitable for global effects.
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 9fe8d1d..641a03a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -161,6 +161,27 @@
                                               int *index,
                                               audio_devices_t device);
 
+        virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                     int index,
+                                                     audio_devices_t device);
+        virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                     int &index,
+                                                     audio_devices_t device);
+        virtual status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
+
+        virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
+
+        status_t setVolumeGroupIndex(IVolumeCurves &volumeCurves, volume_group_t group, int index,
+                                     audio_devices_t device, const audio_attributes_t attributes);
+
+        status_t setVolumeCurveIndex(volume_group_t volumeGroup,
+                                     int index,
+                                     audio_devices_t device,
+                                     IVolumeCurves &volumeCurves);
+
+        status_t getVolumeIndex(const IVolumeCurves &curves, int &index,
+                                audio_devices_t device) const;
+
         // return the strategy corresponding to a given stream type
         virtual uint32_t getStrategyForStream(audio_stream_type_t stream)
         {
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index d826192..5748334 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -222,6 +222,12 @@
             clientConfig, clientEffects, deviceConfig, effects, patchHandle, source);
 }
 
+void AudioPolicyService::AudioPolicyClient::onAudioVolumeGroupChanged(volume_group_t group,
+                                                                      int flags)
+{
+    mAudioPolicyService->onAudioVolumeGroupChanged(group, flags);
+}
+
 audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId(audio_unique_id_use_t use)
 {
     return AudioSystem::newAudioUniqueId(use);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index c19016f..a1b6b0f 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -689,6 +689,53 @@
                                                     device);
 }
 
+status_t AudioPolicyService::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
+                                                         int index, audio_devices_t device)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->setVolumeIndexForAttributes(attributes, index, device);
+}
+
+status_t AudioPolicyService::getVolumeIndexForAttributes(const audio_attributes_t &attributes,
+                                                         int &index, audio_devices_t device)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->getVolumeIndexForAttributes(attributes, index, device);
+}
+
+status_t AudioPolicyService::getMinVolumeIndexForAttributes(const audio_attributes_t &attributes,
+                                                            int &index)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->getMinVolumeIndexForAttributes(attributes, index);
+}
+
+status_t AudioPolicyService::getMaxVolumeIndexForAttributes(const audio_attributes_t &attributes,
+                                                            int &index)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->getMaxVolumeIndexForAttributes(attributes, index);
+}
+
 uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
 {
     if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 76ac191..cf9cf71 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -150,6 +150,20 @@
     mNotificationClients.valueFor(token)->setAudioPortCallbacksEnabled(enabled);
 }
 
+void AudioPolicyService::setAudioVolumeGroupCallbacksEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    int64_t token = ((int64_t)uid<<32) | pid;
+
+    if (mNotificationClients.indexOfKey(token) < 0) {
+        return;
+    }
+    mNotificationClients.valueFor(token)->setAudioVolumeGroupCallbacksEnabled(enabled);
+}
+
 // removeNotificationClient() is called when the client process dies.
 void AudioPolicyService::removeNotificationClient(uid_t uid, pid_t pid)
 {
@@ -200,6 +214,19 @@
     }
 }
 
+void AudioPolicyService::onAudioVolumeGroupChanged(volume_group_t group, int flags)
+{
+    mOutputCommandThread->changeAudioVolumeGroupCommand(group, flags);
+}
+
+void AudioPolicyService::doOnAudioVolumeGroupChanged(volume_group_t group, int flags)
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+    for (size_t i = 0; i < mNotificationClients.size(); i++) {
+        mNotificationClients.valueAt(i)->onAudioVolumeGroupChanged(group, flags);
+    }
+}
+
 void AudioPolicyService::onDynamicPolicyMixStateUpdate(const String8& regId, int32_t state)
 {
     ALOGV("AudioPolicyService::onDynamicPolicyMixStateUpdate(%s, %d)",
@@ -270,7 +297,7 @@
                                                      uid_t uid,
                                                      pid_t pid)
     : mService(service), mUid(uid), mPid(pid), mAudioPolicyServiceClient(client),
-      mAudioPortCallbacksEnabled(false)
+      mAudioPortCallbacksEnabled(false), mAudioVolumeGroupCallbacksEnabled(false)
 {
 }
 
@@ -301,6 +328,15 @@
     }
 }
 
+void AudioPolicyService::NotificationClient::onAudioVolumeGroupChanged(volume_group_t group, 
+                                                                      int flags)
+{
+    if (mAudioPolicyServiceClient != 0 && mAudioVolumeGroupCallbacksEnabled) {
+        mAudioPolicyServiceClient->onAudioVolumeGroupChanged(group, flags);
+    }
+}
+
+
 void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
         const String8& regId, int32_t state)
 {
@@ -330,6 +366,10 @@
     mAudioPortCallbacksEnabled = enabled;
 }
 
+void AudioPolicyService::NotificationClient::setAudioVolumeGroupCallbacksEnabled(bool enabled)
+{
+    mAudioVolumeGroupCallbacksEnabled = enabled;
+}
 
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
@@ -1058,6 +1098,18 @@
                     svc->doOnAudioPatchListUpdate();
                     mLock.lock();
                     }break;
+                case CHANGED_AUDIOVOLUMEGROUP: {
+                    AudioVolumeGroupData *data =
+                            static_cast<AudioVolumeGroupData *>(command->mParam.get());
+                    ALOGV("AudioCommandThread() processing update audio volume group");
+                    svc = mService.promote();
+                    if (svc == 0) {
+                        break;
+                    }
+                    mLock.unlock();
+                    svc->doOnAudioVolumeGroupChanged(data->mGroup, data->mFlags);
+                    mLock.lock();
+                    }break;
                 case SET_AUDIOPORT_CONFIG: {
                     SetAudioPortConfigData *data = (SetAudioPortConfigData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing set port config");
@@ -1302,6 +1354,19 @@
     sendCommand(command);
 }
 
+void AudioPolicyService::AudioCommandThread::changeAudioVolumeGroupCommand(volume_group_t group,
+                                                                           int flags)
+{
+    sp<AudioCommand>command = new AudioCommand();
+    command->mCommand = CHANGED_AUDIOVOLUMEGROUP;
+    AudioVolumeGroupData *data= new AudioVolumeGroupData();
+    data->mGroup = group;
+    data->mFlags = flags;
+    command->mParam = data;
+    ALOGV("AudioCommandThread() adding audio volume group changed");
+    sendCommand(command);
+}
+
 status_t AudioPolicyService::AudioCommandThread::setAudioPortConfigCommand(
                                             const struct audio_port_config *config, int delayMs)
 {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index e19b4e5..5888841 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -111,6 +111,17 @@
                                           int *index,
                                           audio_devices_t device);
 
+    virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int index,
+                                                 audio_devices_t device);
+    virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                 int &index,
+                                                 audio_devices_t device);
+    virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                    int &index);
+    virtual status_t getMaxVolumeIndexForAttributes(const audio_attributes_t &attr,
+                                                    int &index);
+
     virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
     virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
 
@@ -192,6 +203,8 @@
 
     virtual void setAudioPortCallbacksEnabled(bool enabled);
 
+    virtual void setAudioVolumeGroupCallbacksEnabled(bool enabled);
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                            audio_io_handle_t *ioHandle,
                                            audio_devices_t *device);
@@ -275,6 +288,9 @@
                                                   audio_patch_handle_t patchHandle,
                                                   audio_source_t source);
 
+            void onAudioVolumeGroupChanged(volume_group_t group, int flags);
+            void doOnAudioVolumeGroupChanged(volume_group_t group, int flags);
+
 private:
                         AudioPolicyService() ANDROID_API;
     virtual             ~AudioPolicyService();
@@ -404,6 +420,7 @@
             RELEASE_AUDIO_PATCH,
             UPDATE_AUDIOPORT_LIST,
             UPDATE_AUDIOPATCH_LIST,
+            CHANGED_AUDIOVOLUMEGROUP,
             SET_AUDIOPORT_CONFIG,
             DYN_POLICY_MIX_STATE_UPDATE,
             RECORDING_CONFIGURATION_UPDATE
@@ -435,6 +452,7 @@
                                                          int delayMs);
                     void        updateAudioPortListCommand();
                     void        updateAudioPatchListCommand();
+                    void        changeAudioVolumeGroupCommand(volume_group_t group, int flags);
                     status_t    setAudioPortConfigCommand(const struct audio_port_config *config,
                                                           int delayMs);
                     void        dynamicPolicyMixStateUpdateCommand(const String8& regId,
@@ -516,6 +534,12 @@
             audio_patch_handle_t mHandle;
         };
 
+        class AudioVolumeGroupData : public AudioCommandData {
+        public:
+            volume_group_t mGroup;
+            int mFlags;
+        };
+
         class SetAudioPortConfigData : public AudioCommandData {
         public:
             struct audio_port_config mConfig;
@@ -648,6 +672,8 @@
                                                     audio_patch_handle_t patchHandle,
                                                     audio_source_t source);
 
+        virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags);
+
         virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use);
 
      private:
@@ -666,6 +692,7 @@
                             void      onAudioPatchListUpdate();
                             void      onDynamicPolicyMixStateUpdate(const String8& regId,
                                                                     int32_t state);
+                            void      onAudioVolumeGroupChanged(volume_group_t group, int flags);
                             void      onRecordingConfigurationUpdate(
                                                     int event,
                                                     const record_client_info_t *clientInfo,
@@ -676,6 +703,7 @@
                                                     audio_patch_handle_t patchHandle,
                                                     audio_source_t source);
                             void      setAudioPortCallbacksEnabled(bool enabled);
+                            void setAudioVolumeGroupCallbacksEnabled(bool enabled);
 
                             uid_t uid() {
                                 return mUid;
@@ -693,6 +721,7 @@
         const pid_t                         mPid;
         const sp<IAudioPolicyServiceClient> mAudioPolicyServiceClient;
               bool                          mAudioPortCallbacksEnabled;
+              bool                          mAudioVolumeGroupCallbacksEnabled;
     };
 
     class AudioClient : public virtual RefBase {
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 6ae354b..8854eb2 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -73,6 +73,7 @@
                                 int /*delayMs*/) override { return NO_INIT; }
     void onAudioPortListUpdate() override { }
     void onAudioPatchListUpdate() override { }
+    void onAudioVolumeGroupChanged(volume_group_t /*group*/, int /*flags*/) override { }
     audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t /*use*/) override { return 0; }
     void onDynamicPolicyMixStateUpdate(String8 /*regId*/, int32_t /*state*/) override { }
     void onRecordingConfigurationUpdate(int event __unused,