From cd34fbc76cc4a51fa1ea3c435dcbaaacaa1a85bf Mon Sep 17 00:00:00 2001 From: cjybyjk Date: Mon, 5 Sep 2022 05:03:38 +0000 Subject: [PATCH] av: support per-app volume [1/3] Change-Id: Id7fb1b6385c75b05cd3413c776ff577b1d460f88 Signed-off-by: cjybyjk Signed-off-by: Pranav Vashi Signed-off-by: tejas101k --- Android.bp | 1 + aidl/android/media/AppVolumeData.aidl | 27 ++++++ include/media/AppVolume.h | 85 +++++++++++++++++++ media/libaudioclient/AudioSystem.cpp | 21 +++++ media/libaudioclient/IAudioFlinger.cpp | 42 +++++++++ .../android/media/IAudioFlingerService.aidl | 5 ++ .../include/media/AudioSystem.h | 5 ++ .../include/media/IAudioFlinger.h | 16 ++++ services/audioflinger/AudioFlinger.cpp | 65 +++++++++++++- services/audioflinger/AudioFlinger.h | 8 ++ services/audioflinger/IAfThread.h | 5 ++ services/audioflinger/IAfTrack.h | 9 +- services/audioflinger/PlaybackTracks.h | 13 ++- services/audioflinger/Threads.cpp | 56 ++++++++++-- services/audioflinger/Threads.h | 4 + services/audioflinger/Tracks.cpp | 24 ++++++ 16 files changed, 377 insertions(+), 9 deletions(-) create mode 100644 aidl/android/media/AppVolumeData.aidl create mode 100644 include/media/AppVolume.h diff --git a/Android.bp b/Android.bp index 7a2bb9b73ac..617261789e1 100644 --- a/Android.bp +++ b/Android.bp @@ -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", diff --git a/aidl/android/media/AppVolumeData.aidl b/aidl/android/media/AppVolumeData.aidl new file mode 100644 index 00000000000..e0e38e84267 --- /dev/null +++ b/aidl/android/media/AppVolumeData.aidl @@ -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; +} diff --git a/include/media/AppVolume.h b/include/media/AppVolume.h new file mode 100644 index 00000000000..5c12c11ae79 --- /dev/null +++ b/include/media/AppVolume.h @@ -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 +#include +#include +#include +#include + +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 + aidl2legacy_AppVolume(const AppVolumeData& aidl) { + AppVolume legacy; + RETURN_IF_ERROR(legacy.readFromParcelable(aidl)); + return legacy; + } + + inline ConversionResult + legacy2aidl_AppVolume(const AppVolume& legacy) { + AppVolumeData aidl; + RETURN_IF_ERROR(legacy.writeToParcelable(&aidl)); + return aidl; + } +} // namespace media +}; // namespace android + +#endif // APP_VOLUME_H diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 5bfdd5f94d3..5a920f57c9b 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -2617,6 +2617,27 @@ status_t AudioSystem::registerSoundTriggerCaptureStateListener( return NO_ERROR; } +status_t AudioSystem::setAppVolume(const String8& packageName, const float volume) +{ + const sp& 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& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setAppMute(packageName, mute); +} + +status_t AudioSystem::listAppVolumes(std::vector *vols) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->listAppVolumes(vols); +} + status_t AudioSystem::setVibratorInfos( const std::vector& vibratorInfos) { const sp& af = AudioSystem::get_audio_flinger(); diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp index 48f8992b6db..83fbfb87ae1 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -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* vols) { + std::vector aidlRet; + RETURN_STATUS_IF_ERROR(mDelegate->listAppVolumes(&aidlRet).transactionError()); + if (vols != nullptr) { + *vols = VALUE_OR_RETURN_STATUS( + convertContainer>(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( @@ -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* _aidl_return) { + std::vector resultLegacy; + RETURN_BINDER_IF_ERROR(mDelegate->listAppVolumes(&resultLegacy)); + *_aidl_return = VALUE_OR_RETURN_BINDER(convertContainer>( + 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( diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl index 31d3af5f16a..da425fa6623 100644 --- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl +++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl @@ -16,6 +16,7 @@ package android.media; +import android.media.AppVolumeData; import android.media.AudioPatchFw; import android.media.AudioPolicyConfig; import android.media.AudioPortFw; @@ -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. diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h index a1f7941770c..2993dc1cfce 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -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 *vols); + private: class AudioFlingerClient: public IBinder::DeathRecipient, public media::BnAudioFlingerClient diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h index 5a1e037f0e3..155c76f4e8e 100644 --- a/media/libaudioclient/include/media/IAudioFlinger.h +++ b/media/libaudioclient/include/media/IAudioFlinger.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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 *vols) = 0; }; /** @@ -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 *vols) override; + private: const sp mDelegate; }; @@ -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: @@ -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 *vols) override; private: const sp mDelegate; }; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index e6f9c6d6645..8250274bd94 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -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 @@ -2003,6 +2012,58 @@ uint32_t AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const return 0; } + +status_t AudioFlinger::listAppVolumes(std::vector *vols) +{ + std::set 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(); @@ -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(), diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 0f75d6e44b8..b586d6f4e58 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -405,6 +405,14 @@ class AudioFlinger sp 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 *vols); + +private: + std::map mAppVolumeConfigs; + public: // TODO(b/292281786): Remove this when Oboeservice can get access to // openMmapStream through an IAudioFlinger handle directly. diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h index 7084be9364c..3a137a9e20d 100644 --- a/services/audioflinger/IAfThread.h +++ b/services/audioflinger/IAfThread.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -464,6 +465,10 @@ class IAfPlaybackThread : public virtual IAfThreadBase, public virtual VolumeInt virtual bool isTrackActive(const sp& track) const REQUIRES(mutex()) = 0; virtual void addOutputTrack_l(const sp& track) REQUIRES(mutex()) = 0; + virtual status_t setAppVolume(const String8& packageName, const float value) = 0; + virtual status_t setAppMute(const String8& packageName, const bool muted) = 0; + virtual void listAppVolumes(std::set &container) = 0; + virtual AudioStreamOut* getOutput_l() const REQUIRES(mutex()) = 0; virtual AudioStreamOut* getOutput() const EXCLUDES_ThreadBase_Mutex = 0; virtual AudioStreamOut* clearOutput() EXCLUDES_ThreadBase_Mutex = 0; diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h index 2302e137d69..666efccb0d9 100644 --- a/services/audioflinger/IAfTrack.h +++ b/services/audioflinger/IAfTrack.h @@ -323,11 +323,18 @@ class IAfTrack : public virtual IAfTrackBase { virtual sp getVolumeShaperState(int id) const = 0; virtual sp getVolumeHandler() const = 0; /** Set the computed normalized final volume of the track. - * !masterMute * masterVolume * streamVolume * averageLRVolume */ + * !masterMute * !appMuted * masterVolume * streamVolume * averageLRVolume * appVolume */ virtual void setFinalVolume(float volumeLeft, float volumeRight) = 0; virtual float getFinalVolume() const = 0; virtual void getFinalVolume(float* left, float* right) const = 0; + virtual void setAppVolume(float volume) = 0; + virtual float getAppVolume() const = 0; + virtual void setAppMute(bool val) = 0; + virtual bool isAppMuted() = 0; + + virtual String8 getPackageName() const = 0; + using SourceMetadatas = std::vector; using MetadataInserter = std::back_insert_iterator; /** Copy the track metadata in the provided iterator. Thread safe. */ diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index 4a1948ce591..05588dcbdb5 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -152,7 +152,7 @@ class Track : public TrackBase, public virtual IAfTrack, public VolumeProvider { sp getVolumeShaperState(int id) const final; sp getVolumeHandler() const final{ return mVolumeHandler; } /** Set the computed normalized final volume of the track. - * !masterMute * masterVolume * streamVolume * averageLRVolume */ + * !masterMute * !appMuted * masterVolume * streamVolume * averageLRVolume * appVolume */ void setFinalVolume(float volumeLeft, float volumeRight) final; float getFinalVolume() const final { return mFinalVolume; } void getFinalVolume(float* left, float* right) const final { @@ -160,6 +160,13 @@ class Track : public TrackBase, public virtual IAfTrack, public VolumeProvider { *right = mFinalVolumeRight; } + void setAppVolume(float volume); + float getAppVolume() const { return mAppVolume; } + void setAppMute(bool val); + bool isAppMuted() { return mAppMuted; } + + String8 getPackageName() const { return mPackageName; } + using SourceMetadatas = std::vector; using MetadataInserter = std::back_insert_iterator; /** Copy the track metadata in the provided iterator. Thread safe. */ @@ -355,6 +362,8 @@ class Track : public TrackBase, public virtual IAfTrack, public VolumeProvider { for (auto& tp : mTeePatches) { f(tp.patchTrack); } }; + String8 mPackageName; + size_t mPresentationCompleteFrames = 0; // (Used for Mixed tracks) // The number of frames written to the // audio HAL when this track is considered fully rendered. @@ -380,6 +389,8 @@ class Track : public TrackBase, public virtual IAfTrack, public VolumeProvider { // volume float mFinalVolumeRight; // combine master volume, stream type volume and track // volume + float mAppVolume; // volume control for separate processes + bool mAppMuted; sp mAudioTrackServerProxy; bool mResumeToStopping; // track was paused in stopping state. bool mFlushHwPending; // track requests for thread flush diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index e603d338c80..d07e4571307 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -2770,6 +2771,43 @@ ssize_t PlaybackThread::Tracks::remove(const sp& track) return index; } +void PlaybackThread::listAppVolumes(std::set &container) +{ + audio_utils::lock_guard _l(mutex()); + for (sp track : mTracks) { + if (!track->getPackageName().empty()) { + media::AppVolume av; + av.packageName = track->getPackageName(); + av.muted = track->isAppMuted(); + av.volume = track->getAppVolume(); + av.active = mActiveTracks.indexOf(track) >= 0; + container.insert(av); + } + } +} + +status_t PlaybackThread::setAppVolume(const String8& packageName, const float value) +{ + audio_utils::lock_guard _l(mutex()); + for (sp track : mTracks) { + if (packageName == track->getPackageName()) { + track->setAppVolume(value); + } + } + return NO_ERROR; +} + +status_t PlaybackThread::setAppMute(const String8& packageName, const bool value) +{ + audio_utils::lock_guard _l(mutex()); + for (sp track : mTracks) { + if (packageName == track->getPackageName()) { + track->setAppMute(value); + } + } + return NO_ERROR; +} + uint32_t PlaybackThread::correctLatency_l(uint32_t latency) const { return latency; @@ -5657,10 +5695,12 @@ PlaybackThread::mixer_state MixerThread::prepareTracks_l( } sp proxy = track->audioTrackServerProxy(); float volume; - if (track->isPlaybackRestricted() || mStreamTypes[track->streamType()].mute) { + if (track->isPlaybackRestricted() || + mStreamTypes[track->streamType()].mute || track->isAppMuted()) { volume = 0.f; } else { - volume = masterVolume * mStreamTypes[track->streamType()].volume; + volume = masterVolume * mStreamTypes[track->streamType()].volume + * track->getAppVolume(); } handleVoipVolume_l(&volume); @@ -5828,13 +5868,15 @@ PlaybackThread::mixer_state MixerThread::prepareTracks_l( uint32_t vl, vr; // in U8.24 integer format float vlf, vrf, vaf; // in [0.0, 1.0] float format // read original volumes with volume control - float v = masterVolume * mStreamTypes[track->streamType()].volume; + float v = masterVolume * mStreamTypes[track->streamType()].volume + * track->getAppVolume(); // Always fetch volumeshaper volume to ensure state is updated. const sp proxy = track->audioTrackServerProxy(); const float vh = track->getVolumeHandler()->getVolume( track->audioTrackServerProxy()->framesReleased()).first; - if (mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) { + if (mStreamTypes[track->streamType()].mute + || track->isPlaybackRestricted() || track->isAppMuted()) { v = 0; } @@ -6585,11 +6627,13 @@ void DirectOutputThread::processVolume_l(IAfTrack* track, bool lastTrack) const bool clientVolumeMute = (left == 0.f && right == 0.f); - if (mMasterMute || mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) { + if (mMasterMute || mStreamTypes[track->streamType()].mute + || track->isPlaybackRestricted() || track->isAppMuted()) { left = right = 0; } else { float typeVolume = mStreamTypes[track->streamType()].volume; - const float v = mMasterVolume * typeVolume * shaperVolume; + float appVolume = track->getAppVolume(); + const float v = mMasterVolume * typeVolume * shaperVolume * appVolume; if (left > GAIN_FLOAT_UNITY) { left = GAIN_FLOAT_UNITY; diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index ea994a5b09c..b3f647ad0bf 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -886,6 +886,10 @@ class PlaybackThread : public ThreadBase, public virtual IAfPlaybackThread, mTracks.add(track); } + status_t setAppVolume(const String8& packageName, const float value) final; + status_t setAppMute(const String8& packageName, const bool muted) final; + void listAppVolumes(std::set &container) final; + protected: // Code snippets that were lifted up out of threadLoop() virtual void threadLoop_mix() REQUIRES(ThreadBase_ThreadLoop) = 0; diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index fe582eb45fb..05eb505cd8f 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -793,6 +793,20 @@ Track::Track( ALOGV_IF(sharedBuffer != 0, "%s(%d): sharedBuffer: %p, size: %zu", __func__, mId, sharedBuffer->unsecurePointer(), sharedBuffer->size()); + /* get package name */ + PermissionController permissionController; + Vector packages; + permissionController.getPackagesForUid(uid(), packages); + if (!packages.isEmpty()) { + mPackageName = String8(packages[0]); + } else { + mPackageName = ""; + } + + /* init app volume */ + mAppMuted = false; + mAppVolume = 1.0f; + if (mCblk == NULL) { return; } @@ -1541,6 +1555,16 @@ void Track::setFinalVolume(float volumeLeft, float volumeRight) } } +void Track::setAppVolume(float volume) +{ + mAppVolume = volume; +} + +void Track::setAppMute(bool val) +{ + mAppMuted = val; +} + void Track::copyMetadataTo(MetadataInserter& backInserter) const { // Do not forward metadata for PatchTrack with unspecified stream type