通过音量条调节设备音量是通过setStreamVolume方法去设置的,接下来主要看一下与ARC相关的代码
base/services/core/java/com/android/server/audio/AudioService.java
private void setStreamVolume(int streamType, int index, int flags,
@Nullable AudioDeviceAttributes ada,
String callingPackage, String caller, String attributionTag, int uid,
boolean hasModifyAudioSettings) {
---
//这里和adjustStreamVolume一样
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
final int device = (ada == null)
? getDeviceForStream(streamType)
: ada.getInternalType();
---
> [!代码1]
> onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings);
}
代码1
base/services/core/java/com/android/server/audio/AudioService.java
//setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings);
private void onSetStreamVolume(int streamType, int index, int flags, int device,
String caller, boolean hasModifyAudioSettings) {
final int stream = mStreamVolumeAlias[streamType];
setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings);
// setting volume on ui sounds stream type also controls silent mode
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(stream == getUiSoundsStreamType())) {
setRingerMode(getNewRingerMode(stream, index, flags),
TAG + ".onSetStreamVolume", false /*external*/);
}
// setting non-zero volume for a muted stream unmutes the stream and vice versa,
// except for BT SCO stream where only explicit mute is allowed to comply to BT requirements
if (streamType != AudioSystem.STREAM_BLUETOOTH_SCO) {
mStreamStates[stream].mute(index == 0);
}
}
base/services/core/java/com/android/server/audio/AudioService.java
//发送MSG_SET_DEVICE_VOLUME消息,后面的流程和2-4接收到MSG_SET_DEVICE_VOLUME消息音量调节的流程一样
private void setStreamVolumeInt(int streamType,
int index,
int device,
boolean force,
String caller, boolean hasModifyAudioSettings) {
if (isFullVolumeDevice(device)) {
return;
}
VolumeStreamState streamState = mStreamStates[streamType];
if (streamState.setIndex(index, device, caller, hasModifyAudioSettings) || force) {
// Post message to set system volume (it in turn will post a message
// to persist). sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
}
base/services/core/java/com/android/server/audio/AudioService.java
private void setStreamVolumeIndex(int index, int device) {
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
// This allows RX path muting by the audio HAL only when explicitly muted but not when
// index is just set to 0 to repect BT requirements
if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0
&& !isFullyMuted()) {
index = 1;
}
Log.d(TAG,"sug#setStreamVolumeIndexAS#mStreamType = " + mStreamType + "index" + index + "device" + device);
> [!NOTE]
> 进入AudioSystem,开始真正地设置音量了
> mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);
}
接下来我们追一下setStreamVolumeIndex后的流程
//在VolumeStreamState 的setStreamVolumeIndex调用AudioSystem的setStreamVolumeIndexAS,开始真正地设置音量
//frameworks/base/service/java/com/android/server/audio/AudioSystem.java
public class AudioSystem{
......
/** Wrapper for native methods called from AudioService */
public static int setStreamVolumeIndexAS(int stream, int index, int device) {
if (DEBUG_VOLUME) {
Log.i(TAG, "setStreamVolumeIndex: " + STREAM_NAMES[stream]
+ " dev=" + Integer.toHexString(device) + " idx=" + index);
}
return setStreamVolumeIndex(stream, index, device);
}
......
}
//在AudioSystem的setStreamVolumeIndexAS中调用setStreamVolumeIndex方法,setStreamVolumeIndex方法是一个native方法,通过JNI调用AudioSystem native的setStreamVolumeIndex函数:
// frameworks/base/core/jni/android_media_AudioSystem.cpp
static jint
android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
jobject thiz,
jint stream,
jint index,
jint device)
{
return (jint) check_AudioSystem_Command(
AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
index,
(audio_devices_t)device));
}
//在JNI代码中调用AudioSystem的setStreamVolumeIndex函数:
//frameworks/av/media/libaudioclient/AudioSystem.cpp
status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->setStreamVolumeIndex(stream, index, device);
}
//此处创建了一个AudioPolicyService对象,并调用了该对象的setStreamVolume方法。
AudioPolicyService调用了BnAudioPolicyService::onTransact后回去调用自己的setStreamVolumeIndex方法。而setStreamVolumeIndex的实现在AudioPolicyInterfaceImpl.cpp中。
//frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
return mAudioPolicyManager->setStreamVolumeIndex(stream,
index,
device);
}
//这里调用mAudioPolicyManager->setStreamVolumeIndex(stream, index,device);,AudioPolicyManager下的setStreamVolumeIndex定义在AudioPolicyManager.cpp中:
//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
auto attributes = mEngine->getAttributesForStreamType(stream);
ALOGV("%s: stream %s attributes=%s", __func__,
toString(stream).c_str(), toString(attributes).c_str());
return setVolumeIndexForAttributes(attributes, index, device);
}
//在setStreamVolumeIndex调用setVolumeIndexForAttributes函数:
//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
int index,
audio_devices_t device)
{
// Get Volume group matching the Audio Attributes
auto group = mEngine->getVolumeGroupForAttributes(attributes);
if (group == VOLUME_GROUP_NONE) {
ALOGD("%s: no group matching with %s", __FUNCTION__, toString(attributes).c_str());
return BAD_VALUE;
}
ALOGV("%s: group %d matching with %s", __FUNCTION__, group, toString(attributes).c_str());
status_t status = NO_ERROR;
IVolumeCurves &curves = getVolumeCurves(attributes);
VolumeSource vs = toVolumeSource(group);
product_strategy_t strategy = mEngine->getProductStrategyForAttributes(attributes);
status = setVolumeCurveIndex(index, device, curves);
if (status != NO_ERROR) {
ALOGE("%s failed to set curve index for group %d device 0x%X", __func__, group, device);
return status;
}
audio_devices_t curSrcDevice;
auto curCurvAttrs = curves.getAttributes();
if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
auto attr = curCurvAttrs.front();
curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
} else if (!curves.getStreamTypes().empty()) {
auto stream = curves.getStreamTypes().front();
curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types();
} else {
ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
return BAD_VALUE;
}
curSrcDevice = Volume::getDeviceForVolume(curSrcDevice);
// 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.
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
audio_devices_t curDevice = desc->devices().types();
if (curDevice & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
curDevice |= AUDIO_DEVICE_OUT_SPEAKER;
curDevice &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
}
// Inter / intra volume group priority management: Loop on strategies arranged by priority
// If a higher priority strategy is active, and the output is routed to a device with a
// HW Gain management, do not change the volume
bool applyVolume = false;
if (desc->useHwGain()) {
if (!(desc->isActive(toVolumeSource(group)) || isInCall())) {
continue;
}
for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
false /*preferredDevice*/);
if (activeClients.empty()) {
continue;
}
bool isPreempted = false;
bool isHigherPriority = productStrategy < strategy;
for (const auto &client : activeClients) {
if (isHigherPriority && (client->volumeSource() != vs)) {
ALOGV("%s: Strategy=%d (\nrequester:\n"
" group %d, volumeGroup=%d attributes=%s)\n"
" higher priority source active:\n"
" volumeGroup=%d attributes=%s) \n"
" on output %zu, bailing out", __func__, productStrategy,
group, group, toString(attributes).c_str(),
client->volumeSource(), toString(client->attributes()).c_str(), i);
applyVolume = false;
isPreempted = true;
break;
}
// However, continue for loop to ensure no higher prio clients running on output
if (client->volumeSource() == vs) {
applyVolume = true;
}
}
if (isPreempted || applyVolume) {
break;
}
}
if (!applyVolume) {
continue; // next output
}
status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice,
(vs == toVolumeSource(AUDIO_STREAM_SYSTEM)?
TOUCH_SOUND_FIXED_DELAY_MS : 0));
if (volStatus != NO_ERROR) {
status = volStatus;
}
continue;
}
if (!(desc->isActive(vs) || isInCall())) {
continue;
}
if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) {
continue;
}
if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
curSrcDevice |= device;
applyVolume = (Volume::getDeviceForVolume(curDevice) & curSrcDevice) != 0;
} else {
applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
}
if (applyVolume) {
//FIXME: workaround for truncated touch sounds
// delayed volume change for system stream to be removed when the problem is
// handled by system UI
status_t volStatus = checkAndSetVolume(
curves, vs, index, desc, curDevice,
((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
TOUCH_SOUND_FIXED_DELAY_MS : 0));
if (volStatus != NO_ERROR) {
status = volStatus;
}
}
}
mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
return status;
}
//在setVolumeIndexForAttributes中调用checkAndSetVolume:
//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves,
VolumeSource volumeSource,
int index,
const sp<AudioOutputDescriptor>& outputDesc,
audio_devices_t device,
int delayMs,
bool force)
{
// do not change actual attributes volume if the attributes is muted
if (outputDesc->isMuted(volumeSource)) {
ALOGVV("%s: volume source %d muted count %d active=%d", __func__, volumeSource,
outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
return NO_ERROR;
}
VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL);
VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO);
bool isVoiceVolSrc = callVolSrc == volumeSource;
bool isBtScoVolSrc = btScoVolSrc == volumeSource;
audio_policy_forced_cfg_t forceUseForComm =
mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);
// do not change in call volume if bluetooth is connected and vice versa
// if sco and call follow same curves, bypass forceUseForComm
if ((callVolSrc != btScoVolSrc) &&
((isVoiceVolSrc && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
(isBtScoVolSrc && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO))) {
ALOGV("%s cannot set volume group %d volume with force use = %d for comm", __func__,
volumeSource, forceUseForComm);
return INVALID_OPERATION;
}
if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->devices().types();
}
float volumeDb = computeVolume(curves, volumeSource, index, device); //计算volumeDb
if (outputDesc->isFixedVolume(device) ||
// Force VoIP volume to max for bluetooth SCO
((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
volumeDb = 0.0f;
}
outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force); //AudioPolicyService
if (isVoiceVolSrc || isBtScoVolSrc) {
float voiceVolume;
// Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed by the headset
if (isVoiceVolSrc) {
voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
} else {
voiceVolume = index == 0 ? 0.0 : 1.0;
}
if (voiceVolume != mLastVoiceVolume) {
mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
mLastVoiceVolume = voiceVolume;
}
}
return NO_ERROR;
}
//AudioOutputDescriptor 在 android 中有两个实现,分别是 SwAudioOutputDescriptor 和 HwAudioOutputDescriptor,音量设置的执行来到 SwAudioOutputDescriptor::setVolume():
//frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
bool SwAudioOutputDescriptor::setVolume(float volumeDb,
VolumeSource vs, const StreamTypeVector &streamTypes,
audio_devices_t device,
uint32_t delayMs,
bool force)
{
StreamTypeVector streams = streamTypes;
if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, device, delayMs, force)) {
return false;
}
if (streams.empty()) {
streams.push_back(AUDIO_STREAM_MUSIC);
}
for (const auto& devicePort : devices()) {
// APM loops on all group, so filter on active group to set the port gain,
// let the other groups set the stream volume as per legacy
// TODO: Pass in the device address and check against it.
if (device == devicePort->type() &&
devicePort->hasGainController(true) && isActive(vs)) {
ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str());
// @todo: here we might be in trouble if the SwOutput has several active clients with
// different Volume Source (or if we allow several curves within same volume group)
//
// @todo: default stream volume to max (0) when using HW Port gain?
float volumeAmpl = Volume::DbToAmpl(0);
for (const auto &stream : streams) {
mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
}
AudioGains gains = devicePort->getGains();
int gainMinValueInMb = gains[0]->getMinValueInMb();
int gainMaxValueInMb = gains[0]->getMaxValueInMb();
int gainStepValueInMb = gains[0]->getStepValueInMb();
int gainValueMb = ((volumeDb * 100)/ gainStepValueInMb) * gainStepValueInMb;
gainValueMb = std::max(gainMinValueInMb, std::min(gainValueMb, gainMaxValueInMb));
audio_port_config config = {};
devicePort->toAudioPortConfig(&config);
config.config_mask = AUDIO_PORT_CONFIG_GAIN;
config.gain.values[0] = gainValueMb;
return mClientInterface->setAudioPortConfig(&config, 0) == NO_ERROR;
}
}
// Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is enabled
float volumeAmpl = Volume::DbToAmpl(getCurVolume(vs));
if (hasStream(streams, AUDIO_STREAM_BLUETOOTH_SCO)) {
mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mIoHandle, delayMs);
}
for (const auto &stream : streams) {
ALOGV("%s output %d for volumeSource %d, volume %f, delay %d stream=%s", __func__,
mIoHandle, vs, volumeDb, delayMs, toString(stream).c_str());
mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
}
return true;
}
//SwAudioOutputDescriptor 又通过 AudioPolicyClientInterface 设置音量;AudioPolicyClientInterface 的实现为 AudioPolicyService::AudioPolicyClient,设置音量的动作经 AudioPolicyService::AudioPolicyClient 转回 AudioPolicyService,只是这次调用的是 AudioPolicyService::setStreamVolume();
//frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
int AudioPolicyService::setStreamVolume(audio_stream_type_t stream,float volume,
audio_io_handle_t output,int delayMs)
{
return (int)mAudioCommandThread->volumeCommand(stream, volume,output, delayMs);
}
status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
float volume,audio_io_handle_t output,int delayMs)
{
...(封装了一下data跟command)
return sendCommand(command, delayMs);
}
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs) {...(一些命令队列的操作)}
// 处理函数
bool AudioPolicyService::AudioCommandThread::threadLoop()
{
...
while (!exitPending())
{
...
switch (command->mCommand) {
...
case SET_VOLUME:
...(Lock)
VolumeData *data = (VolumeData *)command->mParam.get();
command->mStatus = AudioSystem::setStreamVolume(data->mStream,
data->mVolume,data->mIO);
break;
...
}
}
//AudioPolicyService异步执行这个操作,最后会转到AudioSystem的setStreamVolume:
//frameworks/av/media/libaudioclient/AudioSystem.cpp
status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
af->setStreamVolume(stream, value, output);
return NO_ERROR;
}
//在AudioSystem的setStreamVolume中会调用AudioFlinger的setStreamVolume:
//frameworks/base/media/java/android/media/audioflinger/AudioFlinger.cpp
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
status_t status = checkStreamType(stream);
if (status != NO_ERROR) {
return status;
}
if (output == AUDIO_IO_HANDLE_NONE) {
return BAD_VALUE;
}
LOG_ALWAYS_FATAL_IF(stream == AUDIO_STREAM_PATCH && value != 1.0f,
"AUDIO_STREAM_PATCH must have full scale volume");
AutoMutex lock(mLock);
VolumeInterface *volumeInterface = getVolumeInterface_l(output);
if (volumeInterface == NULL) {
return BAD_VALUE;
}
volumeInterface->setStreamVolume(stream, value);
return NO_ERROR;
}
//AudioFlinger会去获取output对应的PlaybackThread并设置PlaybackThread的音量,如果output == AUDIOIOHANDLE_NONE,则设置所有PlaybackThread的音量。
PlaybackThread设置mStreamTypes的volume。并唤醒PlaybackThread线程
//frameworks/base/media/java/android/media/audioflinger/Threads.cpp
void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
Mutex::Autolock _l(mLock);
mStreamTypes[stream].volume = value;
broadcast_l();
}