精华内容
下载资源
问答
  • 耳机设计知识
    千次阅读
    2019-07-01 08:58:20

    耳机基础知识入门
      一、耳机是如何分类的
      按换能原理(Transducer)分主要是动圈(Dynamic)和静电(Electrostatic)耳机两大类,虽然除这二类之外尚有等磁式等数种,但或是已被淘汰或是用于专业用途市场占有量极少,在此不做讨论。
      动圈耳机原理:目前绝大多数(大约99%以上)的耳机耳塞都属此类,原理类似于普通音箱,处于永磁场中的线圈与振膜相连,线圈在信号电流驱动下带动振膜发声。
      静电耳机:振膜处于变化的电场中,振膜极薄、精确到几微米级(目前STAX新一代的静电耳机振膜已精确到1.35微米),线圈在电场力的驱动下带动振膜发声。
      二、按开放程度分
      主要是开放式、半开放式、封闭式(密闭式)
      开放式的耳机一般听感自然,佩带舒适,常见于家用欣赏的HIFI耳机,声音可以泄露、反之同样也可以听到外界的声音,耳机对耳朵的压迫较小。
      半开放式:没有严格的规定,声音可以只进不出亦可以只出不进,根据需要而做出相应的调整
      封闭式:耳罩对耳朵压迫较大以防止声音出入,声音正确定位清晰,专业监听领域中多见此类,但这类耳机有一个缺点就是低音音染严重,W100就是一个明显的例子。
      三、耳机一些相关参数和音质术语分别代表什么意义
      1.耳机相关参数
      阻抗(Impedance):注意与电阻含义的区别,在直流电(DC)的世界中,物体对电流阻碍的作用叫做电阻,但是在交流电(AC)的领域中则除了电

    更多相关内容
  • 今天我们就一起来了解一下这个行业,现在目前市场上的TWS蓝牙耳机比较杂,几乎每家都在设计、制造生产这个火爆的产品,TWS蓝牙耳机。下面我们就一起来分析一下TWS蓝牙耳机目前的状况。
  • 浅谈耳机生产工艺设计和性能测试耳机基础知识五.doc
  • TWS耳机实现主动降噪(ANC)之机构、电声系统设计与调试流程
  • 蓝牙耳机降噪知识

    千次阅读 2019-09-10 15:42:29
    蓝牙耳机上的降噪,根据原理可以分为以下几种。 1、被动降噪。 这个是指入耳式耳塞,由于耳塞是通过一个硅胶套塞入人耳的耳道的。...通话降噪,是指蓝牙耳机用于通话时,为了让通话的对方可以听的清楚而设计的。常见...

    在这里插入图片描述
    蓝牙耳机上的降噪,根据原理可以分为以下几种。
    1、被动降噪。
    这个是指入耳式耳塞,由于耳塞是通过一个硅胶套塞入人耳的耳道的。所以有较好的隔离外界声音的作用。而且这个降噪是全频的,就是对从20赫兹到20K赫兹的声音都有效,而且,这个被动降噪是无损音质的。所以一般的HiFi耳塞都是入耳式的就是因为这个原因。
    2、通话降噪。
    通话降噪,是指蓝牙耳机用于通话时,为了让通话的对方可以听的清楚而设计的。常见的如高通的CVC降噪。它的原理是利用蓝牙耳机内部的芯片,把通话麦克风接收到的信号进行滤波处理,把外界的风噪等降低。同时,还可以把对方传过来的通话音进行回声削弱处理。
    CVC降噪由于没有额外的麦克风来采集外部的噪音,所以降噪效果目前还是满足不了实际应用。因此有的蓝牙耳机还设计有额外的麦克风,用于收集环境噪声,然后内部的处理器,就会把通话麦克风收集的信号中,减去拾噪麦克风收集的外部噪音。因此这种降噪效果要好很多。这种降噪我们一般叫“上行降噪”。
    3、主动降噪。
    主动降噪,是指在一些特定场合,如高铁/飞机上,通过拾噪麦克风,采集外界的一些有规律的噪声(如飞机发动机的轰鸣声)。通过电路或者算法,把在音乐信号中加入反向的噪音信号,是的人耳听到的耳机中的声音,和外界的噪声直接抵消掉,从而达到降噪效果。
    (上述文章阐述归伦茨科技公司所有,转载请注明出处,更多相关信息欢迎关注微信公众号:lenze_tech或微信号:lenzetech,或者点击:http://www.lenzetech.com/news/)

    展开全文
  • 版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文...数字耳机和模拟耳机 模拟耳机即我们的常见的3.5mm接口的耳机,包括左右声道,地或者mic,如左图。 数字耳机(右图)包含一个usb声卡...

    数字耳机和模拟耳机

            模拟耳机即我们的常见的3.5mm接口的耳机,包括左右声道,地或者mic,如左图。

            数字耳机(右图)包含一个usb声卡+DAC&&ADC+amp+模拟耳机,当数字耳机接入到手机(otg)或者电脑后,手机或者电脑识别到了usb设备,并创建相应的声卡后,数字音频信号通过usb传输到数字耳机后,数字耳机通过DAC转换并放大信号,就可以听到声音了,这也是usb声卡的原理。

         typec耳机(中图)可能是模拟耳机也可能是数字耳机,以耳机内有没有芯片进行判别。本人就在淘宝上买来一款数字耳机(商品上介绍的就是数字耳机),买回来手机用不了,接电脑也识别不了usb设备,后来才发现是typec接口的模拟耳机,严重的虚假宣传。

    手机中模拟和数字耳机的差异

     DAC :Digital to analog converter数字模拟转换器

    AMP:放大器

     TRS:(Tip,Ring,sleeve),指音频插头,参考https://wenku.baidu.com/view/3e0881741a37f111f0855b34.html

    typec耳机介绍

    市面上常见的typec接口方案的耳机接口图。

             图5是小米6x的底面图,取消的3.5mm耳机接口,可以兼容数字耳机和模拟耳机,这一类的机型包括小米note3,华为p20pro,坚果锤子等(数字耳机就是一个usb从设备)。

            电路板设计有一个耳机自动切换ic(模拟耳机的左右声道接在usb+、usb-,因此需要切换开光,如DIO3202A, vbus电平为高,芯片切换到usb通路,vbus电平为低,切换到耳机通路),数字耳机接入耳机后,typec逻辑芯片检测到从设备,cpu上的usb切换到主模式,并提供5v(vbus)给从设备供电,完成相应的数字信号传输。

            

                                                                                    图4(dio3202a)

    兼容模拟耳机的原理,typec逻辑芯片会识别成不同的设备(数字耳机,usb设备  模拟耳机 音频配件)(也可以使用mic来识别耳机的插拔  原理: 模拟耳机接入耳机后由于vbus没电,耳机逻辑ic选择耳机通道,耳机mic检测脚初始化为高,当模拟耳机插入后,mic相当于一个1k的电阻,由于分压,mic脚的电压会拉低,mic_det脚所在的pmic上的内部电压比较器检测到了电平变化进一步触发了耳机mic的中断,进一步判断耳机的类型,从而识别达到耳机)。

     

                                                                                         图5(去掉3.5mm接口)

           图6的手机保留3.5mm的耳机接口,代表机型有华为nova2s,小米5x等。这一类机型typec接口可以接数字耳机,但nova2s上可以听音乐,但打电话时耳机无法使用,这是因为打电话的场景中需要相应的通路支持(跟cpu相关,可参考https://www.synopsys.com/zh-cn/china/resources/dwtb/dwtb-cn-usb-audio-2017q2.html)。

                                                                                         图6(保留3.5mm接口)

    展开全文
  • Android 耳机驱动知识

    千次阅读 2018-12-19 14:03:01
    这部分涉及的硬件知识比较简单,但是软件上对中断的处理,软件检测的鲁棒性,都有比较高的要求,涉及到驱动开发中经常使用的中断申请,工作队列,tasklet,竟态和同步,linux input子系统,android 键值映射等知识。...

    https://yunzhi.github.io/headset_knowledge

     

    工作以后接手的第一个驱动就是android平台下耳机的插拔检测和按键检测。这部分涉及的硬件知识比较简单,但是软件上对中断的处理,软件检测的鲁棒性,都有比较高的要求,涉及到驱动开发中经常使用的中断申请,工作队列,tasklet,竟态和同步,linux input子系统,android 键值映射等知识。

    1.耳机的通用接口为一个裸露的圆柱体,从头端到线侧的直径依次增大,并通过橡胶环进行绝缘而设计,这样方便无论从哪个角度都可以插入。在耳机座上,通过弹片和耳机头的金属环触而形成电路导通。

    2.市面上流通的耳机从接口大小上分3.5mm和2.5mm两种,主要适配不同尺寸的插口,比较常见的是3.5mm。从接口电气特性上分三段式和四段式,四段式在三段耳机的基础上增加了mic端——耳机内部的一个声电转化装置。

    • 三段式耳机接口从头部到线一侧的定义式左声道,右声道,GND。
    • 四段式耳机分美标(CTIA)和欧标(国内要求为欧标,OMTP-Open Mobile Terminal Platform开放移动终端平台),主要区别在于耳机线侧最后两端的定义,美标为左声道(L),右声道(R),GND(G),MIC(M),括号内为缩写,下面为清晰主要采用缩写,国标为L,R,M,G。

    三段和四段耳机的简易电路示例图

    3.从耳机识别的角度来讲,耳机上的电声转化装置(左声道听音器和右声道听音器)可以认为是一个16欧或者32欧的电阻,电阻值根据耳机厂商的设计而不同,一般的标准为16欧或者32欧,但有些比较好的耳机这个内阻值比较大;mic端可以认为是一个大电阻(通常为1k欧)和一个开关(多按键耳机可以认为好多个开关串上不同组值得电阻)。

    耳机标准-美标 (CTIA,通常称为美标)

    从插入端到线分别是: 左声道,右声道,GND,MIC。耳机上德绝缘橡胶环一般是白色的代表品牌:iphone,MOTO,小米,魅族,索尼

    ctia headset

    耳机接口标准 (OMTP,通常称为欧标)

    从插入端到线分别是: 左声道,右声道,MIC,GND。耳机上德绝缘橡胶环一般是黑色的代表品牌:诺基亚,三星,HTC

    omtp headset

    相应的,耳机座也分为支持欧标设计的耳机座和支持美标设计的耳机座。另外,从耳机座左声道的检测方式来又可以分为 “Nomally-closed type”(常闭型) 和 “Normally-open type”(常开型) 两种。其简易设计如下图

    headset jack type

    图中所示的耳机座为美标的。

    • 在常闭型中,不接耳机时,耳机座左声道和检测端HS-DET接触,插入耳机时,HS-DET与HPH-L不导通。

    • 在常开型中,不接耳机时,耳机座左声道和检测端HS-DET不接触,插入耳机时,HS-DET与HPH-L导通。

    下图是一个高通平台下耳机座设计的原理图

    headset detect priciple

    可以看到,该耳机座为常开型,采用了左声道检测的机制——CDC_HS_DET为插入耳机触发硬件中断的的管脚。当没有插入耳机时,由于CDC_HS_DET悬空,而该网络对应的平台端的gpio(输入状态)口为低电平。当插入耳机后,由于耳机左声道内部相当于1个16欧的电阻和GND相接,于是有如下的模拟图:

    headset circuit正常情况下,CDC_HPH_L会有一点电压存在,通过电阻的分压,于是CDC_HS_DET接收到了高电平,引起了软件中断。软件上通过debounce后,检测到持续的高电平,于是认为有耳机插入。这时候需要判断,插入的是三段还是四段。平台上打开mic_bias,当插入的是三段耳机时,MIC_IN2_P端口被拉低(忽略原理图R3501处的NC,应该是个笔误),于是判断为三段耳机。若为四段耳机,MIC_IN2_P的电平接近于MIC_BIAS,软件判断该处的直流电压之后设置识别了四段耳机。当按键按下时,MIC_IN2_P的电压发生变化,触发了系统中断,之后软件通过采样该处的电压值判断按键阻值而确定按下了哪一个按键。

    一般的,一键耳机按下后电阻值在10欧以下,三键带音量加减的耳机上键的电阻范围在60欧到100欧之间,中键在10欧以下,下键在120欧~200欧之间。

    我接触过四个平台的耳机驱动,mtk、高通、Nividia和spreadtrum。除了高通将检测耳机插拔的事件也申请为input设备外,,其他平台都注册为switch/h2w设备。mtk平台的耳机驱动称为ACCDET+EINT的模式,高通的机制叫做MBHC,都是一套看起来特别麻烦的机制。而展讯的code将耳机驱动作为misc下得一个设备驱动来用,很体现linux “write code do one thing and do it well”的哲理。下面来看看展讯的耳机驱动。

    headset.h

     
    1. /*
    2. * Copyright (C) 2012 Spreadtrum Communications Inc.
    3. *
    4. * This software is licensed under the terms of the GNU General Public
    5. * License version 2, as published by the Free Software Foundation, and
    6. * may be copied, distributed, and modified under those terms.
    7. *
    8. * This program is distributed in the hope that it will be useful,
    9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    11. * GNU General Public License for more details.
    12. */
    13.  
    14. #ifndef __HEADSET_H__
    15. #define __HEADSET_H__
    16. #include <linux/switch.h>
    17. #include <linux/input.h>
    18. #include <linux/platform_device.h>
    19. enum {
    20. BIT_HEADSET_OUT = 0,
    21. BIT_HEADSET_MIC = (1 << 0),
    22. BIT_HEADSET_NO_MIC = (1 << 1),
    23. };
    24.  
    25. enum {
    26. HEADSET_BUTTON_DOWN_INVALID = -1,
    27. HEADSET_BUTTON_DOWN_SHORT,
    28. HEADSET_BUTTON_DOWN_LONG,
    29. };
    30.  
    31. struct _headset_gpio {
    32. int active_low;
    33. int gpio;
    34. int irq;
    35. unsigned int irq_type_active;
    36. unsigned int irq_type_inactive;
    37. int debounce;
    38. int debounce_sw;
    39. int holded;
    40. int active;
    41. int irq_enabled;
    42. const char *desc;
    43. struct _headset *parent;
    44. unsigned int timeout_ms;
    45. struct hrtimer timer;
    46. enum hrtimer_restart (*callback)(int active, struct _headset_gpio *hgp);
    47. };
    48.  
    49. struct _headset_keycap {
    50. unsigned int type;
    51. unsigned int key;
    52. };
    53.  
    54. struct _headset_button {
    55. struct _headset_keycap cap[15];
    56. unsigned int (*headset_get_button_code_board_method)(int v);
    57. unsigned int (*headset_map_code2push_code_board_method)(unsigned int code, int push_type);
    58. };
    59.  
    60. struct _headset {
    61. struct switch_dev sdev;
    62. struct input_dev *input;
    63. struct _headset_gpio detect;
    64. struct _headset_gpio button;
    65. int headphone;
    66. int type;
    67. struct work_struct switch_work;
    68. struct workqueue_struct * switch_workqueue;
    69. };
    70.  
    71. #ifndef ARRY_SIZE
    72. #define ARRY_SIZE(A) (sizeof(A)/sizeof(A[0]))
    73. #endif
    74.  
    75. #endif

    headset.c

     
    1. /*
    2. * Copyright (C) 2012 Spreadtrum Communications Inc.
    3. *
    4. * This software is licensed under the terms of the GNU General Public
    5. * License version 2, as published by the Free Software Foundation, and
    6. * may be copied, distributed, and modified under those terms.
    7. *
    8. * This program is distributed in the hope that it will be useful,
    9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    11. * GNU General Public License for more details.
    12. */
    13.  
    14. #include <linux/interrupt.h>
    15. #include <linux/irq.h>
    16. #include <linux/delay.h>
    17. #include <mach/gpio.h>
    18. #include <linux/headset.h>
    19. #include <mach/board.h>
    20.  
    21. #ifndef HEADSET_DETECT_GPIO
    22. #define HEADSET_DETECT_GPIO 165
    23. #endif
    24. #ifndef HEADSET_BUTTON_GPIO
    25. #define HEADSET_BUTTON_GPIO 164
    26. #endif
    27.  
    28. #ifndef HEADSET_DETECT_GPIO_ACTIVE_LOW
    29. #define HEADSET_DETECT_GPIO_ACTIVE_LOW 1
    30. #endif
    31. #ifndef HEADSET_BUTTON_GPIO_ACTIVE_LOW
    32. #define HEADSET_BUTTON_GPIO_ACTIVE_LOW 0
    33. #endif
    34.  
    35. #ifndef HEADSET_DETECT_GPIO_DEBOUNCE_SW
    36. #define HEADSET_DETECT_GPIO_DEBOUNCE_SW 1000
    37. #endif
    38. #ifndef HEADSET_BUTTON_GPIO_DEBOUNCE_SW
    39. #define HEADSET_BUTTON_GPIO_DEBOUNCE_SW 100
    40. #endif
    41.  
    42. static enum hrtimer_restart report_headset_button_status(int active, struct _headset_gpio *hgp);
    43. static enum hrtimer_restart report_headset_detect_status(int active, struct _headset_gpio *hgp);
    44. static struct _headset headset = {
    45. .sdev = {
    46. .name = "h2w",
    47. },
    48. .detect = {
    49. .desc = "headset detect",
    50. .active_low = HEADSET_DETECT_GPIO_ACTIVE_LOW,
    51. .gpio = HEADSET_DETECT_GPIO,
    52. .debounce = 0,
    53. .debounce_sw = HEADSET_DETECT_GPIO_DEBOUNCE_SW,
    54. .irq_enabled = 1,
    55. .callback = report_headset_detect_status,
    56. },
    57. .button = {
    58. .desc = "headset button",
    59. .active_low = HEADSET_BUTTON_GPIO_ACTIVE_LOW,
    60. .gpio = HEADSET_BUTTON_GPIO,
    61. .debounce = 0,
    62. .debounce_sw = HEADSET_BUTTON_GPIO_DEBOUNCE_SW,
    63. .irq_enabled = 1,
    64. .callback = report_headset_button_status,
    65. .timeout_ms = 800, /* 800ms for long button down */
    66. },
    67. };
    68.  
    69.  
    70. #ifndef headset_gpio_init
    71. #define headset_gpio_init(gpio, desc) \
    72. do { \
    73. gpio_request(gpio, desc); \
    74. gpio_direction_input(gpio); \
    75. } while (0)
    76. #endif
    77.  
    78. #ifndef headset_gpio_free
    79. #define headset_gpio_free(gpio) \
    80. gpio_free(gpio)
    81. #endif
    82.  
    83. #ifndef headset_gpio2irq_free
    84. #define headset_gpio2irq_free(irq, args) { }
    85. #endif
    86.  
    87. #ifndef headset_gpio2irq
    88. #define headset_gpio2irq(gpio) \
    89. gpio_to_irq(gpio)
    90. #endif
    91.  
    92. #ifndef headset_gpio_set_irq_type
    93. #define headset_gpio_set_irq_type(irq, type) \
    94. irq_set_irq_type(irq, type)
    95. #endif
    96.  
    97. #ifndef headset_gpio_get_value
    98. #define headset_gpio_get_value(gpio) \
    99. gpio_get_value(gpio)
    100. #endif
    101.  
    102. #ifndef headset_gpio_debounce
    103. #define headset_gpio_debounce(gpio, ms) \
    104. gpio_set_debounce(gpio, ms)
    105. #endif
    106.  
    107. #ifndef headset_hook_detect
    108. #define headset_hook_detect(status) { }
    109. #endif
    110.  
    111. #define HEADSET_DEBOUNCE_ROUND_UP(dw) \
    112. dw = (((dw ? dw : 1) + HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD - 1) / \
    113. HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD) * HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD;
    114.  
    115. static struct _headset_keycap headset_key_capability[20] = {
    116. { EV_KEY, KEY_MEDIA },
    117. { EV_KEY, KEY_END },
    118. { EV_KEY, KEY_RESERVED },
    119. };
    120.  
    121. static unsigned int (*headset_get_button_code_board_method)(int v);
    122. static unsigned int (*headset_map_code2push_code_board_method)(unsigned int code, int push_type);
    123. static __devinit int headset_button_probe(struct platform_device *pdev)
    124. {
    125. struct _headset_button *headset_button = platform_get_drvdata(pdev);
    126. headset_get_button_code_board_method = headset_button->headset_get_button_code_board_method;
    127. headset_map_code2push_code_board_method = headset_button->headset_map_code2push_code_board_method;
    128. memcpy(headset_key_capability, headset_button->cap, sizeof headset_button->cap);
    129. return 0;
    130. }
    131.  
    132. static struct platform_driver headset_button_driver = {
    133. .driver = {
    134. .name = "headset-button",
    135. .owner = THIS_MODULE,
    136. },
    137. .probe = headset_button_probe,
    138. };
    139.  
    140. static unsigned int headset_get_button_code(int v)
    141. {
    142. unsigned int code;
    143. if (headset_get_button_code_board_method)
    144. code = headset_get_button_code_board_method(v);
    145. else
    146. code = KEY_MEDIA;
    147. return code;
    148. }
    149.  
    150. static unsigned int headset_map_code2key_type(unsigned int code)
    151. {
    152. unsigned int key_type = EV_KEY;
    153. int i;
    154. for(i = 0; headset_key_capability[i].key != KEY_RESERVED &&
    155. headset_key_capability[i].key != code && i < ARRY_SIZE(headset_key_capability); i++);
    156. if (i < ARRY_SIZE(headset_key_capability) &&
    157. headset_key_capability[i].key == code)
    158. key_type = headset_key_capability[i].type;
    159. else
    160. pr_err("headset not find code [0x%x]'s maping type\n", code);
    161. return key_type;
    162. }
    163.  
    164. static unsigned int headset_map_code2push_code(unsigned int code, int push_type)
    165. {
    166. if (headset_map_code2push_code_board_method)
    167. return headset_map_code2push_code_board_method(code, push_type);
    168.  
    169. switch (push_type) {
    170. case HEADSET_BUTTON_DOWN_SHORT:
    171. code = KEY_MEDIA;
    172. break;
    173. case HEADSET_BUTTON_DOWN_LONG:
    174. code = KEY_END;
    175. break;
    176. }
    177.  
    178. return code;
    179. }
    180.  
    181. /*tangyao modified on 2013-01-25*/
    182. static void headset_gpio_irq_enable(int enable, struct _headset_gpio *hgp);
    183. #define HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD 50 /* 10 */
    184. static enum hrtimer_restart report_headset_button_status(int active, struct _headset_gpio *hgp)
    185. {
    186. enum hrtimer_restart restart;
    187. static int step = 0;
    188.  
    189. if (active < 0) {
    190. step = 0;
    191. return HRTIMER_NORESTART;
    192. }
    193. if (active) {
    194. restart = HRTIMER_RESTART;
    195. if (++step > 3)
    196. step = 0;
    197. switch (step) {
    198. case 1:
    199. /*short press report*/
    200. input_event(hgp->parent->input,EV_KEY,KEY_MEDIA, 1);
    201. input_sync(hgp->parent->input);
    202. break;
    203. case 2:
    204. /*long press report,first report short press release,then long press start*/
    205. input_event(hgp->parent->input,EV_KEY,KEY_MEDIA, 0);
    206. input_sync(hgp->parent->input);
    207. input_event(hgp->parent->input,EV_KEY,KEY_END, 1);
    208. input_sync(hgp->parent->input);
    209. break;
    210. default:
    211. pr_info("Are you press too long? step = %d\n",step);
    212. }
    213. } else {
    214. restart = HRTIMER_NORESTART;
    215. if (step == 1){
    216. /*short press release report*/
    217. input_event(hgp->parent->input,EV_KEY,KEY_MEDIA, 0);
    218. input_sync(hgp->parent->input);
    219. }else{
    220. /*long press release report*/
    221. input_event(hgp->parent->input,EV_KEY,KEY_END, 0);
    222. input_sync(hgp->parent->input);
    223. }
    224. step = 0;
    225. }
    226.  
    227. return restart;
    228. }
    229.  
    230. static enum hrtimer_restart report_headset_detect_status(int active, struct _headset_gpio *hgp)
    231. {
    232. struct _headset * ht = hgp->parent;
    233. if (active) {
    234. headset_hook_detect(1);
    235. ht->headphone = 0;
    236. /*headphone support,tangyao modified on 2012-01-25*/
    237. ht->headphone = ht->button.active_low ^ headset_gpio_get_value(ht->button.gpio);
    238. if (ht->headphone) {
    239. ht->type = BIT_HEADSET_NO_MIC;
    240. queue_work(ht->switch_workqueue, &ht->switch_work);
    241. pr_info("headphone plug in\n");
    242. } else {
    243. ht->type = BIT_HEADSET_MIC;
    244. queue_work(ht->switch_workqueue, &ht->switch_work);
    245. pr_info("headset plug in\n");
    246. headset_gpio_set_irq_type(ht->button.irq, ht->button.irq_type_active);
    247. headset_gpio_irq_enable(1, &ht->button);
    248. }
    249. } else {
    250. headset_gpio_irq_enable(0, &ht->button);
    251. ht->button.callback(-1, &ht->button);
    252. headset_hook_detect(0);
    253. if (ht->headphone)
    254. pr_info("headphone plug out\n");
    255. else
    256. pr_info("headset plug out\n");
    257. ht->type = BIT_HEADSET_OUT;
    258. queue_work(ht->switch_workqueue, &ht->switch_work);
    259. }
    260. /* use below code only when gpio irq misses state, because of the dithering */
    261. headset_gpio_set_irq_type(hgp->irq, active ? hgp->irq_type_inactive : hgp->irq_type_active);
    262. return HRTIMER_NORESTART;
    263. }
    264.  
    265. static enum hrtimer_restart headset_gpio_timer_func(struct hrtimer *timer)
    266. {
    267. enum hrtimer_restart restart = HRTIMER_RESTART;
    268. struct _headset_gpio *hgp =
    269. container_of(timer, struct _headset_gpio, timer);
    270. int active = hgp->active_low ^ headset_gpio_get_value(hgp->gpio); /* hgp->active */
    271. int green_ch = (!active && &hgp->parent->detect == hgp);
    272. if (active != hgp->active) {
    273. pr_info("The value %s mismatch [%d:%d] at %dms!\n",
    274. hgp->desc, active, hgp->active, hgp->holded);
    275. hgp->holded = 0;
    276. }
    277. pr_debug("%s : %s %s green_ch[%d], holed=%d, debounce_sw=%d\n", __func__,
    278. hgp->desc, active ? "active" : "inactive", green_ch, hgp->holded, hgp->debounce_sw);
    279. hgp->holded += HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD;
    280. if (hgp->holded >= hgp->debounce_sw || green_ch) {
    281. if (hgp->holded == hgp->debounce_sw || \
    282. hgp->holded == hgp->timeout_ms || \
    283. green_ch) {
    284. pr_debug("call headset gpio handler\n");
    285. restart = hgp->callback(active, hgp);
    286. } else
    287. pr_debug("gpio <%d> has kept active for %d ms\n", hgp->gpio, hgp->holded);
    288. }
    289. if (restart == HRTIMER_RESTART)
    290. hrtimer_forward_now(timer,
    291. ktime_set(HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD / 1000,
    292. (HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD % 1000) * 1000000)); /* repeat timer */
    293. return restart;
    294. }
    295.  
    296. static irqreturn_t headset_gpio_irq_handler(int irq, void *dev)
    297. {
    298. struct _headset_gpio *hgp = dev;
    299. hrtimer_cancel(&hgp->timer);
    300. hgp->active = hgp->active_low ^ headset_gpio_get_value(hgp->gpio);
    301. headset_gpio_set_irq_type(hgp->irq, hgp->active ? hgp->irq_type_inactive : hgp->irq_type_active);
    302. pr_debug("%s : %s %s\n", __func__, hgp->desc, hgp->active ? "active" : "inactive");
    303. hgp->holded = 0;
    304. hrtimer_start(&hgp->timer,
    305. ktime_set(HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD / 1000,
    306. (HEADSET_GPIO_DEBOUNCE_SW_SAMPLE_PERIOD % 1000) * 1000000),
    307. HRTIMER_MODE_REL);
    308. return IRQ_HANDLED;
    309. }
    310.  
    311. static void headset_gpio_irq_enable(int enable, struct _headset_gpio *hgp)
    312. {
    313. int action = 0;
    314. if (enable) {
    315. if (!hgp->irq_enabled) {
    316. hrtimer_cancel(&hgp->timer);
    317. hgp->irq_enabled = 1;
    318. action = 1;
    319. hgp->holded = 0;
    320. enable_irq(hgp->irq);
    321. }
    322. } else {
    323. if (hgp->irq_enabled) {
    324. disable_irq(hgp->irq);
    325. hrtimer_cancel(&hgp->timer);
    326. hgp->irq_enabled = 0;
    327. action = 1;
    328. hgp->holded = 0;
    329. }
    330. }
    331. pr_info("%s [ irq=%d ] --- %saction %s\n", __func__, hgp->irq_enabled, action ? "do " : "no ", hgp->desc);
    332. }
    333.  
    334. static void headset_switch_state(struct work_struct *work)
    335. {
    336. struct _headset *ht;
    337. int type;
    338.  
    339. ht = container_of(work, struct _headset, switch_work);
    340. type = ht->type;
    341. switch_set_state(&headset.sdev, type);
    342. pr_info("set headset state to %d\n", type);
    343. }
    344.  
    345. static int __init headset_init(void)
    346. {
    347. int ret, i;
    348. struct _headset *ht = &headset;
    349. ret = switch_dev_register(&ht->sdev);
    350. if (ret < 0) {
    351. pr_err("switch_dev_register failed!\n");
    352. return ret;
    353. }
    354. platform_driver_register(&headset_button_driver);
    355. ht->input = input_allocate_device();
    356. if (ht->input == NULL) {
    357. pr_err("switch_dev_register failed!\n");
    358. goto _switch_dev_register;
    359. }
    360. ht->input->name = "headset-keyboard";
    361. ht->input->id.bustype = BUS_HOST;
    362. ht->input->id.vendor = 0x0001;
    363. ht->input->id.product = 0x0001;
    364. ht->input->id.version = 0x0100;
    365.  
    366. for(i = 0; headset_key_capability[i].key != KEY_RESERVED; i++) {
    367. __set_bit(headset_key_capability[i].type, ht->input->evbit);
    368. input_set_capability(ht->input, headset_key_capability[i].type, headset_key_capability[i].key);
    369. }
    370.  
    371. if (input_register_device(ht->input))
    372. goto _switch_dev_register;
    373.  
    374. headset_gpio_init(ht->detect.gpio, ht->detect.desc);
    375. headset_gpio_init(ht->button.gpio, ht->button.desc);
    376.  
    377. headset_gpio_debounce(ht->detect.gpio, ht->detect.debounce * 1000);
    378. headset_gpio_debounce(ht->button.gpio, ht->button.debounce * 1000);
    379.  
    380. hrtimer_init(&ht->button.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    381. ht->button.timer.function = headset_gpio_timer_func;
    382. HEADSET_DEBOUNCE_ROUND_UP(ht->button.debounce_sw);
    383. HEADSET_DEBOUNCE_ROUND_UP(ht->button.timeout_ms);
    384. ht->button.parent = ht;
    385. ht->button.irq = headset_gpio2irq(ht->button.gpio);
    386. ht->button.irq_type_active = ht->button.active_low ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
    387. ht->button.irq_type_inactive = ht->button.active_low ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW;
    388. ret = request_irq(ht->button.irq, headset_gpio_irq_handler,
    389. ht->button.irq_type_active, ht->button.desc, &ht->button);
    390. if (ret) {
    391. pr_err("request_irq gpio %d's irq failed!\n", ht->button.gpio);
    392. goto _gpio_request;
    393. }
    394. headset_gpio_irq_enable(0, &ht->button);
    395.  
    396. hrtimer_init(&ht->detect.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    397. ht->detect.timer.function = headset_gpio_timer_func;
    398. HEADSET_DEBOUNCE_ROUND_UP(ht->detect.debounce_sw);
    399. ht->detect.parent = ht;
    400. ht->detect.irq = headset_gpio2irq(ht->detect.gpio);
    401. ht->detect.irq_type_active = ht->detect.active_low ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
    402. ht->detect.irq_type_inactive = ht->detect.active_low ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW;
    403. ret = request_irq(ht->detect.irq, headset_gpio_irq_handler,
    404. ht->detect.irq_type_active, ht->detect.desc, &ht->detect);
    405. if (ret) {
    406. pr_err("request_irq gpio %d's irq failed!\n", ht->detect.gpio);
    407. goto _headset_button_gpio_irq_handler;
    408. }
    409.  
    410. INIT_WORK(&ht->switch_work, headset_switch_state);
    411. ht->switch_workqueue = create_singlethread_workqueue("headset_switch");
    412.  
    413. if (ht->switch_workqueue == NULL) {
    414. pr_err("can't create headset switch workqueue\n");
    415. ret = -ENOMEM;
    416. goto _headset_workqueue;
    417. }
    418.  
    419. return 0;
    420. _headset_workqueue:
    421. destroy_workqueue(ht->switch_workqueue);
    422. _headset_button_gpio_irq_handler:
    423. free_irq(ht->button.irq, &ht->button);
    424. headset_gpio2irq_free(ht->button.irq, &ht->button);
    425. _gpio_request:
    426. headset_gpio_free(ht->detect.gpio);
    427. headset_gpio_free(ht->button.gpio);
    428. input_free_device(ht->input);
    429. _switch_dev_register:
    430. platform_driver_unregister(&headset_button_driver);
    431. switch_dev_unregister(&ht->sdev);
    432. return ret;
    433. }
    434. module_init(headset_init);
    435.  
    436. static void __exit headset_exit(void)
    437. {
    438. struct _headset *ht = &headset;
    439. destroy_workqueue(ht->switch_workqueue);
    440. headset_gpio_irq_enable(0, &ht->button);
    441. headset_gpio_irq_enable(0, &ht->detect);
    442. free_irq(ht->detect.irq, &ht->detect);
    443. headset_gpio2irq_free(ht->detect.irq, &ht->detect);
    444. free_irq(ht->button.irq, &ht->button);
    445. headset_gpio2irq_free(ht->button.irq, &ht->button);
    446. headset_gpio_free(ht->detect.gpio);
    447. headset_gpio_free(ht->button.gpio);
    448. input_free_device(ht->input);
    449. platform_driver_unregister(&headset_button_driver);
    450. switch_dev_unregister(&ht->sdev);
    451. }
    452. module_exit(headset_exit);
    453.  
    454. MODULE_DESCRIPTION("headset & button detect driver");
    455. MODULE_AUTHOR("Luther Ge <luther.ge@spreadtrum.com>");
    456. MODULE_LICENSE("GPL");

    分析:

    1. 360-373行,注册input设备。可以看到,一个input设备的注册方法,首先使用input_allocate_device为设备申请相关数据结构,然后初始化该结构的相关成员,如input->name,input->id.vendor, input->id.product, input->id.version(这四个字符串决定了键盘映射文件的名称),然后调用__set_bit设置该input设备支持的事件类型,及调用input_set_capability设置支持的按键值,最后调用input_register_device将输出化完成的数据结构注册到input子系统中。一般的,我们不用去实现他的handle函数,evdev.c就可以完成该目的。

    2. 374-378行,初始化耳机和按键检测时用到的gpio口

    3. 380-394行,申请耳机按键检测的中断处理函数,初始化中断下半段的处理机制。可以看到这里使用了hr_timer这样一个内核中的高精度定时器来实现
    4. 396-417行,申请耳机插拔检测的中断处理函数,初始化中断下半段的处理机制。可以看到这里使用了work_queue这样一个机制来实现。

    可以看到,耳机在中断下半段处理时采用了内核定时器timer来实现。另外,耳机插拔的检测使用了h2w这个class,hook按键上报则采用了input子系统。

    headset插拔识别的框架代码分析

    涉及的相关文件如下hardware/libhardware_legacy/uevent.cframeworks/base/core/jni/android_os_UEventObserver.cppframeworks/base/core/java/android/os/UEventObserver.javaframeworks/services/java/com/android/server/SystemServer.javaframeworks/base/services/java/com/android/server/WiredAccessoryManager.java

    流程待分析

    hook按键的处理

    hook按键通过input子系统上报给Android,在Android手机/system/usr/keylayout/目录下保存着键值映射配置文件。

    一般的,耳机按键对应的按键映射:key 231 CALLkey 122 ENDCALL WAKEkey 166 MEDIA_STOPkey 163 HEADSETHOOKkey 164 MEDIA_PLAY_PAUSEkey 165 MEDIA_PREVIOUSkey 114 VOLUME_DOWNkey 115 VOLUME_UP

    这个按键配置文件第三列的字符串在/frameworks/base/include/androidfw/KeycodeLabels.h (android 4.0), frameworks/native/include/input/KeycodeLabels.h(android 4.4), 被定义成:

     
    1. static const KeycodeLabel KEYCODES[] = {
    2. ...
    3. { "CALL", 5 },
    4. { "ENDCALL", 6 },
    5. ...
    6. { "MEDIA_PLAY_PAUSE", 85 },
    7. { "MEDIA_STOP", 86 },
    8. ...
    9. }

    最终/frameworks/base/core/java/android/view/KeyEvent.java会把这个数字定义成这样的常量:

     
    1. public class KeyEvent extends InputEvent implements Parcelable {
    2. ...
    3. public static final int KEYCODE_CALL = 5;
    4. /** Key code constant: End Call key. */
    5. public static final int KEYCODE_ENDCALL = 6;
    6. ...
    7. /** Key code constant: Play/Pause media key. */
    8. public static final int KEYCODE_MEDIA_PLAY_PAUSE= 85;
    9. /** Key code constant: Stop media key. */
    10. public static final int KEYCODE_MEDIA_STOP = 86;
    11. ...
    12. }

    手机耳机是手机非常重要的功能之一,耳机的插拔检测和按键检测和相对比较麻烦,日常工作中也容易出现一些新的需求,如新的设备需要通过耳机接口被接入到手机中。因此,研究其驱动和应用层的实现还是很有必要的。

    展开全文
  • 骨传导耳机的原理是什么?简单来说就是将声音转化为不同频率的机械振动,通过颅骨、骨迷路、内耳淋巴液传递、螺旋器、听神经、听觉中枢来传递声音。比空气传播的速度更快,损耗更小。 骨传导耳机和一般传统耳机...
  • 无需蓝牙或射频专业知识和经验 经过全面认证的蓝牙模块:FCC、IC、CE、MIC 适用于音频无线数据通信和控制的完整蓝牙解决方案 器件(本参考设计涉及到的主要芯片) LMX9838:蓝牙串行模块,集成了2.4GHz无线控制、蓝牙...
  • typec耳机知识介绍

    千次阅读 2020-09-02 10:21:58
    数字耳机和模拟耳机 模拟耳机即我们的常见的3.5mm接口的耳机,包括左右声道,地或者mic,如左图。 数字耳机(右图)包含一个usb声卡+DAC&&ADC+amp+模拟耳机,当数字耳机接入到手机(otg)或者电脑后,手机...
  • 您将使用之前学习的所有HTML / CSS / Accessibility / Responsive设计知识。 您将没有太多的说明,您可以按自己的方式随意执行它-目标很简单:拥有一个功能齐全的网页,外观与设计器文件相同。 现场演示 :laptop_...
  • 蓝牙耳机主动降噪的基础知识介绍

    千次阅读 2022-04-15 14:31:32
    蓝牙耳机主动降噪的基础知识介绍 1:什么是噪音和为什么要降噪? 噪声的本质:是频率、强弱变化无规律、杂乱无章的机械波。机械波又可以按人耳的识别程度分为一下几个部分:a. 可听见的声音;b. 播放音乐的声音;c. ...
  • 对于非IT专业的人来说,想要挑选蓝牙耳机但那一堆堆数据看的人眼花缭乱,今天小编就来科普一下蓝牙耳机的各种行业知识。 IP指数级别: IP=Ingress Protection(防护等级) IPX1-3级:防水性能差,可防轻微水雾。 ...
  • 降噪耳机的原理

    千次阅读 2022-01-11 00:16:25
    随着科技的发展,耳机这个看着很普通的设备,已经从最开始满足能听的需求,到现在追求更高品质的需求,就像数字音频增强引擎(DSEE)、AI智能降噪、LDAC蓝牙传输技术、Hi-Res Audi...
  • 美标耳机四极接法:从最前头开始数1234,左/右声道/地线/麦系统。 国标耳机四极接法:从最前头开始数1234,左/右声道/麦系统/地线。 它们不同之处,就是地线和麦系统(MIC)两个接触点进行了前后互换。大部份而言...
  • 霍尔伯顿耳机

    2021-02-10 05:50:57
    您将使用之前学习的所有HTML / CSS / Accessibility / Responsive设计知识。 您将没有太多的说明,您可以按自己的方式随意执行它-目标很简单:拥有一个功能齐全的网页,外观与设计器文件相同。 这里是最终结果: ...
  • 毫无疑问,无线蓝牙耳机是近两年推出的最新颖的智能配件之一,它将传统耳机那长长的连接线给取消了,更加便捷的佩戴和使用,一时间受到了非常多用户的喜爱。如今,国内除了苹果外还有许多无线耳机在不断地推出,3.5...
  • 一款音质好的蓝牙耳机对于跑步来说是一种享受,跑步中戴着蓝牙听着优美的旋律,沉浸在自由、愉悦的环境下,身心完全没有束缚,而且舒适度好的蓝牙耳机没有压迫感,所以这时候选到合适的蓝牙耳机就非常有必要。...
  • 让你更深入的了解红外线耳机电路各个部分的接法以至于你的更好的掌握这方面知识
  • 基于Qualcomm QCC3040双Mic cVc通话降噪+ANC主动降噪TWS Mirroring耳机方案
  • 蓝牙耳机可以说是现在最热门的数码产品,但是其中的水分还是有很多,不懂蓝牙耳机行情的人很容易就会被无良商家坑。为了让大家在选购的时候,能做到心中有谱,今天给大家科普一下,选购蓝牙耳机的三大技巧!让你能...
  • 在这两年,真无线蓝牙耳机逐渐开始出现在人们的视野中,从最开始Airpods一代领衔到现如今的百花齐放(当然Airpods二代还是最强的),真无线蓝牙耳机已经在逐渐取代从前的一体式蓝牙耳机,那么为什么真无线蓝牙耳机...
  • 这样既可以帮助学生更好地理解所学专业理论知识,又能进一步激发他们对本专业的热爱与兴趣。 本文所设计的小型通信系统可以很好地满足这一需求。该通信系统由发射机单元和接收机单元组成。一人在发射机单元对着话筒...
  • 用NE5532运算放大器制作降噪耳机
  • 【科技犬】今天科技犬推荐三款耳机,在推荐新品之前,科技犬要给大家科普一个小知识,请详细阅读!当用户使用TWS耳机时,手机通过蓝牙发送数据至一个耳机接收端,此接收端会把立体声通过无线传输的方式转发到另一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,418
精华内容 2,167
关键字:

耳机设计知识