AudioPlaybackConfiguration是一个收集描述音频播放会话信息的类

1.AudioPlaybackConfiguration列表的建立
xref: /frameworks/base/media/java/android/media/PlayerBase.java
protected void baseRegisterPlayer() {
if (!USE_AUDIOFLINGER_MUTING_FOR_OP) {
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
mAppOps = IAppOpsService.Stub.asInterface(b);
// initialize mHasAppOpsPlayAudio
updateAppOpsPlayAudio();
// register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
mAppOpsCallback = new IAppOpsCallbackWrapper(this);
try {
mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
ActivityThread.currentPackageName(), mAppOpsCallback);
} catch (RemoteException e) {
Log.e(TAG, "Error registering appOps callback", e);
mHasAppOpsPlayAudio = false;
}
}
try {
//调用AudioService的trackPlayer方法,并传入PlayerIdCard作为唯一标识
mPlayerIId = getService().trackPlayer(
new PlayerIdCard(mImplType, mAttributes, new IPlayerWrapper(this)));
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, player will not be tracked", e);
}
}
在android中所有的player都继承自PlayerBase类,在PlaererBase类中会调用AudioService的trackPlayer方法,并传入PlayerIdCard作为唯一标识。new PlayerIdCard的时候会传入mAttributes也就是AudioAttributes属性。
xref: /frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public int trackPlayer(PlayerBase.PlayerIdCard pic) {
return mPlaybackMonitor.trackPlayer(pic);
}
在AudioService类中调用PlaybackMonitor的trackPlayer
xref: /frameworks/base/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
new HashMap<Integer, AudioPlaybackConfiguration>();
...........................................................................
public int trackPlayer(PlayerBase.PlayerIdCard pic) {
final int newPiid = AudioSystem.newAudioPlayerId();
if (DEBUG) { Log.v(TAG, "trackPlayer() new piid=" + newPiid); }
final AudioPlaybackConfiguration apc =
new AudioPlaybackConfiguration(pic, newPiid,
Binder.getCallingUid(), Binder.getCallingPid());
apc.init();
sEventLogger.log(new NewPlayerEvent(apc));
synchronized(mPlayerLock) {
//用newPiid作为可以,new一个AudioPlaybackConfiguration作为value
mPlayers.put(newPiid, apc);
}
return newPiid;
}
创建一个HashMap,用newPiid作为key,然后再new一个AudioPlaybackConfiguration作为value, 就这样AudioPlaybackConfiguration列表就建立起来了,后续调用MediaPlayer或AudioTrack都会更新这个列表。
xref: /frameworks/base/media/java/android/media/AudioPlaybackConfiguration.java
public AudioPlaybackConfiguration(PlayerBase.PlayerIdCard pic, int piid, int uid, int pid) {
if (DEBUG) { Log.d(TAG, "new: piid=" + piid + " iplayer=" + pic.mIPlayer); }
mPlayerIId = piid;
mPlayerType = pic.mPlayerType;
mClientUid = uid;
mClientPid = pid;
mPlayerState = PLAYER_STATE_IDLE; //保存播放状态
mPlayerAttr = pic.mAttributes; //保存播放属性
if ((sPlayerDeathMonitor != null) && (pic.mIPlayer != null)) {
mIPlayerShell = new IPlayerShell(this, pic.mIPlayer);
} else {
mIPlayerShell = null;
}
}
保存播放状态,播放属性等信息
2.播放事件传递流程

xref: /frameworks/base/media/java/android/media/PlayerBase.java
private void updateState(int state) {
final int piid;
synchronized (mLock) {
mState = state;
piid = mPlayerIId;
}
try {
//将播放状态传递给AudioService
getService().playerEvent(piid, state);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
+ AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
+ " state will not be tracked for piid=" + piid, e);
}
}
void baseStart() {
// 更新播放状态
updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
synchronized (mLock) {
if (isRestricted_sync()) {
playerSetVolume(true/*muting*/,0, 0);
}
}
}
更新播放状态,调用AudioService的playerEvent将播放状态传递给AudioService
xref: /frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public void playerEvent(int piid, int event) {
mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
}
调用mPlaybackMonitor的playerEvent将播放状态传递给PlaybackMonitor
xref: /frameworks/base/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
public void playerEvent(int piid, int event, int binderUid) {
if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); }
final boolean change;
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (apc == null) {
return;
}
sEventLogger.log(new PlayerEvent(piid, event));
if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
for (Integer uidInteger: mBannedUids) {
if (checkBanPlayer(apc, uidInteger.intValue())) {
// player was banned, do not update its state
sEventLogger.log(new AudioEventLogger.StringEvent(
"not starting piid:" + piid + " ,is banned"));
return;
}
}
}
if (apc.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
// FIXME SoundPool not ready for state reporting
return;
}
if (checkConfigurationCaller(piid, apc, binderUid)) {
//TODO add generation counter to only update to the latest state
checkVolumeForPrivilegedAlarm(apc, event);
//调用AudioPlaybackConfiguration的handleStateEvent,将播放状态传递给AudioPlaybackConfiguration
change = apc.handleStateEvent(event);
} else {
Log.e(TAG, "Error handling event " + event);
change = false;
}
if (change && event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
mDuckingManager.checkDuck(apc);
}
}
if (change) {
dispatchPlaybackChange(event == AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
}
}
调用AudioPlaybackConfiguration的handleStateEvent,将播放状态传递给AudioPlaybackConfiguration
xref: /frameworks/base/media/java/android/media/AudioPlaybackConfiguration.java
public boolean handleStateEvent(int event) {
final boolean changed;
synchronized (this) {
changed = (mPlayerState != event);
//保存播放状态
mPlayerState = event;
if (changed && (event == PLAYER_STATE_RELEASED) && (mIPlayerShell != null)) {
mIPlayerShell.release();
mIPlayerShell = null;
}
}
return changed;
}
用mPlayerState保存传递过来的播放状态event
3.获取当前正在播放的流类型
xref: /frameworks/base/media/java/android/media/AudioPlaybackConfiguration.java
public boolean isActive() {
switch (mPlayerState) {
case PLAYER_STATE_STARTED:
return true;
case PLAYER_STATE_UNKNOWN:
case PLAYER_STATE_RELEASED:
case PLAYER_STATE_IDLE:
case PLAYER_STATE_PAUSED:
case PLAYER_STATE_STOPPED:
default:
return false;
}
}
通过mPlayerState判断当前的播放状态,如果当前的流类型是处于播放的状态则返回true
public AudioAttributes getAudioAttributes() {
return mPlayerAttr;
}
再通过getAudioAttributes获取PlayerBase设置的音频属性,将音频属性AudioAttributes转换成streamType即可获得播放的流类型