本发明涉及一种Android系统双屏异显的两路音频实现方法。

背景技术:

关于Android系统的双屏异显两路音频的实现目前还没有通用的方法,Android系统的双屏异显两路音频的需求是:主屏的声音从主屏对应的声卡输出、副屏的声音从副屏对应声卡输出,不能有混音。

如图1所示,现有的Android系统音频整个框架包括应用层APP、framework层、lib层、hal层、驱动以及硬件。

应用层APP,这是整个音频体系的最上层,因而并不是Android系统实现异显两路音频输出的重点。比如厂商根据特定需求自己写的一个音乐播放器,游戏中使用到声音,或者调节音频的一类软件等等。

Framework层,Android提供了两个功能类,AudioTrack和AudioRecorder;除此以外,Android系统还为我们控制音频系统提供了AudioManager、AudioService及AudioSystem类。这些都是framework为便利上层应用开发所设计的。

Libraries层,framework层的很多类,实际上只是应用程序使用Android库文件的“中介”而已。因为上层应用采用java语言编写,它们需要最直接的java接口的支持,这就是framework层存在的意义之一。而作为“中介”,它们并不会真正去实现具体的功能,或者只实现其中的一部分功能,而把主要重心放在库中来完成。比如上面的AudioTrack、AudioRecorder等等在库中都能找到相对应的类,这些库多数是C++语言编写的。除了上面的类库实现外,音频系统还需要一个“核心中控”,或者用Android中通用的实现来讲,需要一个系统服务,这就是AudioFlinger和AudioPolicyService。

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等等存在的目的,这些Struct数据类型内部大多只是函数指针的定义,是一些“壳”。当AudioFlinger/AudioPolicyService初始化时,它们会去寻找系统中最匹配的实现(这些实现驻留在以audio.primary.*,audio.a2dp.*为名的各种库中)来填充这些“壳”。根据产品的不同,音频设备存在很大差异,在Android的音频架构中,这些问题都是由HAL层的audio.primary等等库来解决的,而不需要大规模地修改上层实现。换句话说,厂商在定制时的重点就是如何提供这部分库的高效实现了。

本发明是基于Android系统的双屏异显两路音频的需求以及现有的Android系统音频整个框架,来实现两路音频输出的。

技术实现要素:

本发明要解决的技术问题,在于提供一种Android系统双屏异显的两路音频实现方法,从而弥补了Android系统的双屏异显两路音频输出的空白。

本发明是这样实现的:一种Android系统双屏异显的两路音频实现方法,包括进入双屏模式过程、播放音频过程和退出双屏模式过程;

所述进入双屏模式过程包括:

步骤S11、响应用户操作而进入双屏模式,首先模拟上报声卡插入事件;

步骤S12、在AudioManager打开第二个声卡;

步骤S13、在AudioFlinger创建新的PlaybackThread;

所述播放音频过程包括;

步骤S21、App要播放声音前先判断是否是主屏播放声音,若是进入步骤S22,若否,进入步骤S23;

步骤S22、设置主屏声音的streamType,根据streamType在第一个声卡播放声音;

步骤S23、设置副屏声音的streamType,根据streamType在第二个声卡播放声音;

所述退出双屏模式过程包括:

步骤S31、响应用户操作而退出双屏模式,首先模拟上报声卡断开事件;

步骤S32、在AudioManager关闭第二个声卡;

步骤S33、在AudioFlinger销毁第二个PlaybackThread,结束。

进一步的,所述步骤S12实现之前需是在PhoneWindow.java的superDispatchKeyEvent里面预先添加force_speaker广播,并设置media.audio.device_policy.db的属性,异显状态下设置该属性为“speaker”,同显状态设置该属性为“hdmi”,然后在InputManagerService.java的start里面接收广播,收到广播后,触发耳机线控事件。

进一步的,所述步骤S12具体是:系统声音默认从hdmi输出,当switchValues为0时,mHeadState的状态设置成BIT_HDMI_AUDIO;当switchValues的值为1时,mHeadState的状态设置包括BIT_HDMI_AUDIO和BIT_USB_HEADSET_DGTL,目的是同时打开hdmi和speaker两路输出,这种情况会触发AudFlinger中的openDuplicateOutput创建两个MixerThread,从而打开第二个声卡。

进一步的,所述步骤S21中,所述App判断是否是主屏播放声音是通过判断media.audio.device_policy.db的属性来实现,若该属性为“speaker”,则判断为异显状态,若该属性为“hdmi”,则判断为同显状态。

进一步的,本发明方法还包括主副屏切换过程,所述主副屏切换过程是:

系统默认从hdmi输出,同屏时声音也从hdmi输出;异显时,副屏的声音从speaker输出,主屏的声音从hdmi输出;首先获取副屏上activity的pid,并设置为“media.audio.activity.pid”属性的值,同屏时,属性值设置为-1

在moveTransitionToSecondDisplay中添加

SystemProperties.set("media.audio.activity.pid",String.valueOf(win.mSession.mPid));

在updateDisplayShowSynchronization中添加

SystemProperties.set("media.audio.activity.pid",String.valueOf(-1));

在audiopolicy的Engine.cpp的getDeviceForStrategyInt中添加

返回AUDIO_DEVICE_OUT_WIRED_HEADSET表示声音最终从speaker输出;

返回AUDIO_DEVICE_OUT_AUX_DIGITAL表示声音最终从hdmi输出。

进一步的,本发明方法还包括输出设备的修改过程:

修改的文件路径:/device/rockchip/common/audio_policy_rk30board.conf

修改的内容包括:

(1)更改全局配置里的输出设备,由AUDIO_DEVICE_OUT_SPEAKER改为AUDIO_DEVICE_OUT_AUX_DIGITAL;

(2)更改primary默认输出设备;

(3)添加dgtl输出。

进一步的,本发明方法还包括增加dgtl库:

复制hardware/rockchip/audio/tinyalsa_hal到hardware/rockchip/audio/tinyalsa_hal_dgtl,并修改Android.mk;

将audio_hw.c中connect_hdmi的值改为false,屏蔽hdmi;

编译生成audio.dgtl.rk30board.so;

最终,如果输出要求是hdmi,AudioFlinger会调用audio.dgtl.primary.so;如果输出要求是speaker,AudioFlinger会调用audio.dgtl.rk30board.so。

本发明具有如下优点:本发明方法通过软件和硬件上的设置,使主屏的声音从主屏对应的声卡输出、副屏的声音从副屏对应声卡输出,最终实现了Android系统双屏异显的两路音频输出,填补了这一技术领域的空白。

附图说明

下面参照附图结合实施例对本发明作进一步的说明。

图1为现有的Android系统的音频框架示意图。

图2为本发明方法执行流程图。

具体实施方式

请参阅图2所示,本发明的Android系统双屏异显的两路音频实现方法,包括进入双屏模式过程、播放音频过程和退出双屏模式过程;

所述进入双屏模式过程包括:

步骤S11、响应用户操作而进入双屏模式,首先模拟上报声卡插入事件;

步骤S12、在AudioManager打开第二个声卡;

步骤S13、在AudioFlinger创建新的PlaybackThread;

所述播放音频过程包括;

步骤S21、App要播放声音前先判断是否是主屏播放声音,若是进入步骤S22,若否,进入步骤S23;

步骤S22、设置主屏声音的streamType,根据streamType在第一个声卡播放声音;

步骤S23、设置副屏声音的streamType,根据streamType在第二个声卡播放声音;

所述退出双屏模式过程包括:

步骤S31、响应用户操作而退出双屏模式,首先模拟上报声卡断开事件;

步骤S32、在AudioManager关闭第二个声卡;

步骤S33、在AudioFlinger销毁第二个PlaybackThread,结束。

所述步骤S12实现之前需是在PhoneWindow.java的superDispatchKeyEvent里面预先添加force_speaker广播,并设置media.audio.device_policy.db的属性,异显状态下设置该属性为“speaker”,同显状态设置该属性为“hdmi”,App即可通过该属性来判断是否是主屏播放声音,添加和设置的具体代码实现过程如下:

然后在InputManagerService.java的start里面接收广播,收到广播后,触发耳机线控事件。具体代码的实现过程是:

所述步骤S12具体是:系统声音默认从hdmi输出,当switchValues为0时,mHeadState的状态设置成BIT_HDMI_AUDIO;当switchValues的值为1时,mHeadState的状态设置包括BIT_HDMI_AUDIO和BIT_USB_HEADSET_DGTL,目的是同时打开hdmi和speaker两路输出,这种情况会触发AudioFlinger中的openDuplicateOutput创建两个MixerThread,从而打开第二个声卡,输出是hdmi还是speaker通过AudioPolicy来进行控制。具体是:

MixerThread*thread1=checkMixerThread_l(output1);
MixerThread*thread2=checkMixerThread_l(output2);

所述步骤S21中,所述App判断是否是主屏播放声音是通过判断media.audio.device_policy.db的属性来实现,若该属性为“speaker”,则判断为异显状态,若该属性为“hdmi”,则判断为同显状态。

本发明方法还包括主副屏切换过程,所述主副屏切换过程是:

系统默认从hdmi输出,同屏时声音也从hdmi输出;异显时,副屏的声音从speaker输出,主屏的声音从hdmi输出;首先获取副屏上activity的pid,并设置为“media.audio.activity.pid”属性的值,同屏时,属性值设置为-1。其代码实现过程是:

在moveTransitionToSecondDisplay中添加

SystemProperties.set("media.audio.activity.pid",String.valueOf(win.mSession.mPid));

在updateDisplayShowSynchronization中添加

SystemProperties.set("media.audio.activity.pid",String.valueOf(-1));

接着在audiopolicy的Engine.cpp的getDeviceForStrategyInt中获取并解析media.audio.device_policy.db的属性,即在audiopolicy的Engine.cpp的getDeviceForStrategyInt中添加:

如果该属性里面的值是speaker,则返回AUDIO_DEVICE_OUT_WIRED_HEADSET,表示声音最终从speaker输出;

如果该属性里面的值是hdmi,则返回AUDIO_DEVICE_OUT_AUX_DIGITAL,表示声音最终从hdmi输出。

本发明方法还包括输出设备的修改过程:

由于原来系统只有一个输出,要满足两路输出,因此需添加一个输出。

修改的文件路径:/device/rockchip/common/audio_policy_rk30board.conf

修改的内容包括:

(1)更改全局配置里的输出设备,由AUDIO_DEVICE_OUT_SPEAKER改为AUDIO_DEVICE_OUT_AUX_DIGITAL,代码实现过程是:

(2)更改primary默认输出设备,代码实现过程是:

(3)添加dgtl输出,即添加一个虚拟输出,代码实现过程是。

本发明方法还包括增加dgtl库,这个库是硬件抽象层的修改,为了给第二个音频输出设备使用,实现两路音频设备同时输出声音,互不冲突,代码实现过程是:

复制hardware/rockchip/audio/tinyalsa_hal到hardware/rockchip/audio/tinyalsa_hal_dgtl,并修改Android.mk;具体如下:

LOCAL_MODULE:=audio.dgtl.$(TARGET_BOARD_HARDWARE)

将audio_hw.c中connect_hdmi的值改为false,屏蔽hdmi;

connet_hdmi=false;

编译生成audio.dgtl.rk30board.so;

最终,如果输出要求是hdmi,AudioFlinger会调用audio.dgtl.primary.so;如果输出要求是speaker,AudioFlinger会调用audio.dgtl.rk30board.so。

最后打上补丁,这些补丁即前面说明的代码实现过程,最后弄了一个整体完整的补丁包:

在framework/base/下打上补丁Dual_Audio_framework_base.patch;

在framework/av/下打上补丁Dual_audio_framework_av.patch;

在hardware/libhardware/下打上补丁Dual_audio_hardware_libhardware.patch。

虽然以上描述了本发明的具体实施方式,但是熟悉本技术领域的技术人员应当理解,我们所描述的具体的实施例只是说明性的,而不是用于对本发明的范围的限定,熟悉本领域的技术人员在依照本发明的精神所作的等效的修饰以及变化,都应当涵盖在本发明的权利要求所保护的范围内。