Loading services/audiopolicy/common/include/Volume.h 0 → 100755 +137 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2015 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. */ #pragma once #include <system/audio.h> #include <utils/Log.h> class VolumeCurvePoint { public: int mIndex; float mDBAttenuation; }; class Volume { public: /** * 4 points to define the volume attenuation curve, each characterized by the volume * index (from 0 to 100) at which they apply, and the attenuation in dB at that index. * we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl() * * @todo shall become configurable */ enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4 }; /** * device categories used for volume curve management. */ enum device_category { DEVICE_CATEGORY_HEADSET, DEVICE_CATEGORY_SPEAKER, DEVICE_CATEGORY_EARPIECE, DEVICE_CATEGORY_EXT_MEDIA, DEVICE_CATEGORY_CNT }; /** * extract one device relevant for volume control from multiple device selection * * @param[in] device for which the volume category is associated * * @return subset of device required to limit the number of volume category per device */ static audio_devices_t getDeviceForVolume(audio_devices_t device) { if (device == AUDIO_DEVICE_NONE) { // this happens when forcing a route update and no track is active on an output. // In this case the returned category is not important. device = AUDIO_DEVICE_OUT_SPEAKER; } else if (popcount(device) > 1) { // Multiple device selection is either: // - speaker + one other device: give priority to speaker in this case. // - one A2DP device + another device: happens with duplicated output. In this case // retain the device on the A2DP output as the other must not correspond to an active // selection if not the speaker. // - HDMI-CEC system audio mode only output: give priority to available item in order. if (device & AUDIO_DEVICE_OUT_SPEAKER) { device = AUDIO_DEVICE_OUT_SPEAKER; } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) { device = AUDIO_DEVICE_OUT_HDMI_ARC; } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) { device = AUDIO_DEVICE_OUT_AUX_LINE; } else if (device & AUDIO_DEVICE_OUT_SPDIF) { device = AUDIO_DEVICE_OUT_SPDIF; } else { device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP); } } /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/ if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) device = AUDIO_DEVICE_OUT_SPEAKER; ALOGW_IF(popcount(device) != 1, "getDeviceForVolume() invalid device combination: %08x", device); return device; } /** * returns the category the device belongs to with regard to volume curve management * * @param[in] device to check upon the category to whom it belongs to. * * @return device category. */ static device_category getDeviceCategory(audio_devices_t device) { switch(getDeviceForVolume(device)) { case AUDIO_DEVICE_OUT_EARPIECE: return DEVICE_CATEGORY_EARPIECE; case AUDIO_DEVICE_OUT_WIRED_HEADSET: case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: return DEVICE_CATEGORY_HEADSET; case AUDIO_DEVICE_OUT_LINE: case AUDIO_DEVICE_OUT_AUX_DIGITAL: /*USB? Remote submix?*/ return DEVICE_CATEGORY_EXT_MEDIA; case AUDIO_DEVICE_OUT_SPEAKER: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: case AUDIO_DEVICE_OUT_USB_ACCESSORY: case AUDIO_DEVICE_OUT_USB_DEVICE: case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: default: return DEVICE_CATEGORY_SPEAKER; } } }; services/audiopolicy/common/managerdefinitions/Android.mk +1 −0 Original line number Original line Diff line number Diff line Loading @@ -5,6 +5,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES:= \ src/DeviceDescriptor.cpp \ src/DeviceDescriptor.cpp \ src/AudioGain.cpp \ src/AudioGain.cpp \ src/StreamDescriptor.cpp \ src/HwModule.cpp \ src/HwModule.cpp \ src/IOProfile.cpp \ src/IOProfile.cpp \ src/AudioPort.cpp \ src/AudioPort.cpp \ Loading services/audiopolicy/common/managerdefinitions/include/AudioGain.h +17 −62 Original line number Original line Diff line number Diff line Loading @@ -16,70 +16,43 @@ #pragma once #pragma once #include <Volume.h> #include <utils/Errors.h> #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/RefBase.h> #include <system/audio.h> #include <system/audio.h> #include <utils/KeyedVector.h> namespace android { namespace android { class VolumeCurvePoint { public: int mIndex; float mDBAttenuation; }; class StreamDescriptor; class StreamDescriptor; class ApmGains class ApmGains { { public : public : // 4 points to define the volume attenuation curve, each characterized by the volume // index (from 0 to 100) at which they apply, and the attenuation in dB at that index. // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl() enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4}; // device categories used for volume curve management. enum device_category { DEVICE_CATEGORY_HEADSET, DEVICE_CATEGORY_SPEAKER, DEVICE_CATEGORY_EARPIECE, DEVICE_CATEGORY_EXT_MEDIA, DEVICE_CATEGORY_CNT }; // returns the category the device belongs to with regard to volume curve management static ApmGains::device_category getDeviceCategory(audio_devices_t device); // extract one device relevant for volume control from multiple device selection static audio_devices_t getDeviceForVolume(audio_devices_t device); static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi); int indexInUi); // default volume curve // default volume curve static const VolumeCurvePoint sDefaultVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultVolumeCurve[Volume::VOLCNT]; // default volume curve for media strategy // default volume curve for media strategy static const VolumeCurvePoint sDefaultMediaVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultMediaVolumeCurve[Volume::VOLCNT]; // volume curve for non-media audio on ext media outputs (HDMI, Line, etc) // volume curve for non-media audio on ext media outputs (HDMI, Line, etc) static const VolumeCurvePoint sExtMediaSystemVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sExtMediaSystemVolumeCurve[Volume::VOLCNT]; // volume curve for media strategy on speakers // volume curve for media strategy on speakers static const VolumeCurvePoint sSpeakerMediaVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerMediaVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[Volume::VOLCNT]; // volume curve for sonification strategy on speakers // volume curve for sonification strategy on speakers static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[Volume::VOLCNT]; static const VolumeCurvePoint sDefaultSystemVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultSystemVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[Volume::VOLCNT]; static const VolumeCurvePoint sHeadsetSystemVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sHeadsetSystemVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sDefaultVoiceVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultVoiceVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sLinearVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sLinearVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sSilentVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sSilentVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sFullScaleVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sFullScaleVolumeCurve[Volume::VOLCNT]; // default volume curves per stream and device category. See initializeVolumeCurves() // default volume curves per stream and device category. See initializeVolumeCurves() static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][ApmGains::DEVICE_CATEGORY_CNT]; static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][Volume::DEVICE_CATEGORY_CNT]; }; }; Loading @@ -98,22 +71,4 @@ public: bool mUseInChannelMask; bool mUseInChannelMask; }; }; // stream descriptor used for volume control class StreamDescriptor { public: StreamDescriptor(); int getVolumeIndex(audio_devices_t device); void dump(int fd); int mIndexMin; // min volume index int mIndexMax; // max volume index KeyedVector<audio_devices_t, int> mIndexCur; // current volume index per device bool mCanBeMuted; // true is the stream can be muted const VolumeCurvePoint *mVolumeCurve[ApmGains::DEVICE_CATEGORY_CNT]; }; }; // namespace android }; // namespace android services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h 0 → 100644 +85 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2015 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. */ #pragma once #include <Volume.h> #include <utils/KeyedVector.h> #include <utils/StrongPointer.h> #include <utils/SortedVector.h> #include <hardware/audio.h> namespace android { // stream descriptor used for volume control class StreamDescriptor { public: StreamDescriptor(); int getVolumeIndex(audio_devices_t device) const; bool canBeMuted() const { return mCanBeMuted; } void clearCurrentVolumeIndex(); void addCurrentVolumeIndex(audio_devices_t device, int index); int getVolumeIndexMin() const { return mIndexMin; } int getVolumeIndexMax() const { return mIndexMax; } void setVolumeIndexMin(int volIndexMin); void setVolumeIndexMax(int volIndexMax); void dump(int fd) const; void setVolumeCurvePoint(Volume::device_category deviceCategory, const VolumeCurvePoint *point); const VolumeCurvePoint *getVolumeCurvePoint(Volume::device_category deviceCategory) const { return mVolumeCurve[deviceCategory]; } private: const VolumeCurvePoint *mVolumeCurve[Volume::DEVICE_CATEGORY_CNT]; KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */ int mIndexMin; /**< min volume index. */ int mIndexMax; /**< max volume index. */ bool mCanBeMuted; /**< true is the stream can be muted. */ }; /** * stream descriptors collection for volume control */ class StreamDescriptorCollection : public DefaultKeyedVector<audio_stream_type_t, StreamDescriptor> { public: StreamDescriptorCollection(); void clearCurrentVolumeIndex(audio_stream_type_t stream); void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index); bool canBeMuted(audio_stream_type_t stream); status_t dump(int fd) const; void setVolumeCurvePoint(audio_stream_type_t stream, Volume::device_category deviceCategory, const VolumeCurvePoint *point); const VolumeCurvePoint *getVolumeCurvePoint(audio_stream_type_t stream, Volume::device_category deviceCategory) const; void setVolumeIndexMin(audio_stream_type_t stream,int volIndexMin); void setVolumeIndexMax(audio_stream_type_t stream,int volIndexMax); }; }; // namespace android services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp +27 −131 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ #endif #endif #include "AudioGain.h" #include "AudioGain.h" #include "StreamDescriptor.h" #include <utils/Log.h> #include <utils/Log.h> #include <utils/String8.h> #include <utils/String8.h> Loading @@ -33,38 +34,38 @@ namespace android { namespace android { const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sDefaultVolumeCurve[Volume::VOLCNT] = { {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f} {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultMediaVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sDefaultMediaVolumeCurve[Volume::VOLCNT] = { {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f} {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sExtMediaSystemVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sExtMediaSystemVolumeCurve[Volume::VOLCNT] = { {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f} {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerMediaVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sSpeakerMediaVolumeCurve[Volume::VOLCNT] = { {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f} {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT] = { ApmGains::sSpeakerMediaVolumeCurveDrc[Volume::VOLCNT] = { {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f} {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sSpeakerSonificationVolumeCurve[Volume::VOLCNT] = { {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f} {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT] = { ApmGains::sSpeakerSonificationVolumeCurveDrc[Volume::VOLCNT] = { {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f} {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f} }; }; Loading @@ -74,47 +75,47 @@ ApmGains::sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT] = { // The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset. // The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset. const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultSystemVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sDefaultSystemVolumeCurve[Volume::VOLCNT] = { {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f} {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT] = { ApmGains::sDefaultSystemVolumeCurveDrc[Volume::VOLCNT] = { {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f} {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sHeadsetSystemVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sHeadsetSystemVolumeCurve[Volume::VOLCNT] = { {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f} {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultVoiceVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sDefaultVoiceVolumeCurve[Volume::VOLCNT] = { {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f} {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sSpeakerVoiceVolumeCurve[Volume::VOLCNT] = { {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f} {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sLinearVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sLinearVolumeCurve[Volume::VOLCNT] = { {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f} {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSilentVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sSilentVolumeCurve[Volume::VOLCNT] = { {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f} {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sFullScaleVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sFullScaleVolumeCurve[Volume::VOLCNT] = { {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f} {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f} }; }; const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT] const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT] [ApmGains::DEVICE_CATEGORY_CNT] = { [Volume::DEVICE_CATEGORY_CNT] = { { // AUDIO_STREAM_VOICE_CALL { // AUDIO_STREAM_VOICE_CALL ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER Loading Loading @@ -196,94 +197,28 @@ const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT] }, }, }; }; //static audio_devices_t ApmGains::getDeviceForVolume(audio_devices_t device) { if (device == AUDIO_DEVICE_NONE) { // this happens when forcing a route update and no track is active on an output. // In this case the returned category is not important. device = AUDIO_DEVICE_OUT_SPEAKER; } else if (popcount(device) > 1) { // Multiple device selection is either: // - speaker + one other device: give priority to speaker in this case. // - one A2DP device + another device: happens with duplicated output. In this case // retain the device on the A2DP output as the other must not correspond to an active // selection if not the speaker. // - HDMI-CEC system audio mode only output: give priority to available item in order. if (device & AUDIO_DEVICE_OUT_SPEAKER) { device = AUDIO_DEVICE_OUT_SPEAKER; } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) { device = AUDIO_DEVICE_OUT_HDMI_ARC; } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) { device = AUDIO_DEVICE_OUT_AUX_LINE; } else if (device & AUDIO_DEVICE_OUT_SPDIF) { device = AUDIO_DEVICE_OUT_SPDIF; } else { device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP); } } /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/ if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) device = AUDIO_DEVICE_OUT_SPEAKER; ALOGW_IF(popcount(device) != 1, "getDeviceForVolume() invalid device combination: %08x", device); return device; } //static ApmGains::device_category ApmGains::getDeviceCategory(audio_devices_t device) { switch(getDeviceForVolume(device)) { case AUDIO_DEVICE_OUT_EARPIECE: return ApmGains::DEVICE_CATEGORY_EARPIECE; case AUDIO_DEVICE_OUT_WIRED_HEADSET: case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: return ApmGains::DEVICE_CATEGORY_HEADSET; case AUDIO_DEVICE_OUT_LINE: case AUDIO_DEVICE_OUT_AUX_DIGITAL: /*USB? Remote submix?*/ return ApmGains::DEVICE_CATEGORY_EXT_MEDIA; case AUDIO_DEVICE_OUT_SPEAKER: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: case AUDIO_DEVICE_OUT_USB_ACCESSORY: case AUDIO_DEVICE_OUT_USB_DEVICE: case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: default: return ApmGains::DEVICE_CATEGORY_SPEAKER; } } //static //static float ApmGains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, float ApmGains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi) int indexInUi) { { ApmGains::device_category deviceCategory = ApmGains::getDeviceCategory(device); Volume::device_category deviceCategory = Volume::getDeviceCategory(device); const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory]; const VolumeCurvePoint *curve = streamDesc.getVolumeCurvePoint(deviceCategory); // the volume index in the UI is relative to the min and max volume indices for this stream type // the volume index in the UI is relative to the min and max volume indices for this stream type int nbSteps = 1 + curve[ApmGains::VOLMAX].mIndex - int nbSteps = 1 + curve[Volume::VOLMAX].mIndex - curve[ApmGains::VOLMIN].mIndex; curve[Volume::VOLMIN].mIndex; int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) / int volIdx = (nbSteps * (indexInUi - streamDesc.getVolumeIndexMin())) / (streamDesc.mIndexMax - streamDesc.mIndexMin); (streamDesc.getVolumeIndexMax() - streamDesc.getVolumeIndexMin()); // find what part of the curve this index volume belongs to, or if it's out of bounds // find what part of the curve this index volume belongs to, or if it's out of bounds int segment = 0; int segment = 0; if (volIdx < curve[ApmGains::VOLMIN].mIndex) { // out of bounds if (volIdx < curve[Volume::VOLMIN].mIndex) { // out of bounds return 0.0f; return 0.0f; } else if (volIdx < curve[ApmGains::VOLKNEE1].mIndex) { } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) { segment = 0; segment = 0; } else if (volIdx < curve[ApmGains::VOLKNEE2].mIndex) { } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) { segment = 1; segment = 1; } else if (volIdx <= curve[ApmGains::VOLMAX].mIndex) { } else if (volIdx <= curve[Volume::VOLMAX].mIndex) { segment = 2; segment = 2; } else { // out of bounds } else { // out of bounds return 1.0f; return 1.0f; Loading Loading @@ -406,43 +341,4 @@ void AudioGain::dump(int fd, int spaces, int index) const write(fd, result.string(), result.size()); write(fd, result.string(), result.size()); } } // --- StreamDescriptor class implementation StreamDescriptor::StreamDescriptor() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true) { mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0); } int StreamDescriptor::getVolumeIndex(audio_devices_t device) { device = ApmGains::getDeviceForVolume(device); // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT if (mIndexCur.indexOfKey(device) < 0) { device = AUDIO_DEVICE_OUT_DEFAULT; } return mIndexCur.valueFor(device); } void StreamDescriptor::dump(int fd) { const size_t SIZE = 256; char buffer[SIZE]; String8 result; snprintf(buffer, SIZE, "%s %02d %02d ", mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax); result.append(buffer); for (size_t i = 0; i < mIndexCur.size(); i++) { snprintf(buffer, SIZE, "%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i)); result.append(buffer); } result.append("\n"); write(fd, result.string(), result.size()); } }; // namespace android }; // namespace android Loading
services/audiopolicy/common/include/Volume.h 0 → 100755 +137 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2015 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. */ #pragma once #include <system/audio.h> #include <utils/Log.h> class VolumeCurvePoint { public: int mIndex; float mDBAttenuation; }; class Volume { public: /** * 4 points to define the volume attenuation curve, each characterized by the volume * index (from 0 to 100) at which they apply, and the attenuation in dB at that index. * we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl() * * @todo shall become configurable */ enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4 }; /** * device categories used for volume curve management. */ enum device_category { DEVICE_CATEGORY_HEADSET, DEVICE_CATEGORY_SPEAKER, DEVICE_CATEGORY_EARPIECE, DEVICE_CATEGORY_EXT_MEDIA, DEVICE_CATEGORY_CNT }; /** * extract one device relevant for volume control from multiple device selection * * @param[in] device for which the volume category is associated * * @return subset of device required to limit the number of volume category per device */ static audio_devices_t getDeviceForVolume(audio_devices_t device) { if (device == AUDIO_DEVICE_NONE) { // this happens when forcing a route update and no track is active on an output. // In this case the returned category is not important. device = AUDIO_DEVICE_OUT_SPEAKER; } else if (popcount(device) > 1) { // Multiple device selection is either: // - speaker + one other device: give priority to speaker in this case. // - one A2DP device + another device: happens with duplicated output. In this case // retain the device on the A2DP output as the other must not correspond to an active // selection if not the speaker. // - HDMI-CEC system audio mode only output: give priority to available item in order. if (device & AUDIO_DEVICE_OUT_SPEAKER) { device = AUDIO_DEVICE_OUT_SPEAKER; } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) { device = AUDIO_DEVICE_OUT_HDMI_ARC; } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) { device = AUDIO_DEVICE_OUT_AUX_LINE; } else if (device & AUDIO_DEVICE_OUT_SPDIF) { device = AUDIO_DEVICE_OUT_SPDIF; } else { device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP); } } /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/ if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) device = AUDIO_DEVICE_OUT_SPEAKER; ALOGW_IF(popcount(device) != 1, "getDeviceForVolume() invalid device combination: %08x", device); return device; } /** * returns the category the device belongs to with regard to volume curve management * * @param[in] device to check upon the category to whom it belongs to. * * @return device category. */ static device_category getDeviceCategory(audio_devices_t device) { switch(getDeviceForVolume(device)) { case AUDIO_DEVICE_OUT_EARPIECE: return DEVICE_CATEGORY_EARPIECE; case AUDIO_DEVICE_OUT_WIRED_HEADSET: case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: return DEVICE_CATEGORY_HEADSET; case AUDIO_DEVICE_OUT_LINE: case AUDIO_DEVICE_OUT_AUX_DIGITAL: /*USB? Remote submix?*/ return DEVICE_CATEGORY_EXT_MEDIA; case AUDIO_DEVICE_OUT_SPEAKER: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: case AUDIO_DEVICE_OUT_USB_ACCESSORY: case AUDIO_DEVICE_OUT_USB_DEVICE: case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: default: return DEVICE_CATEGORY_SPEAKER; } } };
services/audiopolicy/common/managerdefinitions/Android.mk +1 −0 Original line number Original line Diff line number Diff line Loading @@ -5,6 +5,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES:= \ src/DeviceDescriptor.cpp \ src/DeviceDescriptor.cpp \ src/AudioGain.cpp \ src/AudioGain.cpp \ src/StreamDescriptor.cpp \ src/HwModule.cpp \ src/HwModule.cpp \ src/IOProfile.cpp \ src/IOProfile.cpp \ src/AudioPort.cpp \ src/AudioPort.cpp \ Loading
services/audiopolicy/common/managerdefinitions/include/AudioGain.h +17 −62 Original line number Original line Diff line number Diff line Loading @@ -16,70 +16,43 @@ #pragma once #pragma once #include <Volume.h> #include <utils/Errors.h> #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/RefBase.h> #include <system/audio.h> #include <system/audio.h> #include <utils/KeyedVector.h> namespace android { namespace android { class VolumeCurvePoint { public: int mIndex; float mDBAttenuation; }; class StreamDescriptor; class StreamDescriptor; class ApmGains class ApmGains { { public : public : // 4 points to define the volume attenuation curve, each characterized by the volume // index (from 0 to 100) at which they apply, and the attenuation in dB at that index. // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl() enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4}; // device categories used for volume curve management. enum device_category { DEVICE_CATEGORY_HEADSET, DEVICE_CATEGORY_SPEAKER, DEVICE_CATEGORY_EARPIECE, DEVICE_CATEGORY_EXT_MEDIA, DEVICE_CATEGORY_CNT }; // returns the category the device belongs to with regard to volume curve management static ApmGains::device_category getDeviceCategory(audio_devices_t device); // extract one device relevant for volume control from multiple device selection static audio_devices_t getDeviceForVolume(audio_devices_t device); static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi); int indexInUi); // default volume curve // default volume curve static const VolumeCurvePoint sDefaultVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultVolumeCurve[Volume::VOLCNT]; // default volume curve for media strategy // default volume curve for media strategy static const VolumeCurvePoint sDefaultMediaVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultMediaVolumeCurve[Volume::VOLCNT]; // volume curve for non-media audio on ext media outputs (HDMI, Line, etc) // volume curve for non-media audio on ext media outputs (HDMI, Line, etc) static const VolumeCurvePoint sExtMediaSystemVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sExtMediaSystemVolumeCurve[Volume::VOLCNT]; // volume curve for media strategy on speakers // volume curve for media strategy on speakers static const VolumeCurvePoint sSpeakerMediaVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerMediaVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[Volume::VOLCNT]; // volume curve for sonification strategy on speakers // volume curve for sonification strategy on speakers static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[Volume::VOLCNT]; static const VolumeCurvePoint sDefaultSystemVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultSystemVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[Volume::VOLCNT]; static const VolumeCurvePoint sHeadsetSystemVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sHeadsetSystemVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sDefaultVoiceVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sDefaultVoiceVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sLinearVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sLinearVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sSilentVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sSilentVolumeCurve[Volume::VOLCNT]; static const VolumeCurvePoint sFullScaleVolumeCurve[ApmGains::VOLCNT]; static const VolumeCurvePoint sFullScaleVolumeCurve[Volume::VOLCNT]; // default volume curves per stream and device category. See initializeVolumeCurves() // default volume curves per stream and device category. See initializeVolumeCurves() static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][ApmGains::DEVICE_CATEGORY_CNT]; static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][Volume::DEVICE_CATEGORY_CNT]; }; }; Loading @@ -98,22 +71,4 @@ public: bool mUseInChannelMask; bool mUseInChannelMask; }; }; // stream descriptor used for volume control class StreamDescriptor { public: StreamDescriptor(); int getVolumeIndex(audio_devices_t device); void dump(int fd); int mIndexMin; // min volume index int mIndexMax; // max volume index KeyedVector<audio_devices_t, int> mIndexCur; // current volume index per device bool mCanBeMuted; // true is the stream can be muted const VolumeCurvePoint *mVolumeCurve[ApmGains::DEVICE_CATEGORY_CNT]; }; }; // namespace android }; // namespace android
services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h 0 → 100644 +85 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2015 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. */ #pragma once #include <Volume.h> #include <utils/KeyedVector.h> #include <utils/StrongPointer.h> #include <utils/SortedVector.h> #include <hardware/audio.h> namespace android { // stream descriptor used for volume control class StreamDescriptor { public: StreamDescriptor(); int getVolumeIndex(audio_devices_t device) const; bool canBeMuted() const { return mCanBeMuted; } void clearCurrentVolumeIndex(); void addCurrentVolumeIndex(audio_devices_t device, int index); int getVolumeIndexMin() const { return mIndexMin; } int getVolumeIndexMax() const { return mIndexMax; } void setVolumeIndexMin(int volIndexMin); void setVolumeIndexMax(int volIndexMax); void dump(int fd) const; void setVolumeCurvePoint(Volume::device_category deviceCategory, const VolumeCurvePoint *point); const VolumeCurvePoint *getVolumeCurvePoint(Volume::device_category deviceCategory) const { return mVolumeCurve[deviceCategory]; } private: const VolumeCurvePoint *mVolumeCurve[Volume::DEVICE_CATEGORY_CNT]; KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */ int mIndexMin; /**< min volume index. */ int mIndexMax; /**< max volume index. */ bool mCanBeMuted; /**< true is the stream can be muted. */ }; /** * stream descriptors collection for volume control */ class StreamDescriptorCollection : public DefaultKeyedVector<audio_stream_type_t, StreamDescriptor> { public: StreamDescriptorCollection(); void clearCurrentVolumeIndex(audio_stream_type_t stream); void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index); bool canBeMuted(audio_stream_type_t stream); status_t dump(int fd) const; void setVolumeCurvePoint(audio_stream_type_t stream, Volume::device_category deviceCategory, const VolumeCurvePoint *point); const VolumeCurvePoint *getVolumeCurvePoint(audio_stream_type_t stream, Volume::device_category deviceCategory) const; void setVolumeIndexMin(audio_stream_type_t stream,int volIndexMin); void setVolumeIndexMax(audio_stream_type_t stream,int volIndexMax); }; }; // namespace android
services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp +27 −131 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ #endif #endif #include "AudioGain.h" #include "AudioGain.h" #include "StreamDescriptor.h" #include <utils/Log.h> #include <utils/Log.h> #include <utils/String8.h> #include <utils/String8.h> Loading @@ -33,38 +34,38 @@ namespace android { namespace android { const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sDefaultVolumeCurve[Volume::VOLCNT] = { {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f} {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultMediaVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sDefaultMediaVolumeCurve[Volume::VOLCNT] = { {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f} {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sExtMediaSystemVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sExtMediaSystemVolumeCurve[Volume::VOLCNT] = { {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f} {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerMediaVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sSpeakerMediaVolumeCurve[Volume::VOLCNT] = { {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f} {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT] = { ApmGains::sSpeakerMediaVolumeCurveDrc[Volume::VOLCNT] = { {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f} {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sSpeakerSonificationVolumeCurve[Volume::VOLCNT] = { {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f} {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT] = { ApmGains::sSpeakerSonificationVolumeCurveDrc[Volume::VOLCNT] = { {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f} {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f} }; }; Loading @@ -74,47 +75,47 @@ ApmGains::sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT] = { // The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset. // The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset. const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultSystemVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sDefaultSystemVolumeCurve[Volume::VOLCNT] = { {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f} {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT] = { ApmGains::sDefaultSystemVolumeCurveDrc[Volume::VOLCNT] = { {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f} {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sHeadsetSystemVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sHeadsetSystemVolumeCurve[Volume::VOLCNT] = { {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f} {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sDefaultVoiceVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sDefaultVoiceVolumeCurve[Volume::VOLCNT] = { {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f} {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sSpeakerVoiceVolumeCurve[Volume::VOLCNT] = { {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f} {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sLinearVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sLinearVolumeCurve[Volume::VOLCNT] = { {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f} {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sSilentVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sSilentVolumeCurve[Volume::VOLCNT] = { {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f} {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f} }; }; const VolumeCurvePoint const VolumeCurvePoint ApmGains::sFullScaleVolumeCurve[ApmGains::VOLCNT] = { ApmGains::sFullScaleVolumeCurve[Volume::VOLCNT] = { {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f} {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f} }; }; const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT] const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT] [ApmGains::DEVICE_CATEGORY_CNT] = { [Volume::DEVICE_CATEGORY_CNT] = { { // AUDIO_STREAM_VOICE_CALL { // AUDIO_STREAM_VOICE_CALL ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER Loading Loading @@ -196,94 +197,28 @@ const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT] }, }, }; }; //static audio_devices_t ApmGains::getDeviceForVolume(audio_devices_t device) { if (device == AUDIO_DEVICE_NONE) { // this happens when forcing a route update and no track is active on an output. // In this case the returned category is not important. device = AUDIO_DEVICE_OUT_SPEAKER; } else if (popcount(device) > 1) { // Multiple device selection is either: // - speaker + one other device: give priority to speaker in this case. // - one A2DP device + another device: happens with duplicated output. In this case // retain the device on the A2DP output as the other must not correspond to an active // selection if not the speaker. // - HDMI-CEC system audio mode only output: give priority to available item in order. if (device & AUDIO_DEVICE_OUT_SPEAKER) { device = AUDIO_DEVICE_OUT_SPEAKER; } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) { device = AUDIO_DEVICE_OUT_HDMI_ARC; } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) { device = AUDIO_DEVICE_OUT_AUX_LINE; } else if (device & AUDIO_DEVICE_OUT_SPDIF) { device = AUDIO_DEVICE_OUT_SPDIF; } else { device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP); } } /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/ if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) device = AUDIO_DEVICE_OUT_SPEAKER; ALOGW_IF(popcount(device) != 1, "getDeviceForVolume() invalid device combination: %08x", device); return device; } //static ApmGains::device_category ApmGains::getDeviceCategory(audio_devices_t device) { switch(getDeviceForVolume(device)) { case AUDIO_DEVICE_OUT_EARPIECE: return ApmGains::DEVICE_CATEGORY_EARPIECE; case AUDIO_DEVICE_OUT_WIRED_HEADSET: case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: return ApmGains::DEVICE_CATEGORY_HEADSET; case AUDIO_DEVICE_OUT_LINE: case AUDIO_DEVICE_OUT_AUX_DIGITAL: /*USB? Remote submix?*/ return ApmGains::DEVICE_CATEGORY_EXT_MEDIA; case AUDIO_DEVICE_OUT_SPEAKER: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: case AUDIO_DEVICE_OUT_USB_ACCESSORY: case AUDIO_DEVICE_OUT_USB_DEVICE: case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: default: return ApmGains::DEVICE_CATEGORY_SPEAKER; } } //static //static float ApmGains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, float ApmGains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi) int indexInUi) { { ApmGains::device_category deviceCategory = ApmGains::getDeviceCategory(device); Volume::device_category deviceCategory = Volume::getDeviceCategory(device); const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory]; const VolumeCurvePoint *curve = streamDesc.getVolumeCurvePoint(deviceCategory); // the volume index in the UI is relative to the min and max volume indices for this stream type // the volume index in the UI is relative to the min and max volume indices for this stream type int nbSteps = 1 + curve[ApmGains::VOLMAX].mIndex - int nbSteps = 1 + curve[Volume::VOLMAX].mIndex - curve[ApmGains::VOLMIN].mIndex; curve[Volume::VOLMIN].mIndex; int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) / int volIdx = (nbSteps * (indexInUi - streamDesc.getVolumeIndexMin())) / (streamDesc.mIndexMax - streamDesc.mIndexMin); (streamDesc.getVolumeIndexMax() - streamDesc.getVolumeIndexMin()); // find what part of the curve this index volume belongs to, or if it's out of bounds // find what part of the curve this index volume belongs to, or if it's out of bounds int segment = 0; int segment = 0; if (volIdx < curve[ApmGains::VOLMIN].mIndex) { // out of bounds if (volIdx < curve[Volume::VOLMIN].mIndex) { // out of bounds return 0.0f; return 0.0f; } else if (volIdx < curve[ApmGains::VOLKNEE1].mIndex) { } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) { segment = 0; segment = 0; } else if (volIdx < curve[ApmGains::VOLKNEE2].mIndex) { } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) { segment = 1; segment = 1; } else if (volIdx <= curve[ApmGains::VOLMAX].mIndex) { } else if (volIdx <= curve[Volume::VOLMAX].mIndex) { segment = 2; segment = 2; } else { // out of bounds } else { // out of bounds return 1.0f; return 1.0f; Loading Loading @@ -406,43 +341,4 @@ void AudioGain::dump(int fd, int spaces, int index) const write(fd, result.string(), result.size()); write(fd, result.string(), result.size()); } } // --- StreamDescriptor class implementation StreamDescriptor::StreamDescriptor() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true) { mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0); } int StreamDescriptor::getVolumeIndex(audio_devices_t device) { device = ApmGains::getDeviceForVolume(device); // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT if (mIndexCur.indexOfKey(device) < 0) { device = AUDIO_DEVICE_OUT_DEFAULT; } return mIndexCur.valueFor(device); } void StreamDescriptor::dump(int fd) { const size_t SIZE = 256; char buffer[SIZE]; String8 result; snprintf(buffer, SIZE, "%s %02d %02d ", mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax); result.append(buffer); for (size_t i = 0; i < mIndexCur.size(); i++) { snprintf(buffer, SIZE, "%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i)); result.append(buffer); } result.append("\n"); write(fd, result.string(), result.size()); } }; // namespace android }; // namespace android