AudioService
来源:互联网 发布:mac如何解密外置硬盘 编辑:程序博客网 时间:2024/05/24 06:56
一 重要字段和对象
1. AudioSystem 定义了三种平台类型:普通平台,phone平台和TV 平台。 这三种类型的不同流之间可能是通用的。
所以在AudioService中定义了三个数组如下
1) 普通平台
private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_RING, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING AudioSystem.STREAM_MUSIC, // STREAM_MUSIC AudioSystem.STREAM_ALARM, // STREAM_ALARM AudioSystem.STREAM_RING, // STREAM_NOTIFICATION AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED AudioSystem.STREAM_RING, // STREAM_DTMF AudioSystem.STREAM_MUSIC // STREAM_TTS };
普通平台的system流,notification流,DTMP流,蓝牙电话流和ring 流是通用的, TTS 和music 流是通用的。
2) phone 平台
private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_RING, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING AudioSystem.STREAM_MUSIC, // STREAM_MUSIC AudioSystem.STREAM_ALARM, // STREAM_ALARM AudioSystem.STREAM_RING, // STREAM_NOTIFICATION AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED AudioSystem.STREAM_RING, // STREAM_DTMF AudioSystem.STREAM_MUSIC // STREAM_TTS };
3) TV 平台
private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] { AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM AudioSystem.STREAM_MUSIC, // STREAM_RING AudioSystem.STREAM_MUSIC, // STREAM_MUSIC AudioSystem.STREAM_MUSIC, // STREAM_ALARM AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED AudioSystem.STREAM_MUSIC, // STREAM_DTMF AudioSystem.STREAM_MUSIC // STREAM_TTS };
这三个数组根据平台不同,向private int[] mStreamVolumeAlias赋予不同的数组。
在流进行控制的时候,根据mStreamVolumeAlias 对于流进行转换。
2. 内部类
内部类VolumeStreamState 保存了一个音频流的音量相关的信息。
public class VolumeStreamState { private final int mStreamType; private final int mIndexMin; private final int mIndexMax; private boolean mIsMuted; private String mVolumeIndexSettingName; private int mObservedDevices; private final SparseIntArray mIndexMap = new SparseIntArray(8); private final Intent mVolumeChanged; private final Intent mStreamDevicesChanged; private VolumeStreamState(String settingName, int streamType) { mVolumeIndexSettingName = settingName; mStreamType = streamType; mIndexMin = MIN_STREAM_VOLUME[streamType] * 10; mIndexMax = MAX_STREAM_VOLUME[streamType] * 10; /* *向底层注册音频流 */ AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10); /* *readSetting() 方法初始化mIndexMap, 保存不同输出设备(DEVICE_OUT) 的音量 */ readSettings(); mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION); mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType); mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION); mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType); }......}
以下方法创建一个数组来保存所有音频流的VolumeStreamState对象
private void createStreamStates() { int numStreamTypes = AudioSystem.getNumStreamTypes(); VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; for (int i = 0; i < numStreamTypes; i++) { streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); } checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); checkMuteAffectedStreams(); }
二 重要流程和方法
1. 音量控制
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller, int uid) { if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType + ", flags=" + flags + ", caller=" + caller); int streamType; boolean isMute = isMuteAdjust(direction); // 音频流有没有被锁定, 如果锁定, 只能控制锁定的音频流 if (mVolumeControlStream != -1) { streamType = mVolumeControlStream; } else { streamType = getActiveStreamType(suggestedStreamType); } ensureValidStreamType(streamType); final int resolvedStream = mStreamVolumeAlias[streamType]; //进行流控制转换 // Play sounds on STREAM_RING only. if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && resolvedStream != AudioSystem.STREAM_RING) { flags &= ~AudioManager.FLAG_PLAY_SOUND; } // For notifications/ring, show the ui before making any adjustments // Don't suppress mute/unmute requests if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) { direction = 0; flags &= ~AudioManager.FLAG_PLAY_SOUND; flags &= ~AudioManager.FLAG_VIBRATE; if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment"); } adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid); }
这里需要说明一下场景控制的getActiveStreamType 的方法
private int getActiveStreamType(int suggestedStreamType) { switch (mPlatformType) { case AudioSystem.PLATFORM_VOICE: if (isInCommunication()) { // 电话在通话中 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); return AudioSystem.STREAM_BLUETOOTH_SCO; // 蓝牙电话 } else { // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); return AudioSystem.STREAM_VOICE_CALL; //普通电话 } } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) { //是否在进行音视频播放 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); return AudioSystem.STREAM_MUSIC; } else { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default"); return AudioSystem.STREAM_RING; } } else if (isAfMusicActiveRecently(0)) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); return AudioSystem.STREAM_MUSIC; } break; case AudioSystem.PLATFORM_TELEVISION: if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { // TV always defaults to STREAM_MUSIC return AudioSystem.STREAM_MUSIC; } break; default: if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); return AudioSystem.STREAM_BLUETOOTH_SCO; } else { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL"); return AudioSystem.STREAM_VOICE_CALL; } } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION, StreamOverride.sDelayMs) || AudioSystem.isStreamActive(AudioSystem.STREAM_RING, StreamOverride.sDelayMs)) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION"); return AudioSystem.STREAM_NOTIFICATION; } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC"); return AudioSystem.STREAM_MUSIC; } else { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_NOTIFICATION as default"); return AudioSystem.STREAM_NOTIFICATION; } } break; } if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); return suggestedStreamType; }
在通话过程中, 返回的你当前使用的phone流。在音视频播放过程中, 返回的流AudioSystem.STREAM_MUSIC。
如果在开发过程中需要进行场景控制, 可以在此修改。
然后进入adjustStreamVolume 方法。
private void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage, String caller, int uid) { if (mUseFixedVolume) { return; } if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction + ", flags=" + flags + ", caller=" + caller); ensureValidDirection(direction); ensureValidStreamType(streamType); boolean isMuteAdjust = isMuteAdjust(direction); if (isMuteAdjust && !isStreamAffectedByMute(streamType)) { return; } // use stream type alias here so that streams with same alias have the same behavior, // including with regard to silent mode control (e.g the use of STREAM_RING below and in // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) int streamTypeAlias = mStreamVolumeAlias[streamType]; /* * 取出对应流的VolumeStreamState */ VolumeStreamState streamState = mStreamStates[streamTypeAlias]; final int device = getDeviceForStream(streamTypeAlias); int aliasIndex = streamState.getIndex(device); boolean adjustVolume = true; int step;...... flags &= ~AudioManager.FLAG_FIXED_VOLUME; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && ((device & mFixedVolumeDevices) != 0)) { flags |= AudioManager.FLAG_FIXED_VOLUME; // Always toggle between max safe volume and 0 for fixed volume devices where safe // volume is enforced, and max and 0 for the others. // This is simulated by stepping by the full allowed volume range if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && (device & mSafeMediaVolumeDevices) != 0) { step = mSafeMediaVolumeIndex; } else { step = streamState.getMaxIndex(); } if (aliasIndex != 0) { aliasIndex = step; } } else { // convert one UI step (+/-1) into a number of internal units on the stream alias step = rescaleIndex(10, streamType, streamTypeAlias); }...... int oldIndex = mStreamStates[streamType].getIndex(device); // 静音设置 if (isMuteAdjust) { boolean state; if (direction == AudioManager.ADJUST_TOGGLE_MUTE) { state = !streamState.mIsMuted; } else { state = direction == AudioManager.ADJUST_MUTE; } if (streamTypeAlias == AudioSystem.STREAM_MUSIC) { setSystemAudioMute(state); } for (int stream = 0; stream < mStreamStates.length; stream++) { if (streamTypeAlias == mStreamVolumeAlias[stream]) { if (!(readCameraSoundForced() && (mStreamStates[stream].getStreamType() == AudioSystem.STREAM_SYSTEM_ENFORCED))) { mStreamStates[stream].mute(state); } } } } else if ((direction == AudioManager.ADJUST_RAISE) && !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex); mVolumeController.postDisplaySafeVolumeWarning(flags); } else if (streamState.adjustIndex(direction * step, device, caller) // 设置音量 || streamState.mIsMuted) { // Post message to set system volume (it in turn will post a // message to persist). if (streamState.mIsMuted) { // Unmute the stream if it was previously muted if (direction == AudioManager.ADJUST_RAISE) { // unmute immediately for volume up streamState.mute(false); } else if (direction == AudioManager.ADJUST_LOWER) { if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) { sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE, streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY); } } } // 发出通知 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE, device, 0, streamState, 0); } ...... int index = mStreamStates[streamType].getIndex(device); //更新volume UI 信息 sendVolumeUpdate(streamType, oldIndex, index, flags); }
这里最重要是三个操作
1. streamState.adjustIndex 方法
2. sendMsg方法。
3. sendVolumeUpdate 方法
首先看streamState.adjustIndex 方法, 它调用了streamState.setIndex 方法。 这个方法将音量值更新保存, 并将音量变化映射到对应的aliased stream。
但是它没有将音量变化设置到底层。
再看 sendMsg方法,处理MSG_SET_DEVICE_VOLUME, 调用setDeviceVolume 方法。
private void setDeviceVolume(VolumeStreamState streamState, int device) { synchronized (VolumeStreamState.class) { // 调用VolumeStreamState的applyDeviceVolume。 // 这个函数的内容很简单,就是在调用AudioSystem.setStreamVolumeIndex() // 到这里,音量就被设置到底层的AudioFlinger里面去了 streamState.applyDeviceVolume_syncVSS(device); // Apply change to all streams using this one as alias int numStreamTypes = AudioSystem.getNumStreamTypes();// ӳ�䵽alias stream for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (streamType != streamState.mStreamType && mStreamVolumeAlias[streamType] == streamState.mStreamType) { // Make sure volume is also maxed out on A2DP device for aliased stream // that may have a different device selected int streamDevice = getDeviceForStream(streamType); if ((device != streamDevice) && mAvrcpAbsVolSupported && ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) { mStreamStates[streamType].applyDeviceVolume_syncVSS(device); } mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice); } } } // 发送消息给mAudioHandler,其处理函数将会调用persitVolume()函数这将会把音量的 //设置信息存储到SettingsProvider中 // AudioService在初始化时,将会从SettingsProvider中将音量设置读取出来并进行设置 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, SENDMSG_QUEUE, device, 0, streamState, PERSIST_DELAY); }
接下来,分析一下sendVolumeUpdate()函数,它用于通知外界音量发生了变化。
这个函数将音量的变化通过广播的形式通知给了其他感兴趣得模块。同时,它还特别通知了mVolumePanel。mVolumePanel是VolumePanel类的一个实例。我们所看到的音量调节通知框就是它了。
- AudioService
- AudioService调整stream音量
- AudioService源码分析
- Android - AudioService(Java)
- 音频管理AudioService
- 深入理解AudioService
- 002 AudioService音频设备管理
- 对AudioService 的认识(1)
- AudioService 之 AudioFocus简单例子
- Android笔记-AudioSystem与AudioService
- Android多媒体:AudioSystem,AudioService和AudioManager
- AudioService 和AudioManager 以及使用举例.
- android audio 源码分析之AudioService
- Binder Hook技术实战(AudioService)
- 《深入理解Android 卷III》第三章 深入理解AudioService
- 《深入理解Android 卷III》第三章 深入理解AudioService
- 记一次基于android audioservice/policy开发新功能经历
- 《深入理解Android 卷III》第三章 深入理解AudioService
- Ubuntu上使用gensim计算文档间的相似度
- 常见的垃圾收集器
- HDU 1806 Frequent values(线段树+离散化+二分)
- vector用法
- hibernate整合spring异常处理
- AudioService
- Docker网络基础-yellowcong
- 集合框架——定义泛型接口
- mysql索引实例----第二章实战篇
- Android APK安装过程
- 回文串类型题目集锦
- 【iOS】TestFlight 发布包测试
- 关于fork一些有意思的问题
- 【其他】神舟精盾K470-i3 D3更换支持5GHz的双频无线网卡