Skip to content
This repository has been archived by the owner on Jul 15, 2024. It is now read-only.

Commit

Permalink
av: support per-app volume [1/3]
Browse files Browse the repository at this point in the history
Change-Id: Id7fb1b6385c75b05cd3413c776ff577b1d460f88
Signed-off-by: cjybyjk <[email protected]>
Signed-off-by: Pranav Vashi <[email protected]>
Signed-off-by: tejas101k <[email protected]>
  • Loading branch information
cjybyjk authored and joeyhuab committed May 8, 2024
1 parent 781ce7e commit cd34fbc
Show file tree
Hide file tree
Showing 16 changed files with 377 additions and 9 deletions.
1 change: 1 addition & 0 deletions Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ aidl_interface {
double_loadable: true,
local_include_dir: "aidl",
srcs: [
"aidl/android/media/AppVolumeData.aidl",
"aidl/android/media/InterpolatorConfig.aidl",
"aidl/android/media/InterpolatorType.aidl",
"aidl/android/media/MicrophoneInfoFw.aidl",
Expand Down
27 changes: 27 additions & 0 deletions aidl/android/media/AppVolumeData.aidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2022 Project Kaleidoscope
*
* 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}
*/
parcelable AppVolumeData {
@utf8InCpp String packageName;
int muted;
float volume;
int active;
}
85 changes: 85 additions & 0 deletions include/media/AppVolume.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2022 Project Kaleidoscope
*
* 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.
*/

#ifndef APP_VOLUME_H
#define APP_VOLUME_H

#include <android/media/AppVolumeData.h>
#include <utils/String8.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <media/AidlConversionUtil.h>

namespace android {
namespace media {
class AppVolume : public Parcelable {
public:
String8 packageName;
bool muted;
float volume;
bool active;

bool operator <(const AppVolume &obj) const {
if (active != obj.active) return active < obj.active;
return packageName < obj.packageName;
}

virtual status_t writeToParcel(Parcel* parcel) const {
AppVolumeData parcelable;
return writeToParcelable(&parcelable)
?: parcelable.writeToParcel(parcel);
}

virtual status_t writeToParcelable(AppVolumeData* parcelable) const {
parcelable->packageName = packageName.c_str();
parcelable->muted = muted;
parcelable->volume = volume;
parcelable->active = active;
return OK;
}

virtual status_t readFromParcel(const Parcel* parcel) {
AppVolumeData data;
return data.readFromParcel(parcel)
?: readFromParcelable(data);
}

virtual status_t readFromParcelable(const AppVolumeData& parcelable) {
packageName = parcelable.packageName.c_str();
muted = parcelable.muted;
volume = parcelable.volume;
active = parcelable.active;
return OK;
}
};

inline ConversionResult<AppVolume>
aidl2legacy_AppVolume(const AppVolumeData& aidl) {
AppVolume legacy;
RETURN_IF_ERROR(legacy.readFromParcelable(aidl));
return legacy;
}

inline ConversionResult<AppVolumeData>
legacy2aidl_AppVolume(const AppVolume& legacy) {
AppVolumeData aidl;
RETURN_IF_ERROR(legacy.writeToParcelable(&aidl));
return aidl;
}
} // namespace media
}; // namespace android

#endif // APP_VOLUME_H
21 changes: 21 additions & 0 deletions media/libaudioclient/AudioSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2617,6 +2617,27 @@ status_t AudioSystem::registerSoundTriggerCaptureStateListener(
return NO_ERROR;
}

status_t AudioSystem::setAppVolume(const String8& packageName, const float volume)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setAppVolume(packageName, volume);
}

status_t AudioSystem::setAppMute(const String8& packageName, const bool mute)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setAppMute(packageName, mute);
}

status_t AudioSystem::listAppVolumes(std::vector<media::AppVolume> *vols)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->listAppVolumes(vols);
}

status_t AudioSystem::setVibratorInfos(
const std::vector<media::AudioVibratorInfo>& vibratorInfos) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
Expand Down
42 changes: 42 additions & 0 deletions media/libaudioclient/IAudioFlinger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,28 @@ status_t AudioFlingerClientAdapter::getMasterBalance(float* balance) const{
return statusTFromBinderStatus(mDelegate->getMasterBalance(balance));
}

status_t AudioFlingerClientAdapter::setAppVolume(const String8& packageName, const float value) {
std::string packageNameAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_String8_string(packageName));
return mDelegate->setAppVolume(packageNameAidl, value).transactionError();
}

status_t AudioFlingerClientAdapter::setAppMute(const String8& packageName, const bool value) {
std::string packageNameAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_String8_string(packageName));
return mDelegate->setAppMute(packageNameAidl, value).transactionError();
}

status_t AudioFlingerClientAdapter::listAppVolumes(std::vector<media::AppVolume>* vols) {
std::vector<media::AppVolumeData> aidlRet;
RETURN_STATUS_IF_ERROR(mDelegate->listAppVolumes(&aidlRet).transactionError());
if (vols != nullptr) {
*vols = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<media::AppVolume>>(aidlRet, media::aidl2legacy_AppVolume));
}
return OK;
}

status_t AudioFlingerClientAdapter::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output) {
AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
Expand Down Expand Up @@ -1014,6 +1036,26 @@ Status AudioFlingerServerAdapter::getMasterBalance(float* _aidl_return) {
return Status::fromStatusT(mDelegate->getMasterBalance(_aidl_return));
}

Status AudioFlingerServerAdapter::setAppVolume(const std::string& packageName, const float value) {
String8 packageNameLegacy = VALUE_OR_RETURN_BINDER(
aidl2legacy_string_view_String8(packageName));
return Status::fromStatusT(mDelegate->setAppVolume(packageNameLegacy, value));
}

Status AudioFlingerServerAdapter::setAppMute(const std::string& packageName, const bool value) {
String8 packageNameLegacy = VALUE_OR_RETURN_BINDER(
aidl2legacy_string_view_String8(packageName));
return Status::fromStatusT(mDelegate->setAppMute(packageNameLegacy, value));
}

Status AudioFlingerServerAdapter::listAppVolumes(std::vector<media::AppVolumeData>* _aidl_return) {
std::vector<media::AppVolume> resultLegacy;
RETURN_BINDER_IF_ERROR(mDelegate->listAppVolumes(&resultLegacy));
*_aidl_return = VALUE_OR_RETURN_BINDER(convertContainer<std::vector<media::AppVolumeData>>(
resultLegacy, media::legacy2aidl_AppVolume));
return Status::ok();
}

Status AudioFlingerServerAdapter::setStreamVolume(AudioStreamType stream, float value,
int32_t output) {
audio_stream_type_t streamLegacy = VALUE_OR_RETURN_BINDER(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package android.media;

import android.media.AppVolumeData;
import android.media.AudioPatchFw;
import android.media.AudioPolicyConfig;
import android.media.AudioPortFw;
Expand Down Expand Up @@ -92,6 +93,10 @@ interface IAudioFlingerService {
void setMasterBalance(float balance);
float getMasterBalance();

void setAppVolume(@utf8InCpp String packageName, float value);
void setAppMute(@utf8InCpp String packageName, boolean muted);
AppVolumeData[] listAppVolumes();

/*
* Set/gets stream type state. This will probably be used by
* the preference panel, mostly.
Expand Down
5 changes: 5 additions & 0 deletions media/libaudioclient/include/media/AudioSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <android/media/audio/common/AudioMMapPolicyType.h>
#include <android/media/audio/common/AudioPort.h>
#include <media/AidlConversionUtil.h>
#include <media/AppVolume.h>
#include <media/AudioContainers.h>
#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioPolicy.h>
Expand Down Expand Up @@ -774,6 +775,10 @@ class AudioSystem

static int32_t getAAudioHardwareBurstMinUsec();

static status_t setAppVolume(const String8& packageName, const float value);
static status_t setAppMute(const String8& packageName, const bool value);
static status_t listAppVolumes(std::vector<media::AppVolume> *vols);

private:

class AudioFlingerClient: public IBinder::DeathRecipient, public media::BnAudioFlingerClient
Expand Down
16 changes: 16 additions & 0 deletions media/libaudioclient/include/media/IAudioFlinger.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <utils/Errors.h>
#include <binder/IInterface.h>
#include <media/AidlConversion.h>
#include <media/AppVolume.h>
#include <media/AudioClient.h>
#include <media/AudioCommonTypes.h>
#include <media/DeviceDescriptorBase.h>
Expand Down Expand Up @@ -388,6 +389,10 @@ class IAudioFlinger : public virtual RefBase {

virtual status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
struct audio_port_v7 *mixPort) const = 0;

virtual status_t setAppVolume(const String8& packageName, const float value) = 0;
virtual status_t setAppMute(const String8& packageName, const bool value) = 0;
virtual status_t listAppVolumes(std::vector<media::AppVolume> *vols) = 0;
};

/**
Expand Down Expand Up @@ -505,6 +510,10 @@ class AudioFlingerClientAdapter : public IAudioFlinger {
status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
struct audio_port_v7 *mixPort) const override;

status_t setAppVolume(const String8& packageName, const float value) override;
status_t setAppMute(const String8& packageName, const bool value) override;
status_t listAppVolumes(std::vector<media::AppVolume> *vols) override;

private:
const sp<media::IAudioFlingerService> mDelegate;
};
Expand Down Expand Up @@ -606,6 +615,9 @@ class AudioFlingerServerAdapter : public media::BnAudioFlingerService {
GET_AUDIO_POLICY_CONFIG =
media::BnAudioFlingerService::TRANSACTION_getAudioPolicyConfig,
GET_AUDIO_MIX_PORT = media::BnAudioFlingerService::TRANSACTION_getAudioMixPort,
SET_APP_VOLUME = media::BnAudioFlingerService::TRANSACTION_setAppVolume,
SET_APP_MUTE = media::BnAudioFlingerService::TRANSACTION_setAppMute,
LIST_APP_VOLUMES = media::BnAudioFlingerService::TRANSACTION_listAppVolumes,
};

protected:
Expand Down Expand Up @@ -742,6 +754,10 @@ class AudioFlingerServerAdapter : public media::BnAudioFlingerService {
Status getAudioMixPort(const media::AudioPortFw& devicePort,
const media::AudioPortFw& mixPort,
media::AudioPortFw* _aidl_return) override;

Status setAppVolume(const std::string& packageName, const float value) override;
Status setAppMute(const std::string& packageName, const bool value) override;
Status listAppVolumes(std::vector<media::AppVolumeData> *vols) override;
private:
const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
};
Expand Down
65 changes: 64 additions & 1 deletion services/audioflinger/AudioFlinger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,15 @@ status_t AudioFlinger::createTrack(const media::CreateTrackRequest& _input,
output.portId = portId;

if (lStatus == NO_ERROR) {
// set volume
String8 trackCreatorPackage = track->getPackageName();
if (!trackCreatorPackage.empty() &&
mAppVolumeConfigs.find(trackCreatorPackage) != mAppVolumeConfigs.end()) {
media::AppVolume config = mAppVolumeConfigs[trackCreatorPackage];
track->setAppMute(config.muted);
track->setAppVolume(config.volume);
}

// no risk of deadlock because AudioFlinger::mutex() is held
audio_utils::lock_guard _dl(thread->mutex());
// Connect secondary outputs. Failure on a secondary output must not imped the primary
Expand Down Expand Up @@ -2003,6 +2012,58 @@ uint32_t AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
return 0;
}


status_t AudioFlinger::listAppVolumes(std::vector<media::AppVolume> *vols)
{
std::set<media::AppVolume> volSet;
audio_utils::lock_guard _l(mutex());
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
mPlaybackThreads.valueAt(i)->listAppVolumes(volSet);
}

vols->insert(vols->begin(), volSet.begin(), volSet.end());

return NO_ERROR;
}

status_t AudioFlinger::setAppVolume(const String8& packageName, const float value)
{
audio_utils::lock_guard _l(mutex());
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
mPlaybackThreads.valueAt(i)->setAppVolume(packageName, value);
}

if (mAppVolumeConfigs.find(packageName) == mAppVolumeConfigs.end()) {
media::AppVolume vol;
vol.packageName = packageName;
vol.volume = value;
vol.muted = false;
mAppVolumeConfigs[packageName] = vol;
} else {
mAppVolumeConfigs[packageName].volume = value;
}
return NO_ERROR;
}

status_t AudioFlinger::setAppMute(const String8& packageName, const bool value)
{
audio_utils::lock_guard _l(mutex());
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
mPlaybackThreads.valueAt(i)->setAppMute(packageName, value);
}

if (mAppVolumeConfigs.find(packageName) == mAppVolumeConfigs.end()) {
media::AppVolume vol;
vol.packageName = packageName;
vol.volume = 1.0f;
vol.muted = value;
mAppVolumeConfigs[packageName] = vol;
} else {
mAppVolumeConfigs[packageName].muted = value;
}
return NO_ERROR;
}

status_t AudioFlinger::setVoiceVolume(float value)
{
status_t ret = initCheck();
Expand Down Expand Up @@ -4835,7 +4896,9 @@ status_t AudioFlinger::onTransactWrapper(TransactionCode code,
case TransactionCode::UPDATE_SECONDARY_OUTPUTS:
case TransactionCode::SET_BLUETOOTH_VARIABLE_LATENCY_ENABLED:
case TransactionCode::IS_BLUETOOTH_VARIABLE_LATENCY_ENABLED:
case TransactionCode::SUPPORTS_BLUETOOTH_VARIABLE_LATENCY: {
case TransactionCode::SUPPORTS_BLUETOOTH_VARIABLE_LATENCY:
case TransactionCode::SET_APP_VOLUME:
case TransactionCode::SET_APP_MUTE: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
Expand Down
8 changes: 8 additions & 0 deletions services/audioflinger/AudioFlinger.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,14 @@ class AudioFlinger

sp<EffectsFactoryHalInterface> getEffectsFactory();

public:
status_t setAppVolume(const String8& packageName, const float value);
status_t setAppMute(const String8& packageName, const bool value);
status_t listAppVolumes(std::vector<media::AppVolume> *vols);

private:
std::map<String8, media::AppVolume> mAppVolumeConfigs;

public:
// TODO(b/292281786): Remove this when Oboeservice can get access to
// openMmapStream through an IAudioFlinger handle directly.
Expand Down
Loading

0 comments on commit cd34fbc

Please sign in to comment.