开发环境
OpenHarmony5.0.2 RK3568
音频芯片:rk809,音频芯片在核心板pmic中,rk809引出的耳机和喇叭
遇到问题
编译后耳机有声音,但喇叭没有,拔插入耳机扬声器也没声音
解决思路
采用默认ADM方式,没用ALSA方式,修改默认的寄存器配置,使扬声器和耳机同时有声,耳机插拔调用寄存器修改扬声器静音还是播放来进行控制。目前只是解决这两个问题,其他音频相关没测试,例如录音之类的功能,后续调试到再完善。
修改代码
1、修改SELinux系统权限
文件地址:base/security/selinux_adapter/selinux.gni
declare_args() {
selinux_adapter_enforce = false
}
hdc shell 执行 getenforce 命令 验证输出应为 Permissive
修改权限避免引起的问题,查看日志
permissive=1 处于宽容模式,只告警不做访问拦截。
permissive=0 强制模式时,做拦截
2、修改设备树
耳机检测配置
rk_headset: rk-headset {
compatible = "rockchip_headset";
headset_gpio = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>; //改成自己的gpio
pinctrl-names = "default";
pinctrl-0 = <&hp_det>;
//io-channels = <&saradc 1>;
};
声卡配置
rk809_sound: rk809-sound {
status = "okay";
compatible = "simple-audio-card";
simple-audio-card,format = "i2s";
simple-audio-card,name = "rockchip,rk809-codec";
simple-audio-card,mclk-fs = <256>;
simple-audio-card,cpu {
sound-dai = <&i2s1_8ch>;
};
simple-audio-card,codec {
sound-dai = <&rk809_codec>;
};
};
rk809_codec: codec {
#sound-dai-cells = <0>;
compatible = "rockchip,rk809-codec", "rockchip,rk817-codec";
clocks = <&cru I2S1_MCLKOUT>;
clock-names = "mclk";
assigned-clocks = <&cru I2S1_MCLKOUT>, <&cru I2S1_MCLK_TX_IOE>;
assigned-clock-rates = <12288000>;
assigned-clock-parents = <&cru I2S1_MCLKOUT_TX>, <&cru I2S1_MCLKOUT_TX>;
pinctrl-names = "default";
pinctrl-0 = <&i2s1m0_mclk>;
hp-volume = <3>;
spk-volume = <20>;
capture_volume = <255>;
//use-ext-amplifier;
//mic-in-differential;
status = "okay";
};
3、修改播放路径配置
该文件定义了 不同音频场景下的硬件设备开关状态,用于控制音频信号的输入/输出路由,确保系统在不同使用场景下切换正确的音频路径,修改如下文件
drivers/peripheral/audio/config/audio_paths.json
vendor/hihope/default_core_system/hals/audio/audio_paths.json
vendor/hihope/rk3568/hals/audio/audio_paths.json
........
"hdf_audio_codec_primary_dev0": [
{
"deep-buffer-playback": [
{
"Headphones": [
{
"name": "Speaker1 Switch",
"value": 1 //改1
}
........
此文件修改后对于代码的解析地址
drivers/hdf_core/framework/model/audio/dispatch/src/audio_control_dispatch.c
对应的方法如下,查看输出日志如果修改后没变化,可以删除out目录重新编译。
static int32_t ControlHostElemWrite(const struct HdfDeviceIoClient *client,
struct HdfSBuf *reqData, struct HdfSBuf *rspData)
4、修改默认的寄存器配置
修改后删除out目录重新编译,不然不会生效
vendor/hihope/rk3568_mini_system/hdf_config/khdf/audio/analog_headset_config.hcs
root {
platform {
template headset_info {
match_attr = "";
serviceName = "";
}
headset :: headset_info {
headset_gpio = 60; //自己计算gpio
//hook_gpio = 0; //注释掉
.........
文档默认配置耳机检测的GPIO为Gpio3 RK_PC3
Gpio3 RK_PC3
bank =3
group=2
X=3
number=2*8+3=19
Pin=3*32+19=115
vendor/hihope/default_core_system/hdf_config/khdf/audio/codec_config.hcs
vendor/hihope/rk3568/hdf_config/khdf/audio/codec_config.hcs
.....................
regConfig {
/* reg, value */
initSeqConfig = [
0x38, 0x18, //修改
0x41, 0xf7, //修改
.....................
5、修改耳机检测相关代码
文件位置:
device/board/hihope/rk3568/audio_drivers/headset_monitor/src/analog_headset_core.c
方法static int32_t LinuxReadConfig(struct device_node *node, struct HeadsetPdata *pdata)
.........
/* hook */
ret = of_get_named_gpio_flags(node, "hook_gpio", 0, &pdata->hookGpio);
if (ret < 0) {
AUDIO_DEVICE_LOG_WARNING("----Can not read property hookGpio.-----");
pdata->hookGpio = 0;
/* adc mode */
//pdata->isHookAdcMode = true;
pdata->isHookAdcMode = false;//修改后
} else {
ret = of_property_read_u32(node, "hook_down_type", &pdata->hookDownType);
if (ret < 0) {
AUDIO_DEVICE_LOG_WARNING("have not set hookDownType,set >hook< insert type low level default.");
pdata->hookDownType = 0;
}
// pdata->isHookAdcMode = false;
pdata->isHookAdcMode = true;//修改后
}
............
新增方法控制扬声器开关
device/board/hihope/rk3568/audio_drivers/codec/rk809_codec/include/rk809_codec_impl.h
新增接口
/*扬声器开关控制0=关1=开*/
int32_t Rk809DeviceSpeakerControl(uint32_t val);
device/board/hihope/rk3568/audio_drivers/codec/rk809_codec/src/rk809_codec_impl.c
新增实现方法
//扬声器关闭
static const struct RegDefaultVal g_rk817SpeakerCloseReg[] = {
{ RK817_CODEC_DDAC_MUTE_MIXCTL, 0xa0 },
{ RK817_CODEC_ACLASSD_CFG1, 0x69 },
{ RK817_CODEC_ACLASSD_CFG2, 0x44 },
};
static const struct RegConfig g_rk817SpeakerCloseRegConfig = {
.regVal = g_rk817SpeakerCloseReg,
.size = ARRAY_SIZE(g_rk817SpeakerCloseReg),
};
//扬声器打开
static const struct RegDefaultVal g_rk817SpeakerOpenReg[] = {
/* CLASS D mode */
{ RK817_CODEC_DDAC_MUTE_MIXCTL,0x18},
/* CLASS D enable */
{ RK817_CODEC_ACLASSD_CFG1,0xa5},
/* restart CLASS D, OCPP/N */
{ RK817_CODEC_ACLASSD_CFG2,0xf7},
};
static const struct RegConfig g_rk817SpeakerOpenRegConfig = {
.regVal = g_rk817SpeakerOpenReg,
.size = ARRAY_SIZE(g_rk817SpeakerOpenReg),
};
/*扬声器开关控制0=关1=开*/
int32_t Rk809DeviceSpeakerControl(uint32_t val){
int32_t ret;
if(val==0){
ret = RK809DeviceRegConfig(g_rk817SpeakerCloseRegConfig);
if (ret != HDF_SUCCESS) {
return HDF_FAILURE;
}
}else if(val==1){
ret = RK809DeviceRegConfig(g_rk817SpeakerOpenRegConfig);
if (ret != HDF_SUCCESS) {
return HDF_FAILURE;
}
}else{
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
device/board/hihope/rk3568/audio_drivers/headset_monitor/src/analog_headset_gpio.c
调用方法
/* 根据插入状态控制扬声器开关*/
static void ControlSpeakerState(int32_t level)
{
if(level == HEADSET_IN){
//关扬声器
Rk809DeviceSpeakerControl(0);
}else {
//开扬声器
Rk809DeviceSpeakerControl(1);
}
}
CheckState方法调用
static int32_t CheckState(struct HeadsetPriv *hs, bool *beChange){
..............
if (level2 < 0) {
return HDF_FAILURE;
}
/* 根据插入状态控制扬声器开关*/
ControlSpeakerState(level2);
..................
修改默认驱动值
device/board/hihope/rk3568/audio_drivers/codec/rk809_codec/src/rk809_codec_linux_driver.c
static const struct reg_default rk817_reg_defaults[] = {
.............
{ RK817_CODEC_ADAC_CFG0, 0x00 },
{ RK817_CODEC_ADAC_CFG1, PWD_DACBIAS_ON | PWD_DACD_ON |
PWD_DACL_ON | PWD_DACR_ON }, //修改
{ RK817_CODEC_DDAC_POPD_DACST, 0x82 },
{ RK817_CODEC_DDAC_VOLL, 0x00 },
.............
{ RK817_CODEC_DDAC_LMT2, 0x00 },
{ RK817_CODEC_DDAC_MUTE_MIXCTL, 0x18 }, //修改
{ RK817_CODEC_DDAC_RVOLL, 0xff },
.............
{ RK817_CODEC_AHP_CFG0, 0x80 },//修改
{ RK817_CODEC_AHP_CFG1, 0x1f },
{ RK817_CODEC_AHP_CP, 0x11 }, //修改
{ RK817_CODEC_ACLASSD_CFG1, 0xa5 }, //修改
{ RK817_CODEC_ACLASSD_CFG2, 0xf7 }, //修改
{ RK817_CODEC_APLL_CFG0, 0x04 },
.............
6、修改耳机插入后设备优先级相关代码(改不改影响不大)
文件位置:
foundation/multimedia/audio_framework/services/audio_policy/server/include/service/manager/pnp_server/audio_pnp_param.h
增加定义常量
.............
#define UEVENT_STATE_ANALOG_HP0 "HEADPHONE=0"
#define UEVENT_STATE_ANALOG_HP1 "HEADPHONE=1"
.............
修改业务判断
文件位置:
foundation/multimedia/audio_framework/services/audio_policy/server/src/service/manager/pnp_server/audio_socket_thread.cpp
修改方法,此处不能检测到耳机设备新增,只能是麦克,先注释掉麦克,后期调试麦克再观察。
int32_t AudioSocketThread::SetAudioPnpServerEventValue(AudioEvent *audioEvent, struct AudioPnpUevent *audioPnpUevent)
....................
//if (strstr(audioPnpUevent->state, UEVENT_STATE_ANALOG_HS0) != NULL) {
if (strstr(audioPnpUevent->state, UEVENT_STATE_ANALOG_HP0) != NULL) {
audioEvent->eventType = PNP_EVENT_DEVICE_REMOVE;
} // else if (strstr(audioPnpUevent->state, UEVENT_STATE_ANALOG_HS1) != NULL) {
else if (strstr(audioPnpUevent->state, UEVENT_STATE_ANALOG_HP1) != NULL) {
audioEvent->eventType = PNP_EVENT_DEVICE_ADD;
} else{
....................
添加默认设备
foundation/multimedia/audio_framework/services/audio_policy/server/src/service/audio_device_manager.cpp
void AudioDeviceManager::AddDefaultDevices(const sptr<AudioDeviceDescriptor> &devDesc)
{
DeviceType devType = devDesc->deviceType_;
//if (devType == DEVICE_TYPE_EARPIECE) {
if (devType == DEVICE_TYPE_EARPIECE || devType == DEVICE_TYPE_WIRED_HEADSET) { //修改
earpiece_ = devDesc;
} else if (devType == DEVICE_TYPE_SPEAKER) {
speaker_ = devDesc;
//} else if (devType == DEVICE_TYPE_MIC) {
} else if (devType == DEVICE_TYPE_MIC || devType == DEVICE_TYPE_WIRED_HEADSET) { //修改
defalutMic_ = devDesc;
}
}
7、备注
目前修改后,用自带播放器播放音乐扬声器正常有声,拔插入耳机后扬声器中断正常。其他情况未测试。注意:配置文件HCS之类的修改后删除out目录再次编译,不然不生效。目前只做到这个程度,后期有问题优化再更新。
ALSA适配参考:audio适配方案_逸薇 -Laval社区