基于Android O平台Audio Focus分析(主要结合Car)(上)

基于Android O平台Audio Focus分析(主要结合Car)

1.调用示例

packages/apps/Car/LocalMediaPlayer/src/com/android/car/media/localmediaplayer/Player.java

private boolean requestAudioFocus(Runnable onSuccess) {
  
        int result = mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN);
        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
  
            onSuccess.run();
            return true;
        }
        return false;
    }

2.根据调用参数,找到对应的实现

media/java/android/media/AudioManager.java

public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
  
        ...
            status = requestAudioFocus(l,
                    new AudioAttributes.Builder()
                            .setInternalLegacyStreamType(streamType).build(),
                    durationHint,
                    0 /* flags, legacy behavior */);
        ...
        return status;
    }

接口前面的英文注释没贴上来,挑选重要的

参数:durationHint

AUDIOFOCUS_GAIN_TRANSIENT

表明请求是短暂的,临时的,焦点很快会被放弃。比如播放驾驶转向,或者notifications sounds.

AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK

表明之前的焦点owner可以继续播放,但是需要ducks自己的output,压低自己的声音,供申请者做一个短暂的播放。(想象电台主播那种效果)

AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE

对于从系统中获益的临时请求,不会播放诸如通知之类的破坏性声音,用于诸如语音备忘录录音或语音识别之类的场景)。EXCLUSIVE是独家的意思,TRANSIENT是短暂的意思

简单来理解就是

我的请求是短暂的,但是我不希望这时候有嘟嘟之类的notifications声音打扰,我要独占

AUDIOFOCUS_GAIN

for a focus request of unknown duration such as the playback of a song or a video.

中间经过各种弯弯绕绕,如果按照最普通的调用方式,都可以不用关注了。

直接可以去看实现了:

services/core/java/com/android/server/audio/AudioService.java

public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,IAudioPolicyCallback pcb, int sdk) {
  
        // permission checks
        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
  
            if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
  
                if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
                            android.Manifest.permission.MODIFY_PHONE_STATE)) {
  
                    Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
                }
            } else {
  
                // only a registered audio policy can be used to lock focus
                synchronized (mAudioPolicies) {
  
                    if (!mAudioPolicies.containsKey(pcb.asBinder())) {
  
                        Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
                        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
                    }
                }
            }
        }

        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
                clientId, callingPackageName, flags, sdk);
    }

暂时没搞懂这个AUDIOFOCUS_FLAG_LOCK意味着什么。所以,继续走

services/core/java/com/android/server/audio/MediaFocusControl.java

//requestAudioFocus@MediaFocusControl
protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,int sdk) {
  
    ...
      if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
  
                //取出栈顶
                final FocusRequester fr = mFocusStack.peek();
                if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
  
                  //栈顶的GainRequest和GrantFlags和完全和新来的请求一致
                    cb.unlinkToDeath(afdh, 0);
                    notifyExtPolicyFocusGrant_syncAf(fr.toAudioFocusInfo(),
                            AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
                }
                //前面的if没有return
                //说明请求原因不一致,把栈顶拿掉
                if (!focusGrantDelayed) {
  
                    mFocusStack.pop();
                    // the entry that was "popped" is the same that was "peeked" above
                    fr.release();
                }
            }

  //到这,栈顶之前的焦点owner已经不存在了
  *******************************
      // 底下这个函数干的事情主要是这样
      // 栈顶的ClientID同新请求一致(reason不一致),pop it,
        //然后,(注意这个)发出失去焦点的通知...
        //else 遍历整个stack,有一致的ClientId(reason不一致),pop it,
        //因为不在栈顶,所以不持有焦点,所以不用通知!
      removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/);
      
      final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
                    clientId, afdh, callingPackageName, Binder.getCallingUid(), this, sdk);
      if (focusGrantDelayed) {
  
                ...
            } else {
  
                if (!mFocusStack.empty()) {
  
                    //翻译下函数名字:广播_焦点失去_从获得
                    propagateFocusLossFromGain_syncAf(focusChangeHint, nfr);
                }
                // 将焦点请求nrf推到mFocusStack栈顶
                mFocusStack.push(nfr);
                //处理_焦点获得_从请求
                //焦点的状态切换
                //请求-获得-失去
                nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
            }
    ...
}

我们来研究下这个mFocusStack

private final Stack<
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值