当前位置: 首页 > news >正文

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

http://www.dtcms.com/a/354206.html

相关文章:

  • JVM之CMS、G1|ZGC详解以及选型对比
  • SynClub-百度在海外推出的AI社交产品
  • A-Level物理课程全解析:知识点、学习计划与培训机构推荐
  • 网络编程-连接、发送、接收数据学习
  • React Hooks 完全指南:从基础到高级的实战技巧
  • C++ 由 std::thread 初始化想到的
  • TencentOS Server 4.4 下创建mysql容器无法正常运行的问题
  • wireshark解析FLV插件分享
  • 嵌入式Linux(Exynos 4412)笔记
  • 3459. 最长 V 形对角线段的长度
  • 设计模式理解
  • Nishang PowerShell工具:原理详解+使用方法+渗透实战
  • Go+Gdal 完成高性能GIS数据空间分析
  • 深度学习:常用的损失函数的使用
  • “java简单吗?”Java的“简单”与PHP的挑战:编程语言哲学-优雅草卓伊凡
  • 白话FNN、RNN、Attention和self-attention等
  • 《从有限元到深度学习:我的金属疲劳研究进阶之路》
  • 反内卷加速全产业链价值重塑 通威股份等行业龙头或率先受益
  • 基于 C# OpenCVSharp 的模板匹配检测技术方案
  • 计算机日常答疑,一起寻找问题的最优解
  • select
  • SM4加密算法
  • Karatsuba
  • 前端工程化与AI融合:构建智能化开发体系
  • 4-4.Python 数据容器 - 字典 dict(字典 dict 概述、字典的定义与调用、字典的遍历、字典的常用方法)
  • CPU 虚拟化之Cpu Models
  • 代码随想录刷题Day43
  • 时间轮定时器HashedWheelTimer
  • WSL设置静态IP
  • window程序打包