WUKONG100 UIS7885芯片Audio适配
Audio驱动框架介绍
Audio驱动框架基于HDF驱动框架实现,Audio驱动框架的组成:

社区RK3568走的是ADM适配,WUKONG100在以前采用tinyasla,因此在OpenHarmony上适配ALSA框架
音频驱动选的四种集成方案如下:

音频驱动框架模型,向上服务于多媒体音频子系统,便于系统开发者能够更便捷的根据场景来开发应用。向下服务于具体的设备厂商,芯片厂商可以根据此驱动架构,进行各自驱动的开发及HAL层接口的调用。
对于芯片而言,音频驱动已经支持alsa,只要通过alsa-lib对到HDF层,就可以实现快速开发和适配OpenHarmony系统。
ALSA适配
ALSA使用OpenHarmony上自带的三方库alsa-lib对接WUKONG100底层的音频驱动,集成三方库alsa-utils工具以确认底层驱动设备节点是否正常
# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: sprdphonesc2730 [sprdphone-sc2730], device 0: FE_ST_NORMAL_AP01 (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 1: FE_ST_NORMAL_AP23 (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 3: FE_ST_FAST (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 5: FE_ST_VOICE (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 6: FE_ST_VOIP (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 7: FE_ST_FM (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 10: FE_ST_LOOP (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 12: FE_ST_A2DP_PCM (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 15: FE_ST_FM_DSP (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 18: FE_ST_VOICE_PCM_P (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 19: FE_ST_TEST_CODEC (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 24: DisplayPort MultiMedia (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sprdphonesc2730 [sprdphone-sc2730], device 25: FE_ST_MM_P (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
通过amixer配置播放、录音的音频通路后,使用aplay、arecord测试设备驱动的播放、录音效果
aplay -M -D hw:0,0 /etc/dynamic.wav
arecord -M -D hw:0,0 -r 8000 -c 1 -f S16_LE --period-size=640 --buffer-size=2560 /data/arecold.wav
HDF层适配
-
社区主干走的是ADM,默认没有开启ALSA编译,因此需要在产品//vendor/revoview/wukong100目录下的config.json中开启
drivers_peripheral_audio_feature_alsa_lib = true -
//vendor/revoview/wukong100/hals/audio目录下的ALSA相关的配置文件需要修改
alsa_adapter.json是设备匹配的配置文件
{ "adapters": [ { "name": "primary", "cardId": 0, "cardName": "sprdphonesc2730" }, { "name": "hdmi", "cardId": 1, "cardName": "rockchiphdmi" } ] }alsa_paths.json是音频通路的配置文件,不同场景下音频的Speaker、Mic通话等需要写入相应的配置
audio_policy_config.xml 是音频核心策略配置文件,音频流类型、使用场景、音频端口、路由规则等需要在此配置
通话切换路由、听筒扬声器切换更新音频路由需要将updateRouteSupport设置为true
<globalConfigs> <defaultOutput adapter="primary" pipe="primary_output" device="Speaker"/> <commonConfigs> <attribute name="updateRouteSupport" value="true"/> <attribute name="maxRendereres" value="128"/> <attribute name="maxCapturers" value="16"/> </commonConfigs> -
社区主干对alsa_paths.json文件的解析有问题,修改后已合入主干
#include "cJSON.h" #include "osal_mem.h" #include "securec.h" #include "audio_common.h" #ifdef IDL_MODE #define HDF_LOG_TAG AUDIO_HDI_IMPL @@ -27,9 +28,9 @@ #define SPEAKER "Speaker" #define HEADPHONES "Headphones" #define MIC "Mic" #define HS_MIC "MicHs" #define EARPIECE "Earpiece" #define BLUETOOTH_SCO "Bluetooth" #define BLUETOOTH_SCO_HEADSET "Bluetooth_SCO_Headset" #define JSON_UNPRINT 1 @@ -42,7 +43,8 @@ #define AUDIO_DEV_ON 1 #define AUDIO_DEV_OFF 0 #define HDF_PATH_NUM_MAX (32 * 4) #define ADM_VALUE_SIZE 4 -
增加设备切换和路由信息的切换修改,已合入主干
int32_t AudioAdapterUpdateAudioRoute( struct IAudioAdapter *adapter, const struct AudioRoute *route, int32_t *routeHandle) { AUDIO_FUNC_LOGI("Enter."); struct AudioHwAdapter *hwAdapter = (struct AudioHwAdapter *)adapter; if (hwAdapter == NULL) { AUDIO_FUNC_LOGE("AudioAdapterUpdateAudioRoute Invalid input param!"); return AUDIO_ERR_INVALID_PARAM; } if (renderId_ <= -1 || renderId_ >= MAX_AUDIO_STREAM_NUM) { AUDIO_FUNC_LOGE("render is Invalid"); return AUDIO_ERR_INVALID_PARAM; } AUDIO_FUNC_LOGI("AudioAdapterUpdateAudioRoute renderId_: %{public}d", renderId_); struct IAudioRender *render = (struct IAudioRender *)hwAdapter->infos.renderServicePtr[renderId_]; struct AudioHwRender *hwRender = (struct AudioHwRender *)render; if (hwRender == NULL) { AUDIO_FUNC_LOGE("hwRender is NULL!"); return AUDIO_ERR_INTERNAL; } if (hwRender->devCtlHandle == NULL) { AUDIO_FUNC_LOGE("RenderSetVoiceVolume Bind Fail!"); return AUDIO_ERR_INTERNAL; } InterfaceLibModeRenderPassthrough *pInterfaceLibModeRender = AudioPassthroughGetInterfaceLibModeRender(); if (pInterfaceLibModeRender == NULL || *pInterfaceLibModeRender == NULL) { AUDIO_FUNC_LOGE("InterfaceLibModeRender not exist"); return HDF_FAILURE; } int32_t ret = (*pInterfaceLibModeRender)(hwRender->devCtlHandle, &hwRender->renderParam, AUDIODRV_CTL_IOCTL_UPDATE_ROUTER); if (ret < 0) { AUDIO_FUNC_LOGE("Audio RENDER_CLOSE FAIL"); } return AUDIO_SUCCESS; } -
增加通话音量调节,已合入主干
int32_t AudioAdapterSetVoiceVolume(struct IAudioAdapter *adapter, float volume) { AUDIO_FUNC_LOGD("AudioAdapterSetVoiceVolume Enter."); int32_t ret = 0; struct AudioHwAdapter *hwAdapter = (struct AudioHwAdapter *)adapter; if (hwAdapter == NULL) { AUDIO_FUNC_LOGE("AudioAdapterSetVoiceVolume Invalid input param!"); return AUDIO_ERR_INVALID_PARAM; } if (renderId_ <= -1 || renderId_ >= MAX_AUDIO_STREAM_NUM) { AUDIO_FUNC_LOGE("render is Invalid"); return AUDIO_ERR_INVALID_PARAM; } AUDIO_FUNC_LOGI("AudioAdapterSetVoiceVolume renderId_: %{public}d", renderId_); struct IAudioRender *render = (struct IAudioRender *)hwAdapter->infos.renderServicePtr[renderId_]; struct AudioHwRender *hwRender = (struct AudioHwRender *)render; if (hwRender == NULL) { AUDIO_FUNC_LOGE("hwRender is NULL!"); return AUDIO_ERR_INTERNAL; } if (volume < 0 || volume > 1) { AUDIO_FUNC_LOGE("AudioAdapterSetVoiceVolume volume param Is error!"); return AUDIO_ERR_INVALID_PARAM; } if (hwRender->devCtlHandle == NULL) { AUDIO_FUNC_LOGE("RenderSetVoiceVolume Bind Fail!"); return AUDIO_ERR_INTERNAL; } InterfaceLibModeRenderPassthrough *pInterfaceLibModeRender = AudioPassthroughGetInterfaceLibModeRender(); if (pInterfaceLibModeRender == NULL || *pInterfaceLibModeRender == NULL) { AUDIO_FUNC_LOGE("InterfaceLibModeRender not exist"); return HDF_FAILURE; } hwRender->renderParam.renderMode.ctlParam.voiceVolume = volume; ret = (*pInterfaceLibModeRender)(hwRender->devCtlHandle, &hwRender->renderParam, AUDIODRV_CTL_IOCTL_VOICE_VOLUME_WRITTE); if (ret < 0) { AUDIO_FUNC_LOGE("Audio RENDER_CLOSE FAIL"); } return AUDIO_SUCCESS; } -
社区主干RK3568音频代码没有通话功能,WUKONG100在ALSA方案的基础上实现了音频通话,在//device/board/revoview/wukong100/audio_alsa/目录进行了重新适配,主要是添加了通话场景对render、captuer的处理,切换不同场景时音频通路的切换,通话在对render设备设置同时需要对capture同时进行处理等
int32_t RenderGetSceneDev(enum AudioCategory scene) { if (scene < AUDIO_IN_MEDIA || scene > AUDIO_MMAP_NOIRQ) { scene = AUDIO_IN_MEDIA; } if (scene == AUDIO_IN_CALL) { return SND_CALL_PCM_DEV; } else { return SND_DEFAULT_PCM_DEV; } } static bool CheckSceneIsChange(enum AudioCategory scene) { if (scene != AUDIO_IN_CALL) { if (g_currentScene == AUDIO_IN_CALL || g_currentScene == AUDIO_MMAP_NOIRQ) { return true; } else { return false; } } else { if (g_currentScene != AUDIO_IN_CALL) { return true; } else { return false; } } } static int32_t UpdateAudioRenderRoute(struct AlsaRender *renderIns, const struct AudioHwRenderParam *handleData) { CHECK_NULL_PTR_RETURN_DEFAULT(renderIns); struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)renderIns; CHECK_NULL_PTR_RETURN_DEFAULT(cardIns); int32_t ret; int32_t devCount = handleData->renderMode.hwInfo.pathSelect.deviceInfo.deviceNum; AUDIO_FUNC_LOGI("UpdateAudioRenderRoute devCount:%{public}d!", devCount); if (devCount < 0 || devCount > PATHPLAN_COUNT) { AUDIO_FUNC_LOGE("devCount is error!"); return HDF_FAILURE; } struct AlsaMixerCtlElement elems[devCount]; for (int i = 0; i < devCount; i++) { SndElementItemInit(&elems[i]); elems[i].numid = 0; elems[i].name = handleData->renderMode.hwInfo.pathSelect.deviceInfo.deviceSwitchs[i].deviceSwitch; elems[i].value = handleData->renderMode.hwInfo.pathSelect.deviceInfo.deviceSwitchs[i].value; } ret = SndElementGroupWrite(cardIns, elems, devCount); if (ret < 0) { AUDIO_FUNC_LOGE("render SndElementGroupWrite fail"); return HDF_FAILURE; } return HDF_SUCCESS; }
audio-framework适配
audio-framework作为通用代码,WUKONG100不涉及对此仓库的修改