背景:
在做一些音频播放或者录音时候,经常会有对当前系统是否有正在处于活跃录音中的判断需求。
对于做audio系统开发的同学来说这个都很简单哈,直接dumpsys audioflinger相关输出就可以一目了然:
看这个input thread下面的是否有active的track既可以。
但是对于普通app应该来如何判断呢?
今天来分析一下如何通过系统现有的api来实现对当前系统有哪些活跃的播放track和活跃的录音track。
相关api介绍:
/**
* Returns the current active audio playback configurations of the device
* @return a non-null list of playback configurations. An empty list indicates there is no
* playback active when queried.
* @see AudioPlaybackConfiguration
*/
public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
final IAudioService service = getService();
try {
return service.getActivePlaybackConfigurations();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Returns the current active audio recording configurations of the device.
* @return a non-null list of recording configurations. An empty list indicates there is
* no recording active when queried.
* @see AudioRecordingConfiguration
*/
public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
final IAudioService service = getService();
try {
return service.getActiveRecordingConfigurations();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
解释如下:
getActivePlaybackConfigurations
主要负责返回当前活跃的playback的相关信息
getActiveRecordingConfigurations
主要负责返回当前活跃的录音trace的相关信息
使用demo进行调用相关的api
void getAudioRecordConfig() {
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
List<AudioPlaybackConfiguration> list = audioManager.getActivePlaybackConfigurations();
for ( AudioPlaybackConfiguration audioRecordingConfiguration : list) {
Log.i("xxx","getAudioRecordConfig audioRecordingConfiguration " +audioRecordingConfiguration);
}
List<AudioRecordingConfiguration> list1 = audioManager.getActiveRecordingConfigurations();
for ( AudioRecordingConfiguration audioRecordingConfiguration : list1) {
Log.i("lsm888","getAudioRecordConfig audioRecordingConfiguration " +audioRecordingConfiguration);
}
}
getAudioRecordConfig原理源码分析:
下面就以Record部分的信息获取作为案例进行源码分析,playback部分就一样参考record既可以。
frameworks/base/media/java/android/media/AudioManager.java
/**
* Returns the current active audio recording configurations of the device.
* @return a non-null list of recording configurations. An empty list indicates there is
* no recording active when queried.
* @see AudioRecordingConfiguration
*/
public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
final IAudioService service = getService();
try {
//调用到audioservice部分接口
return service.getActiveRecordingConfigurations();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
下面看看audioservice部分接口实现
frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
final boolean isPrivileged = Binder.getCallingUid() == Process.SYSTEM_UID
|| (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
MODIFY_AUDIO_ROUTING));
return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged);
}
isPrivileged代表一些特权的app可以获取直接获取所有的信息。
再看看:
frameworks/base/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
List<AudioRecordingConfiguration> getActiveRecordingConfigurations(boolean isPrivileged) {
List<AudioRecordingConfiguration> configs = new ArrayList<AudioRecordingConfiguration>();
synchronized (mRecordStates) {
//获取的是mRecordStates中active进行返回
for (RecordingState state : mRecordStates) {
if (state.isActiveConfiguration()) {
configs.add(state.getConfig());
}
}
}
// AudioRecordingConfiguration objects never get updated. If config changes,
// the reference to the config is set in RecordingState.
if (!isPrivileged) {
configs = anonymizeForPublicConsumption(configs);
}
return configs;
}
那么接下来看看mRecordStates变量来自哪里?这块比较复杂涉及到audioflinger,policy等部分,下一篇文章再分享。
命令行进行dump查看:
AudioRecordingConfiguration部分的输出情况
使用如下命令:
adb shell dumpsys audio
主要看如下的dump信息:
RecordActivityMonitor dump time: 10:46:46 AM
riid 14623; active? true
session:14609 -- source client=MIC, dev=2ch 48000Hz ENCODING_PCM_16BIT -- uid:10150 -- patch:21 -- pack:com.example.remotesubmix -- format client=2ch 48000Hz ENCODING_PCM_16BIT, dev=2ch 48000Hz ENCODING_PCM_16BIT -- silenced:false -- effects client=, dev=

AudioPlaybackConfiguration部分的输出情况:
PlaybackActivityMonitor dump time: 11:07:42 AM
playback listeners:
(S)com.android.server.audio.PlaybackActivityMonitor$PlayMonitorClient@79b7d56 (S)com.android.server.audio.PlaybackActivityMonitor$PlayMonitorClient@3e8c1d7 (S)com.android.server.audio.PlaybackActivityMonitor$PlayMonitorClient@8743ac4
players:
(not logged) AudioPlaybackConfiguration piid:14599 deviceId:0 type:android.media.SoundPool u/pid:1000/2838 state:idle attr:AudioAttributes: usage=USAGE_ASSISTANCE_SONIFICATION content=CONTENT_TYPE_SONIFICATION flags=0x800 tags= bundle=null sessionId:0 mutedState:none FormatInfo{isSpatialized=false, channelMask=0x0, sampleRate=0}
AudioPlaybackConfiguration piid:14607 deviceId:0 type:android.media.SoundPool u/pid:10123/3072 state:idle attr:AudioAttributes: usage=USAGE_ASSISTANCE_SONIFICATION content=CONTENT_TYPE_SONIFICATION flags=0x800 tags= bundle=null sessionId:0 mutedState:none FormatInfo{isSpatialized=false, channelMask=0x0, sampleRate=0}
AudioPlaybackConfiguration piid:14663 deviceId:2 type:android.media.AudioTrack u/pid:10095/5042 state:started attr:AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_MUSIC flags=0x900 tags= bundle=null sessionId:14649 mutedState:none FormatInfo{isSpatialized=false, channelMask=0x3, sampleRate=48000}
ducked players piids:
faded out players piids:
muted player piids due to call/ring:
banned uids:

原文内容参考:
https://mp.weixin.qq.com/s/pQr-HrW0EUoi5QHTMOGEBQ
更多framework实战干货,请关注下面“千里马学框架”

被折叠的 条评论
为什么被折叠?



