從函數 AudioFlinger::PlaybackThread::Track::start 開始分析。
frameworks\base\services\AudioFlinger.cpp
status_t AudioFlinger::PlaybackThread::Track::start() { status_t status = NO_ERROR; LOGV("start(%d), calling thread %d session %d", mName, IPCThreadState::self()->getCallingPid(), mSessionId); sp<ThreadBase> thread = mThread.promote(); if (thread != 0) { Mutex::Autolock _l(thread->mLock); int state = mState; // here the track could be either new, or restarted // in both cases "unstop" the track if (mState == PAUSED) { mState = TrackBase::RESUMING; LOGV("PAUSED => RESUMING (%d) on thread %p", mName, this); } else { mState = TrackBase::ACTIVE; LOGV("? => ACTIVE (%d) on thread %p", mName, this); } if (!isOutputTrack() && state != ACTIVE && state != RESUMING) { thread->mLock.unlock(); status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType, mSessionId); thread->mLock.lock(); } if (status == NO_ERROR) { PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); playbackThread->addTrack_l(this); } else { mState = state; } } else { status = BAD_VALUE; } return status; }
status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; return aps->startOutput(output, stream, session); } status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) { if (mpPolicyManager == NULL) { return NO_INIT; } LOGV("startOutput() tid %d", gettid()); Mutex::Autolock _l(mLock); return mpPolicyManager->startOutput(output, stream, session);
}
// 主要的處理是從這兒開始的 status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) { LOGV("startOutput() output %d, stream %d, session %d", output, stream, session); ssize_t index = mOutputs.indexOfKey(output); if (index < 0) { LOGW("startOutput() unknow output %d", output); return BAD_VALUE; } AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); // 函數 getStrategy 就是根據 stream type 返回特定的 strategy routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
需要知道每種策略分別是用來做什么的。
所以首先要知道策略對應的 stream type
AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy( AudioSystem::stream_type stream) { // stream to strategy mapping switch (stream) { case AudioSystem::VOICE_CALL: // 電話來了 case AudioSystem::BLUETOOTH_SCO: // 藍牙耳機接通了 return STRATEGY_PHONE; case AudioSystem::RING: // 鈴聲響了 case AudioSystem::NOTIFICATION: // 通知,例如界面中最上面一欄中有消息了 case AudioSystem::ALARM: // 警告,電池沒電時的警告? case AudioSystem::ENFORCED_AUDIBLE: return STRATEGY_SONIFICATION; case AudioSystem::DTMF: // 可參考鏈接:http://baike.baidu.com/view/171916.htm return STRATEGY_DTMF; default: LOGE("unknown stream type"); case AudioSystem::SYSTEM: // 系統聲音采用 media strategy, 例如,如果正在播放音樂的時候按鍵, // mute 掉音樂,並切換 output 的話,將導致 很差的用戶體驗。 // 其中可以得到以下信息: // 1、按鍵聲音屬於 system stream type 。 // 2、策略的改變將會導致 output 的切換 // 3、優先級高的策略 start 時會 mute 掉優先級低的策略 // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs // while key clicks are played produces a poor result case AudioSystem::TTS: // TTS 就是 Text To Speech case AudioSystem::MUSIC: return STRATEGY_MEDIA; } }
// incremenent usage count for this stream on the requested output: // NOTE that the usage count is the same for duplicated output and hardware output which is // necassary for a correct control of hardware output routing by startOutput() and stopOutput() // 增加請求的 output 上該 stream 的使用計數 // 注意: duplicated output 和 hardware output 中的使用計數是相同的。 // 因為這對通過 startOutput() 函數和 stopOutput() 函數正確地控制 hardware output routing 是必要的。 outputDesc->changeRefCount(stream, 1); void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta) { // forward usage count change to attached outputs // 如果是 duplicated 的,需要改變它所包含的兩個 output 中的使用計數。 if (isDuplicated()) { mOutput1->changeRefCount(stream, delta); mOutput2->changeRefCount(stream, delta); } if ((delta + (int)mRefCount[stream]) < 0) { LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]); mRefCount[stream] = 0; return; } mRefCount[stream] += delta; LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]); }
setOutputDevice(output, getNewDevice(output)); uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache) { uint32_t device = 0; AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); // check the following by order of priority to request a routing change if necessary: // 1: we are in call or the strategy phone is active on the hardware output: // use device for strategy phone // 2: the strategy sonification is active on the hardware output: // use device for strategy sonification // 3: the strategy media is active on the hardware output: // use device for strategy media // 4: the strategy DTMF is active on the hardware output: // use device for strategy DTMF // 根據以下的優先級順序,來檢查必要的路線改變 // 1、如果來電話了,或者 hardware output 中的 strategy phone 是活動的, // 則使用 phone strategy 。 // 有兩種情況會使用到 strategy phone ,來電話了和藍牙耳機接通了。 // 2、如果 hardware output 中的 strategy sonification 是活動的, // 則使用 strategy sonification . // 有四種情況會使用 stratety sonification ,來電鈴聲,通知,警告, // 和是 ENFORCED_AUDIBLE stream 的時候。 // 3、如果 hardware output 中的 strategy media 是活動的, // 則使用 strategy media . // Media 播放, 系統聲音和 TTS 會使用 media 策略。 // 4、如果 hardware output 中的 strategy DTMF 是活動的, // 則使用 strategy DTMF . // 在 stream type 是 DTMF 的時候會使用 DTMF 策略。 // 關於 DTMF 請參考 http://baike.baidu.com/view/171916.htm if (isInCall() || outputDesc->isUsedByStrategy(STRATEGY_PHONE)) { // bool isUsedByStrategy(routing_strategy strategy) { return (strategyRefCount(strategy) != 0);}
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) { device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) { device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) { device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); }
LOGV("getNewDevice() selected device %x", device); return device;
}
// 檢查 output 中是否使用了指定的 strategy uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount(routing_strategy strategy) { uint32_t refCount = 0; for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { if (getStrategy((AudioSystem::stream_type)i) == strategy) { refCount += mRefCount[i]; } } return refCount; }
bool AudioPolicyManagerBase::isInCall() { // 函數 AudioPolicyManagerBase::setPhoneState 中會改變 mPhoneState 的值 // 調用關系:android_media_AudioSystem_setPhoneState // 調用 AudioSystem::setPhoneState // 調用 AudioPolicyService::setPhoneState // 調用 AudioPolicyManagerBase::setPhoneState return isStateInCall(mPhoneState); }
bool AudioPolicyManagerBase::isStateInCall(int state) { return ((state == AudioSystem::MODE_IN_CALL) || (state == AudioSystem::MODE_IN_COMMUNICATION)); enum audio_mode { MODE_INVALID = -2, MODE_CURRENT = -1, MODE_NORMAL = 0, MODE_RINGTONE, MODE_IN_CALL, MODE_IN_COMMUNICATION, NUM_MODES // not a valid entry, denotes end-of-list }; uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache) { uint32_t device = 0; if (fromCache) { LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]); return mDeviceForStrategy[strategy]; } switch (strategy) { case STRATEGY_DTMF: if (!isInCall()) { // 不是打電話過來或者在通話中的話,DTMF strategy 和 MEDIA strategy 規則一樣 // when off call, DTMF strategy follows the same rules as MEDIA strategy device = getDeviceForStrategy(STRATEGY_MEDIA, false); break; } // 有電話打過來,或者在通話中的話, DTMF strategy 和 PHONE strategy 規則一致 // when in call, DTMF and PHONE strategies follow the same rules // FALL THROUGH case STRATEGY_PHONE: // 對於 PHONE strategy , 首先判斷是否強制要求使用了什么設備,然后再根據優先級順序,尋找可用的 device // for phone strategy, we first consider the forced use and then the available devices by order // of priority switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { case AudioSystem::FORCE_BT_SCO: if (!isInCall() || strategy != STRATEGY_DTMF) { // 不是上述兩種情況的話,肯定是outputDesc->isUsedByStrategy(STRATEGY_PHONE)作為條件走到這一步的 device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT; if (device) break; } device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET; if (device) break; device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO; if (device) break; // 如果請求了 SCO device ,但是沒有 SCO device 可用,則進入 default case // if SCO device is requested but no SCO device is available, fall back to default case // FALL THROUGH default: // FORCE_NONE device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE; if (device) break; device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET; if (device) break; #ifdef WITH_A2DP // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP if (!isInCall()) { device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP; if (device) break; device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; if (device) break; } #endif device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE; if (device == 0) { LOGE("getDeviceForStrategy() earpiece device not found"); } break; case AudioSystem::FORCE_SPEAKER: if (!isInCall() || strategy != STRATEGY_DTMF) { device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT; if (device) break; } #ifdef WITH_A2DP // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to // A2DP speaker when forcing to speaker output if (!isInCall()) { device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; if (device) break; } #endif device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; if (device == 0) { LOGE("getDeviceForStrategy() speaker device not found"); } break; } break; case STRATEGY_SONIFICATION: // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by // handleIncallSonification(). if (isInCall()) { device = getDeviceForStrategy(STRATEGY_PHONE, false); break; } device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; if (device == 0) { LOGE("getDeviceForStrategy() speaker device not found"); } // The second device used for sonification is the same as the device used by media strategy // FALL THROUGH case STRATEGY_MEDIA: { uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL; if (device2 == 0) { device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HDMI; } if (device2 == 0) { device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE; } if (device2 == 0) { device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET; } #ifdef WITH_A2DP if (mA2dpOutput != 0) { if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) { break; } if (device2 == 0) { device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP; } if (device2 == 0) { device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; } if (device2 == 0) { device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; } } #endif if (device2 == 0) { device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; } // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION, 0 otherwise device |= device2; if (device == 0) { LOGE("getDeviceForStrategy() speaker device not found"); } } break; default: LOGW("getDeviceForStrategy() unknown strategy: %d", strategy); break; } LOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device); return device; }
void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs) { LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs); AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); // 如果 output 是 duplicated 的,直接去處理其包含的兩個 output if (outputDesc->isDuplicated()) { setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); return; } #ifdef WITH_A2DP // filter devices according to output selected if (output == m A2dpOutput) { device &= AudioSystem::DEVICE_OUT_ALL_A2DP; } else { device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP; } #endif uint32_t prevDevice = (uint32_t)outputDesc->device(); // Do not change the routing if: // - the requestede device is 0 // - the requested device is the same as current device and force is not specified. // Doing this check here allows the caller to call setOutputDevice() without conditions if ((device == 0 || device == prevDevice) && !force) { LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output); return; } // 修改 output 中的 current device outputDesc->mDevice = device; // mute media streams if both speaker and headset are selected if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) { setStrategyMute(STRATEGY_MEDIA, true, output); // mute 掉指定 strategy 對應的所有 stream void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output, int delayMs) { LOGV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output); for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { if (getStrategy((AudioSystem::stream_type)stream) == strategy) { setStreamMute(stream, on, output, delayMs); void AudioPolicyManagerBase::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs) { StreamDescriptor &streamDesc = mStreams[stream]; AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); LOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]); if (on) { if (outputDesc->mMuteCount[stream] == 0) { // 如果該 stream 還沒有 mute 過,則對其進行 mute if (streamDesc.mCanBeMuted) { // mute 其實就是將 stream 的音量設置為 0 // checkAndSetVolume 函數在此處就先不看了,等到下面看音量設置的時候在分析 checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs); } } // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored // 將 mute 計數加1,以防止聲音改變被忽略 outputDesc->mMuteCount[stream]++; } else { if (outputDesc->mMuteCount[stream] == 0) { // 如果 mute 計數為0,不進行任何操作 LOGW("setStreamMute() unmuting non muted stream!"); return; } if (--outputDesc->mMuteCount[stream] == 0) { // mute 計數減1,若 mute 計數變為0,則將 stream 變為 mute off // 也就是恢復 stream 的音量 checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs); } } }
usleep(outputDesc->mLatency*2*1000); } // do the routing AudioParameter param = AudioParameter(); param.addInt(String8(AudioParameter::keyRouting), (int)device); // 調用的其實是函數 AudioPolicyService::setParameters // 會通過函數 AudioPolicyService::AudioCommandThread::parametersCommand 向 AudioCommandThread 的 command list // 添加一個 command // AudioPolicyService::AudioCommandThread::threadLoop 函數中會處理 command list 中的 command // 對於 SET_PARAMETERS command ,最終調用了函數 AudioSystem::setParameters // 調用了 AudioFlinger::setParameters 函數 // 調用了 AudioFlinger::ThreadBase::setParameters 函數添加成員到 mNewParameters // 函數 AudioFlinger::MixerThread::checkForNewParameters_l 中會處理 mNewParameters 中的參數 // 函數 AudioFlinger::MixerThread::threadLoop 會調用函數 AudioFlinger::MixerThread::checkForNewParameters_l mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs); // update stream volumes according to new device applyStreamVolumes(output, device, delayMs);
+++++++++++++++++++++++++AudioPolicyManagerBase::applyStreamVolumes+++++++++++++++++++++++++++++++++++++++ 從函數 AudioPolicyManagerBase::setOutputDevice 進入: void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, uint32_t device, int delayMs) { LOGV("applyStreamVolumes() for output %d and device %x", output, device); for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, device, delayMs);
++++++++++++++++++++++++++AudioPolicyManagerBase::checkAndSetVolume++++++++++++++++++++++++++++++++++++++ 從函數 AudioPolicyManagerBase::applyStreamVolumes 進入: status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force /* = false */) { // do not change actual stream volume if the stream is muted // 如果 stream 是 mute ,並不真正去改變其音量 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 // 如果鏈接了藍牙耳機,則不去改變 VOICE_CALL 的音量,反之亦然 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); +++++++++++++++++++++++++++AudioPolicyManagerBase::computeVolume+++++++++++++++++++++++++++++++++++++ 從函數 AudioPolicyManagerBase::checkAndSetVolume 進入: float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device) { float volume = 1.0; AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); StreamDescriptor &streamDesc = mStreams[stream]; if (device == 0) { device = outputDesc->device(); } int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); volume = AudioSystem::linearToLog(volInt);
++++++++++++++++++++++++++AudioSystem::linearToLog++++++++++++++++++++++++++++++++++++++ 從函數 AudioPolicyManagerBase::computeVolume 進入: // convert volume steps to natural log scale // change this value to change volume scaling static const float dBPerStep = 0.5f; // shouldn't need to touch these static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f; static const float dBConvertInverse = 1.0f / dBConvert; float AudioSystem::linearToLog(int volume) { // float v = volume ? exp(float(100 - volume) * dBConvert) : 0; // LOGD("linearToLog(%d)=%f", volume, v); // return v; return volume ? exp(float(100 - volume) * dBConvert) : 0; } 返回到函數 AudioPolicyManagerBase::computeVolume
--------------------------AudioSystem::linearToLog-------------------------------------- // if a headset is connected, apply the following rules to ring tones and notifications // to avoid sound level bursts in user's ears: // - always attenuate ring tones and notifications volume by 6dB // - if music is playing, always limit the volume to current music volume, // with a minimum threshold at -36dB so that notification is always perceived. // 如果連接了耳機,為了防止在用戶耳朵中產生爆音,對鈴聲和警告聲需要使用以下規則: // - 對鈴聲和警告聲總是減弱 6dB。 // - 如果正在播放音樂,鈴聲和警告聲不應該高於音樂聲音, // 不過,下限是 -36dB if ((device & (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP | AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) && ((getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) || (stream == AudioSystem::SYSTEM)) && streamDesc.mCanBeMuted) { // Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB // #define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5 volume *= SONIFICATION_HEADSET_VOLUME_FACTOR; // 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 (outputDesc->mRefCount[AudioSystem::MUSIC] || mLimitRingtoneVolume) { float musicVol = computeVolume(AudioSystem::MUSIC, mStreams[AudioSystem::MUSIC].mIndexCur, output, device); // Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB // #define SONIFICATION_HEADSET_VOLUME_MIN 0.016 float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ? musicVol : SONIFICATION_HEADSET_VOLUME_MIN; if (volume > minVol) { volume = minVol; LOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol); } } } return volume; } 返回到函數 AudioPolicyManagerBase::checkAndSetVolume
---------------------------AudioPolicyManagerBase::computeVolume------------------------------------- // We actually change the volume if: // - the float value returned by computeVolume() changed // - the force flag is set // 只有當 compute 返回的音量與當前的音量不同,或者強制要求改音量時,才會去真正改變音量 if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || 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);
+++++++++++++++++++++++++++AudioPolicyService::setStreamVolume+++++++++++++++++++++++++++++++++++++ 從函數 AudioPolicyManagerBase::checkAndSetVolume 進入: status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs) { // 函數 AudioPolicyService::AudioCommandThread::volumeCommand 會調用函數 AudioPolicyService::AudioCommandThread::insertCommand_l // 往 mAudioCommands 中添加成員。 // 函數 AudioPolicyService::AudioCommandThread::threadLoop 會處理 mAudioCommands 中的成員 // 對於 SET_VOLUME 命令,調用了函數 AudioSystem::setStreamVolume return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs);
+++++++++++++++++++++++++++++AudioSystem::setStreamVolume+++++++++++++++++++++++++++++++++++ 從函數 AudioPolicyService::setStreamVolume 進入: status_t AudioSystem::setStreamVolume(int stream, float value, int output) { if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; af->setStreamVolume(stream, value, output);
++++++++++++++++++++++++++++AudioFlinger::setStreamVolume++++++++++++++++++++++++++++++++++++ 從函數 AudioSystem::setStreamVolume 進入: status_t AudioFlinger::setStreamVolume(int stream, float value, int output) { // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return BAD_VALUE; } AutoMutex lock(mLock); PlaybackThread *thread = NULL; if (output) { thread = checkPlaybackThread_l(output); if (thread == NULL) { return BAD_VALUE; } } mStreamTypes[stream].volume = value; if (thread == NULL) { for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) { mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value); } } else { thread->setStreamVolume(stream, value);
+++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::setStreamVolume+++++++++++++++++++++++++++++++++++ 從函數 AudioFlinger::setStreamVolume 進入: status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value) { #ifdef LVMX int audioOutputType = LifeVibes::getMixerType(mId, mType); if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { LifeVibes::setStreamVolume(audioOutputType, stream, value); } #endif // 這一塊在看 testPlaybackHeadPositionIncrease 代碼的時候已經介紹過 mStreamTypes[stream].volume = value; return NO_ERROR; } 返回到函數 AudioFlinger::setStreamVolume ------------------------------AudioFlinger::PlaybackThread::setStreamVolume---------------------------------- } return NO_ERROR; }
返回到函數 AudioSystem::setStreamVolume ----------------------------AudioFlinger::setStreamVolume------------------------------------ return NO_ERROR; } 返回到函數 AudioPolicyService::setStreamVolume -----------------------------AudioSystem::setStreamVolume----------------------------------- } 返回到函數 AudioPolicyManagerBase::checkAndSetVolume ---------------------------AudioPolicyService::setStreamVolume------------------------------------- } 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) { // 這兒與 setStreamVolume 函數類似,最終調用到了函數 AudioFlinger::setVoiceVolume // 不過,setVoiceVolume最終會調用底層接口,改變硬件音量 // 這一塊也在看 testPlaybackHeadPositionIncrease 代碼的時候有看過 mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } } return NO_ERROR; } 返回到函數 AudioPolicyManagerBase::applyStreamVolumes --------------------------AudioPolicyManagerBase::checkAndSetVolume-------------------------------------- } } 返回到函數 AudioPolicyManagerBase::setOutputDevice -------------------------AudioPolicyManagerBase::applyStreamVolumes--------------------------------------- // if changing from a combined headset + speaker route, unmute media streams // 前面,如果該條件成立,我們做了 mute 操作,此處要做恢復 if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) { setStrategyMute(STRATEGY_MEDIA, false, output, delayMs); } } 返回到函數 AudioPolicyManagerBase::startOutput ----------------------------AudioPolicyManagerBase::setOutputDevice------------------------------------ // handle special case for sonification while in call if (isInCall()) { handleIncallSonification(stream, true, false); ++++++++++++++++++++++++++++AudioPolicyManagerBase::handleIncallSonification++++++++++++++++++++++++++++++++++++ 從函數 AudioPolicyManagerBase::startOutput 進入: void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, bool stateChange) { // if the stream pertains to sonification strategy and we are in call we must // mute the stream if it is low visibility. If it is high visibility, we must play a tone // in the device used for phone strategy and play the tone if the selected device does not // interfere with the device used for phone strategy // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as // many times as there are active tracks on the output // 如果 stream 是 sonification strategy 的,並且其可見性低, 如果有電話打入則 mute 該 stream 。 // 如果其可見性高,我們必須在 phone strategy 使用的 device 中播放 tone ,並且如果選定的 device // 與 phone strategy 不相干的話,也要播放 tone 。 // 如果 stateChange 是 true ,則我們肯定是從函數 setPhoneState 進來的, // 我們必須 mute / unmute output 中所有的 active track 。 if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) { AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput); LOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d", stream, starting, outputDesc->mDevice, stateChange); if (outputDesc->mRefCount[stream]) { // 只有 output 中存在 active 的該類型的 stream 時才做處理 int muteCount = 1; if (stateChange) { muteCount = outputDesc->mRefCount[stream]; } if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
++++++++++++++++++++++++++++AudioSystem::isLowVisibility++++++++++++++++++++++++++++++++++++ 從函數 AudioPolicyManagerBase::handleIncallSonification 進入: bool AudioSystem::isLowVisibility(stream_type stream) { // 以下這幾種 stream 的可見性低,其他的都是高的 if (stream == AudioSystem::SYSTEM || stream == AudioSystem::NOTIFICATION || stream == AudioSystem::RING) { return true; } else { return false; } } 返回到函數 AudioPolicyManagerBase::handleIncallSonification ----------------------------AudioSystem::isLowVisibility------------------------------------ LOGV("handleIncallSonification() low visibility, muteCount %d", muteCount); for (int i = 0; i < muteCount; i++) { setStreamMute(stream, starting, mHardwareOutput); } } else { LOGV("handleIncallSonification() high visibility"); if (outputDesc->device() & getDeviceForStrategy(STRATEGY_PHONE)) { LOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount); for (int i = 0; i < muteCount; i++) { setStreamMute(stream, starting, mHardwareOutput); } } if (starting) { mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL); } else { mpClientInterface->stopTone(); } } } } } 返回到函數 AudioPolicyManagerBase::startOutput ----------------------------AudioPolicyManagerBase::handleIncallSonification------------------------------------ } // apply volume rules for current stream and device if necessary checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, outputDesc->device()); return NO_ERROR; } 返回到函數 AudioPolicyService::startOutput -----------------------------AudioPolicyManagerBase::startOutput----------------------------------- } 返回到函數 AudioSystem::startOutput -----------------------------AudioPolicyService::startOutput----------------------------------- } 返回到函數 AudioFlinger::PlaybackThread::Track::start ----------------------------AudioSystem::startOutput------------------------------------ thread->mLock.lock(); } if (status == NO_ERROR) { PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); playbackThread->addTrack_l(this); } else { mState = state; } } else { status = BAD_VALUE; } return status; } ###########################################################
&&&&&&&&&&&&&&&&&&&&&&&總結&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
各種聲音控制策略的實現主要在 Audio Policy Manager 中。
其中會根據 stream type 和當前的狀態對各種 stream 的音量作必要的修改。
以達成以下的優先級效果:
Priority Strategy Type Stream Type
4 STRATEGY_PHONE VOICE_CALL
BLUETOOTH_SCO
3 STRATEGY_SONIFICATION RING
NOTIFICATION
ALARM
ENFORCED_AUDIBLE
2 STRATEGY_MEDIA SYSTEM
TTS
MUSIC
1 STRATEGY_DTMF DTMF
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&