更多信息请访问:51CTO与华为官方共建的鸿蒙技术社区https://ost.51cto。comOpenHarmony3.1Release版增加按键音量调节功能,如下图:音量调节一般理解为按下按键触发中断,音量调节在中断处理函数中完成。那么在OpenHarmonyAudioService中是怎么做到的呢?1、按钮的注册,作为输入模块,由多模输入子系统管理。在Audio子系统中,AudioPolicy进程加载多模子系统,订阅按键事件处理。根据按键操作,触发音量调节接口,通过PulseAudio调用HDI接口。HDI接口通过AudioDriverModel完成音量调节。下面分别介绍各个模块的具体执行流程。按键输入和多模式输入1.按键注册。KEY信息配置和节点配置,参见vendor/hihope/rk3568/hdf_config/khdf/input/input_config.hcs,通过RegisterKeyDevice在HDF_KEY模块中注册Vol+/Vol-,由input统一管理。CkeyConfig{keyList=["power","VolUp","VolDown","Up","Down","Left","Right"];keyInfoList{key1{match_attr="key_device0";/*0:touch1:key2:keyboard3:mouse4:button5:crown6:encoder*/inputType=1;keyName="电源";gpioNum=1;中断标志=3;去抖动时间=80;}key2{keyName="volUp";gpioNum=31;中断标志=1;去抖动时间=80;}key3{keyName="volDown";gpioNum=32;中断标志=1;去抖动时间=80;}}}openHarmony中KEY与多模式输入的简单关系。如何连接多模输入和AudioService结合音频组件架构图,AudioPolicy主要完成Audio设备和音量的管理。++AudioPolicyServer完成依赖模块的加载,音量键的调节与多模输入模块相关。voidAudioPolicyServer::OnAddSystemAbility(int32_tsystemAbilityId,conststd::string&deviceId){switch(systemAbilityId){caseMULTIMODAL_INPUT_SERVICE_ID://3101......SubscribeKeyEvents();休息;......}}2。SubscribeKeyEvents接口完成了Vol+/Vol-按键事件的订阅,当前Input事件触发后会执行相应的action。C++voidAudioPolicyServer::SubscribeKeyEvents(){//按键信息配置MMI::InputManager*im=MMI::InputManager::GetInstance();std::set预键;std::shared_ptrkeyOption_down=std::make_shared();keyOption_down->SetPreKeys(preKeys);keyOption_down->SetFinalKey(OHOS::MMI::KeyEvent::KEYCODE_VOLUME_DOWN);keyOption_down->SetFinalKeyDown(true);keyOption_down->SetFinalKeyDuration(0);//键触发的事件im->SubscribeKeyEvent(keyOption_down,[=](std::shared_ptrkeyEventCallBack){std::lock_guardlock(volumeKeyEventMutex_);AudioStreamTypestreamInFocus=GetStreamInFocus();if(streamInFocus==AudioStreamType::STREAM_DEFAULT){streamInFocus=AudioStreamType::STREAM_MUSIC;}//获取当前音量floatcurrentVolume=GetStreamVolume(streamInFocus);if(ConvertVolumeToInt(currentVolume)<=MIN_VOLUME_LEVEL){for(autoit=volumeChangeCbsMap_.begin();it!=volumeChangeCbsMap_.end();++it){std::shared_ptrvolumeChangeCb=it->second;if(volumeChangeCb==nullptr){MEDIA_ERR_LOG("volumeChangeCb:客户端的nullptr:%{public}d",it->first);继续;}volumeChangeCb->OnVolumeKeyEvent(streamInFocus,MIN_VOLUME_LEVEL,true);}返回;}//设置音量SetStreamVolume(streamInFocus,currentVolume-GetVolumeFactor(),true);});如何设置AudioService的音量1.然后上面的订阅事件,AudioPolicyServer调用AudioPolicyService类,AudioPolicyService再在这个接口调用AudioAdapterManager::SetStreamVolume,完成WriteVolumeToKvStore保存音量值(kv:Key,value),然后调用AudioServiceAdapter::mAudioServiceAdapter->SetVolume(streamType,volume);设置音量。2.AudioServiceAdapter::SetVolume接口。PulseAudio作为一个Audio服务,SetVolume通过调用PulseAudio的接口完成音量设置。C++int32_tPulseAudioServiceAdapterImpl::SetVolume(AudioStreamTypestreamType,floatvolume){......pa_threaded_mainloop_lock(mMainLoop);pa_operation*operation=pa_context_get_sink_input_info_list(mContext,PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb,reinterpret_cast(userData.get()));......returnSUCCESS;}该接口中PaGetSinkInputInfoVolumeCb作为回调函数,通过pa_context_set_sink_input_volume接口完成音量设置的具体工作。C++voidPulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb(pa_context*c,constpa_sink_input_info*i,inteol,void*userdata){......pa_cvolumecv=i->volume;uint32_tvolume=pa_sw_volume_from_linear(vollu);设置(volu&cv,i->channel_map.channels,volume);pa_operation_unref(pa_context_set_sink_input_volume(c,i->index,&cv,NULL,NULL));......return;}以上类的关系见图,如下:pulseaudio如何与HDI接口1.module-hdi-sink/module-hdi-source(foundation/multimedia/audio_standard/frameworks/native/pulseaudio/src/modules/hdi)作为PulseAudio模块,系统启动过程由audiopolicy进程控制加载启动。2.renderer_sink_adapter(foundation/multimedia/audio_standard/frameworks/native/audiorenderer/src/renderer_sink_adapter.c)作为hdi-sink和renderer之间的适配层,完成接口的封装和定义。C++structRendererSinkAdapter{int32_t(*RendererSinkInit)(constSinkAttr*attr);void(*RendererSinkDeInit)(void);int32_t(*RendererSinkStart)(void);int32_t(*RendererSinkStop)(void);int32_t(*RendererRenderFrame)(char*data,uint64_tlen,uint64_t*writeLen);int32_t(*RendererSinkSetVolume)(向左浮动,向右浮动);int32_t(*RendererSinkGetLatency)(uint32_t*latency);};其中,RendererSinkSetVolume接口完成音量设置,LoadSinkAdapter接口根据不同的设备类型,给出不同的接口实现。C++int32_tLoadSinkAdapter(constchar*device,structRendererSinkAdapter**sinkAdapter){......if(!strcmp(device,g_deviceClassPrimary)){MEDIA_INFO_LOG("%{public}s:主设备",__func__);......adapter->RendererSinkSetVolume=AudioRendererSinkSetVolume;......g_deviceClass=CLASS_TYPE_PRIMARY;}elseif(!strcmp(device,g_deviceClassA2Dp)){MEDIA_INFO_LOG("%{public}s:a2dpdevice",__func__);......adapter->RendererSinkSetVolume=BluetoothRendererSinkSetVolume;......g_deviceClass=CLASS_TYPE_A2DP;}else{MEDIA_ERR_LOG("%{public}s:设备不支持",__func__);免费(适配器);返回错误;}......}3.如何连接RendererSinkSetVolume与HDI接口。以主设备为例,RendererSinkSetVolume对应的实现是AudioRendererSinkSetVolume,它调用了g_audioRendrSinkInstance->SetVolume,即AudioRendererSink::SetVolume接口。C++int32_tAudioRendererSink::SetVolume(floatleft,floatright){......ret=audioRender_->volume.SetVolume(reinterpret_cast(audioRender_),volume);if(ret){MEDIA_ERR_LOG("AudioRendererSink::Setvolumefailed!");}returnret;}audioRender的定义是structAudioRender*audioRender,AudioRender是HDI接口,其定义参考(drivers/peripheral/audio/interfaces/include/audio_render.h)。HDI如何完成音量设置,可以参考AudioHDI的测试用例,本文不再赘述(*drivers/peripheral/audio/test/systemtest/hdi/render/src/audio_hdirender_volume_test.cpp)。更多资讯请浏览:?????????????????????????????????????????????????????????