Audio System调节音量分析

1.调节音量:
先从上层往下一步步的走吧,和大家分享一下刨根问底的乐趣。
在应用中先实例化一个AudioManager:
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
am对象就可以调用关于音量调节的方法:这些方法的定义都在audiomanager.java中。
在audiomanager.java文件中的方法调用audioservice.java的方法:

  1. public void adjustStreamVolume(int streamType, int direction, int flags) 方法体

public void adjustStreamVolume(int streamType, int direction, int flags) {
IAudioService service = getService();
try {
service.adjustStreamVolume(streamType, direction, flags);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustStreamVolume", e);
}
}
调用IAudioService service = getService();获得audio服务,下面是服务接口:
service.adjustStreamVolume(streamType, direction, flags);他们在IAudioService.java中定义。
在audioservice.java中有该方法的实现。
public void adjustStreamVolume(int streamType, int direction, int flags) {
ensureValidDirection(direction);
ensureValidStreamType(streamType);
VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex;
boolean adjustVolume = true;
// If either the client forces allowing ringer modes for this adjustment,
// or the stream type is one that is affected by ringer modes
if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0

streamType == AudioSystem.STREAM_RING) {
// Check if the ringer mode changes with this volume adjustment. If
// it does, it will handle adjusting the volume, so we won't below
adjustVolume = checkForRingerModeChange(oldIndex, direction);
}
// If stream is muted, adjust last audible index only
int index;
if (streamState.muteCount() != 0) {
index = streamState.mLastAudibleIndex;
} else {
if (adjustVolume && streamState.adjustIndex(direction)) {
// Post message to set system volume (it in turn will post a message
// to persist). Do not change volume if stream is muted sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0,streamState, 0);
}
index = streamState.mIndex;
}
// UI
mVolumePanel.postVolumeChanged(streamType, flags);
// Broadcast Intent
sendVolumeUpdate(streamType, oldIndex, index);
}
在这个函数中:

  1. checkForRingerModeChange(oldIndex, direction);

oldIndex是以前的音量,direction表示增加还是降低音量。这个函数用于检测改变铃声模式,如振动,静音等,是通过调用setRingerMode函数来实现的。而setRingerMode通过发送广播(调用broadcastRingerMode函数)来通知模式的改变。

  1. sendMsg(): 发送消息,处理这个消息的是handleMessage()函数,调用setStreamVolumeIndex来调节音量,

private void setStreamVolumeIndex(int stream, int index) {
AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10);
}
现在又跑到audiosystem.java中。调用audiosystem.java中的setStreamVolumeIndex
public static native int setStreamVolumeIndex(int stream, int index);通过JNI调用再看看audiosystem.cpp。在audiosystem.cpp中的setStreamVolumeIndex如下:
status_t AudioSystem::setStreamVolumeIndex(stream_type stream, int index)
{
const sp& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->setStreamVolumeIndex(stream, index);
}
其实,最终是通过AudioPolicyService的对应函数实现的。再看看AudioPolicyService.cpp文件中的setStreamVolumeIndex。
status_t AudioPolicyService::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
{
if (mpPolicyManager == NULL) {
return NO_INIT;
}
if (!checkPermission()) {
return PERMISSION_DENIED;
}
if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
return BAD_VALUE;
}
return mpPolicyManager->setStreamVolumeIndex(stream, index);
}
mpPolicyManager->setStreamVolumeIndex(stream, index);
是在AudioPolicyInterface.h中声明,在AudioPolicyManagerBase.cpp中从新定义的成员函数。
#include 有此为证!
status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
return BAD_VALUE;
}
// Force max volume if stream cannot be muted
if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
LOGD("setStreamVolumeIndex() stream %d, index %d", stream, index);
mStreams[stream].mIndexCur = index;
// compute and apply stream volume on all outputs according to connected device
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt, mOutputs.valueAt->device());
if (volStatus != NO_ERROR) {
status = volStatus;
}
}
return status;
}
在AudioPolicyManagerBase.cpp中找到checkAndSetVolume。
status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force)
{
// do not change actual stream volume if the stream is muted
if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
LOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]);
return NO_ERROR;
}
// do not change in call volume if bluetooth is connected and vice versa
if((stream==AudioSystem::VOICE_CALL&&mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||(stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
LOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
return INVALID_OPERATION;
}
float volume = computeVolume(stream, index, output, device);
// We actually change the volume if:
// - the float value returned by computeVolume() changed
// - the force flag is set
if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
(stream == AudioSystem::VOICE_CALL) || force) {
mOutputs.valueFor(output)->mCurVolume[stream] = volume;
LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::DTMF ||
stream == AudioSystem::BLUETOOTH_SCO) {
// offset value to reflect actual hardware volume that never reaches 0
// 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
volume = 0.01 + 0.99 * volume;
}
mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
}
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::BLUETOOTH_SCO) {
float voiceVolume;
// Force voice volume to max for bluetooth SCO as volume is managed by the headset
if (stream == AudioSystem::VOICE_CALL) {
voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
} else {
voiceVolume = 1.0;
}
if (voiceVolume != mLastVoiceVolume && output == mHardwareOutput) {
mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
mLastVoiceVolume = voiceVolume;
}
}
return NO_ERROR;
}
mpClientInterface对象不在该文件中声明,但是它由构造函数AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)的参数传递过来。现在找一下AudioPolicyManagerBase在哪里被实例化,经查找在AudioPolicyService::AudioPolicyService()
: BnAudioPolicyService() , mpPolicyManager(NULL)
{
char value[PROPERTY_VALUE_MAX];
// start tone playback thread
mTonePlaybackThread = new AudioCommandThread(String8(""));
// start audio commands thread
mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));
#if defined (GENERIC_AUDIO) || defined (AUDIO_POLICY_TEST)
mpPolicyManager = new AudioPolicyManagerBase(this);
LOGV("build for GENERIC_AUDIO - using generic audio policy");
#else
// if running in emulation - use the emulator driver
if (property_get("ro.kernel.qemu", value, 0)) {
LOGV("Running in emulation - using generic audio policy");
mpPolicyManager = new AudioPolicyManagerBase(this);
}
else {
LOGV("Using hardware specific audio policy");
mpPolicyManager = createAudioPolicyManager(this);
}
#endif
// load properties
property_get("ro.camera.sound.forced", value, "0");
mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
}中被实例化。
在AudioPolicyService类继承了public BnAudioPolicyService, public AudioPolicyClientInterface,
public IBinder::DeathRecipient三个类,在AudioPolicyService中找到函数setStreamVolume和setVoiceVolume
status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream,
float volume,
audio_io_handle_t output,
int delayMs)
{
return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs);
}
status_t AudioPolicyService::setVoiceVolume(float volume, int delayMs)
{
return mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
}
他们都是调用mAudioCommandThread类中的函数,实现音量的改变。
status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume, int delayMs)
{
status_t status = NO_ERROR;
AudioCommand *command = new AudioCommand();
command->mCommand = SET_VOICE_VOLUME;
VoiceVolumeData *data = new VoiceVolumeData();
data->mVolume = volume;
command->mParam = data;
if (delayMs == 0) {
command->mWaitStatus = true;
} else {
command->mWaitStatus = false;
}
Mutex::Autolock _l(mLock);
insertCommand_l(command, delayMs);
LOGV("AudioCommandThread() adding set voice volume volume %f", volume);
mWaitWorkCV.signal();
if (command->mWaitStatus) {
command->mCond.wait(mLock);
status = command->mStatus;
mWaitWorkCV.signal();
}
return status;
}

status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream,
float volume,
int output,
int delayMs)
{
status_t status = NO_ERROR;
AudioCommand *command = new AudioCommand();
command->mCommand = SET_VOLUME;
VolumeData *data = new VolumeData();
data->mStream = stream;
data->mVolume = volume;
data->mIO = output;
command->mParam = data;
if (delayMs == 0) {
command->mWaitStatus = true;
} else {
command->mWaitStatus = false;
}
Mutex::Autolock _l(mLock);
insertCommand_l(command, delayMs);
LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d",
stream, volume, output);
mWaitWorkCV.signal();
if (command->mWaitStatus) {
command->mCond.wait(mLock);
status = command->mStatus;
mWaitWorkCV.signal();
}
return status;
}
以上两个函数中都是自动加锁后,开始调节音量。
Mutex::Autolock _l(mLock);
insertCommand_l(command, delayMs);函数定义如下:
// insertCommand_l() must be called with mLock held
void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
{
ssize_t i;
Vector removedCommands;
command->mTime = systemTime() + milliseconds(delayMs);
// acquire wake lock to make sure delayed commands are processed
if (mName != "" && mAudioCommands.isEmpty()) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, mName.string());
}
// check same pending commands with later time stamps and eliminate them
for (i = mAudioCommands.size()1; i >= 0; i-) {
AudioCommand *command2 = mAudioCommands[i];
// commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
if (command2->mTime <= command->mTime) break;
if (command2->mCommand != command->mCommand) continue;
switch (command->mCommand) {
case SET_PARAMETERS: {
ParametersData *data = (ParametersData *)command->mParam;
ParametersData *data2 = (ParametersData *)command2->mParam;
if (data->mIO != data2->mIO) break;
LOGV("Comparing parameter command %s to new command %s",
data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
AudioParameter param = AudioParameter(data->mKeyValuePairs);
AudioParameter param2 = AudioParameter(data2->mKeyValuePairs);
for (size_t j = 0; j < param.size(); j++) {
String8 key;
String8 value;
param.getAt(j, key, value);
for (size_t k = 0; k < param2.size(); k++) {
String8 key2;
String8 value2;
param2.getAt(k, key2, value2);
if (key2 == key) {
param2.remove(key2);
LOGV("Filtering out parameter %s", key2.string());
break;
}
}
}
// if all keys have been filtered out, remove the command.
// otherwise, update the key value pairs
if (param2.size() == 0) {
removedCommands.add(command2);
} else {
data2->mKeyValuePairs = param2.toString();
}
} break;
case SET_VOLUME: {
VolumeData *data = (VolumeData *)command->mParam;
VolumeData *data2 = (VolumeData *)command2->mParam;
if (data->mIO != data2->mIO) break;
if (data->mStream != data2->mStream) break;
LOGV("Filtering out volume command on output %d for stream %d",
data->mIO, data->mStream);
removedCommands.add(command2);
} break;
case SET_FM_VOLUME: {
removedCommands.add(command2);
} break;
case START_TONE:
case STOP_TONE:
default:
break;
}
}
// remove filtered commands
for (size_t j = 0; j < removedCommands.size(); j++) {
// removed commands always have time stamps greater than current command
for (size_t k = i + 1; k < mAudioCommands.size(); k++) {
if (mAudioCommands[k] == removedCommands[j]) {
LOGV("suppressing command: %d", mAudioCommands[k]->mCommand);
mAudioCommands.removeAt(k);
break;
}
}
}
removedCommands.clear();
// insert command at the right place according to its time stamp
LOGV("inserting command: %d at index %d, num commands %d",
command->mCommand, (int)i+1, mAudioCommands.size());
mAudioCommands.insertAt(command, i + 1);
}
3. mVolumePanel.postVolumeChanged(streamType, flags); //更新音量改变UI.
4. sendVolumeUpdate:发送AudioManager.VOLUME_CHANGED_ACTION,处理intent的目的是用于播放那个短促的蜂鸣声(见ToneGenerator.java的startTone)。
5. ToneGenerator.java的startTone的分析: 通过jni调用到ToneGenerator.cpp的startTone函数。

  1. public void adjustVolume(int direction, int flags) 方法体

public void adjustVolume(int direction, int flags) {
IAudioService service = getService();
try {
service.adjustVolume(direction, flags);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustVolume", e);
}
}
调用IAudioService service = getService();
service.adjustVolume(direction, flags);他们在IAudioService.java中定义。在audioservice.java中有该方法的实现。查找方法同上

  1. public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags)

方法体
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
IAudioService service = getService();
try {
service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustVolume", e);
}
}
调用IAudioService service = getService();
service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
他们在IAudioService.java文件中定义。在audioservice.java中有该方法的实现。
查找方法同上
4.public void setStreamVolume(int streamType, int index, int flags) 方法体
public void setStreamVolume(int streamType, int index, int flags) {
IAudioService service = getService();
try {
service.setStreamVolume(streamType, index, flags);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setStreamVolume", e);
}
}
调用IAudioService service = getService();
service.setStreamVolume(streamType, index, flags);
他们在IAudioService.java文件中定义。在audioservice.java中有该方法的实现。
现在转到IAudioService.java文件:IAudioService.java文件是接口文件,在audioservice.java文件中实现音量调节函数的定义。
查找方法同上

 

你可能感兴趣的:(audio)