Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34037424 authored by Amy's avatar Amy Committed by shubang
Browse files

Add setStreamPath handlers and do input switching according to the new

active path.

ag/4959473

SetStreamPath diff is based on Patch 2

Test: local test.
Bug: 112477738
Change-Id: I9628330dd2cbb48c1ccba7da40ebc28a05f3a495
parent 225d55a4
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -333,6 +333,14 @@ final class Constants {
    static final String PROPERTY_HDMI_CEC_NEVER_CLAIM_PLAYBACK_LOGICAL_ADDRESS =
            "ro.hdmi.property_hdmi_cec_never_claim_playback_logical_address";

    /**
     * Property to indicate if the current device is a cec switch device.
     *
     * <p> Default is false.
     */
    static final String PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH =
            "ro.hdmi.property_is_device_hdmi_cec_switch";

    // Set to false to allow playback device to go to suspend mode even
    // when it's an active source. True by default.
    static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
+35 −10
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;

import java.util.HashMap;

/**
 * Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in Android
 * system.
@@ -62,9 +64,17 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
    // AVR as audio receiver.
    @ServiceThreadOnly private boolean mArcEstablished = false;

    // If the current device uses TvInput for ARC. We assume all other inputs also use TvInput
    // when ARC is using TvInput.
    private boolean mArcIntentUsed = SystemProperties
            .get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, "0").contains("tvinput");

    // Keeps the mapping (HDMI port ID to TV input URI) to keep track of the TV inputs ready to
    // accept input switching request from HDMI devices. Requests for which the corresponding
    // input ID is not yet registered by TV input framework need to be buffered for delayed
    // processing.
    private final HashMap<Integer, String> mTvInputs = new HashMap<>();

    protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
        super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
        mSystemAudioControlFeatureEnabled = true;
@@ -75,6 +85,13 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
                Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true);
        mAutoTvOff = mService.readBooleanSetting(
                Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED, true);
        // TODO(amyjojo): make the map ro property.
        mTvInputs.put(Constants.CEC_SWITCH_HDMI1,
                "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
        mTvInputs.put(Constants.CEC_SWITCH_HDMI2,
                "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
        mTvInputs.put(Constants.CEC_SWITCH_HDMI3,
                "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
    }

    @Override
@@ -594,20 +611,23 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
        int port = getLocalPortFromPhysicalAddress(physicalAddress);
        // Wake up if the new Active Source is the current device or under it
        // or if Arc is enabled.
        if ((isArcEnabled() || port >= 0) && mService.isPowerStandbyOrTransient()) {
        // or if System Audio Control is enabled.
        if ((isSystemAudioActivated() || port >= 0) && mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }

        if (isArcEnabled() && port < 0) {
            // New active source will trigger arc input switching.
        if (isSystemAudioActivated() && port < 0) {
            // If system audio mode is on and the new active source is not under the current device,
            // Will switch to ARC input.
            // TODO(b/115637145): handle system aduio without ARC
            routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
        } else if (port >= 0) {
            // TODO(amyjojo): Routing Control input swithcing.
        } else if (mIsSwitchDevice && port >= 0) {
            // If current device is a switch and the new active source is under it,
            // will switch to the corresponding active path.
            routeToInputFromPortId(port);
        }
    }

    @Override
    protected void routeToInputFromPortId(int portId) {
        if (mArcIntentUsed) {
            routeToTvInputFromPortId(portId);
@@ -622,14 +642,19 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
            return;
        }
        // TODO(amyjojo): handle if switching to the current input
        if (portId == Constants.CEC_SWITCH_HOME) {
        if (portId == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
            switchToHomeTvInput();
        } else if (portId == Constants.CEC_SWITCH_ARC) {
            switchToTvInput(SystemProperties.get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT));
            // TODO(amyjojo): check if setParameters is still needed.
            return;
        } else {
            // TODO(amyjojo): map port number parsed from physical address to LocalActivePort id
            String uri = mTvInputs.get(portId);
            if (uri != null) {
                switchToTvInput(mTvInputs.get(portId));
            } else {
                HdmiLogger.debug("Port number does not match any Tv Input.");
                return;
            }
        }

        setLocalActivePort(portId);
+2 −1
Original line number Diff line number Diff line
@@ -266,7 +266,8 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
        setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
    }

    private void wakeUpIfActiveSource() {
    @Override
    protected void wakeUpIfActiveSource() {
        if (!mIsActiveSource) {
            return;
        }
+59 −14
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.hdmi;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.IHdmiControlCallback;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
@@ -38,6 +39,11 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
    // Indicate if current device is Active Source or not
    private boolean mIsActiveSource = false;

    // Device has cec switch functionality or not.
    // Default is false.
    protected boolean mIsSwitchDevice = SystemProperties.getBoolean(
            Constants.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);

    // Local active port number used for Routing Control.
    // This records the default active port or the previous valid active port.
    // Default is HOME input.
@@ -123,19 +129,52 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
        return true;
    }

    @Override
    @ServiceThreadOnly
    void setIsActiveSource(boolean on) {
    protected boolean handleSetStreamPath(HdmiCecMessage message) {
        assertRunOnServiceThread();
        mIsActiveSource = on;
        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
        // If current device is the target path, set to Active Source.
        // If the path is under the current device, should switch
        if (physicalAddress == mService.getPhysicalAddress() && mService.isPlaybackDevice()) {
            setAndBroadcastActiveSource(message, physicalAddress);
        }
        switchInputOnReceivingNewActivePath(physicalAddress);
        return true;
    }

    protected void maySendActiveSource(int dest) {
        if (mIsActiveSource) {
            mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
                    mAddress, mService.getPhysicalAddress()));
    // Method to switch Input with the new Active Path.
    // All the devices with Switch functionality should implement this.
    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
        // do nothing
    }

    // Active source claiming needs to be handled in the parent class
    // since we decide who will be the active source when the device supports
    // multiple device types in this method.
    // This method should only be called when the device can be the active source.
    protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress) {
        // If the device has both playback and audio system logical addresses,
        // playback will claim active source. Otherwise audio system will.
        HdmiCecLocalDevice deviceToBeActiveSource = mService.playback();
        if (deviceToBeActiveSource == null) {
            deviceToBeActiveSource = mService.audioSystem();
        }
        if (this == deviceToBeActiveSource) {
            ActiveSource activeSource = ActiveSource.of(mAddress, physicalAddress);
            setIsActiveSource(true);
            setActiveSource(activeSource);
            wakeUpIfActiveSource();
            maySendActiveSource(message.getSource());
        }
    }

    @ServiceThreadOnly
    void setIsActiveSource(boolean on) {
        assertRunOnServiceThread();
        mIsActiveSource = on;
    }

    @ServiceThreadOnly
    // Check if current device is the Active Source
    boolean isActiveSource() {
@@ -143,16 +182,22 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
        return mIsActiveSource;
    }

    // Method to switch Input with the port id.
    // All the devices with Switch functionality should implement this.
    protected void routeToInputFromPortId(int portId) {
        // do nothing
    protected void wakeUpIfActiveSource() {
        if (!mIsActiveSource) {
            return;
        }
        // Wake up the device if the power is in standby mode
        if (mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }
        return;
    }

    // Method to switch Input with the new Active Path.
    // All the devices with Switch functionality should implement this.
    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
        // do nothing
    protected void maySendActiveSource(int dest) {
        if (mIsActiveSource) {
            mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
                    mAddress, mService.getPhysicalAddress()));
        }
    }

    @VisibleForTesting
+5 −1
Original line number Diff line number Diff line
@@ -2114,11 +2114,15 @@ public class HdmiControlService extends SystemService {
        return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
    }

    boolean isPlaybackDevice() {
        return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_PLAYBACK);
    }

    boolean isTvDeviceEnabled() {
        return isTvDevice() && tv() != null;
    }

    private HdmiCecLocalDevicePlayback playback() {
    protected HdmiCecLocalDevicePlayback playback() {
        return (HdmiCecLocalDevicePlayback)
                mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK);
    }