Android音量系统分析

下面以Android 6.0为例来说明。

一、音频流、音频设备、音量三角关系

AudioSystem.java中定义的音频流格式:

int STREAM_VOICE_CALL = 0;    电话

int STREAM_SYSTEM = 1;   系统

int STREAM_RING = 2;  响铃和消息

int STREAM_MUSIC = 3;   音乐

int STREAM_ALARM = 4;  闹钟

int STREAM_NOTIFICATION = 5;  通知

int STREAM_BLUETOOTH_SCO = 6;  蓝牙

int STREAM_SYSTEM_ENFORCED = 7;   强制系统声音

int STREAM_DTMF = 8;  双音多频

int STREAM_TTS = 9;  语音

总共10种音频流,因Android版本不同可能存在差异。

音量与音频流是息息相关的。每种音频流至少对应一种音量,当然也可以多种音频流对应一种音量。

在AudioService.java中定义了这种对应关系,

private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
   // STREAM_VOICE_CALL    AudioSystem.STREAM_VOICE_CALL,
    // STREAM_SYSTEM    AudioSystem.STREAM_RING,
   // STREAM_RING         AudioSystem.STREAM_RING,
   // STREAM_MUSIC                AudioSystem.STREAM_MUSIC, 
   // STREAM_ALARM          AudioSystem.STREAM_ALARM, 
    // STREAM_NOTIFICATION         AudioSystem.STREAM_RING,
   // STREAM_BLUETOOTH_SCO          AudioSystem.STREAM_BLUETOOTH_SCO,
    // STREAM_SYSTEM_ENFORCED    AudioSystem.STREAM_RING,
    // STREAM_DTMF       AudioSystem.STREAM_RING, 
    // STREAM_TTS        AudioSystem.STREAM_MUSIC      };

从上面定义可以看到系统音频流,响铃与消息音频流,通知音频流,强制声音音频流,DTMF这五种音频流共用一个音量,音乐与语音是共用一个音量( AudioSystem.STREAM_MUSIC)

上面这个定义是用于通话的Android平台上的(比如手机),Android还定义了两种,分别用在电视或者机顶盒上的定义:。。。

不同设备调整音量后互不影响

我们知道在使用手机扬声器播放音乐时调整音量后,如果插入耳机,从耳机听到的音量并没有变化。在Android系统中,定义了一系统输入和输出设备,针对每个输入与输出设备的音量也是不一样的。下面是Android系统在audio.h定义的部份音频设备。
输出设备:

AUDIO_DEVICE_OUT_EARPIECE                  = 0x1,// 听筒AUDIO_DEVICE_OUT_SPEAKER                   = 0x2,// 扬声器AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4,//线控耳机AUDIO_DEVICE_OUT_WIRED_HEADPHONE           = 0x8,//普通耳机AUDIO_DEVICE_OUT_BLUETOOTH_SCO             = 0x10,//单声道蓝牙耳机AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET     = 0x20,//蓝牙电话 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT      = 0x40, //车载免提蓝牙设备AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 = 0x80, //立体声蓝牙耳机

输入设备,比如:

AUDIO_DEVICE_IN_BUILTIN_MIC     = AUDIO_DEVICE_BIT_IN | 0x4, //手机自带MICAUDIO_DEVICE_IN_VOICE_CALL     = AUDIO_DEVICE_BIT_IN| 0x40,//电话MIC

可以说每个音频流对应到每种设备都有一个音量。比如,对于同一个STREAM_MUSIC流,对扬声器和耳机的音量是分开存储的。不考虑相同的情况,音量个数=音频流*音频设备。

 

二、音量的缓存与持久化

音量的缓存是通过AudioService.java的内部类VolumeStreamState来设置。

音量的持久化在Android 6.0以前是保存到设置数据库setting.dbSystem表中

android6.0之后在data/data/com.android.providers.settings/databases目录下找不到settings.db数据库原因:

在6.0上面,Google修改了SettingsProvider,这次修改,涉及到了 
global,secure,system 三个表;并且实现方式从之前的数据库,改为异步性能更加优 
良的xml,每个用户都有自己的一份SettingsProvider设置xml文档。通常位于 
/data/system/users/userid/ 下面。

结论:

AudioManager mAudioManager = (AudioManager) FRApplication.getInstance().currentActivity().getSystemService(FRApplication.getInstance().currentActivity().AUDIO_SERVICE);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, voice, 0);

以上代码执行会影响 setting.dbSystem表中的 字段 volume_music_speaker ,测试设备android5.1

三、音量的设置流程

设置音量通常有以下方法:

通过AudioManager来设置

通过AudioTrack/MediaPlayer来设置


1.通过AudioManager来设置 

我们先看一下AudioManager音量的设置过程

图3.1AudioManager音量设置流程

AudioManager只是一个轻量级的封装类,由Context创建,工作在APK进程中,通过IBinder的机制,负责与JAVA层的音频服务AudioService进行交互。

AudioManager类提供了setStreamVolume方法来对一种stream type对应的音量进行设置:


public void setStreamVolume(int streamType, int index, int flags) { 
IAudioService service = getService(); 
try { 
service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName()); 
} catch (RemoteException e) { 
Log.e(TAG, "Dead object in setStreamVolume", e); 

从代码中可以看出,setStreamVolume就是通过IPC调用AudioService的方法,用一个类图来表示AudioManager和AudioService的关系:

Android 音量系统分析

图3.2 AudioManager &; AudioService

AudioManager通过代理对象访问工作在SystemServer中的AudioService服务,调用其setStreamVolume方法来设置音量。

 

上面说过AudioService通过VolumeStreamState来缓存各种音频流的音量,并且通过mStreamStates来记录各种音频流的音量。设置音量最终是通过 VolumeStreamState. applyDeviceVolume_syncVSS函数调用AudioSystem.setStreamVolumeIndex函数来传入device类型、音量index以及stream类型,告知音频系统,“使用这种device播放这种stream类型的音频播放操作,都将使用这个音量index”。代码如下:


status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream, 
int index, 
audio_devices_t device) 

const sp<IAudioPolicyService>&; aps = AudioSystem::get_audio_policy_service(); 
if (aps == 0) return PERMISSION_DENIED; 
return aps->setStreamVolumeIndex(stream, index, device); 

AudioSystem主要对AudioPolicyService进行了封装,所以接下来的操作都是由AudioPolicyService来完成的。

 

setStreamVolumeIndex是AudioSystem通过IBinder调用了AudioPolicyService的setStreamVolumeIndex函数,AudioPolicyService继承了AudioPolicyClientInterface类,他有一个AudioPolicyInterface类的成员指针mpPolicyManager,实际上就是指向了AudioPolicyManager,最终是调用了AudioPolicyManager的setStreamVolumeIndex函数。(实际上AudioPolicyService是通过成员指针mpPolicyManager访问AudioPolicyManager,而AudioPolicyManager则通过AudioPolicyClientInterface(mpClientInterface)访问AudioPolicyService)。

 

AudioPolicyManager调用setStreamVolumeIndex后会引发AudioPolicyService执行一个SET_VOLUME的CommandThread,在这个CommandThread中调用了AudioSystem的静态方法setStreamVolume,具体如下:


status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value, 
audio_io_handle_t output) 

if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE; 
const sp<IAudioFlinger>&; af = AudioSystem::get_audio_flinger(); 
if (af == 0) return PERMISSION_DENIED; 
af->setStreamVolume(stream, value, output); 
return NO_ERROR; 

在这个函数里调用了AudioFlinger的setStreamVolume。在AudioFlinger的setStreamVolume中调用了PlaybackThread的setStreamVolume.

 

AudioFlinger通过checkPlaybachTread方法,通过AudioPolicy传入IO句柄(audio_io_handle_t),来定位到具体的PlaybackThread,调用其setStreamVolume方法,这个方法将音量值缓存到stream对应的stream_type_t对象中,这样,PlaybackThread便知道每种stream对应的音量了。具体如下:


status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, 
audio_io_handle_t output) 

...... 
if (thread == NULL) { 
for (size_t i = 0; i < mPlaybackThreads.size(); i++) { 
mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value); 

} else { 
thread->setStreamVolume(stream, value); 

return NO_ERROR; 

在PlaybackThread的setStreamVolume中只是保存当前音量值,然后发送通知在输出音频时按新的音量计算。


2. 通过AudioTrack/MediaPlayer来设置 

Android Framework的音频子系统中,每一个音频流对应着一个AudioTrack类的一个实例。每个AudioTrack在创建时会注册到AudioFlinger中,AudioFlinger在AudioPolicy的辅助下,为每个AudioTrack对象建立与某个具体的工作线程的对应关系,并通知这个工作线程创建了一个Track对象与这个AudioTrack进行对应。由AudioFlinger把所有的AudioTrack进行混合(Mixer),然后输送到AudioHardware中进行播放。最多可以创建32个音频流。

 

AudioMixer进行混音的时候,需要知道每个Track播放音频的音量,这个音量是由stream音量、master音量和track音量相乘出来的,stream音量就是AudioPolicy设置进来的,master volume由用户设置,track volume由调用者通过AudioTrack.setVolume来设置。AudioTrack.setVolume所设置的track volume,是一个取值为0~1.0的浮点数

 

通常,AudioTrack和AudioFlinger并不在同一个进程中,它们通过android中的binder机制建立联系。

 

AudioTrack通过setVolume设置音量后,会记录入共享内存中,然后由AudioFlinger去读取。


四、小结 

整个Android音量设置还是比较复杂,其中包括持久化及各个模块的缓存及同步更新。所涉及到的音频系统子模块包括AudioService、AudioPolicy和AudioFlinger,每个子模块都用各自的数据结构缓存了stream音量,持久化在设置数据库的system表中或者XML中。

参考网址:http://www.vccoo.com/v/b5ghyx_4

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 是目前智能手机市场占有率最高的操作系统之一,而音频系统是 Android 系统的重要组成部分,它也与用户体验密切相关。音频系统主要包括音频硬件、音频框架以及音频后处理等部分。 不同品牌的智能手机使用的音频硬件有所不同,但基本都有麦克风、扬声器、耳机插口等音频接口。其中,麦克风负责录音,扬声器负责外放音频,耳机插口可以让用户通过耳机接口听取音频,避免干扰他人。 音频框架是 Android 系统中的软件部分,它可以为应用程序提供音频输入和输出功能。音频框架主要包括音频输入/输出接口、音频流管理、音频效果等功能。各种应用程序可以通过音频输入/输出接口的开发包(SDK)实现音频的录制、播放和处理等功能。在音频流管理方面,Android 系统中使用 AudioManager 类来管理各种音频流的控制,如音量调整、暂停和恢复等操作。在音频效果方面,Android 系统提供了一系列的音频效果处理器,如均衡器、虚拟环绕声等,供应用程序实现各种音效。 音频后处理是指对音频信号进行二次处理,以改善音质或实现声音特效等目的。它在智能手机中发挥了重要作用,如麦克风降噪、回声消除等。音频后处理技术的应用带来了更好的听觉体验。 总之,音频系统是 Android 系统不可或缺的一部分,它保证了智能手机有较好的音质、音量和音效,为用户提供更优秀的使用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值