技术领域  
 
 [0001]  
 
 本发明涉及一种Android系统双屏异显的两路音频实现方法。  
 
 背景技术  
 
 [0002]  
 
 关于Android系统的双屏异显两路音频的实现目前还没有通用的方法,Android系  
 
 统的双屏异显两路音频的需求是:主屏的声音从主屏对应的声卡输出、副屏的声音从副屏  
 
 对应声卡输出,不能有混音。  
 
 [0003]  
 
 如图1所示,现有的Android系统音频整个框架包括应用层APP、framework层、lib  
 
 层、hal层、驱动以及硬件。  
 
 [0004]  
 
 应用层APP,这是整个音频体系的最上层,因而并不是Android系统实现异显两路  
 
 音频输出的重点。比如厂商根据特定需求自己写的一个音乐播放器,游戏中使用到声音,或  
 
 者调节音频的一类软件等等。  
 
 [0005]  
 
 Framework层,Android提供了两个功能类,AudioTrack和AudioRecorder;除此以  
 
 外,A nd r o id系统还为我们控制音频系统提供了 A ud i o Ma na g e r、A ud i o Se r v i c e及  
 
 AudioSystem类。这些都是framework为便利上层应用开发所设计的。  
 
 [0006]  
 
 Libraries层,framework层的很多类,实际上只是应用程序使用Android库文件的  
 
 “ 中介 ” 而已。因为上层应用采用java语言编写,它们需要最直接的java接口的支持,这就是  
 
 framework层存在的意义之一。而作为 “ 中介 ” ,它们并不会真正去实现具体的功能,或者只  
 
 实现其中的一部分功能 ,而把主要重心放在库中来完成。比如上面的 A ud i o T ra c k、  
 
 AudioRecorder等等在库中都能找到相对应的类,这些库多数是C++语言编写的。除了上面  
 
 的类库实现外,音频系统还需要一个 “ 核心中控 ” ,或者用Android中通用的实现来讲,需要  
 
 一个系统服务,这就是AudioFlinger和AudioPolicyService。  
 
 [0007]  
 
 HAL层,从设计上来看,硬件抽象层是AudioFlinger直接访问的对象。这说明了两  
 
 个问题,一方面AudioFlinger并不直接调用底层的驱动程序;另一方面,AudioFlinger上层  
 
 (包括和它同一层的MediaPlayerService)的模块只需要与它进行交互就可以实现音频相  
 
 关的功能了。因而我们可以认为AudioFlinger是Android音频系统中真正的 “ 隔离板 ” ,无论  
 
 下面如何变化,上层的实现都可以保持兼容。音频方面的硬件抽象层主要分为两部分,即  
 
 AudioFlinger和AudioPolicyService。实际上后者并不是一个真实的设备,只是采用虚拟  
 
 设备的方式来让厂商可以方便地定制出自己的策略。抽象层的任务是将AudioFlinger/  
 
 AudioPolicyService真正地与硬件设备关联起来,但又必须提供灵活的结构来应对变  
 
 化——特别是对于Android这个更新相当频繁的系统。比如以前Android系统中的Audio系  
 
 统依赖于alsa - lib,但后期就变为了tinyalsa,这样的转变不应该对上层造成破坏。因而  
 
 AudioHAL提供了统一的接口来定义它与AudioFlinger/AudioPolicyService之间的通信方  
 
 式,这就是audio_hw_device、audio_stream_in及audio_stream_out等等存在的目的,这些  
 
 S t r u c t数据类型内部大多只是函数指针的定义 ,是一些 “ 壳 ” 。当 A u d i o F l i n g e r /  
 
 AudioPolicyService初始化时,它们会去寻找系统中最匹配的实现(这些实现驻留在以  
 
 说 明 书  
 
 1/9 页  
 
 4  
 
 CN 108132771 A  
 
 4 audio .primary .* ,audio .a2dp .*为名的各种库中)来填充这些 “ 壳 ” 。根据产品的不同,音频  
 
 设备存在很大差异,在Android的音频架构中,这些问题都是由HAL层的audio .primary等等  
 
 库来解决的,而不需要大规模地修改上层实现。换句话说,厂商在定制时的重点就是如何提  
 
 供这部分库的高效实现了。  
 
 [0008]  
 
 本发明是基于Android系统的双屏异显两路音频的需求以及现有的Android系统  
 
 音频整个框架,来实现两路音频输出的。  
 
 发明内容  
 
 [0009]  
 
 本发明要解决的技术问题,在于提供一种Android系统双屏异显的两路音频实现  
 
 方法,从而弥补了Android系统的双屏异显两路音频输出的空白。  
 
 [0010]  
 
 本发明是这样实现的:一种Android系统双屏异显的两路音频实现方法,包括进入  
 
 双屏模式过程、播放音频过程和退出双屏模式过程;  
 
 [0011]  
 
 所述进入双屏模式过程包括:  
 
 [0012]  
 
 步骤S11、响应用户操作而进入双屏模式,首先模拟上报声卡插入事件;  
 
 [0013]  
 
 步骤S12、在AudioManager打开第二个声卡;  
 
 [0014]  
 
 步骤S13、在AudioFlinger创建新的PlaybackThread;  
 
 [0015]  
 
 所述播放音频过程包括;  
 
 [0016]  
 
 步骤S21、App要播放声音前先判断是否是主屏播放声音,若是进入步骤S22,若否,  
 
 进入步骤S23;  
 
 [0017]  
 
 步骤S22、设置主屏声音的streamType,根据streamType在第一个声卡播放声音;  
 
 [0018]  
 
 步骤S23、设置副屏声音的streamType,根据streamType在第二个声卡播放声音;  
 
 [0019]  
 
 所述退出双屏模式过程包括:  
 
 [0020]  
 
 步骤S31、响应用户操作而退出双屏模式,首先模拟上报声卡断开事件;  
 
 [0021]  
 
 步骤S32、在AudioManager关闭第二个声卡;  
 
 [0022]  
 
 步骤S33、在AudioFlinger销毁第二个PlaybackThread,结束。  
 
 [0023]  
 
 进 一 步 的 ,所 述 步 骤 S 1 2 实 现 之 前 需 是 在 P h o n e W i n d o w . j a v a 的  
 
 superDispatchKeyEvent里面预先添加force_speaker广播,并设置media .audio .device_  
 
 policy .db的属性,异显状态下设置该属性为 “ speaker ” ,同显状态设置该属性为 “ hdmi ” ,然  
 
 后在InputManagerService .java的start里面接收广播,收到广播后,触发耳机线控事件。  
 
 [0024]  
 
 进一步的,所述步骤S12具体是:系统声音默认从hdmi输出,当switchValues为0  
 
 时,mHeadState的状态设置成BIT_HDMI_AUDIO;当switchValues的值为1时,mHeadState的  
 
 状态设置包括BIT_HDMI_AUDIO和BIT_USB_HEADSET_DGTL,目的是同时打开hdmi和speaker  
 
 两路输出,这种情况会触发AudFlinger中的openDuplicateOutput创建两个MixerThread,  
 
 从而打开第二个声卡。  
 
 [0025]  
 
 进一步的 ,所述步骤 S 21中 ,所述 A p p判断是否是主屏播放声音是通过判断  
 
 media .audio .device_policy .db的属性来实现,若该属性为 “ speaker ” ,则判断为异显状  
 
 态,若该属性为 “ hdmi ” ,则判断为同显状态。  
 
 [0026]  
 
 进一步的,本发明方法还包括主副屏切换过程,所述主副屏切换过程是:  
 
 [0027]  
 
 系统默认从hdmi输出,同屏时声音也从hdmi输出;异显时,副屏的声音从speaker  
 
 说 明 书  
 
 2/9 页  
 
 5  
 
 CN 108132771 A  
 
 5 输 出 ,主 屏的 声 音 从 h d m i 输 出 ;首 先 获 取 副 屏 上 a c t i v i t y 的 p i d ,并 设 置 为  
 
 “ media .audio .activity .pid ” 属性的值,同屏时,属性值设置为 - 1  
 
 [0028]  
 
 在moveTransitionToSecondDisplay中添加  
 
 [0029]  
 
 SystemProperties .set ("media .audio .activity .pid" ,String .valueOf  
 
 (win .mSession .mPid));  
 
 [0030]  
 
 在updateDisplayShowSynchronization中添加  
 
 [0031]  
 
 SystemProperties .set("media .audio .activity .pid" ,String .valueOf( - 1));  
 
 [0032]  
 
 在audiopolicy的Engine .cpp的getDeviceForStrategyInt中添加  
 
 [0033]  
 
 返回AUDIO_DEVICE_OUT_WIRED_HEADSET表示声音最终从speaker输出;  
 
 [0034]  
 
 返回AUDIO_DEVICE_OUT_AUX_DIGITAL表示声音最终从hdmi输出。  
 
 [0035]  
 
 进一步的,本发明方法还包括输出设备的修改过程:  
 
 [0036]  
 
 修改的文件路径:/device/rockchip/common/audio_policy_rk30board .conf  
 
 [0037]  
 
 修改的内容包括:  
 
 [0038]  
 
 (1)更改全局配置里的输出设备,由AUDIO_DEVICE_OUT_SPEAKER改为AUDIO_  
 
 DEVICE_OUT_AUX_DIGITAL;  
 
 [0039]  
 
 (2)更改primary默认输出设备;  
 
 [0040]  
 
 (3)添加dgtl输出。  
 
 [0041]  
 
 进一步的,本发明方法还包括增加dgtl库:  
 
 [0042]  
 
 复制hardware/rockchip/audio/tinyalsa_hal到hardware/rockchip/audio/  
 
 tinyalsa_hal_dgtl,并修改Android .mk;  
 
 [0043]  
 
 将audio_hw .c中connect_hdmi的值改为false,屏蔽hdmi;  
 
 [0044]  
 
 编译生成audio .dgtl .rk30board .so;  
 
 [0045]  
 
 最终,如果输出要求是hdmi,AudioFlinger会调用audio .dgtl .primary .so;如果  
 
 输出要求是speaker,AudioFlinger会调用audio .dgtl .rk30board .so。  
 
 [0046]  
 
 本发明具有如下优点:本发明方法通过软件和硬件上的设置,使主屏的声音从主  
 
 屏对应的声卡输出、副屏的声音从副屏对应声卡输出,最终实现了Android系统双屏异显的  
 
 两路音频输出,填补了这一技术领域的空白。  
 
 附图说明  
 
 [0047]  
 
 下面参照附图结合实施例对本发明作进一步的说明。  
 
 [0048]  
 
 图1为现有的Android系统的音频框架示意图。  
 
 [0049]  
 
 图2为本发明方法执行流程图。  
 
 具体实施方式  
 
 [0050]  
 
 请参阅图2所示,本发明的Android系统双屏异显的两路音频实现方法,包括进入  
 
 双屏模式过程、播放音频过程和退出双屏模式过程;  
 
 [0051]  
 
 所述进入双屏模式过程包括:  
 
 [0052]  
 
 步骤S11、响应用户操作而进入双屏模式,首先模拟上报声卡插入事件;  
 
 [0053]  
 
 步骤S12、在AudioManager打开第二个声卡;  
 
 说 明 书  
 
 3/9 页  
 
 6  
 
 CN 108132771 A  
 
 6 [0054]  
 
 步骤S13、在AudioFlinger创建新的PlaybackThread;  
 
 [0055]  
 
 所述播放音频过程包括;  
 
 [0056]  
 
 步骤S21、App要播放声音前先判断是否是主屏播放声音,若是进入步骤S22,若否,  
 
 进入步骤S23;  
 
 [0057]  
 
 步骤S22、设置主屏声音的streamType,根据streamType在第一个声卡播放声音;  
 
 [0058]  
 
 步骤S23、设置副屏声音的streamType,根据streamType在第二个声卡播放声音;  
 
 [0059]  
 
 所述退出双屏模式过程包括:  
 
 [0060]  
 
 步骤S31、响应用户操作而退出双屏模式,首先模拟上报声卡断开事件;  
 
 [0061]  
 
 步骤S32、在AudioManager关闭第二个声卡;  
 
 [0062]  
 
 步骤S33、在AudioFlinger销毁第二个PlaybackThread,结束。  
 
 [0063]  
 
 所述步骤S12实现之前需是在PhoneWindow .java的superDispatchKeyEvent里面  
 
 预先添加force_speaker广播,并设置media .audio .device_policy .db的属性,异显状态下  
 
 设置该属性为 “ speaker ” ,同显状态设置该属性为 “ hdmi ” ,App即可通过该属性来判断是否  
 
 是主屏播放声音,添加和设置的具体代码实现过程如下:  
 
 [0064]  
 
 [0065]  
 
 然后在InputManagerService .java的start里面接收广播,收到广播后,触发耳机  
 
 说 明 书  
 
 4/9 页  
 
 7  
 
 CN 108132771 A  
 
 7 线控事件。具体代码的实现过程是:  
 
 [0066]  
 
 [0067]  
 
 [0068]  
 
 所述步骤 S1 2具体是:系统声音默认从 hd m i输出,当 s w i t c h Va l ue s为 0时 ,  
 
 mHeadState的状态设置成BIT_HDMI_AUDIO;当switchValues的值为1时,mHeadState的状态  
 
 说 明 书  
 
 5/9 页  
 
 8  
 
 CN 108132771 A  
 
 8 设置包括BIT_HDMI_AUDIO和BIT_USB_HEADSET_DGTL,目的是同时打开hdmi和speaker两路  
 
 输出,这种情况会触发AudioFlinger中的openDuplicateOutput创建两个MixerThread,从  
 
 而打开第二个声卡,输出是hdmi还是speaker通过AudioPolicy来进行控制。具体是:  
 
 [0069]  
 
 MixerThread*thread1=checkMixerThread_l(output1);  
 
 [0070]  
 
 MixerThread*thread2=checkMixerThread_l(output2);  
 
 [0071]  
 
 所 述 步 骤 S 2 1 中 ,所 述 A p p 判 断 是 否 是 主 屏 播 放 声 音 是 通 过 判 断  
 
 media .audio .device_policy .db的属性来实现,若该属性为 “ speaker ” ,则判断为异显状  
 
 态,若该属性为 “ hdmi ” ,则判断为同显状态。  
 
 [0072]  
 
 本发明方法还包括主副屏切换过程,所述主副屏切换过程是:  
 
 [0073]  
 
 系统默认从hdmi输出,同屏时声音也从hdmi输出;异显时,副屏的声音从speaker  
 
 输 出 ,主 屏的 声 音 从 h d m i 输 出 ;首 先 获 取 副 屏 上 a c t i v i t y 的 p i d ,并 设 置 为  
 
 “ media .audio .activity .pid ” 属性的值,同屏时,属性值设置为 - 1。其代码实现过程是:  
 
 [0074]  
 
 在moveTransitionToSecondDisplay中添加  
 
 [0075]  
 
 SystemProperties .set ("media .audio .activity .pid" ,String .valueOf  
 
 (win .mSession .mPid));  
 
 [0076]  
 
 在updateDisplayShowSynchronization中添加  
 
 [0077]  
 
 SystemProperties .set("media .audio .activity .pid" ,String .valueOf( - 1));  
 
 [0078]  
 
 接着在audiopolicy的Engine .cpp的getDeviceForStrategyInt中获取并解析  
 
 m e d i a .a u d i o .d e v i c e _ p o l i c y .d b的属性 ,即在 
 a u d i o p o l i c y的 E n g i n e .c p p的  
  getDeviceForStrategyInt中添加:  
  [0079]  
  说 明 书  
  6/9 页  
  9  
  CN 108132771 A  
  9 [0080]  
  [0081]  
  如果该属性里面的值是speaker,则返回AUDIO_DEVICE_OUT_WIRED_HEADSET,表示  
  声音最终从speaker输出;  
  [0082]  
  如果该属性里面的值是hdmi,则返回AUDIO_DEVICE_OUT_AUX_DIGITAL,表示声音  
  最终从hdmi输出。  
  [0083]  
  本发明方法还包括输出设备的修改过程:  
  [0084]  
  由于原来系统只有一个输出,要满足两路输出,因此需添加一个输出。  
  [0085]  
  修改的文件路径:/device/rockchip/common/audio_policy_rk30board .conf  
  [0086]  
  修改的内容包括:  
  [0087]  
  (1)更改全局配置里的输出设备,由AUDIO_DEVICE_OUT_SPEAKER改为AUDIO_  
  DEVICE_OUT_AUX_DIGITAL,代码实现过程是:  
  [0088]  
  [0089]  
  (2)更改primary默认输出设备,代码实现过程是:  
  [0090]  
  说 明 书  
  7/9 页  
  10  
  CN 108132771 A  
  10 [0091]  
  [0092]  
  (3)添加dgtl输出,即添加一个虚拟输出,代码实现过程是。  
  [0093]  
  [0094]  
  本发明方法还包括增加dgtl库,这个库是硬件抽象层的修改,为了给第二个音频  
  输出设备使用,实现两路音频设备同时输出声音,互不冲突,代码实现过程是:  
  [0095]  
  复制hardware/rockchip/audio/tinyalsa_hal到hardware/rockchip/audio/  
  tinyalsa_hal_dgtl,并修改Android .mk;具体如下:  
  [0096]  
  LOCAL_MODULE:=audio .dgtl .$(TARGET_BOARD_HARDWARE)  
  [0097]  
  将audio_hw .c中connect_hdmi的值改为false,屏蔽hdmi;  
  [0098]  
  connet_hdmi=false;  
  说 明 书  
  8/9 页  
  11  
  CN 108132771 A  
  11 [0099]  
  编译生成audio .dgtl .rk30board .so;  
  [0100]  
  最终,如果输出要求是hdmi,AudioFlinger会调用audio .dgtl .primary .so;如果  
  输出要求是speaker,AudioFlinger会调用audio .dgtl .rk30board .so。  
  [0101]  
  最后打上补丁,这些补丁即前面说明的代码实现过程,最后弄了一个整体完整的  
  补丁包:  
  [0102]  
  在framework/base/下打上补丁Dual_Audio_framework_base .patch;  
  [0103]  
  在framework/av/下打上补丁Dual_audio_framework_av .patch;  
  [0104]  
  在 h a r d w a r e / l i b h a r d w a r e / 下 打 上 补 丁 D u a l _ a u d i o _ h a r d w a r e _  
  libhardware .patch。  
  [0105]  
  虽然以上描述了本发明的具体实施方式,但是熟悉本技术领域的技术人员应当理  
  解,我们所描述的具体的实施例只是说明性的,而不是用于对本发明的范围的限定,熟悉本  
  领域的技术人员在依照本发明的精神所作的等效的修饰以及变化,都应当涵盖在本发明的  
  权利要求所保护的范围内。