最近在开发过程中,很多客户需要定制USB Audio设备用于会议时当麦克音箱使用,但是Android原生系统对外接USB Audio设备的兼容性并不好,特别是外设厂商五花八门,可能标准都不一样。这样导致每次换个设备就要调试,很麻烦。。。下面把个人调试的过程简单说明下。
1、拿个设备复现问题,一开始可能一脸懵逼,这该从何入手呢?Android系统整个audio系统这么庞大,到底是哪里出的问题呢?应用层、HAL层、还是kernel,除非你是真的很熟悉每个流程,否则跟我一样懵圈了。
我的习惯就是先看当前的打印,看看到底走了哪些地方,可能很多地方也没有打印,但是大概的还是可以有迹可循。然后再把跑过的地方源码翻出来,大概阅读下,相应的地方加入自己的打印,追踪一下具体的流程。
2、功夫不负有心人,终于在我的苦苦追寻下找到了可疑点。
在该文件下frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp,主要有两个函数checkAndSetVolume()、computeVolume()。
3、checkAndSetVolume()检测设置音量,根据实际情况设置不同设备音量。Android原生系统会判断当前设备类型,但实际情况不同厂商设备可能存在差异,导致被过滤掉了,从而导致设置音量时未执行。
status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,int index,const sp<AudioOutputDescriptor>& outputDesc,audio_devices_t device,int delayMs,bool force){// do not change actual stream volume if the stream is mutedif (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);// do not change in call volume if bluetooth is connected and vice versaif ((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();}float volumeDb = computeVolume(stream, index, device);if (outputDesc->isFixedVolume(device)) {volumeDb = 0.0f;}// Android Patch Beginif (stream == AUDIO_STREAM_MUSIC) {//去掉device判断,所有设备都跑/*if ((device & AUDIO_DEVICE_OUT_SPEAKER) ||(device & AUDIO_DEVICE_OUT_HDMI_ARC) ||(device & AUDIO_DEVICE_OUT_SPDIF) ||(device & AUDIO_DEVICE_OUT_ALL_A2DP) ||(device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {*/sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();float volumeDbToAmpl = Volume::DbToAmpl(volumeDb);if (af != NULL) {ALOGD("%s: index %d, device 0x%x, volume %f(Db %f)", __FUNCTION__, index, device, volumeDbToAmpl, volumeDb);//af->setMasterVolume(volumeDbToAmpl);//设置声音使用volumeDb变量af->setMasterVolume(volumeDb);//volumeDb = 0.0f;} else {ALOGE("%s: can Not set master volume because af is null", __FUNCTION__);}//}}//Android Patch EndoutputDesc->setVolume(volumeDb, stream, device, delayMs, force);if (stream == AUDIO_STREAM_VOICE_CALL ||stream == AUDIO_STREAM_BLUETOOTH_SCO) {float voiceVolume;// Force voice volume to max for bluetooth SCO as volume is managed by the headsetif (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;}
4、computeVolume()方法计算好当前需要设置的音量。在使用的过程当中声音值会有偏差,具体如何转化看个人情况。最后需要添加对AUDIO_DEVICE_OUT_USB_DEVICE设备的支持,否则USB设备音量控制有问题。
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_MUSIC){volumeDB = (float)index / 100;}// handle the case of accessibility active while a ringtone is playing: if the ringtone is much// louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch// exploration of the dialer UI. In this situation, bring the accessibility volume closer to// the ringtone volumeif ((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 a headset is connected, apply the following rules to ring tones and notifications// to avoid sound level bursts in user's ears:// - always attenuate notifications volume by 6dB// - attenuate ring tones volume by 6dB unless music is not playing and// speaker is part of the select devices// - if music is playing, always limit the volume to current music volume,// with a minimum threshold at -36dB so that notification is always perceived.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 stoppedif (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 playedif ((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) ||//添加AUDIO_DEVICE_OUT_USB_DEVICE设备判断,否则usb设备无法控制(Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_USB_DEVICE) ||stream_strategy != STRATEGY_SONIFICATION) {volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;}}return volumeDB;}
如果觉得《Android8.0中外接USB Audio设备无法控制音量问题》对你有帮助,请点赞、收藏,并留下你的观点哦!