• Android T CEC AVC Feature


    AVC是android T 在cec部分添加的一个feature。以盒子为例,它会在playback device cec状态更新时尝试去确认TV是否是支持的,如果支持就更新该设备的avc flag,并在音量调节时通知TV进行音量更新。

    和以前版本的区别,目前看就是在直接进行音量更新setStreamVolume时会发送 message进行直接更新,但是adjustStreamVolume仍然还是依赖,这样的话作用就大打折扣。鉴于目前支持这个消息的机器应该也是几乎没有,暂时看意义比较有限。此外,android为了支持这个feature,在playback内部也增加了DeviceDiscovery的设计,也增加了cec bus的负担。

    1.开机时就向AudioDeviceVolumeManager注册了OnDeviceVolumeBehaviorChangedListener

    HdmiControlService.java

    1. @Override
    2. public void onBootPhase(int phase) {
    3. if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
    4. mDisplayManager = getContext().getSystemService(DisplayManager.class);
    5. mTvInputManager = (TvInputManager) getContext().getSystemService(
    6. Context.TV_INPUT_SERVICE);
    7. mPowerManager = new PowerManagerWrapper(getContext());
    8. mPowerManagerInternal = new PowerManagerInternalWrapper();
    9. mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
    10. mStreamMusicMaxVolume = getAudioManager().getStreamMaxVolume(AudioManager.STREAM_MUSIC);
    11. if (mAudioDeviceVolumeManager == null) {
    12. mAudioDeviceVolumeManager =
    13. new AudioDeviceVolumeManagerWrapper(getContext());
    14. }
    15. getAudioDeviceVolumeManager().addOnDeviceVolumeBehaviorChangedListener(
    16. mServiceThreadExecutor, this::onDeviceVolumeBehaviorChanged);
    17. } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
    18. runOnServiceThread(this::bootCompleted);
    19. }
    20. }
    1. /**
    2. * @hide
    3. * Interface definition of a callback to be invoked when the volume behavior of an audio device
    4. * is updated.
    5. */
    6. public interface OnDeviceVolumeBehaviorChangedListener {
    7. /**
    8. * Called on the listener to indicate that the volume behavior of a device has changed.
    9. * @param device the audio device whose volume behavior changed
    10. * @param volumeBehavior the new volume behavior of the audio device
    11. */
    12. void onDeviceVolumeBehaviorChanged(
    13. @NonNull AudioDeviceAttributes device,
    14. @AudioManager.DeviceVolumeBehavior int volumeBehavior);
    15. }

    这里后面再分析。

    1. /**
    2. * Listener for changes to the volume behavior of an audio output device. Caches the
    3. * volume behavior of devices used for Absolute Volume Control.
    4. */
    5. @VisibleForTesting
    6. @ServiceThreadOnly
    7. void onDeviceVolumeBehaviorChanged(AudioDeviceAttributes device, int volumeBehavior) {
    8. assertRunOnServiceThread();
    9. if (AVC_AUDIO_OUTPUT_DEVICES.contains(device)) {
    10. synchronized (mLock) {
    11. mAudioDeviceVolumeBehaviors.put(device, volumeBehavior);
    12. }
    13. checkAndUpdateAbsoluteVolumeControlState();
    14. }
    15. }
    1. // Audio output devices used for Absolute Volume Control
    2. private static final List AVC_AUDIO_OUTPUT_DEVICES =
    3. Collections.unmodifiableList(Arrays.asList(AUDIO_OUTPUT_DEVICE_HDMI,
    4. AUDIO_OUTPUT_DEVICE_HDMI_ARC, AUDIO_OUTPUT_DEVICE_HDMI_EARC));

    PLAYBACK相关的AUDIO_OUTPUT_DEVICE_HDMI,TV类型的AUDIO_OUTPUT_DEVICE_HDMI_ARC, AUDIO_OUTPUT_DEVICE_HDMI_EARC都属于AVC设备。

    当系统的AVC设备对应的volume behaviour发生变更时,就会通过checkAndUpdateAbsoluteVolumeControlState来检查和更新HdmiControlService内部的状态。

    2. 进行volume control behavior更新的时间。

    监听cec status的设计在T上这里的实现再次发生变更,直接通过DEVICE_OUT_HDMI的volume behaviour的方式来更新cec sink device的状态。

    首先如果DEVICE_OUT_HDMI设备有过AudioService的setDeviceVolumeBehavior接口设置过behaviour的话,就不再更新了。

    这里有一个问题,如果cec不可用了,然后也设置过FULL的behaviour的话,盒子的音量键将完全失去作用。

    1. //==========================================================================================
    2. // Hdmi CEC:
    3. // - System audio mode:
    4. // If Hdmi Cec's system audio mode is on, audio service should send the volume change
    5. // to HdmiControlService so that the audio receiver can handle it.
    6. // - CEC sink:
    7. // OUT_HDMI becomes a "full volume device", i.e. output is always at maximum level
    8. // and volume changes won't be taken into account on this device. Volume adjustments
    9. // are transformed into key events for the HDMI playback client.
    10. //==========================================================================================
    11. @GuardedBy("mHdmiClientLock")
    12. private void updateHdmiCecSinkLocked(boolean hdmiCecSink) {
    13. if (!hasDeviceVolumeBehavior(AudioSystem.DEVICE_OUT_HDMI)) {
    14. if (hdmiCecSink) {
    15. if (DEBUG_VOL) {
    16. Log.d(TAG, "CEC sink: setting HDMI as full vol device");
    17. }
    18. setDeviceVolumeBehaviorInternal(
    19. new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
    20. AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL,
    21. "AudioService.updateHdmiCecSinkLocked()");
    22. } else {
    23. if (DEBUG_VOL) {
    24. Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
    25. }
    26. // Android TV devices without CEC service apply software volume on
    27. // HDMI output
    28. setDeviceVolumeBehaviorInternal(
    29. new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
    30. AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE,
    31. "AudioService.updateHdmiCecSinkLocked()");
    32. }
    33. postUpdateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
    34. "HdmiPlaybackClient.DisplayStatusCallback");
    35. }
    36. }

    只有persistDeviceVolumeBehavior才会将volume behaviour记录到system settings里面,比如

    _id:36 name:AudioService_DeviceVolumeBehavior_hdmi pkg:android value:1 default:1 defaultSystemSet:true

    1. public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
    2. @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @Nullable String pkgName) {
    3. // verify permissions
    4. enforceModifyAudioRoutingPermission();
    5. // verify arguments
    6. Objects.requireNonNull(device);
    7. AudioManager.enforceValidVolumeBehavior(deviceVolumeBehavior);
    8. sVolumeLogger.log(new AudioEventLogger.StringEvent("setDeviceVolumeBehavior: dev:"
    9. + AudioSystem.getOutputDeviceName(device.getInternalType()) + " addr:"
    10. + device.getAddress() + " behavior:"
    11. + AudioDeviceVolumeManager.volumeBehaviorName(deviceVolumeBehavior)
    12. + " pack:" + pkgName).printLog(TAG));
    13. if (pkgName == null) {
    14. pkgName = "";
    15. }
    16. if (device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) {
    17. avrcpSupportsAbsoluteVolume(device.getAddress(),
    18. deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
    19. return;
    20. }
    21. setDeviceVolumeBehaviorInternal(device, deviceVolumeBehavior, pkgName);
    22. persistDeviceVolumeBehavior(device.getInternalType(), deviceVolumeBehavior);
    23. }

    AudioService在设置MyHdmiControlStatusChangeListenerCallback时必然会调用updateHdmiCecSinkLocked来更新一次volume behaviour。

    1. @VisibleForTesting
    2. void addHdmiControlStatusChangeListener(
    3. final IHdmiControlStatusChangeListener listener) {
    4. final HdmiControlStatusChangeListenerRecord record =
    5. new HdmiControlStatusChangeListenerRecord(listener);
    6. try {
    7. listener.asBinder().linkToDeath(record, 0);
    8. } catch (RemoteException e) {
    9. Slog.w(TAG, "Listener already died");
    10. return;
    11. }
    12. synchronized (mLock) {
    13. mHdmiControlStatusChangeListenerRecords.add(record);
    14. }
    15. // Inform the listener of the initial state of each HDMI port by generating
    16. // hotplug events.
    17. runOnServiceThread(new Runnable() {
    18. @Override
    19. public void run() {
    20. synchronized (mLock) {
    21. if (!mHdmiControlStatusChangeListenerRecords.contains(record)) return;
    22. }
    23. // Return the current status of mHdmiControlEnabled;
    24. synchronized (mLock) {
    25. invokeHdmiControlStatusChangeListenerLocked(listener, mHdmiControlEnabled);
    26. }
    27. }
    28. });
    29. }

        private class MyHdmiControlStatusChangeList
  • 相关阅读:
    FasterViT:英伟达提出分层注意力,构造高吞吐CNN-ViT混合网络 | ICLR 2024
    Ubuntu下安装Python
    c++ stl(标准模板库)
    服务器文件操作 ChannelSftp 的用法
    C++ std::string 删除指定字符
    怎么在Windows10中找回Windows7的照片查看器(Windows 照片查看器)win10新的照片查看器太难用了
    【推荐系统】方法论 | 数据驱动 | 深度学习RS
    Leetcode算法题
    用excel计算一个矩阵的转置矩阵
    mac下vue-cli从2.9.6升级到最新版本
  • 原文地址:https://blog.csdn.net/xlnaan/article/details/126308237