文章目录
- 1.KEY的注册。 KEY信息配置与节点配置,见vendor/hihope/rk3568/hdf_config/khdf/input/input_config.hcs,通过RegisterKeyDevice将Vol+/Vol-注册到HDF_KEY模块中,由input统一管理。 CkeyConfig { keyList = ["power", "VolUp", "VolDown", "Up", "Down", "Left", "Right"]; keyInfoList { key1 { match_attr = "key_device0"; /* 0:touch 1:key 2:keyboard 3:mouse 4:button 5:crown 6:encoder */ inputType = 1; keyName = "power"; gpioNum = 1; irqFlag = 3; debounceTime = 80; } key2 { keyName = "volUp"; gpioNum = 31; irqFlag = 1; debounceTime = 80; } key3 { keyName = "volDown"; gpioNum = 32; irqFlag = 1; debounceTime = 80; } } } 在openHarmony中KEY与多模输入的简单关系图。
- 结合音频组件架构图,AudioPolicy主要完成Audio设备、音量等管理工作。 ++AudioPolicyServer完成依赖模块的加载,音量按键的调节与多模输入模块相关。void AudioPolicyServer::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId){ switch (systemAbilityId) { case MULTIMODAL_INPUT_SERVICE_ID: // 3101 ...... SubscribeKeyEvents(); break; ...... }} 2.SubscribeKeyEvents接口完成Vol+/Vol-按键事件的订阅,当前Input事件触发后会执行对应的动作。 C++void AudioPolicyServer::SubscribeKeyEvents(){ // 按键信息配置 MMI::InputManager *im = MMI::InputManager::GetInstance(); std::set<int32_t> preKeys; std::shared_ptr<OHOS::MMI::KeyOption> keyOption_down = std::make_shared<OHOS::MMI::KeyOption>(); keyOption_down->SetPreKeys(preKeys); keyOption_down->SetFinalKey(OHOS::MMI::KeyEvent::KEYCODE_VOLUME_DOWN); keyOption_down->SetFinalKeyDown(true); keyOption_down->SetFinalKeyDownDuration(0); // key触发的事件 im->SubscribeKeyEvent(keyOption_down, [=](std::shared_ptr<MMI::KeyEvent> keyEventCallBack) { std::lock_guard<std::mutex> lock(volumeKeyEventMutex_); AudioStreamType streamInFocus = GetStreamInFocus(); if (streamInFocus == AudioStreamType::STREAM_DEFAULT) { streamInFocus = AudioStreamType::STREAM_MUSIC; } // 获取当前音量 float currentVolume = GetStreamVolume(streamInFocus); if (ConvertVolumeToInt(currentVolume) <= MIN_VOLUME_LEVEL) { for (auto it = volumeChangeCbsMap_.begin(); it != volumeChangeCbsMap_.end(); ++it) { std::shared_ptr<VolumeKeyEventCallback> volumeChangeCb = it->second; if (volumeChangeCb == nullptr) { MEDIA_ERR_LOG("volumeChangeCb: nullptr for client : %{public}d", it->first); continue; } volumeChangeCb->OnVolumeKeyEvent(streamInFocus, MIN_VOLUME_LEVEL, true); } return; } // 设置音量 SetStreamVolume(streamInFocus, currentVolume-GetVolumeFactor(), true); });
- 1.接着上述订阅事件,AudioPolicyServer通过调用AudioPolicyService类,AudioPolicyService继而调用AudioAdapterManager::SetStreamVolume。 此接口中,通过完成WriteVolumeToKvStore音量值的保存(kv:Key,value),继而调用AudioServiceAdapter::mAudioServiceAdapter->SetVolume(streamType, volume);进行音量设置。 2.AudioServiceAdapter::SetVolume接口。 PulseAudio作为Audio服务,SetVolume通过调用PulseAudio的接口完成音量设置。 C++int32_t PulseAudioServiceAdapterImpl::SetVolume(AudioStreamType streamType, float volume){ ...... pa_threaded_mainloop_lock(mMainLoop); pa_operation *operation = pa_context_get_sink_input_info_list(mContext, PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb, reinterpret_cast<void*>(userData.get())); ...... return SUCCESS;} 此接口中PaGetSinkInputInfoVolumeCb作为回调函数,通过pa_context_set_sink_input_volume接口完成音量设置的具体工作。 C++void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb(pa_context *c, const pa_sink_input_info *i, int eol,void *userdata){ ...... pa_cvolume cv = i->volume; uint32_t volume = pa_sw_volume_from_linear(vol); pa_cvolume_set(&cv, i->channel_map.channels, volume); pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, NULL, NULL)); ...... return;} 上述类之间的关系见图,如下:
- 1.module-hdi-sink/module-hdi-source(foundation/multimedia/audio_standard/frameworks/native/pulseaudio/src/modules/hdi)作为PulseAudio的module,系统启动过程被audiopolicy进程加载启动。 2.renderer_sink_adapter(foundation/multimedia/audio_standard/frameworks/native/audiorenderer/src/renderer_sink_adapter.c) 作为hdi-sink和renderer之间的适配层,完成接口封装与定义。 C++struct RendererSinkAdapter { int32_t (*RendererSinkInit)(const SinkAttr *attr); void (*RendererSinkDeInit)(void); int32_t (*RendererSinkStart)(void); int32_t (*RendererSinkStop)(void); int32_t (*RendererRenderFrame)(char *data, uint64_t len, uint64_t *writeLen); int32_t (*RendererSinkSetVolume)(float left, float right); int32_t (*RendererSinkGetLatency)(uint32_t *latency);}; 其中RendererSinkSetVolume接口完成音量设置,LoadSinkAdapter接口根据不同的设备类型,给出不同的接口实现。 C++int32_t LoadSinkAdapter(const char *device, struct RendererSinkAdapter **sinkAdapter){ ...... if (!strcmp(device, g_deviceClassPrimary)) { MEDIA_INFO_LOG("%{public}s: primary device", __func__); ...... adapter->RendererSinkSetVolume = AudioRendererSinkSetVolume; ...... g_deviceClass = CLASS_TYPE_PRIMARY; } else if (!strcmp(device, g_deviceClassA2Dp)) { MEDIA_INFO_LOG("%{public}s: a2dp device", __func__); ...... adapter->RendererSinkSetVolume = BluetoothRendererSinkSetVolume; ...... g_deviceClass = CLASS_TYPE_A2DP; } else { MEDIA_ERR_LOG("%{public}s: Device not supported", __func__); free(adapter); return ERROR; } ......} 3.RendererSinkSetVolume如何与HDI接口对接。 以primary device为例,RendererSinkSetVolume对应的实现为AudioRendererSinkSetVolume,调用g_audioRendrSinkInstance->SetVolume,即AudioRendererSink::SetVolume接口。 C++int32_t AudioRendererSink::SetVolume(float left, float right){ ...... ret = audioRender_->volume.SetVolume(reinterpret_cast<AudioHandle>(audioRender_), volume); if (ret) { MEDIA_ERR_LOG("AudioRendererSink::Set volume failed!"); } return ret;} audioRender的定义为struct AudioRender *audioRender,AudioRender即为HDI接口,其定义参考(drivers/peripheral/audio/interfaces/include/audio_render.h)。 HDI如何完成音量设置,可以参考Audio HDI的测试用例,本文将不描述(*drivers/peripheral/audio/test/systemtest/hdi/render/src/audio_hdirender_volume_test.cpp)。 想了解更多内容,请访问: 51CTO和华为官方合作共建的鸿蒙技术社区 https://ost.51cto.com

OpenHarmony3.1 Release版本新增按键音量调节功能,如下图:

音量调节通俗的理解为按下按键,触发中断,中断处理函数中完成音量的调节。
那么在OpenHarmony Audio Service中是怎么完成的呢?
1.按键的注册,按键作为input模块,被多模输入子系统管理。
在Audio子系统中,AudioPolicy进程加载了多模子系统,并订阅的按键事件处理。根据按键的操作,触发音量调节接口,并通过PulseAudio调用HDI的接口,HDI接口通过Audio Dirver Model完成音量的调节。

下文将展开描述各个模块具体的执行流程。
1.KEY的注册。
KEY信息配置与节点配置,见vendor/hihope/rk3568/hdf_config/khdf/input/input_config.hcs,通过RegisterKeyDevice将Vol+/Vol-注册到HDF_KEY模块中,由input统一管理。
C
keyConfig {
keyList = ["power", "VolUp", "VolDown", "Up", "Down", "Left", "Right"];
keyInfoList {
key1 {
match_attr = "key_device0";
/* 0:touch 1:key 2:keyboard 3:mouse 4:button 5:crown 6:encoder */
inputType = 1;
keyName = "power";
gpioNum = 1;
irqFlag = 3;
debounceTime = 80;
}
key2 {
keyName = "volUp";
gpioNum = 31;
irqFlag = 1;
debounceTime = 80;
}
key3 {
keyName = "volDown";
gpioNum = 32;
irqFlag = 1;
debounceTime = 80;
}
}
}
在openHarmony中KEY与多模输入的简单关系图。

结合音频组件架构图,AudioPolicy主要完成Audio设备、音量等管理工作。
++
AudioPolicyServer完成依赖模块的加载,音量按键的调节与多模输入模块相关。
void AudioPolicyServer::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
{
switch (systemAbilityId) {
case MULTIMODAL_INPUT_SERVICE_ID: // 3101
......
SubscribeKeyEvents();
break;
......
}
}

2.SubscribeKeyEvents接口完成Vol+/Vol-按键事件的订阅,当前Input事件触发后会执行对应的动作。
C++
void AudioPolicyServer::SubscribeKeyEvents()
{
// 按键信息配置
MMI::InputManager *im = MMI::InputManager::GetInstance();
std::set<int32_t> preKeys;
std::shared_ptr<OHOS::MMI::KeyOption> keyOption_down = std::make_shared<OHOS::MMI::KeyOption>();
keyOption_down->SetPreKeys(preKeys);
keyOption_down->SetFinalKey(OHOS::MMI::KeyEvent::KEYCODE_VOLUME_DOWN);
keyOption_down->SetFinalKeyDown(true);
keyOption_down->SetFinalKeyDownDuration(0);
// key触发的事件
im->SubscribeKeyEvent(keyOption_down, [=](std::shared_ptr<MMI::KeyEvent> keyEventCallBack) {
std::lock_guard<std::mutex> lock(volumeKeyEventMutex_);
AudioStreamType streamInFocus = GetStreamInFocus();
if (streamInFocus == AudioStreamType::STREAM_DEFAULT) {
streamInFocus = AudioStreamType::STREAM_MUSIC;
}
// 获取当前音量
float currentVolume = GetStreamVolume(streamInFocus);
if (ConvertVolumeToInt(currentVolume) <= MIN_VOLUME_LEVEL) {
for (auto it = volumeChangeCbsMap_.begin(); it != volumeChangeCbsMap_.end(); ++it) {
std::shared_ptr<VolumeKeyEventCallback> volumeChangeCb = it->second;
if (volumeChangeCb == nullptr) {
MEDIA_ERR_LOG("volumeChangeCb: nullptr for client : %{public}d", it->first);
continue;
}
volumeChangeCb->OnVolumeKeyEvent(streamInFocus, MIN_VOLUME_LEVEL, true);
}
return;
}
// 设置音量
SetStreamVolume(streamInFocus, currentVolume-GetVolumeFactor(), true);
});
1.接着上述订阅事件,AudioPolicyServer通过调用AudioPolicyService类,AudioPolicyService继而调用AudioAdapterManager::SetStreamVolume。
此接口中,通过完成WriteVolumeToKvStore音量值的保存(kv:Key,value),继而调用AudioServiceAdapter::mAudioServiceAdapter->SetVolume(streamType, volume);进行音量设置。
2.AudioServiceAdapter::SetVolume接口。
PulseAudio作为Audio服务,SetVolume通过调用PulseAudio的接口完成音量设置。
C++
int32_t PulseAudioServiceAdapterImpl::SetVolume(AudioStreamType streamType, float volume)
{
......
pa_threaded_mainloop_lock(mMainLoop);
pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb, reinterpret_cast<void*>(userData.get()));
......
return SUCCESS;
}
此接口中PaGetSinkInputInfoVolumeCb作为回调函数,通过pa_context_set_sink_input_volume接口完成音量设置的具体工作。
C++
void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb(pa_context *c, const pa_sink_input_info *i, int eol,void *userdata)
{
......
pa_cvolume cv = i->volume;
uint32_t volume = pa_sw_volume_from_linear(vol);
pa_cvolume_set(&cv, i->channel_map.channels, volume);
pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, NULL, NULL));
......
return;
}
上述类之间的关系见图,如下:

1.module-hdi-sink/module-hdi-source(foundation/multimedia/audio_standard/frameworks/native/pulseaudio/src/modules/hdi)作为PulseAudio的module,系统启动过程被audiopolicy进程加载启动。
2.renderer_sink_adapter(foundation/multimedia/audio_standard/frameworks/native/audiorenderer/src/renderer_sink_adapter.c) 作为hdi-sink和renderer之间的适配层,完成接口封装与定义。
C++
struct RendererSinkAdapter {
int32_t (*RendererSinkInit)(const SinkAttr *attr);
void (*RendererSinkDeInit)(void);
int32_t (*RendererSinkStart)(void);
int32_t (*RendererSinkStop)(void);
int32_t (*RendererRenderFrame)(char *data, uint64_t len, uint64_t *writeLen);
int32_t (*RendererSinkSetVolume)(float left, float right);
int32_t (*RendererSinkGetLatency)(uint32_t *latency);
};
其中RendererSinkSetVolume接口完成音量设置,LoadSinkAdapter接口根据不同的设备类型,给出不同的接口实现。
C++
int32_t LoadSinkAdapter(const char *device, struct RendererSinkAdapter **sinkAdapter)
{
......
if (!strcmp(device, g_deviceClassPrimary)) {
MEDIA_INFO_LOG("%{public}s: primary device", __func__);
......
adapter->RendererSinkSetVolume = AudioRendererSinkSetVolume;
......
g_deviceClass = CLASS_TYPE_PRIMARY;
} else if (!strcmp(device, g_deviceClassA2Dp)) {
MEDIA_INFO_LOG("%{public}s: a2dp device", __func__);
......
adapter->RendererSinkSetVolume = BluetoothRendererSinkSetVolume;
......
g_deviceClass = CLASS_TYPE_A2DP;
} else {
MEDIA_ERR_LOG("%{public}s: Device not supported", __func__);
free(adapter);
return ERROR;
}
......
}
3.RendererSinkSetVolume如何与HDI接口对接。
以primary device为例,RendererSinkSetVolume对应的实现为AudioRendererSinkSetVolume,调用g_audioRendrSinkInstance->SetVolume,即AudioRendererSink::SetVolume接口。
C++
int32_t AudioRendererSink::SetVolume(float left, float right)
{
......
ret = audioRender_->volume.SetVolume(reinterpret_cast<AudioHandle>(audioRender_), volume);
if (ret) {
MEDIA_ERR_LOG("AudioRendererSink::Set volume failed!");
}
return ret;
}
audioRender的定义为struct AudioRender *audioRender,AudioRender即为HDI接口,其定义参考(drivers/peripheral/audio/interfaces/include/audio_render.h)。
HDI如何完成音量设置,可以参考Audio HDI的测试用例,本文将不描述(*drivers/peripheral/audio/test/systemtest/hdi/render/src/audio_hdirender_volume_test.cpp)。
