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 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即可获得播放的流类型