ARC1.3-功放设备音量初始化

章节2-1中TV设备接收到< System Audio Mode Status> 消息后会调用setSystemAudioMode方法设置音频模式
setSystemAudioMode方法中调用了

mService.setSystemAudioActivated(on)方法这个方法用于激活或停用系统音频模式。当on参数为true时,它会将音频输出切换到通过HDMI输出或者其它外部音频设备。当onfalse时,它会将音频输出切换回设备的内置扬声器

mService.announceSystemAudioModeChange(on)方法,这个方法用于通知系统音频模式发生了变化。当on参数为true时,它会通知系统音频模式已经切换到外部设备。当onfalse时,它会通知系统音频模式已经切换回设备内置扬声器

startArcAction(true)方法,开始激活ARC功能的动作(这个方法在如何判断是否已激活ARC功能,功放设备是否与安卓设备建立连接)中有分析。

mService.setSystemAudioActivated(on)以及mService.announceSystemAudioModeChange(on)方法只要知道他们的作用就行,具体流程是怎么处理的这里就不追下去了,有兴趣的大佬可以继续追下去分析到时候可以一起交流

void setSystemAudioMode(boolean on) {  
    if (!isSystemAudioControlFeatureEnabled() && on) {  
        HdmiLogger.debug("Cannot turn on system audio mode "  
                + "because the System Audio Control feature is disabled.");  
        return;    }  
    HdmiLogger.debug("System Audio Mode change[old:%b new:%b]",  
            mService.isSystemAudioActivated(), on);  
    updateAudioManagerForSystemAudio(on);  
    synchronized (mLock) {  
        if (mService.isSystemAudioActivated() != on) {  
            mService.setSystemAudioActivated(on);  
            mService.announceSystemAudioModeChange(on);  
        }  
        if (on && !mArcEstablished) { 
	        //调用了startArcAction方法开始激活ARC功能
            startArcAction(true);  
        } else if (!on) {  
            startArcAction(false);  
        }  
    }  
}

在章节2-1中startArcAction方法最后调用了enableArc方法激活ARC功能。

这个方法中也调用了notifyArcStatusToAudioService方法将Arc状态通知给音频服务
base/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java

void enableArc(List<byte[]> supportedSads) {  
    assertRunOnServiceThread();  
    HdmiLogger.debug("Set Arc Status[old:%b new:true]", mArcEstablished);  
  
    enableAudioReturnChannel(true);  
    notifyArcStatusToAudioService(true, supportedSads);  
    mArcEstablished = true;  
}

//mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0)

private void notifyArcStatusToAudioService(boolean enabled, List<byte[]> supportedSads) {  
    // Note that we don't set any name to ARC.  
    AudioDeviceAttributes attributes = new AudioDeviceAttributes(  
            AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_ARC, "", "",  
            new ArrayList<AudioProfile>(), supportedSads.stream()  
            .map(sad -> new AudioDescriptor(AudioDescriptor.STANDARD_EDID,  
                    AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, sad))  
            .collect(Collectors.toList()));  
    mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);  
}

base/services/core/java/com/android/server/audio/AudioService.java
//mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller)

public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,  
        @ConnectionState int state, String caller) {  
    enforceModifyAudioRoutingPermission();  
    if (state != CONNECTION_STATE_CONNECTED  
            && state != CONNECTION_STATE_DISCONNECTED) {  
        throw new IllegalArgumentException("Invalid state " + state);  
    }  
    new MediaMetrics.Item(mMetricsId + "setWiredDeviceConnectionState")  
            .set(MediaMetrics.Property.ADDRESS, attributes.getAddress())  
            .set(MediaMetrics.Property.CLIENT_NAME, caller)  
            .set(MediaMetrics.Property.DEVICE,  
                    AudioSystem.getDeviceName(attributes.getInternalType()))  
            .set(MediaMetrics.Property.NAME, attributes.getName())  
            .set(MediaMetrics.Property.STATE,  
                    state == CONNECTION_STATE_CONNECTED ? "connected" : "disconnected")  
            .record();  
  
    if ((attributes.getInternalType() == AudioSystem.DEVICE_OUT_AUX_DIGITAL) && (state == CONNECTION_STATE_CONNECTED)) {  
        updataFormatForEdid();  
    }  
  
    mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller);  
}

base/services/core/java/com/android/server/audio/AudioDeviceBroker.java

/*package*/ void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,  
        @AudioService.ConnectionState int state, String caller) {  
    //TODO move logging here just like in setBluetooth* methods  
    synchronized (mDeviceStateLock) {  
        mDeviceInventory.setWiredDeviceConnectionState(attributes, state, caller);  
    }  
}

base/services/core/java/com/android/server/audio/AudioDeviceInventory.java

/*package*/ int setWiredDeviceConnectionState(AudioDeviceAttributes attributes,  
        @AudioService.ConnectionState int state, String caller) {  
    synchronized (mDevicesLock) {  
        int delay = checkSendBecomingNoisyIntentInt(  
                attributes.getInternalType(), state, AudioSystem.DEVICE_NONE);  
        mDeviceBroker.postSetWiredDeviceConnectionState(  
                new WiredDeviceConnectionState(attributes, state, caller), delay);  
        return delay;  
    }  
}

base/services/core/java/com/android/server/audio/AudioDeviceBroker.java

/*package*/ void postSetWiredDeviceConnectionState(  
        AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) {  
    sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay);  
}
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:  
    synchronized (mDeviceStateLock) {  
        mDeviceInventory.onSetWiredDeviceConnectionState(  
                (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);  
    }  
    break;

base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
//handleDeviceConnection

/*package*/ void onSetWiredDeviceConnectionState(  
                        AudioDeviceInventory.WiredDeviceConnectionState wdcs) {  
    int type = wdcs.mAttributes.getInternalType();  
  
    AudioService.sDeviceLogger.log(new AudioServiceEvents.WiredDevConnectEvent(wdcs));  
  
    MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId  
            + "onSetWiredDeviceConnectionState")  
            .set(MediaMetrics.Property.ADDRESS, wdcs.mAttributes.getAddress())  
            .set(MediaMetrics.Property.DEVICE,  
                    AudioSystem.getDeviceName(type))  
            .set(MediaMetrics.Property.STATE,  
                    wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED  
                            ? MediaMetrics.Value.DISCONNECTED : MediaMetrics.Value.CONNECTED);  
    synchronized (mDevicesLock) {  
        if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)  
                && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {  
            mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/,  
                    "onSetWiredDeviceConnectionState state DISCONNECTED");  
        }  
  
        if (!handleDeviceConnection(wdcs.mAttributes,  
                wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {  
            // change of connection state failed, bailout  
            mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")  
                    .record();  
            return;        }  
        if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {  
            if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {  
                mDeviceBroker.setBluetoothA2dpOnInt(false, false /*fromA2dp*/,  
                        "onSetWiredDeviceConnectionState state not DISCONNECTED");  
            }  
            mDeviceBroker.checkMusicActive(type, wdcs.mCaller);  
        }  
        if (type == AudioSystem.DEVICE_OUT_HDMI) {  
            mDeviceBroker.checkVolumeCecOnHdmiConnection(wdcs.mState, wdcs.mCaller);  
        }  
        sendDeviceConnectionIntent(type, wdcs.mState,  
                wdcs.mAttributes.getAddress(), wdcs.mAttributes.getName());  
        updateAudioRoutes(type, wdcs.mState);  
    }  
    mmi.record();  
}

//mDeviceBroker.postAccessoryPlugMediaUnmute(device);

/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,  
        boolean isForTesting) {  
    int device = attributes.getInternalType();  
    String address = attributes.getAddress();  
    String deviceName = attributes.getName();  
    if (AudioService.DEBUG_DEVICES) {  
        Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:"  
                + Integer.toHexString(device) + " address:" + address  
                + " name:" + deviceName + ")");  
    }  
    MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "handleDeviceConnection")  
            .set(MediaMetrics.Property.ADDRESS, address)  
            .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(device))  
            .set(MediaMetrics.Property.MODE, connect  
                    ? MediaMetrics.Value.CONNECT : MediaMetrics.Value.DISCONNECT)  
            .set(MediaMetrics.Property.NAME, deviceName);  
    synchronized (mDevicesLock) {  
        final String deviceKey = DeviceInfo.makeDeviceListKey(device, address);  
        if (AudioService.DEBUG_DEVICES) {  
            Slog.i(TAG, "deviceKey:" + deviceKey);  
        }  
        DeviceInfo di = mConnectedDevices.get(deviceKey);  
        boolean isConnected = di != null;  
        if (AudioService.DEBUG_DEVICES) {  
            Slog.i(TAG, "deviceInfo:" + di + " is(already)Connected:" + isConnected);  
        }  
        if (connect && !isConnected) {  
            final int res;  
            if (isForTesting) {  
                res = AudioSystem.AUDIO_STATUS_OK;  
            } else {  
                res = mAudioSystem.setDeviceConnectionState(attributes,  
                        AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);  
            }  
            if (res != AudioSystem.AUDIO_STATUS_OK) {  
                final String reason = "not connecting device 0x" + Integer.toHexString(device)  
                        + " due to command error " + res;  
                Slog.e(TAG, reason);  
                mmi.set(MediaMetrics.Property.EARLY_RETURN, reason)  
                        .set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED)  
                        .record();  
                return false;            }  
            mConnectedDevices.put(deviceKey, new DeviceInfo(  
                    device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));  
            mDeviceBroker.postAccessoryPlugMediaUnmute(device);  
            mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();  
            return true;        } else if (!connect && isConnected) {  
            mAudioSystem.setDeviceConnectionState(attributes,  
                    AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);  
            // always remove even if disconnection failed  
            mConnectedDevices.remove(deviceKey);  
            mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();  
            return true;        }  
        Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey  
                + ", deviceSpec=" + di + ", connect=" + connect);  
    }  
    mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record();  
    return false;}

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

public void postAccessoryPlugMediaUnmute(int newDevice) {  
    sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,  
            newDevice, 0, null, 0);  
}

case MSG_ACCESSORY_PLUG_MEDIA_UNMUTE:  
    onAccessoryPlugMediaUnmute(msg.arg1);  
    break;

//mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);

private void onAccessoryPlugMediaUnmute(int newDevice) {  
    if (DEBUG_VOL) {  
        Log.i(TAG, String.format("onAccessoryPlugMediaUnmute newDevice=%d [%s]",  
                newDevice, AudioSystem.getOutputDeviceName(newDevice)));  
    }  
  
    if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS  
            && !isStreamMutedByRingerOrZenMode(AudioSystem.STREAM_MUSIC)  
            && DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice)  
            && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted  
            && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0  
            && getDeviceSetForStreamDirect(AudioSystem.STREAM_MUSIC).contains(newDevice)) {  
        if (DEBUG_VOL) {  
            Log.i(TAG, String.format("onAccessoryPlugMediaUnmute unmuting device=%d [%s]",  
                    newDevice, AudioSystem.getOutputDeviceName(newDevice)));  
        }  
        mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);  
    }  
}

//MSG_SET_ALL_VOLUMES

public boolean mute(boolean state) {  
    Log.d(TAG,"zfp#mute");  
    boolean changed = false;  
    synchronized (VolumeStreamState.class) {  
        if (state != mIsMuted) {  
            changed = true;  
            mIsMuted = state;  
  
            // Set the new mute volume. This propagates the values to  
            // the audio system, otherwise the volume won't be changed            
            // at the lower level.            
            sendMsg(mAudioHandler,  
                    MSG_SET_ALL_VOLUMES,  
                    SENDMSG_QUEUE,  
                    0,  
                    0,  
                    this, 0);  
        }  
    }  
    if (changed) {  
        // Stream mute changed, fire the intent.  
        Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);  
        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);  
        intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);  
        sendBroadcastToAll(intent);  
    }  
    return changed;  
}

//setAllVolumes

case MSG_SET_ALL_VOLUMES:  
    setAllVolumes((VolumeStreamState) msg.obj);  
    break;

//mStreamStates[streamType].applyAllVolumes()

private void setAllVolumes(VolumeStreamState streamState) {  
  
    // Apply volume  
    streamState.applyAllVolumes();  
  
    // Apply change to all streams using this one as alias  
    int numStreamTypes = AudioSystem.getNumStreamTypes();  
    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {  
        if (streamType != streamState.mStreamType &&  
                mStreamVolumeAlias[streamType] == streamState.mStreamType) {  
            mStreamStates[streamType].applyAllVolumes();  
        }  
    }  
}

//setStreamVolumeIndex

public void applyAllVolumes() {  
    synchronized (VolumeStreamState.class) {  
        // apply device specific volumes first  
        Log.d(TAG,"zfp#applyAllVolumes");  
        int index;  
        for (int i = 0; i < mIndexMap.size(); i++) {  
            final int device = mIndexMap.keyAt(i);  
            if (device != AudioSystem.DEVICE_OUT_DEFAULT) {  
                if (isFullyMuted()) {  
                    index = 0;  
                } else if (isAbsoluteVolumeDevice(device)  
                        || isA2dpAbsoluteVolumeDevice(device)  
                        || AudioSystem.isLeAudioDeviceType(device)) {  
                    index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);  
                } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {  
                    index = (mIndexMax + 5)/10;  
                } else {  
                    index = (mIndexMap.valueAt(i) + 5)/10;  
                }  
                setStreamVolumeIndex(index, device);  
            }  
        }  
        // apply default volume last: by convention , default device volume will be used  
        // by audio policy manager if no explicit volume is present for a given device type        
        if (isFullyMuted()) {  
            index = 0;  
        } else {  
            index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;  
        }  
        setStreamVolumeIndex(index, AudioSystem.DEVICE_OUT_DEFAULT);  
    }  
}

//mAudioSystem.setStreamVolumeIndexAS

private void setStreamVolumeIndex(int index, int device) {  
    // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.  
    // This allows RX path muting by the audio HAL only when explicitly muted but not when    
    // index is just set to 0 to repect BT requirements   
    if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0  
            && !isFullyMuted()) {  
        index = 1;  
    }  
    boolean arcStatus = SystemProperties.getBoolean("sys.skg.arc.inserted", false);  
    if (mStreamType == AudioSystem.STREAM_MUSIC && arcStatus){  
        if (device == AudioSystem.DEVICE_OUT_SPDIF || device == AudioSystem.DEVICE_OUT_SPDIF_1  
                || device == AudioSystem.DEVICE_OUT_HDMI || device == AudioSystem.DEVICE_OUT_HDMI_1){  
            return;  
        }  
    }  
    Log.d(TAG,"zfp#setStreamVolumeIndex#index = " + index + "device = " + device + "mStreamType = " + mStreamType);  
    mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);  
  
}

base/media/java/android/media/AudioSystem.java
//setStreamVolumeIndex

public static int setStreamVolumeIndexAS(int stream, int index, int device) {  
    if (DEBUG_VOLUME) {  
        Log.i(TAG, "setStreamVolumeIndex: " + STREAM_NAMES[stream]  
                + " dev=" + Integer.toHexString(device) + " idx=" + index);  
    }  
    return setStreamVolumeIndex(stream, index, device);  
}

private static native int setStreamVolumeIndex(int stream, int index, int device);
//当ARC设备唤醒时还会调用AudioService.java的 方法更新设备声音状态

base/media/java/android/media/AudioSystem.java

private void updateVolumeStates(int device, int streamType, String caller) {  
    Log.d(TAG,"sug#updateVolumeStates");  
    // Handle device volume aliasing of SPEAKER_SAFE.  
    if (device == AudioSystem.DEVICE_OUT_SPEAKER_SAFE) {  
        device = AudioSystem.DEVICE_OUT_SPEAKER;  
    }  
    if (!mStreamStates[streamType].hasIndexForDevice(device)) {  
        // set the default value, if device is affected by a full/fix/abs volume rule, it  
        // will taken into account in checkFixedVolumeDevices()        
        mStreamStates[streamType].setIndex(  
                mStreamStates[mStreamVolumeAlias[streamType]]  
                        .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),  
                device, caller, true /*hasModifyAudioSettings*/);  
    }  
  
    // Check if device to be updated is routed for the given audio stream  
    // This may include devices such as SPEAKER_SAFE.    
    List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt(  
            new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build(),  
            true /* forVolume */);  
    for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) {  
        if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType(  
                device)) {  
            mStreamStates[streamType].checkFixedVolumeDevices();  
  
            // Unmute streams if required and device is full volume  
            Log.d(TAG,"sug#updateVolumeStates#device = " + device);  

> [!NOTE]
> 当设备音频流为静音状态并且设备为ARC设备时解除设备静音
>             if (isStreamMute(streamType) && (mFullVolumeDevices.contains(device) || isArcDevice(device))) {  
>                 mStreamStates[streamType].mute(false);  
>             }  

        }  
    }  
}
2、android设备开机时启动AudioService初始化设备音量
public AudioService(Context context, AudioSystemAdapter audioSystem,  
        SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper,  
        AppOpsManager appOps) {

---

> [!代码1]
> 创建并启动名为AudioService的循环消息处理线程
> createAudioSystemThread();

---

> [!代码2]
> 根据平台不同,选择Stream别名的定义策略。比如TV电视会STREAM_VOLUME_ALIAS_TELEVISION,手机会使用STREAM_VOLUME_ALIAS_VOICE
> updateStreamVolumeAlias(false /*updateVolumes*/, TAG);

---

> [!代码3]
> 开机初始化流以及设备的音量onInitStreamsAndVolumes()//内部线程在处理MSG_INIT_STREAMS_VOLUMES消息时调用
> queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_STREAMS_VOLUMES,  
>         0 /* arg1 */,  0 /* arg2 */, null /* obj */,  0 /* delay */);


}
代码3

//createStreamStates();

private void onInitStreamsAndVolumes() {  
    createStreamStates();  
  
    // must be called after createStreamStates() as it uses MUSIC volume as default if no  
    // persistent data    initVolumeGroupStates();  
  
    // mSafeUsbMediaVolumeIndex must be initialized after createStreamStates() because it  
    // relies on audio policy having correct ranges for volume indexes.    
    mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();  
  
    // Call setRingerModeInt() to apply correct mute  
    // state on streams affected by ringer mode.    mRingerAndZenModeMutedStreams = 0;  
    setRingerModeInt(getRingerModeInternal(), false);  
  
    final float[] preScale = new float[3];  
    preScale[0] = mContext.getResources().getFraction(  
            com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,  
            1, 1);  
    preScale[1] = mContext.getResources().getFraction(  
            com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,  
            1, 1);  
    preScale[2] = mContext.getResources().getFraction(  
            com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,  
            1, 1);  
    for (int i = 0; i < preScale.length; i++) {  
        if (0.0f <= preScale[i] && preScale[i] <= 1.0f) {  
            mPrescaleAbsoluteVolume[i] = preScale[i];  
        }  
    }  
  
    initExternalEventReceivers();  
  
    // check on volume initialization  
    checkVolumeRangeInitialization("AudioService()");  
}
private void createStreamStates() {  
    int numStreamTypes = AudioSystem.getNumStreamTypes();  

> [!代码3-1]
> 传入音频流创建streams对象
>     VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];  

  
    for (int i = 0; i < numStreamTypes; i++) {  
        streams[i] =  
                new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);  
    }  
  

> [!代码3-2]
> 检查所有固定音量设备
>     checkAllFixedVolumeDevices();  

> [!代码3-3]
> 检查所有音频流的值
>     checkAllAliasStreamVolumes();  

> [!代码3-4]
>     checkMuteAffectedStreams();  

> [!代码3-5]
>     updateDefaultVolumes();  

}
代码3-1
private VolumeStreamState(String settingName, int streamType) {  
    mVolumeIndexSettingName = settingName;  
  
    mStreamType = streamType;  
    mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;  
    mIndexMinNoPerm = mIndexMin; // may be overwritten later in updateNoPermMinIndex()  
    mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;  

> [!NOTE]
> 通知AudioPolicyService设置最大和最小音量等级
>     final int status = AudioSystem.initStreamVolume(  
>             streamType, mIndexMin / 10, mIndexMax / 10);  

    if (status != AudioSystem.AUDIO_STATUS_OK) {  
        sLifecycleLogger.log(new AudioEventLogger.StringEvent(  
                 "VSS() stream:" + streamType + " initStreamVolume=" + status)  
                .printLog(ALOGE, TAG));  
        sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,  
                "VSS()" /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);  
    }  
  

> [!代码3-1-1]
> 从SettingProvider中读取当前StreamType对应的各个device的默认音量等级,如果SettingProvider中没有配置,就使用AudioSystem.DEFAULT_STREAM_VOLUME[]数组中的配置
>     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);  
}

代码3-1-1

public void readSettings() {  
    ......
    
    synchronized (VolumeStreamState.class) {  
        for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {  
  
            // retrieve current volume for device  
            // if no volume stored for current stream and device, use default volume if default            
            // device, continue otherwise            
            int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?  
                    AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;  
            int index;  
            if (!hasValidSettingsName()) {  
                index = defaultIndex;  
            } else {  
                String name = getSettingNameForDevice(device);  

> [!NOTE]
> 获取音量值
>                 index = mSettings.getSystemIntForUser(  
>                         mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);  

            }  
            if (index == -1) {  
                continue;  
            }  
  

> [!NOTE]
> 将音量值put到集合中
>             mIndexMap.put(device, getValidIndex(10 * index,  
>                     true /*hasModifyAudioSettings*/));  

        }  
    }  
}
代码3-2

//mStreamStates[streamType].checkFixedVolumeDevices()

private void checkAllFixedVolumeDevices()  
{  
    int numStreamTypes = AudioSystem.getNumStreamTypes();  
    for (int streamType = 0; streamType < numStreamTypes; streamType++) {  
        mStreamStates[streamType].checkFixedVolumeDevices();  
    }  
}
public void checkFixedVolumeDevices() {  
    synchronized (VolumeStreamState.class) {  
        // ignore settings for fixed volume devices: volume should always be at max or 0  
        if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {  
            for (int i = 0; i < mIndexMap.size(); i++) {  
                int device = mIndexMap.keyAt(i);  
                int index = mIndexMap.valueAt(i);  

> [!NOTE]
> 当为满音量设备时传入最大音量值
>                 if (isFullVolumeDevice(device)  
>                         || (isFixedVolumeDevice(device) && index != 0)) {  
>                     mIndexMap.put(device, mIndexMax);  
>                 }  

> [!NOTE]
> 同步更新设备音量值
>                 applyDeviceVolume_syncVSS(device);  

            }  
        }  
    }  
}
代码3-3
private void checkAllAliasStreamVolumes() {  
    synchronized (mSettingsLock) {  
        synchronized (VolumeStreamState.class) {  
            int numStreamTypes = AudioSystem.getNumStreamTypes();  
            for (int streamType = 0; streamType < numStreamTypes; streamType++) {  

> [!NOTE]
> 拷贝当前StreamType对应别名的音量
>                 mStreamStates[streamType]  
>                         .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);  

                // apply stream volume  
                if (!mStreamStates[streamType].mIsMuted) {  

> [!NOTE]
> 设置当前streamType所有对应device的音量等级到AudioPolicyService中
>                     mStreamStates[streamType].applyAllVolumes();  

                }  
            }  
        }  
    }  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值