android 记录一个蓝牙上下曲问题

qq音乐等三方app的音乐上下曲控制问题的分析过程
 android版本:10
问题描述:
    三方app(qq音乐等)连接上车机蓝牙后 控制上下曲无反应。而本地音乐是可控的
对比正常和异常的log发现问题出在 mCurrentFullUserRecord.getMediaButtonSessionLocked()为空
android/frameworks/base/services/core/java/com/android/server/media/MediaSessionService.java
        private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
            boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
        MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
        if (session != null) {
        .....
mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids(); 三方app的uid没有加入到这个列表中,导致session为空
android/frameworks/base/services/core/java/com/android/server/media/MediaSessionStack.java
public void updateMediaButtonSessionIfNeeded() {
    if (DEBUG) {
        Log.d(TAG, "updateMediaButtonSessionIfNeeded, callers=" + Debug.getCallers(2));
    }
    IntArray audioPlaybackUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids(); 
    for (int i = 0; i < audioPlaybackUids.size(); i++) {
        MediaSessionRecord mediaButtonSession =
                findMediaButtonSession(audioPlaybackUids.get(i));
        if (mediaButtonSession != null) {
            // Found the media button session.
            mAudioPlayerStateMonitor.cleanUpAudioPlaybackUids(mediaButtonSession.getUid());
            if (mMediaButtonSession != mediaButtonSession) {
                updateMediaButtonSession(mediaButtonSession);
            }
            return;
        }
    }
}
getSortedAudioPlaybackClientUids 实际就是获取AudioPlayerStateMonitor的mSortedAudioPlaybackClientUids数组 由onPlaybackConfigChanged 传过来的
android/frameworks/base/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java

dispatchPlaybackConfigChange传参
./android/frameworks/base/media/java/android/media/AudioManager.java
private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
    @Override
    public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
            boolean flush) {
        if (flush) {
            Binder.flushPendingCommands();
        }
        synchronized(mPlaybackCallbackLock) {
            if (mPlaybackCallbackList != null) {
                for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
                    final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
                    if (arci.mHandler != null) {
                        final Message m = arci.mHandler.obtainMessage(
                                MSSG_PLAYBACK_CONFIG_CHANGE,
                                new PlaybackConfigChangeCallbackData(arci.mCb, configs));
                        arci.mHandler.sendMessage(m);
                    }
                }
            }
        }
    }

};
 android/frameworks/base/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
private void dispatchPlaybackChange(boolean iplayerReleased) {
    synchronized (mClients) {
        // typical use case, nobody is listening, don't do any work
        if (mClients.isEmpty()) {
            return;
        }
    }
    if (DEBUG) { Log.v(TAG, "dispatchPlaybackChange to " + mClients.size() + " clients"); }
    final List<AudioPlaybackConfiguration> configsSystem;
    // list of playback configurations for "public consumption". It is only computed if there
    // are non-system playback activity listeners.
    final List<AudioPlaybackConfiguration> configsPublic;
    synchronized (mPlayerLock) {
        if (mPlayers.isEmpty()) {
            return;
        }
        configsSystem = new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
    }
    synchronized (mClients) {
        // was done at beginning of method, but could have changed
        if (mClients.isEmpty()) {
            return;
        }
        configsPublic = mHasPublicClients ? anonymizeForPublicConsumption(configsSystem) : null;
        final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
        while (clientIterator.hasNext()) {
            final PlayMonitorClient pmc = clientIterator.next();
            try {
                // do not spam the logs if there are problems communicating with this client
                if (pmc.mErrorCount < PlayMonitorClient.MAX_ERRORS) {
                    if (pmc.mIsPrivileged) {
                        pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsSystem,
                                iplayerReleased);
                    } else {
                        // non-system clients don't have the control interface IPlayer, so
                        // they don't need to flush commands when a player was released
                        pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsPublic, false);
                    }
                }
            } catch (RemoteException e) {
                pmc.mErrorCount++;
                Log.e(TAG, "Error (" + pmc.mErrorCount +
                        ") trying to dispatch playback config change to " + pmc, e);
            }
        }
    }
}
最终追踪到 piid 是-1,直接return了
public void playerEvent(int piid, int event, int binderUid) {
 if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d ,binderUid=%d)", piid, event ,binderUid)); }
 final boolean change;
 synchronized(mPlayerLock) {
     final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
     if (apc == null) {
          Log.e(TAG,"playerEvent apc is null(" + binderUid + ")");
         return;
     }
......
piid在updateState中由mPlayerIId赋值

mPlayerIId 则在baseRegisterPlayer进行初始化 

而本地音乐可以控制是因为本地音乐用的是MediaPlayer实现的 在其构造函数会调用baseRegisterPlayer
而三方app都是用AudioTrack进行实现的 有些构造函数并未调用baseRegisterPlayer
android/frameworks/base/media/java/android/media/PlayerBase.java:110:    protected void baseRegisterPlayer() {
android/frameworks/base/media/java/android/media/PlayerBase.java:174:           baseRegisterPlayer();
android/frameworks/base/media/java/android/media/SoundPool.java:166:        baseRegisterPlayer();
android/frameworks/base/media/java/android/media/HwAudioSource.java:59:        baseRegisterPlayer();
android/frameworks/base/media/java/android/media/MediaPlayer.java:677:        baseRegisterPlayer();
android/frameworks/base/media/java/android/media/AudioTrack.java:873:        baseRegisterPlayer();
android/frameworks/base/media/java/android/media/AudioTrack.java:905:            baseRegisterPlayer();
修改如下(已验证):
    void baseStart() {
        if (DEBUG) { Log.v(TAG, "baseStart() piid=" + mPlayerIId); }
/*  start */
        if(mPlayerIId == AudioPlaybackConfiguration.PLAYER_PIID_INVALID){
           baseRegisterPlayer();
           Log.v(TAG, "1 baseStart() piid=" + mPlayerIId);
        }
/*  end */
        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
        synchronized (mLock) {
            if (isRestricted_sync()) {
                playerSetVolume(true/*muting*/,0, 0);
            }
        }
    }
具体原因还是没有搞清楚,有机会再看
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值