音量调节JAVA层
按键调节 和 滑动条调节 整体流程区别不大,就将图和在一起了
按键调节
protected void adjustStreamVolume(int streamType, int direction, int flags,
String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
int keyEventMode) {
// lyh 检查调节方向 和 流类型
ensureValidDirection(direction);
ensureValidStreamType(streamType);
// lyh 是否是关于静音的调节(滑动条触发的)
boolean isMuteAdjust = isMuteAdjust(direction);
if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
return;
}
// lyh 流类型的组名
int streamTypeAlias = mStreamVolumeAlias[streamType];
// lyh 根据流类型的别名在流类型列表中找到对应的流信息
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
// lyh 拿device
final int device = getDeviceForStream(streamTypeAlias);
// lyh 当前音量下标值
int aliasIndex = streamState.getIndex(device);
boolean adjustVolume = true;
int step;
// lyh 计算步长
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
mSafeMediaVolumeDevices.contains(device)) {
step = safeMediaVolumeIndex(device);
} else {
step = streamState.getMaxIndex();
}
if (aliasIndex != 0) {
aliasIndex = step;
}
} else {
// convert one UI step (+/-1) into a number of internal units on the stream alias
step = rescaleStep(10, streamType, streamTypeAlias);
}
// lyh 看起来是调节音量时能否改变ringermode状态(组别是:STREAM_SYSTEM 第二个条件成立)
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(streamTypeAlias == getUiSoundsStreamType())) {
int ringerMode = getRingerModeInternal();
// lyh 重要方法
final int result = checkForRingerModeChange(aliasIndex, direction, step,
streamState.mIsMuted, callingPackage, flags);
adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
}
// lyh 音量下标值,不知道和aliasIndex有什么区别
int oldIndex = mStreamStates[streamType].getIndex(device);
// lyh 第一次点击 direction = 0 ,第二次 = 1
if (adjustVolume
&& (direction != AudioManager.ADJUST_SAME) && (keyEventMode != VOL_ADJUST_END)) {
mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
// lyh 滑动条的,设置同一组下的音量状态
if (isMuteAdjust) {
boolean state;
if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
state = !streamState.mIsMuted;
} else {
state = direction == AudioManager.ADJUST_MUTE;
}
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioMute(state);
}
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (streamTypeAlias == mStreamVolumeAlias[stream]) {
if (!(readCameraSoundForced()
&& (mStreamStates[stream].getStreamType()
== AudioSystem.STREAM_SYSTEM_ENFORCED))) {
mStreamStates[stream].mute(state);
}
}
}
} else if ((direction == AudioManager.ADJUST_RAISE) &&
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
// lyh 安全音量提示
mVolumeController.postDisplaySafeVolumeWarning(flags);
} else if (!isFullVolumeDevice(device)
&& (streamState.adjustIndex(direction * step, device, caller,
hasModifyAudioSettings)
|| streamState.mIsMuted)) {
if (streamState.mIsMuted) {
if (direction == AudioManager.ADJUST_RAISE) {
streamState.mute(false);
} else if (direction == AudioManager.ADJUST_LOWER) {
if (mIsSingleVolume) {
sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
}
}
}
// lyh 发送Handler消息
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
}
// lyh 调整后的音量新下标
final int newIndex = mStreamStates[streamType].getIndex(device);
// lyh HDMI 相关
if (adjustVolume) {
synchronized (mHdmiClientLock) {
if (mHdmiManager != null) {
...
}
}
}
// lyh 更新
sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_DEVICE_VOLUME:
setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
break;
}
}
void setDeviceVolume(VolumeStreamState streamState, int device) {
synchronized (VolumeStreamState.class) {
// Apply volume
// lyh 设置音量
streamState.applyDeviceVolume_syncVSS(device);
// Apply change to all streams using this one as alias
// 修改同一组下的流音量
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != streamState.mStreamType &&
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
// Make sure volume is also maxed out on A2DP device for aliased stream
// that may have a different device selected
int streamDevice = getDeviceForStream(streamType);
if ((device != streamDevice) && mAvrcpAbsVolSupported
&& AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {
mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
}
mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
}
}
}
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
PERSIST_DELAY);
}
void applyDeviceVolume_syncVSS(int device) {
int index;
if (isFullyMuted()) {
index = 0;
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& mAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} else if (isFullVolumeDevice(device)) {
index = (mIndexMax + 5)/10;
} else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
} else {
index = (getIndex(device) + 5)/10;
}
setStreamVolumeIndex(index, device);
}
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;
}
int streamType = mStreamType;
if (mStreamType >= AudioSystem.STREAM_VOICE_CALL_GS_MIN && mStreamType <= AudioSystem.STREAM_VOICE_CALL_GS_MAX) {
streamType = AudioSystem.STREAM_VOICE_CALL;
}
if (DEBUG_VOL) Log.i(TAG, "setStreamVolumeIndex mStreamType " + mStreamType + ", streamType " + streamType + ", index " + index);
AudioSystem.setStreamVolumeIndexAS(streamType, index, device);
}
滑动条调节
private void setStreamVolume() {
ensureValidStreamType(streamType);
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
// lyh 拿device
final int device = getDeviceForStream(streamType);
int oldIndex;
synchronized (mSafeMediaVolumeStateLock) {
// reset any pending volume command
mPendingVolumeCommand = null;
oldIndex = streamState.getIndex(device);
index = rescaleIndex(index * 10, streamType, streamTypeAlias);
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
}
// lyh 检查是否安全音量
if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
mVolumeController.postDisplaySafeVolumeWarning(flags);
mPendingVolumeCommand = new StreamVolumeCommand(
streamType, index, flags, device);
} else {
// lyh 调节音量
onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings);
index = mStreamStates[streamType].getIndex(device);
}
}
// lyh 音量更新
sendVolumeUpdate(streamType, oldIndex, index, flags, device);
}
private void onSetStreamVolume() {
final int stream = mStreamVolumeAlias[streamType];
// lyh
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*/);
}
}
private void setStreamVolumeInt() {
VolumeStreamState streamState = mStreamStates[streamType];
// 发送Handler消息,与按键调节流程一致了
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
音量调节Native层
static jint
android_media_AudioSystem_setStreamVolumeIndex()
{
return (jint) check_AudioSystem_Command(
AudioSystem::setStreamVolumeIndex()
);
}
status_t AudioSystem::setStreamVolumeIndex()
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
return aps->setStreamVolumeIndex(stream, index, device);
}
status_t AudioPolicyManager::setStreamVolumeIndex()
{
return setVolumeIndexForAttributes(attributes, index, device);
}
status_t AudioPolicyManager::setVolumeIndexForAttributes()
{
// lyh 遍历所有设备
for (size_t i = 0; i < mOutputs.size(); i++) {
// lyh 设备描述符
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
DeviceTypeSet curDevices = desc->devices().types();
// lyh 检查并设置音量
status_t volStatus = checkAndSetVolume(
curves, vs, index, desc, curDevices,
((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
TOUCH_SOUND_FIXED_DELAY_MS : 0));
}
mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
return status;
}
status_t AudioPolicyManager::checkAndSetVolume()
{
// lyh 计算音量
float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
// lyh 设置音量 SwAudioOutputDescriptor::setVolume
outputDesc->setVolume(
volumeDb, volumeSource, curves.getStreamTypes(), deviceTypes, delayMs, force);
return NO_ERROR;
}
bool SwAudioOutputDescriptor::setVolume()
{
for (const auto& devicePort : devices()) {
// lyh 遍历设置音量
for (const auto &stream : streams) {
// lyh mClientInterface == AudioPolicyService
mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
}
}
}
return true;
}
int AudioPolicyService::setStreamVolume()
{
return (int)mAudioCommandThread->volumeCommand(stream, volume,
output, delayMs);
}
status_t AudioPolicyService::AudioCommandThread::volumeCommand()
{
sp<AudioCommand> command = new AudioCommand();
command->mCommand = SET_VOLUME;
sp<VolumeData> data = new VolumeData();
data->mStream = stream;
data->mVolume = volume;
data->mIO = output;
command->mParam = data;
command->mWaitStatus = true;
// lyh 发送指令[SET_VOLUME]去调节音量
return sendCommand(command, delayMs);
}
status_t AudioPolicyService::AudioCommandThread::sendCommand()
{
{
Mutex::Autolock _l(mLock);
insertCommand_l(command, delayMs);
// lyh 唤醒AudioCommandThread
mWaitWorkCV.signal();
}
Mutex::Autolock _l(command->mLock);
while (command->mWaitStatus) {
nsecs_t timeOutNs = kAudioCommandTimeoutNs + milliseconds(delayMs);
if (command->mCond.waitRelative(command->mLock, timeOutNs) != NO_ERROR) {
command->mStatus = TIMED_OUT;
command->mWaitStatus = false;
}
}
return command->mStatus;
}
bool AudioPolicyService::AudioCommandThread::threadLoop()
{
switch (command->mCommand) {
case SET_VOLUME: {
// lyh 又回到AudioSystem跨进程调用AudioFlinger
command->mStatus = AudioSystem::setStreamVolume(data->mStream,
data->mVolume,
data->mIO);
mLock.lock();
}
break;
}
}
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
// lyh 通过继承关系知道【VolumeInterface = PlaybackThread】
VolumeInterface *volumeInterface = getVolumeInterface_l(output);
if (volumeInterface == NULL) {
return BAD_VALUE;
}
volumeInterface->setStreamVolume(stream, value);
return NO_ERROR;
}
void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
Mutex::Autolock _l(mLock);
// 赋值
mStreamTypes[stream].volume = value;
// lyh 通知,PlaybackThread线程(例MixerThread)
broadcast_l();
}