耳机插拔流程

Android 音频策略(音频优先级,音频输入输入,声音优先级) Android音频策略主要是在 frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp中,接下来我们看一下如何根据自己的需求在这个文件中调整自己的 音频输入输出策略。这里做了后插优先,就是那个设备最后插入声音就从哪个设备走,包括输入和输出,主要就是通过获取最后插入的设备类型来动态的调整声音优先级即可。音频输出策略是在Engine::getDeviceForStrategyInt这个函数里面:我们主要捡重要的讲。2.1、音频输出策略。 阅读详情

1.1      耳机

在Android系统中,有线耳机分两种,一种带mic,一种不带mic,带mic的耳机被称为Headset,不带mic的耳机被称为HeadPhone。在audio.h中,有以下几个设备来表示耳机:

       AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4,

AUDIO_DEVICE_OUT_WIRED_HEADPHONE           = 0x8,

AUDIO_DEVICE_IN_WIRED_HEADSET         = AUDIO_DEVICE_BIT_IN | 0x10,

         对于Headset的插入检测,一般通过jack耳机插座来完成,大概原理是使用带检测机构的耳机插座,将检测脚连到GPIO中断上,耳机插入时,是的检测脚的电平变化,引起中断。通过GPIO的值判断耳机是插入还是拔出。

1.2      Uevent

目前使用的耳机插拔事件使用的是UEvent。但是也可以使用InputEvent,这种设置在frameworks/base/core/res/res/values/config.xml中,设置项为

<boolname="config_useDevInputEventForAudioJack">false</bool>

值为false,所以目前kernel是用Uevent来通知应用层耳机插拔的。

什么是Uevent:

1.    内核通知应用的一种方式

2.    目前使用socket进行内核和应用的通信

3.    uevent就是一个特殊格式的字符串,如下,这应该是插入鼠标的Uevent

"add@/class/input/input9/mouse2\0    // message

ACTION=add\0                         // action type

DEVPATH=/class/input/input9/mouse2\0 // path in /sys

SUBSYSTEM=input\0                    // subsystem (class)

SEQNUM=1064\0                        // sequence number

PHYSDEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2­2/2­2:1.0\0  // device path in /sys

PHYSDEVBUS=usb\0      // bus

PHYSDEVDRIVER=usbhid\0 // driver

MAJOR=13\0            // major number

MINOR=34\0",          // minor number

内核发送uevent使用kobject_uevent_env,它还有一个wrapper是kobject_uevent,这个函数使用的比较多

1.3      UEvent是怎么工作的?

1.3.1       Switch驱动

Switch是在android中实现的一个module,可动态加载,是一个驱动。 Switch相关的代码在在drivers\switch\switch_class.c和drivers\switch\switch_gpio.c中,其中switch_gpio基于platform_device框架,在switch_class.c中,Export了以下两个函数供switch_gpio使用

    EXPORT_SYMBOL_GPL(switch_dev_register);

EXPORT_SYMBOL_GPL(switch_dev_unregister);

而Switch_gpio.c是驱动模块栈的更靠近设备的一层,这个设备就是gpio,初始化函数是

gpio_switch_probe{

         switch_dev_register(&switch_data->sdev);

         gpio_request(switch_data->gpio,pdev->name);

         gpio_direction_input(switch_data->gpio);

         gpio_to_irq(switch_data->gpio);

         request_irq//申请GPIO中断

         gpio_switch_work

}

这货是个platform驱动,它会调用

static int __init gpio_switch_init(void)

{

         returnplatform_driver_register(&gpio_switch_driver);

}

把自己注册成一个platform驱动。Platform是一种虚拟总线,和spi,emmc等都是类似的。

基于platform device/driver框架,在probe函数中完成初始化,包括获取gpio的使用权限,设置gpio方向为输入,注册switch_dev设备,为gpio分配中断,指定中断服务程序,初始化一个gpio_switch_work工作,最后读取gpio初始状态。  

在switch_class.c中,调用switch_set_state->switch_gpio_print_state输出GPIO状态到 sysfs。

Sysfs是一个虚拟的文件系统,由linux内核提供,通过使用虚拟文件,sysfs向用户空间公布了关于内核子系统的信息,硬件设备和相关的设备驱动。但是这个文件系统并不是被上层直接使用的,它仅仅是作为比较直观的方式提供给human being检查状态用的。

而真正发送uevent是在switch_class.c的这个函数里:

void switch_set_state(struct switch_dev *sdev,int state)

最终通过kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp)发送。

kobject_uevent_env的流程如下:

1.    调用kobject_uevent_env之前,系统已经调用uevent_net_init(struct net *net)完成了初始化工作,也就是创建了socket,并创建了netlink,如下:

         netlink_kernel_create(net,NETLINK_KOBJECT_UEVENT,1, NULL, NULL, THIS_MODULE);

                   sock_create_lite(PF_NETLINK,SOCK_DGRAM, unit, &sock)

                   __netlink_create(&init_net,sock, cb_mutex, unit)

2.    netlink_broadcast_filtered,netlink广播uevent信息。

         sk_for_each_bound

                   do_one_broadcast(sk,&info);

上面提到了Netlink socket,下面看看这是啥:

Netlink socket是一种Linux特有的socket,用于实现用户进程与内核进程之间通信的一种特殊的进程间通信方式(IPC) ,也是网络应用程序与内核通信的最常用的接口。
Netlink 是一种在内核和用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就能使用 Netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 Netlink。

1.3.2       Netlink Socket通信

用户空间程序只需要创建一个NETLINK socket描述符,就可以侦听Uevent了,如下:

sockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);

AF_NETLINK 是一种“domain”,定义了通信使用的协议,比如我们通常使用的IPV4协议。

<sys/socket.h>定义的所有的协议如下: 

AF_UNIX,

AF_LOCAL

AF_INET

IPv4

AF_INET6

IPv6

AF_IPX

IPX

AF_NETLINK

Kernel

AF_X25

ITU-T

AF_AX25

Amateur

AF_ATMPVC

Access

AF_APPLETALK

AppleTal

AF_PACKET

Low

AF_ALG

Interface

事实上,Framework就是写了一个很简单的socket网络程序:

在uevent.c (hardware\libhardware_legacy\uevent)中,看函数uevent_init,

s =socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);

setsockopt(s,SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));

bind(s,(struct sockaddr *) &addr, sizeof(addr)

再看uevent_next_event(char* buffer, intbuffer_length)

int count =recv(fd, buffer, buffer_length, 0);

其实就是读取socket的内容到buffer中。

1.3.3       观察者模式

拿到socket的内容后,需要通知对它感兴趣的模块。这里就使用了观察者模式。Android在frameworks/base/services/java/com/android/server/WiredAccessoryManager. java中实现对UEvent的处理。在这个文件中,从UEventObserver中继承了类WiredAccessoryObserver,在makeObservedUEventList中将要观察的事件加入到UEvent系统中:

 

UeventObserver持有一个静态的UEventThread对象,所有子类Observer都共享一个Thread。

private staticUEventThread sThread;

UeventThread是一个静态类,有一个Array:

private finalArrayList<Object> mKeysAndObservers = new ArrayList<Object>();

各种子类Observer都添加key和observer到mKeysAndObservers。比如,WiredAccessoryObserver添加(“DEVPATH= /devices/virtual/switch/h2w”,this),(“DEVPATH= /devices/virtual/switch/usb_audio”,this),(“DEVPATH= /devices/virtual/switch/hdmi”,this)到mKeysAndObservers。这个Thread不断的去读取AF_NETLINK中的数据,并对注册进去的key字符串进行匹配,匹配上的调用改key对应的observer的onUevent函数。

如何匹配的?

private voidsendEvent(String message){

for(;;){

if(message.contains(key))

mTempObserversToSignal.add(observer);

}

for (;;) {

final UEventObserverobserver = mTempObserversToSignal.get(i);

observer.onUEvent(event);

}

}

这个onUEvent经过一系列无聊的调用,最终调到

AudioManager:: setWiredDeviceConnectionState(intdevice, int state, String name),自此进入Audio子系统

1.4      Audio子系统

最终会到Audio Policy中的setDeviceConnectionState来,它有两个参数,一个表示设备id,另一个表示该设备是插入还是拔出。比如设备id 4代表的是HEADSET,而当state是AUDIO_POLICY_DEVICE_STATE_AVAILABLE时表示插入,当AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE时表示拔出。当设备有hw module与之相对应时(getModuleForDevice),会增加或减少mAvailableOutputDevices和mAvailableInputDevices。

Android音频相关(七)Audio log 分析篇 1.new devices的查看 log中的new devices 要看Audio-baes.h 在安卓9.0上是可以看 //OUT_AUX_DIGITAL的。这个主要是看当前播放音频的设备是什么。位置在 例如 new devices 0x2 其实就是speaker在播放声音。 enum { AUDIO_DEVICE_NONE = 0u, // 0x0 AUDIO_D... 阅读详情

相关推荐

Android 耳机插拔处理流程

最近遇到一个bug: 当播放音乐时,插拔耳机,此时闹钟响起,闹钟响铃没有声音。 刚开始以为是闹钟问题,浪费了不少时间,后来发现,插拔耳机后,音乐播放也会出现没有声音。 使用命令, adb shell getevent 发现,插拔耳机时,底层事件有正常上报。 adb shell  parameter status >  status.log  查看,log中,当耳机拔出后,还是HeadSet

哈喽沃德 6908

Android audio设备的定义

audio设备的定义位于AudioSystem.h文件中 enum audio_devices { // output devices 1.输出设备: DEVICE_OUT_EARPIECE = 0x1, // 听筒 DEVICE_OUT_SPEAKER = 0x2, // 扬声器 DEVICE_OUT_WIRED_HEADSET = 0x4, // 线控耳机,可

蓝蓝的天 2万+

ca6240拔插

课程设计老师要的东西

Android 耳机插拔流程源码跟踪浅析

Android 耳机插拔流程源码跟踪浅析

哈喽沃德 1271

如何设计一个低代码平台

近些年来,低代码发展火热,各种低代码平台如雨后春笋纷纷崛起,这些平台各定位不同,优劣不同,用户的选择空间很大。那么,如果用户想从零开始设计一个低代码平台,该如何做呢?

Jarod_Chou的博客 8260

避坑指南:Vue调用摄像头常见6大报错解决方案(navigator.mediaDevices全兼容方案)

本文深入剖析了在Vue应用中调用摄像头时常见的六大报错,如权限拒绝、设备未找到等,并提供了基于navigator.mediaDevices的全兼容解决方案。内容涵盖从HTTPS环境配置、浏览器兼容性处理到摄像头资源管理与高级错误处理,旨在帮助开发者构建稳定可靠的企业级摄像头应用。

Black的专栏 341

【audio】耳机插拔/线控按键识别流程

耳机插拔/线控按键识别流程 1.文档概述 本文以msm8909平台,android N为例,介绍了通用情况下,耳机插拔的流程步骤,以及对耳机类型的识别逻辑。以方便在项目工作中经常会遇到耳机不被识别,或者识别后不能正常工作等情况,都可以参考此文档检测判断逻辑,确定问题根本,理解底层框架。 2.耳机的类型 从主观来看,耳机分三段耳机和四段耳机,而四段耳机又分为欧标和美标两种。通常,四段

Lieke的博客 2万+

量化策略缺数据?一份QMT/PTrade免费数据清单与特殊数据源QtFactor评测

本文为量化策略开发者提供QMT和PTrade平台的免费数据资源清单,并深度评测QtFactor在补充特色数据方面的价值。涵盖Tick级数据、Level2行情、资金流向等关键信息,帮助开发者在预算有限的情况下构建高效数据解决方案,特别适合打板策略和日内回转交易。

weixin_29058331的博客 417

Android耳机耳机,Android 耳机插拔流程源码跟踪浅析

Android 开发过程中,使用耳机控制拍照,控制音乐播放,控制打电话等,线控再到蓝牙控... 耳机也在不断升级,耳机插拔的程序这一块也在不断完善。因此,在定制开发过程中,阅读这部分流程代码是必修的功课了,至少首先的要搞清楚程序走的线路流程。下面结合我在实际工作过程中遇到的bug,需求定制等做个简单的总结。第一节,插拔耳机时,事件上报抓取事件命令:查看有哪些事件可以getPS C:\Users\...

weixin_42467088的博客 665

Light Tools 8.4 在 win10系统上的安装方法(64位)

** 总的来说安装LT需要以下步骤(折腾了三天终于装好): 安装LT软件–禁用签名–加载含数字签名的第三方inf–添加注册表/安装驱动/添加密钥–成功破解 一、下载对应的LightTools 8.4版本软件,如下图为解压后的文件: 并选择 进行默认安装。 二、禁用数字签名。这里我用了两种方法,一种不行就换另一种,最终成功禁用。 方法1: 1、输入“cmd”并以管理员身份运行; 2、输入或复制 bcdedit.exe /set nointegritychecks on (此命令若没成功,再试bcded

weixin_45560953的博客 1万+

WPS访问权限不足怎么解决??具体怎么操作?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值。

**My Coding Family** 4171

【audio】耳机插拔 线控按键识别流程【转】

耳机插拔/线控按键识别流程 耳机插拔/线控按键识别流程 1.文档概述 本文以msm8909平台,android N为例,介绍了通用情况下,耳机插拔的流程步骤,以及对耳机类型的识别逻辑。以方便在项目工作中经常会遇到耳机不被识别,或者识别后不能正常工作等情况,都可以参考此文档检测判断逻辑,确定问题根本,理解底层框架。 2.耳机的类型 从主观来看,耳机分三段耳机和四段耳机,而四段耳机又分为欧标和美标两种...

weixin_30266829的博客 632

想重装OpenClaw?先执行这4步彻底卸载,避免配置冲突

在重装OpenClaw之前,彻底卸载是非常重要的一步。如果不彻底卸载,可能会导致: - 残留的配置文件与新安装的版本冲突 - 旧的依赖包干扰新的安装过程 - 服务冲突导致启动失败 - 数据混乱影响系统稳定性

一键难忘的博客 1043

Android设备耳机插拔流程

有线耳机插入流程: 一、UEventObserver.java 有线设备输入输出插入消息处理 二、WiredAccessoryManager.java 1、消息处理 private final Handler mHandler = new Handler(Looper.myLooper(), null, true) public void handleMessage(Message msg) switch (msg.what) { ca

nihaoma95278的博客 1733

pandas教程:2012 Federal Election Commission Database 2012联邦选举委员会数据库

里面包含了支持者的名字,职业和雇主,地址,赞助金额。我们可以已经能想到如何切割、整理数据,来提取赞助者的统计数据,或提取宣传活动的模式,这里我们展示一些不同的分析方法。可以看到有些职业是同一种工作类型,指代的是同一个东西。这两个连续操作是分别独立执行的,一个结束后,另一个才开始。上,这里我是把数据集压缩成了ZIP格式,解压后能正常导入)。我觉得也有必要好好了解一下,这个网站做了很好的讲解,),所以我们最好添加这样的信息。这样的情况,即把两个索引操作连在一起。,发现映射关系被正常执行了,所以这里的。

Cachel Wood的博客 350

AutoSAR配置与实践(实践篇)13.1 如何添加一个NVM BLOCK

解决办法:如下红框选项都不要自定义,否则无法自动生成对应RAM/ROM映射接口函数。传送门–AUTOSAR配置与实践—总目录传送门–AUTOSAR配置与实践—总目录。

nihaoljq2010的博客 3040

android 耳机插拔流程

SystemServer.java中:private void startOtherServices() { // ... traceBeginAndSlog("StartWiredAccessoryManager"); try { // Listen for wired headset changes inputManager.setWiredAcc

deactor的博客 2434

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Android4.x耳机插拔检测实现方法

Android4.x耳机插拔检测实现方法 2.耳机的类型 从主观来看,耳机分三段耳机和四段耳机,而四段耳机又分为欧标和美标两种。通常,四段耳机被写作headset,而三段耳机写作headphones。具体的区别如下图: l三段耳机:线序分别为,L、R、G,没有MIC端,所以三段耳机无法使用mic,只能接受声音,另外,三段耳机L,R线序长度正常,G端比较长 l四段-美标(CTIA)...

late0001的专栏 2944

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

安卓audio外接设备连接,大致流程图

audiomanager

aningxiaoxixi的博客 782

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

上一篇: 线程通信原理之一:线程本地存储(TLS)
下一篇: 求大数阶乘算法
我把葡萄酿成酒
博客等级 码龄12年 275粉丝 198原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值