Native的流程处理
前面只是说了AudioService中的逻辑,最终是通过AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
设置到native层的。那么我们就来看看native是怎么处理的。
音频device
setStreamVolumeIndex根据device和流类型来设置,换言之,每种设备的每种流类型的音量是分开的,可以不一样。比如蓝牙耳机的Music音量可以是15,而Speaker的音量可以是5。那么问题来了,上层根本没有 这些逻辑?这个是怎么实现的。我们先来看,怎么获取到的设备!
* frameworks/base/services/core/java/com/android/server/audio/AudioService.java::VolumeStreamState
public int observeDevicesForStream_syncVSS(boolean checkOthers) {
final int devices = AudioSystem.getDevicesForStream(mStreamType);
if (devices == mObservedDevices) {
return devices;
}
final int prevDevices = mObservedDevices;
mObservedDevices = devices;
if (checkOthers) {
// one stream's devices have changed, check the others
observeDevicesForStreams(mStreamType);
}
// log base stream changes to the event log
if (mStreamVolumeAlias[mStreamType] == mStreamType) {
EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
}
sendBroadcastToAll(mStreamDevicesChanged
.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
.putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
return devices;
}
device是通过AudioSystem.getDevicesForStream(mStreamType)
获取到的,mStreamType是流类型,不是映射的别名。
native的getDevicesForStream函数如下:
audio_devices_t AudioSystem::getDevicesForStream(audio_stream_type_t stream)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return AUDIO_DEVICE_NONE;
return aps->getDevicesForStream(stream);
}
最后都是通过AudioPolicy来决定的。
* frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream)
{
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
return AUDIO_DEVICE_NONE;
}
if (mAudioPolicyManager == NULL) {
return AUDIO_DEVICE_NONE;
}
Mutex::Autolock _l(mLock);
return mAudioPolicyManager->getDevicesForStream(stream);
}
mAudioPolicyManagers是AudioPolicy的核心,AudioPolicyService起来的时候就创建了mAudioPolicyManager以及相应的一些线程。
frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
void AudioPolicyService::onFirstRef()
{
{
Mutex::Autolock _l(mLock);
// start tone playback thread
mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
// start audio commands thread
mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
// start output activity command thread
mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
mAudioPolicyClient = new AudioPolicyClient(this);
mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
}
// load audio processing modules
sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
{
Mutex::Autolock _l(mLock);
mAudioPolicyEffects = audioPolicyEffects;
}
}
mAudioPolicyManager通过createAudioPolicyManager函数创建的,AOSP的createAudioPolicyManager如下:
* frameworks/av/services/audiopolicy/manager/AudioPolicyFactory.cpp
extern "C" AudioPolicyInterface* createAudioPolicyManager(
AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManager(clientInterface);
}
Vendor也可以自己实现自己的AudioPolicyManager,比如高通的:
* hardware/qcom/audio/policy_hal/AudioPolicyManager.cpp
extern "C" AudioPolicyInterface* createAudioPolicyManager(
AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManagerCustom(clientInterface);
}
我们继续来看getDevicesForStream函数:
* frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stream) {
// By checking the range of stream before calling getStrategy, we avoid
// getStrategy's behavior for invalid streams. getStrategy would do a ALOGE
// and then return STRATEGY_MEDIA, but we want to return the empty set.
if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) {
return AUDIO_DEVICE_NONE;
}
audio_devices_t devices = AUDIO_DEVICE_NONE;
for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
audio_devices_t curDevices =
getDeviceForStrategy((routing_strategy)curStrategy, false /*fromCache*/);
SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(curDevices, mOutputs);
for (size_t i = 0; i < outputs.size(); i++) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
if (outputDesc->isStreamActive((audio_stream_type_t)curStream)) {
curDevices |= outputDesc->device();
}
}
devices |= curDevices;
}
/*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
and doesn't really need to.*/
if (devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
devices |= AUDIO_DEVICE_OUT_SPEAKER;
devices &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
}
return devices;
}
- streamsMatchForvolume 就是判断两个是否相等
- getStrategy函数,将stream转换为Strategy
- getDeviceForStrategy 根据 Strategy 获取device
- getOutputsForDevice 获取device相关的output
- output相关的device,outputDesc->device()
音频流到音频策略的映射
在native会将流转换为策略,根据策略选择设备等。
* frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
routing_strategy AudioPolicyManager::getStrategy(audio_stream_type_t stream) const
{
ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH");
return mEngine->getStrategyForStream(stream);
}
mEngine是在AudioPolicyManager的构造函数中生成的。
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
:
... ...
{
... ...
// Once policy config has been parsed, retrieve an instance of the engine and initialize it.
audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
if (!engineInstance) {
ALOGE("%s: Could not get an instance of policy engine", __FUNCTION__);
return;
}
// Retrieve the Policy Manager Interface
mEngine = engineInstance->queryInterface<AudioPolicyManagerInterface>();
if (mEngine == NULL) {
ALOGE("%s: Failed to get Policy Engine Interface", __FUNCTION__);
return;
}
mEngine->setObserver(this);
status_t status = mEngine->initCheck();
Engine可以可以配置的,根据 USE_CONFIGURABLE_AUDIO_POLICY
定义,我们这里分析Default的enginedefault。
* frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream)
{
// stream to strategy mapping
switch (stream) {
case AUDIO_STREAM_VOICE_CALL:
case AUDIO_STREAM_BLUETOOTH_SCO:
return STRATEGY_PHONE;
case AUDIO_STREAM_RING:
case AUDIO_STREAM_ALARM:
return STRATEGY_SONIFICATION;
case AUDIO_STREAM_NOTIFICATION:
return STRATEGY_SONIFICATION_RESPECTFUL;
case AUDIO_STREAM_DTMF:
return STRATEGY_DTMF;
default:
ALOGE("unknown stream type %d", stream);
case AUDIO_STREAM_SYSTEM:
// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
// while key clicks are played produces a poor result
case AUDIO_STREAM_MUSIC:
return STRATEGY_MEDIA;
case AUDIO_STREAM_ENFORCED_AUDIBLE:
return STRATEGY_ENFORCED_AUDIBLE;
case AUDIO_STREAM_TTS:
return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
case AUDIO_STREAM_ACCESSIBILITY:
return STRATEGY_ACCESSIBILITY;
case AUDIO_STREAM_REROUTING:
return STRATEGY_REROUTING;
}
}
native声音流的定义:
* system/media/audio/include/system/audio-base.h
typedef enum {
AUDIO_STREAM_DEFAULT = -1, // (-1)
AUDIO_STREAM_MIN = 0,
AUDIO_STREAM_VOICE_CALL = 0,
AUDIO_STREAM_SYSTEM = 1,
AUDIO_STREAM_RING = 2,
AUDIO_STREAM_MUSIC = 3,
AUDIO_STREAM_ALARM = 4,
AUDIO_STREAM_NOTIFICATION = 5,
AUDIO_STREAM_BLUETOOTH_SCO = 6,
AUDIO_STREAM_ENFORCED_AUDIBLE = 7,
AUDIO_STREAM_DTMF = 8,
AUDIO_STREAM_TTS = 9,
AUDIO_STREAM_ACCESSIBILITY = 10,
AUDIO_STREAM_REROUTING = 11,
AUDIO_STREAM_PATCH = 12,
AUDIO_STREAM_PUBLIC_CNT = 11, // (ACCESSIBILITY + 1)
AUDIO_STREAM_FOR_POLICY_CNT = 12, // PATCH
AUDIO_STREAM_CNT = 13, // (PATCH + 1)
} audio_stream_type_t;
策略定义:
* frameworks/av/services/audiopolicy/common/include/RoutingStrategy.h
enum routing_strategy {
STRATEGY_MEDIA,
STRATEGY_PHONE,
STRATEGY_SONIFICATION,
STRATEGY_SONIFICATION_RESPECTFUL,
STRATEGY_DTMF,
STRATEGY_ENFORCED_AUDIBLE,
STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
STRATEGY_ACCESSIBILITY,
STRATEGY_REROUTING,
NUM_STRATEGIES
};
相互将的对应关系如下:
流代号 | 流类型 | Strategy映射 | 描述 |
---|---|---|---|
0 | STREAM_VOICE_CALL | STRATEGY_PHONE | 通话相关音频 |
6 | AUDIO_STREAM_BLUETOOTH_SCO | STRATEGY_PHONE | 蓝牙SCO通话相关音频 |
2 | AUDIO_STREAM_RING | STRATEGY_SONIFICATION | 铃声 |
4 | AUDIO_STREAM_ALARM | STRATEGY_SONIFICATION | 闹钟 |
5 | AUDIO_STREAM_NOTIFICATION | STRATEGY_SONIFICATION_RESPECTFUL | 通知音 |
8 | AUDIO_STREAM_DTMF | STRATEGY_DTMF | DTMF音 |
1 | AUDIO_STREAM_SYSTEM | STRATEGY_MEDIA | 系统音 |
3 | AUDIO_STREAM_MUSIC | STRATEGY_MEDIA | 媒体音 |
7 | AUDIO_STREAM_ENFORCED_AUDIBLE | STRATEGY_ENFORCED_AUDIBLE | 强制为Speaker出声 |
9 | AUDIO_STREAM_TTS | STRATEGY_TRANSMITTED_THROUGH_SPEAKER | TTS 播报 |
10 | AUDIO_STREAM_ACCESSIBILITY | STRATEGY_ACCESSIBILITY | 辅助音 |
11 | AUDIO_STREAM_REROUTING | STRATEGY_REROUTING | 动态输出混音 |
AUDIO_STREAM_ENFORCED_AUDIBLE 这个流是不让用户静音的,强制为Speaker出声。比如拍照音,拍照音是必须Speaker出声的,防偷拍。
回到getDevicesForStream函数~
获取设备
根据流类型,获取到策略后,再根据策略获取相关的设备。
* frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
bool fromCache)
{
// Routing
// see if we have an explicit route
// scan the whole RouteMap, for each entry, convert the stream type to a strategy
// (getStrategy(stream)).
// if the strategy from the stream type in the RouteMap is the same as the argument above,
// and activity count is non-zero and the device in the route descriptor is available
// then select this device.
for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
routing_strategy routeStrategy = getStrategy(route->mStreamType);
if ((routeStrategy == strategy) && route->isActiveOrChanged() &&
(mAvailableOutputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
return route->mDeviceDescriptor->type();
}
}
if (fromCache) {
ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
strategy, mDeviceForStrategy[strategy]);
return mDeviceForStrategy[strategy];
}
return mEngine->getDeviceForStrategy(strategy);
}
最终通过mEngine来实现的。STRATEGY_TRANSMITTED_THROUGH_SPEAKER
* frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
{
DeviceVector availableOutputDevices = mApmObserver->getAvailableOutputDevices();
DeviceVector availableInputDevices = mApmObserver->getAvailableInputDevices();
const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();
return getDeviceForStrategyInt(strategy, availableOutputDevices,
availableInputDevices, outputs);
}
主要实现在 getDeviceForStrategyInt 函数中。getDeviceForStrategyInt函数非常长。这里就不贴全部的代码。起主要有以下几个方面决定:
- 是否在通话中
- 当前是什么流出于Active状态
- 有没有ForceUse
我们来看看STRATEGY_SONIFICATION_RESPECTFUL,AUDIO_STREAM_NOTIFICATION场景的:
case STRATEGY_SONIFICATION_RESPECTFUL:
if (isInCall()) {
device = getDeviceForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
} else if (outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
// while media is playing on a remote device, use the the sonification behavior.
// Note that we test this usecase before testing if media is playing because
// the isStreamActive() method only informs about the activity of a stream, not
// if it's for local playback. Note also that we use the same delay between both tests
device = getDeviceForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
//user "safe" speaker if available instead of normal speaker to avoid triggering
//other acoustic safety mechanisms for notification
if ((device & AUDIO_DEVICE_OUT_SPEAKER) &&
(availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
}
} else if (outputs.isStreamActive(
AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
|| outputs.isStreamActive(
AUDIO_STREAM_ACCESSIBILITY, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY))
{
// while media/a11y is playing (or has recently played), use the same device
device = getDeviceForStrategyInt(
STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
} else {
// when media is not playing anymore, fall back on the sonification behavior
device = getDeviceForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
//user "safe" speaker if available instead of normal speaker to avoid triggering
//other acoustic safety mechanisms for notification
if ((device & AUDIO_DEVICE_OUT_SPEAKER) &&
(availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
}
}
break;
- 如果是通话中,转换为STRATEGY_SONIFICATION
- 如果Remote Music Active,转换为STRATEGY_SONIFICATION,但是如果支持SPEAKER_SAFE,优先使用SPEAKER_SAFE
- 如果AUDIO_STREAM_MUSIC或AUDIO_STREAM_ACCESSIBILITY,转换为STRATEGY_MEDIA
- 其余情况,采用STRATEGY_SONIFICATION,但是如果支持SPEAKER_SAFE,优先使用SPEAKER_SAFE
具体情况,具体看,比较复杂的。Anyway,到此,我们的device算是获取到了。
Native设置音量
音量都是通过AudioSystem的setStreamVolumeIndex函数,设置到native的:
public void applyDeviceVolume_syncVSS(int device) {
int index;
if (mIsMuted) {
index = 0;
} else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} else if ((device & mFullVolumeDevices) != 0) {
index = (mIndexMax + 5)/10;
} else {
index = (getIndex(device) + 5)/10;
}
AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
}
中间的过程省略,我们直接AudioPolicyManager的实现:
* frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
... ...
// Force max volume if stream cannot be muted
if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);
ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d",
stream, device, index);
// update other private stream volumes which follow this one
for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
}
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
(isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
continue;
}
routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy(
curStrategy, false /*fromCache*/));
if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
((curStreamDevice & device) == 0)) {
continue;
}
bool applyVolume;
if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
curStreamDevice |= device;
applyVolume = (curDevice & curStreamDevice) != 0;
} else {
applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
stream, curStreamDevice);
}
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((audio_stream_type_t)curStream, index, desc, curDevice,
(stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);
if (volStatus != NO_ERROR) {
status = volStatus;
}
}
}
}
return status;
}
- mVolumeCurves, 流的描述,是一个集合,用StreamDescriptorCollection表示。具体的流用StreamDescriptor描述。前面的流都是用一个int类型来描述的,现在用StreamDescriptor来描述了。
frameworks/av/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
- Volume的index值,通过addCurrentVolumeIndex,保存到了StreamDescriptor中:
* frameworks/av/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
void StreamDescriptor::addCurrentVolumeIndex(audio_devices_t device, int index)
{
mIndexCur.add(device, index);
}
Volume按照device保存到mIndexCur中:
KeyedVector<audio_devices_t, int> mIndexCur;
- mOutputs 当前的输出设备
每一个输出设备用SwAudioOutputDescriptor
描述:
frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
- 获取设备,再次确认
Volume::getDeviceForVolume
static audio_devices_t getDeviceForVolume(audio_devices_t device)
{
if (device == AUDIO_DEVICE_NONE) {
device = AUDIO_DEVICE_OUT_SPEAKER;
} else if (popcount(device) > 1) {
if (device & AUDIO_DEVICE_OUT_SPEAKER) {
device = AUDIO_DEVICE_OUT_SPEAKER;
} else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
} 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;
return device;
}
- 根据流获取策略,根据测试获取device,再根据device判断是否需要应用音量,音量是通过
checkAndSetVolume
来生效的。
如果当前没有任何流处在active,音量设置时是没有生效的,这根据前面的applyVolume来决定。如果这个时候没有生效,后续在startSource
时,也会checkAndSetVolume。
* frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
int index,
const sp<AudioOutputDescriptor>& outputDesc,
audio_devices_t device,
int delayMs,
bool force)
{
// 静音,不修改音量值
if (outputDesc->mMuteCount[stream] != 0) {
ALOGVV("checkAndSetVolume() stream %d muted count %d",
stream, outputDesc->mMuteCount[stream]);
return NO_ERROR;
}
audio_policy_forced_cfg_t forceUseForComm =
mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);
// 如果是蓝牙通话,不修改音量值,反之亦然
if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
(stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) {
ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
stream, forceUseForComm);
return INVALID_OPERATION;
}
if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->device();
}
// 关键代码computeVolume,计算音量值,将index值转换为Db值。
float volumeDb = computeVolume(stream, index, device);
if (outputDesc->isFixedVolume(device)) {
volumeDb = 0.0f;
}
// 设置音量
outputDesc->setVolume(volumeDb, stream, device, delayMs, force);
// 通话音量,SCO设置为最大,headset自己管理。
if (stream == AUDIO_STREAM_VOICE_CALL ||
stream == AUDIO_STREAM_BLUETOOTH_SCO) {
float voiceVolume;
if (stream == AUDIO_STREAM_VOICE_CALL) {
voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream);
} else {
voiceVolume = 1.0;
}
if (voiceVolume != mLastVoiceVolume) {
mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
mLastVoiceVolume = voiceVolume;
}
}
return NO_ERROR;
}
计算音量Db值
* frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
float volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
// 处理辅助功能开启,响铃的场景
if ((stream == AUDIO_STREAM_ACCESSIBILITY)
&& (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
&& isStreamActive(AUDIO_STREAM_RING, 0)) {
const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
}
// 通话中的场景
if ((stream != AUDIO_STREAM_VOICE_CALL) && (device & AUDIO_DEVICE_OUT_EARPIECE) && isInCall()) {
switch (stream) {
case AUDIO_STREAM_SYSTEM:
case AUDIO_STREAM_RING:
case AUDIO_STREAM_MUSIC:
case AUDIO_STREAM_ALARM:
case AUDIO_STREAM_NOTIFICATION:
case AUDIO_STREAM_ENFORCED_AUDIBLE:
case AUDIO_STREAM_DTMF:
case AUDIO_STREAM_ACCESSIBILITY: {
const float maxVoiceVolDb = computeVolume(AUDIO_STREAM_VOICE_CALL, index, device)
+ IN_CALL_EARPIECE_HEADROOM_DB;
if (volumeDB > maxVoiceVolDb) {
ALOGV("computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f",
stream, volumeDB, AUDIO_STREAM_VOICE_CALL, maxVoiceVolDb);
volumeDB = maxVoiceVolDb;
}
} break;
default:
break;
}
}
// 插耳机的场景,防止响铃等声音过大
const routing_strategy stream_strategy = getStrategy(stream);
if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_WIRED_HEADSET |
AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
AUDIO_DEVICE_OUT_USB_HEADSET)) &&
((stream_strategy == STRATEGY_SONIFICATION)
|| (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
|| (stream == AUDIO_STREAM_SYSTEM)
|| ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
(mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) &&
mVolumeCurves->canBeMuted(stream)) {
// when the phone is ringing we must consider that music could have been paused just before
// by the music application and behave as if music was active if the last music track was
// just stopped
if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
mLimitRingtoneVolume) {
volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC,
mVolumeCurves->getVolumeIndex(AUDIO_STREAM_MUSIC,
musicDevice),
musicDevice);
float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB;
if (volumeDB > minVolDB) {
volumeDB = minVolDB;
ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDB, musicVolDB);
}
if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
// on A2DP, also ensure notification volume is not too low compared to media when
// intended to be played
if ((volumeDB > -96.0f) &&
(musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDB)) {
ALOGV("computeVolume increasing volume for stream=%d device=0x%X from %f to %f",
stream, device,
volumeDB, musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
volumeDB = musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
}
}
} else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
stream_strategy != STRATEGY_SONIFICATION) {
volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
}
}
return volumeDB;
}
Db值通过mVolumeCurves->volIndexToDb,进行转换,转换后,再根据实际的场景进行调整。
我们先来看看Volume::getDeviceCategory
,Audio这边就死麻烦,各种概念。device_category将设备进行分类。
* frameworks/av/services/audiopolicy/common/include/Volume.h
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:
case AUDIO_DEVICE_OUT_USB_HEADSET:
return DEVICE_CATEGORY_HEADSET;
case AUDIO_DEVICE_OUT_LINE:
case AUDIO_DEVICE_OUT_AUX_DIGITAL:
case AUDIO_DEVICE_OUT_USB_DEVICE:
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_REMOTE_SUBMIX:
default:
return DEVICE_CATEGORY_SPEAKER;
}
}
volIndexToDb函数 如下:
float StreamDescriptorCollection::volIndexToDb(audio_stream_type_t stream, device_category category,
int indexInUi) const
{
const StreamDescriptor &streamDesc = valueAt(stream);
return Gains::volIndexToDb(streamDesc.getVolumeCurvePoint(category),
streamDesc.getVolumeIndexMin(), streamDesc.getVolumeIndexMax(),
indexInUi);
}
float Gains::volIndexToDb(const VolumeCurvePoint *curve, int indexMin, int indexMax, int indexInUi)
{
// the volume index in the UI is relative to the min and max volume indices for this stream type
int nbSteps = 1 + curve[Volume::VOLMAX].mIndex - curve[Volume::VOLMIN].mIndex;
int volIdx = (nbSteps * (indexInUi - indexMin)) / (indexMax - indexMin);
// find what part of the curve this index volume belongs to, or if it's out of bounds
int segment = 0;
if (volIdx < curve[Volume::VOLMIN].mIndex) { // out of bounds
return VOLUME_MIN_DB;
} else if (volIdx < curve[Volume::VOLKNEE1].mIndex) {
segment = 0;
} else if (volIdx < curve[Volume::VOLKNEE2].mIndex) {
segment = 1;
} else if (volIdx <= curve[Volume::VOLMAX].mIndex) {
segment = 2;
} else { // out of bounds
return 0.0f;
}
// linear interpolation in the attenuation table in dB
float decibels = curve[segment].mDBAttenuation +
((float)(volIdx - curve[segment].mIndex)) *
( (curve[segment+1].mDBAttenuation -
curve[segment].mDBAttenuation) /
((float)(curve[segment+1].mIndex -
curve[segment].mIndex)) );
ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]",
curve[segment].mIndex, volIdx,
curve[segment+1].mIndex,
curve[segment].mDBAttenuation,
decibels,
curve[segment+1].mDBAttenuation);
return decibels;
}
Db值都是配置在audio_policy_volumes.xml中的。AOSP的
frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml
安装流和设备分类来区分,比如,耳机的通话音量:
<volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
<point>100,0</point>
</volume>
除了直接定义值,还可以引用其他的,比如耳机的媒体音量,DEFAULT_MEDIA_VOLUME_CURVE。
<volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_HEADSET"
ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
DEFAULT_MEDIA_VOLUME_CURVE在另外已给表中:
* frameworks/av/services/audiopolicy/config/default_volume_tables.xml
<reference name="DEFAULT_MEDIA_VOLUME_CURVE">
<!-- Default Media reference Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
所以,我们调节音量时,根据音量的index,来转为对应的db,最终生效的是db。很多用户反馈上面音量调的很大了,但是实际的声音还是小,可能就调调整一下这里的db配置了。
音量生效
计算后的Db值通过setVolume函数设置给output
outputDesc->setVolume(volumeDb, stream, device, delayMs, force);
函数如下:
bool SwAudioOutputDescriptor::setVolume(float volume,
audio_stream_type_t stream,
audio_devices_t device,
uint32_t delayMs,
bool force)
{
bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);
if (changed) {
// Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
// enabled
float volume = Volume::DbToAmpl(mCurVolume[stream]);
if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
mClientInterface->setStreamVolume(
AUDIO_STREAM_VOICE_CALL, volume, mIoHandle, delayMs);
}
mClientInterface->setStreamVolume(stream, volume, mIoHandle, delayMs);
}
return changed;
}
- 先将音量值保存到Descriptor中
bool AudioOutputDescriptor::setVolume(float volume,
audio_stream_type_t stream,
audio_devices_t device __unused,
uint32_t delayMs,
bool force)
{
// We actually change the volume if:
// - the float value returned by computeVolume() changed
// - the force flag is set
if (volume != mCurVolume[stream] || force) {
ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volume, delayMs);
mCurVolume[stream] = volume;
return true;
}
return false;
}
每个output都是安装流类型来保存的mCurVolume[stream]
- 通过mClientInterface的setStreamVolume接口
* frameworks/av/services/audiopolicy/service/AudioPolicyClientImpl.cpp
status_t AudioPolicyService::AudioPolicyClient::setStreamVolume(audio_stream_type_t stream,
float volume, audio_io_handle_t output,
int delay_ms)
{
return mAudioPolicyService->setStreamVolume(stream, volume, output,
delay_ms);
}
AudioPolicyService通过AudioCommandThread,传给AudioManager
* 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);
}
对应的命令:SET_VOLUME
bool AudioPolicyService::AudioCommandThread::threadLoop()
{
nsecs_t waitTime = -1;
mLock.lock();
while (!exitPending())
{
sp<AudioPolicyService> svc;
while (!mAudioCommands.isEmpty() && !exitPending()) {
... ...
case SET_VOLUME: {
VolumeData *data = (VolumeData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set volume stream %d, \
volume %f, output %d", data->mStream, data->mVolume, data->mIO);
command->mStatus = AudioSystem::setStreamVolume(data->mStream,
data->mVolume,
data->mIO);
}break;
最终还是通过AudioSystem的接口来完成:
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;
}
AudioFlinger的setStreamVolume函数如下:
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
ALOGI("setStreamVolume: stream %d, value %f, output %d", stream, value, output);
// 权限
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
// 流类型
status_t status = checkStreamType(stream);
if (status != NO_ERROR) {
return status;
}
ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume");
AutoMutex lock(mLock);
Vector<VolumeInterface *> volumeInterfaces;
//获取volumeInterface
if (output != AUDIO_IO_HANDLE_NONE) {
VolumeInterface *volumeInterface = getVolumeInterface_l(output);
if (volumeInterface == NULL) {
return BAD_VALUE;
}
volumeInterfaces.add(volumeInterface);
}
// 保存音量Db值
mStreamTypes[stream].volume = value;
if (volumeInterfaces.size() == 0) {
volumeInterfaces = getAllVolumeInterfaces_l();
}
// 设置音量值
for (size_t i = 0; i < volumeInterfaces.size(); i++) {
volumeInterfaces[i]->setStreamVolume(stream, value);
}
return NO_ERROR;
}
VolumeInterface 主要用以设置音量,PlaybackThread和MmapPlaybackThread实现VolumeInterface具体的接口:
class VolumeInterface {
public:
virtual ~VolumeInterface() {}
virtual void setMasterVolume(float value) = 0;
virtual void setMasterMute(bool muted) = 0;
virtual void setStreamVolume(audio_stream_type_t stream, float value) = 0;
virtual void setStreamMute(audio_stream_type_t stream, bool muted) = 0;
virtual float streamVolume(audio_stream_type_t stream) const = 0;
};
我们来看看PlaybackThread的setStreamVolume函数:
void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
Mutex::Autolock _l(mLock);
size_t size = mEffectChains.size();
mStreamTypes[stream].volume = value;
for (size_t i = 0; i < size; i++) {
mEffectChains[i]->setStreamVolume_l(stream, value);
}
broadcast_l();
}
PlaybackThread将音量值保存下来了,并设置到音效中。
OK,到此,都全是设置音量的过程,那么是在什么地方生效的呢?
对于MixerThread来说,是在这里生效的,音量值最终会被混音,设置到数据流中。
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
Vector< sp<Track> > *tracksToRemove)
{
... ...
// compute volume for this track
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 typeVolume = mStreamTypes[track->streamType()].volume;
float v = masterVolume * typeVolume;
if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
vl = vr = 0;
vlf = vrf = vaf = 0.;
if (track->isPausing()) {
track->setPaused();
}
} else {
sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
gain_minifloat_packed_t vlr = proxy->getVolumeLR();
vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
// track volumes come from shared memory, so can't be trusted and must be clamped
if (vlf > GAIN_FLOAT_UNITY) {
ALOGV("Track left volume out of range: %.3g", vlf);
vlf = GAIN_FLOAT_UNITY;
}
if (vrf > GAIN_FLOAT_UNITY) {
ALOGV("Track right volume out of range: %.3g", vrf);
vrf = GAIN_FLOAT_UNITY;
}
const float vh = track->getVolumeHandler()->getVolume(
track->mAudioTrackServerProxy->framesReleased()).first;
// now apply the master volume and stream type volume and shaper volume
vlf *= v * vh;
vrf *= v * vh;
// assuming master volume and stream type volume each go up to 1.0,
// then derive vl and vr as U8.24 versions for the effect chain
const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT;
vl = (uint32_t) (scaleto8_24 * vlf);
vr = (uint32_t) (scaleto8_24 * vrf);
// vl and vr are now in U8.24 format
uint16_t sendLevel = proxy->getSendLevel_U4_12();
// send level comes from shared memory and so may be corrupt
if (sendLevel > MAX_GAIN_INT) {
ALOGV("Track send level out of range: %04X", sendLevel);
sendLevel = MAX_GAIN_INT;
}
// vaf is represented as [0.0, 1.0] float by rescaling sendLevel
vaf = v * sendLevel * (1. / MAX_GAIN_INT);
}
我们可以通过adb命令,将thread的各个流的音量都dump出来:
$ adb shell dumpsys media.audio_flinger | grep "Stream volumes in dB"
Stream volumes in dB: 0:-24, 1:-27, 2:-25, 3:-52, 4:0, 5:-27, 6:0, 7:-6, 8:-27, 9:0, 10:-47, 11:0, 12:0
Stream volumes in dB: 0:-24, 1:-27, 2:-25, 3:-52, 4:0, 5:-27, 6:0, 7:-6, 8:-27, 9:0, 10:-47, 11:0, 12:0
Stream volumes in dB: 0:-24, 1:-27, 2:-25, 3:-52, 4:0, 5:-27, 6:0, 7:-6, 8:-27, 9:0, 10:-47, 11:0, 12:0