【Android 7.0 Audio】:通话中的音频调用接口
2017年10月20日 23:49:18 yangchangwen83 阅读数:471 标签: Android Audio Audio架androidaudio 更多
个人分类: 06_Android音频系统
转载自http://blog.csdn.net/xiashaohua/article/details/53842414
对于Audio在通话中的处理,根据不同的功能,有不同的调用路径,
1) 通话中 打开speaker 流程 enableSpeaker
对于在通话中打开扬声器,走图示1的调用路径,
在telephony部分,调用流程如下,
InCallAudioManager. enableSpeaker--telecomAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER)/binderIPC-- mInCallService.setAudioRoute(route);-- mPhone.setAudioRoute(route);-- mInCallAdapter.setAudioRoute(route);--mAdapter.setAudioRoute(route);/binder IPC--…--CallsManager.
setAudioRoute --mCallAudioManager.setAudioRoute(route)--CallAudioRouteStateMachine.sendMessageWithSessionInfo / CallAudioRouteStateMachine.USER_SWITCH_SPEAKER/--通过ActiveSpeakerRoute向下..—setSpeakerphoneOn-- mAudioManager.setSpeakerphoneOn(on)
这样,就到了Audio系统了,根据之前的章节,就知道接下来就是AM/AService/ASystem了,
AudioManager.setSpeakerphoneOn/ binder IPC--setSpeakerphoneOn --/ mForcedUseForComm = AudioSystem.FORCE_SPEAKER / sendMsg(mAudioHandler,MSG_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0) /内部handler--setForceUse --setForceUseInt_SyncDevices -- AudioSystem.setForceUse/jni-AudioSystem::setForceUse
在native部分的调用流程如下,
AudioSystem::setForceUse--AudioPolicyService::setForceUse(AudioPolicyInterfaceImpl.cpp)--AudioPolicyManager::setForceUse
APM处理部分如下,
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) {
if (mEngine->setForceUse(usage, config) != NO_ERROR) { ALOGW("setForceUse() could not set force cfg %d for usage %d", config, usage); return; }
checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs();
if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/); updateCallRouting(newDevice); } for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i); audio_devices_t newDevice = getNewOutputDevice(outputDesc, true /*fromCache*/); if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) { setOutputDevice(outputDesc, newDevice, (newDevice != AUDIO_DEVICE_NONE)); } if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) { applyStreamVolumes(outputDesc, newDevice, 0, true); } }
audio_io_handle_t activeInput = mInputs.getActiveInput(); if (activeInput != 0) { sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput); audio_devices_t newDevice = getNewInputDevice(activeInput); // Force new input selection if the new device can not be reached via current input if (activeDesc->mProfile->getSupportedDevices().types() & (newDevice & ~AUDIO_DEVICE_BIT_IN)) { setInputDevice(activeInput, newDevice); } else { closeInput(activeInput); } } }
|
a)mEngine->setForceUse
实现在Engine.cpp里面,主要是判断当前对设备设置是否合逻辑,并给mForceUse的成员赋值。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) { switch(usage) { case AUDIO_POLICY_FORCE_FOR_COMMUNICATION: if (config != AUDIO_POLICY_FORCE_SPEAKER && config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_NONE) { ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config); return BAD_VALUE; } mForceUse[usage] = config; break; |
b)checkA2dpSuspend
checkA2dpSuspend--AudioPolicyService::AudioPolicyClient::suspendOutput--AudioFlinger::suspendOutput--thread->suspend
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void suspend() { (void) android_atomic_inc(&mSuspended); } |
最终是给&mSuspended赋值。
c)checkOutputForStrategy 根据策略类型和当前设置获取设备类型,并最input和output进行处理,最后invalidateStream。
其中,
AudioPolicyManager::checkOutputForStrategy--audio_devices_tAudioPolicyManager::getDeviceForStrategy--mEngine->getDeviceForStrategy,
Engine.cpp里,
根据strategy为STRATEGY_PHONE,以及刚刚设置的mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]为AUDIO_POLICY_FORCE_SPEAKER,匹配到正确的设备类型,刚好为AUDIO_DEVICE_OUT_SPEAKER,
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy, DeviceVector availableOutputDevices, DeviceVector availableInputDevices, const SwAudioOutputCollection &outputs) const { uint32_t device = AUDIO_DEVICE_NONE; uint32_t availableOutputDevicesType = availableOutputDevices.types();
switch (strategy) { case STRATEGY_PHONE:
switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
case AUDIO_POLICY_FORCE_SPEAKER: // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to // A2DP speaker when forcing to speaker output
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER; break; } break; |
d)之后是updateCallRouting,设置device的操作。
2)dtmf音
在telephony模块,调用流程(这里只分析了声音播放,并不包含信令处理)
CallsManager.playDtmfTone --DtmfLocalTonePlayer .playTone--mToneGenerator.startTone
在Audio模块,调用流程
ToneGenerator.startTone--jni--android_media_ToneGenerator_startTone--ToneGenerator::startTone
ToneGenerator则直接使用了AT,先initAudioTrack创建AT实例,prepareWave生成PCM数据,再mpAudioTrack->start()开始,
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ToneGenerator::startTone(tone_type toneType, int durationMs) {
toneType = getToneForRegion(toneType);
if (mState == TONE_IDLE) { ALOGV("startTone: try to re-init AudioTrack"); if (!initAudioTrack()) { return lResult; } }
if (mState == TONE_INIT) { if (prepareWave()) { ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000)); lResult = true; mState = TONE_STARTING; if (clock_gettime(CLOCK_MONOTONIC, &mStartTime) != 0) { mStartTime.tv_sec = 0; } mLock.unlock(); mpAudioTrack->start(); … } mLock.unlock(); }
|
可以看到,initAudioTrack创建AT实例时,使用了AUDIO_OUTPUT_FLAG_FAST的方式播放,通过audioCallback回调完成数据填充。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ToneGenerator::initAudioTrack() {
// Open audio track in mono, PCM 16bit, default sampling rate, default buffer size mpAudioTrack = new AudioTrack(); ALOGV("Create Track: %p", mpAudioTrack.get());
mpAudioTrack->set(mStreamType, 0, // sampleRate AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_MONO, 0, // frameCount AUDIO_OUTPUT_FLAG_FAST, audioCallback, this, // user 0, // notificationFrames 0, // sharedBuffer mThreadCanCallJava, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_CALLBACK);
if (mpAudioTrack->initCheck() != NO_ERROR) { ALOGE("AudioTrack->initCheck failed"); goto initAudioTrack_exit; }
mpAudioTrack->setVolume(mVolume);
mState = TONE_INIT;
return true;
initAudioTrack_exit:
ALOGV("Init failed: %p", mpAudioTrack.get());
// Cleanup mpAudioTrack.clear();
return false; } |
这条通道走的是AF的路径,并不在上图的三个path之中。
3)标记3的场景有,Telephony向Audio设置当前是通话状态,这个会用setMode (MODE_INCALL);向Audio设置当前是VOICE通话还是LTE通话,这个会用AudioSystem::setParameters(),
vendor\qcom\proprietary\qcril\qcril_qmi\qcril_am.cc