Android10 音频系统之AudioPlaybackConfiguration
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 mHasAppOpsPlayAudioupdateAppOpsPlayAudio();// register a callback to monitor whether the OP_PLAY_AUDIO is still allowedmAppOpsCallback = 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作为valuemPlayers.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 {//将播放状态传递给AudioServicegetService().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 statesEventLogger.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 reportingreturn;}if (checkConfigurationCaller(piid, apc, binderUid)) {//TODO add generation counter to only update to the latest statecheckVolumeForPrivilegedAlarm(apc, event);//调用AudioPlaybackConfiguration的handleStateEvent,将播放状态传递给AudioPlaybackConfigurationchange = 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即可获得播放的流类型