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类的一个实例。我们所看到的音量调节通知框就是它了。




原创粉丝点击