首页 > 代码库 > Android底层开发之耳机插拔与音频通道切换实例
Android底层开发之耳机插拔与音频通道切换实例
Android底层开发之耳机插拔与音频通道切换实例
由于使用的是耳机 麦克分离式的耳机,所以要分别上报事件。在Android系统层耳机插孔的检测是基于/sys/class/switch/h2w/state的值来判断的(以4.4.4_r2为例子位于WiredAccessoryManager.java)。
只要在内核中实现一个「或真或假」的基于switch类的h2w开关。Android系统就可以监听到插拔信息。
在播放音乐的时候插入耳机,使用tinymix(参考:Android音频底层调试-基于tinyalsa)命令可以查找到Playback Path的值从SPK变为HP_NO_MIC,就可以说明耳机插拔软件检测正常了。
# tinymix
Mixer name: ‘RK_RK616_TINY‘
Number of controls: 7
ctl type num name value
0 ENUM 1 Playback Path HP_NO_MIC
1 ENUM 1 Capture MIC Path MIC OFF
2 ENUM 1 Voice Call Path OFF
3 ENUM 1 Voip Path OFF
4 INT 2 Speaker Playback Volume 24 24
5 INT 2 Headphone Playback Volume 24 24
6 ENUM 1 Modem Input Enable ON
#
但是喇叭还在响,说明没有被关闭。查查原理图「功放上的控制脚」是在哪个GPIO上接着呢。
根据手册得出只要GPIO2_D7可以输出低电平就能实现喇叭的关闭,使用万用表测得在插入耳机后该管脚仍然为高电平,查看代码修改记录在上一个版本同事是直接在rk_headset.c耳机插拔程序中修改将其拉低的,这样可以实现但是觉得不妥,Android上层应该也是有音频通道切换的,根据上层来控制比较好。这样插入耳机的时候也可以强制开启喇叭,把「使用哪个音频通信的决定权」交给给用户。
这个应该是在内核中实现的,因为Alsa已经正常切换了,就说明上层已经调用相应的接口了。从驱动中来分析。
设备资源:可以看到Speak和handphone的使能GPIO都给的是RK30_PIN2_PD7。
static struct rk616_platform_data rk616_pdata = {
.power_init = rk616_power_on_init,
.power_deinit = rk616_power_deinit,
.scl_rate = RK616_SCL_RATE,
.lcd0_func = INPUT, //port lcd0 as input
.lcd1_func = INPUT, //port lcd1 as input
.lvds_ch_nr = 1, //the number of used lvds channel
.hdmi_irq = RK30_PIN2_PD6,
.spk_ctl_gpio = RK30_PIN2_PD7,
.hp_ctl_gpio = RK30_PIN2_PD7,
};
设备驱动中控制音频输出通道的函数:
static int rk616_playback_path_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
......
case HP_PATH:
case HP_NO_MIC:
case RING_HP:
case RING_HP_NO_MIC:
rk616_set_gpio(RK616_CODEC_SET_SPK, GPIO_LOW);
if (pre_path == OFF)
rk616_codec_power_up(RK616_CODEC_PLAYBACK);
snd_soc_update_bits(codec, RK616_SPKL_CTL,
RK616_VOL_MASK, HPOUT_VOLUME); //, volume (bit 0-4)
snd_soc_update_bits(codec, RK616_SPKR_CTL,
RK616_VOL_MASK, HPOUT_VOLUME);
rk616_set_gpio(RK616_CODEC_SET_HP, GPIO_HIGH);
break;
......
}
可见在输出到耳机通道时,禁用 SPEAKER和使能HP都是设置的GPIO_HIGH,最后RK30_PIN2_PD7仍然为高电平,没有禁用SPEAKER。原理图并没有单独的耳机的使能管脚。在资源中将hp_ctl_gpio设置为INVALID_GPIO,问题得以解决。
额外收获:原理耳机那里一直都是有音频输出的,无论插入不插入耳机;插入耳机时仅仅是将SPEAKER禁止了。
误入的歧途:
1.误以为要去看Android上层代码在各种类中追寻了很久,真是浪费时间,如果使用tinymix查看音频通道切换正常,说明内核以上的都没有问题了,出问题也是出在了内核以及硬件上。
总结:庞大的Android系统容不得你每一块都了解的很细致,但是如果会很好的划分层次,问题就会很好解决。记录的重点不在于具体的型号版本等等比较虚的方面,而是在遇到此类问题分析的思路。
Android底层开发之耳机插拔与音频通道切换实例