OpenHarmony3.1 按下音量按键后Audio service发生的哪些事

系统 OpenHarmony
在Audio子系统中,AudioPolicy进程加载了多模子系统,并订阅的按键事件处理。根据按键的操作,触发音量调节接口,并通过PulseAudio调用HDI的接口,HDI接口通过Audio Dirver Model完成音量的调节。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

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

音量调节通俗的理解为按下按键,触发中断,中断处理函数中完成音量的调节。

那么在OpenHarmony Audio Service中是怎么完成的呢?

1.按键的注册,按键作为input模块,被多模输入子系统管理。

在Audio子系统中,AudioPolicy进程加载了多模子系统,并订阅的按键事件处理。根据按键的操作,触发音量调节接口,并通过PulseAudio调用HDI的接口,HDI接口通过Audio Dirver Model完成音量的调节。

下文将展开描述各个模块具体的执行流程。

Key输入与多模输入

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与多模输入的简单关系图。

多模输入与AudioService如何联系

结合音频组件架构图,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);
});

Audio Service如何进行音量设置

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;
}

上述类之间的关系见图,如下:

pulseaudio如何与HDI接口对接

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​



责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2022-06-01 22:41:29

转场动画鸿蒙

2022-05-07 16:13:59

DevEcoTool鸿蒙

2022-07-06 20:40:27

舒尔特方格鸿蒙

2022-06-28 14:42:26

ETS购物车应用

2022-07-27 14:30:15

分布式数据鸿蒙

2022-04-26 14:33:21

鸿蒙操作系统

2022-06-01 22:35:25

滑杆组件鸿蒙

2021-02-25 10:02:32

开机键Linux内存

2017-12-28 15:40:16

开源LinuxGitHub

2013-02-25 11:40:04

云计算大数据阿里云

2011-03-31 09:20:45

URLDNSWeb应用程序

2022-03-28 15:40:34

harmony鸿蒙操作系统

2023-03-07 15:46:20

鸿蒙音频渲染

2022-04-11 13:57:38

HarmonyRelease操作系统

2022-06-14 15:07:04

IPC客户端服务端

2021-04-20 19:15:51

浏览器网络URL

2022-07-04 16:41:16

IPC通信HiTrace

2022-06-22 09:14:23

事件打点HiSysEvent

2014-09-25 10:36:33

点赞
收藏

51CTO技术栈公众号