Loading services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +69 −16 Original line number Diff line number Diff line Loading @@ -60,6 +60,17 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { // AVR as audio receiver. @ServiceThreadOnly private boolean mArcEstablished = false; /** * Return value of {@link #getLocalPortFromPhysicalAddress(int)} */ private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1; private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0; // Local active port number used for Routing Control. // Default 0 means HOME is the current active path. Temp solution only. // TODO(amyjojo): adding system constants for Atom inputs port and TIF mapping. private int mLocalActivePath = 0; protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mSystemAudioControlFeatureEnabled = true; Loading Loading @@ -147,6 +158,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { return true; } @Override @ServiceThreadOnly protected boolean handleSetStreamPath(HdmiCecMessage message) { assertRunOnServiceThread(); int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); // If current device is the target path, playback device should handle it. // If the path is under the current device, should switch int port = getLocalPortFromPhysicalAddress(physicalAddress); if (port > 0) { routeToPort(port); } return true; } @Override @ServiceThreadOnly protected int getPreferredAddress() { Loading Loading @@ -396,7 +421,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mService.wakeUp(); } int targetPhysicalAddress = getActiveSource().physicalAddress; if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress); if (newSystemAudioMode && port >= 0) { switchToAudioInput(); } // TODO(b/80297700): Mute device when TV terminates the system audio control Loading @@ -411,27 +437,44 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { } /** * Method to check if the target device belongs to the subtree of the current device or not. * Method to parse target physical address to the port number on the current device. * * <p>Return true if it does or if the two devices share the same physical address. * <p>This check assumes target address is valid. * @param targetPhysicalAddress is the physical address of the target device * @return * <p>If the target device is under the current device, return the port number of current device * that the target device is connected to. * * <p>This check assumes both device physical address and target address are valid. * <p>If the target device has the same physical address as the current device, return * {@link #TARGET_SAME_PHYSICAL_ADDRESS}. * * @param targetPhysicalAddress is the physical address of the target device * <p>If the target device is not under the current device, return * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}. */ protected boolean isPhysicalAddressMeOrBelow(int targetPhysicalAddress) { protected int getLocalPortFromPhysicalAddress(int targetPhysicalAddress) { int myPhysicalAddress = mService.getPhysicalAddress(); int xor = targetPhysicalAddress ^ myPhysicalAddress; // Return true if two addresses are the same // or if they only differs for one byte, but not the first byte, // and myPhysicalAddress is 0 after that byte if (xor == 0 || ((xor & 0x0f00) == xor && (myPhysicalAddress & 0x0fff) == 0) || ((xor & 0x00f0) == xor && (myPhysicalAddress & 0x00ff) == 0) || ((xor & 0x000f) == xor && (myPhysicalAddress & 0x000f) == 0)) { return true; if (myPhysicalAddress == targetPhysicalAddress) { return TARGET_SAME_PHYSICAL_ADDRESS; } int finalMask = 0xF000; int mask; int port = 0; for (mask = 0x0F00; mask > 0x000F; mask >>= 4) { if ((myPhysicalAddress & mask) == 0) { port = mask & targetPhysicalAddress; break; } else { finalMask |= mask; } return false; } if (finalMask != 0xFFFF && (finalMask & targetPhysicalAddress) == myPhysicalAddress) { while (mask != 0x000F) { mask >>= 4; port >>= 4; } return port; } return TARGET_NOT_UNDER_LOCAL_DEVICE; } protected void switchToAudioInput() { Loading Loading @@ -529,4 +572,14 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { assertRunOnServiceThread(); mAutoDeviceOff = autoDeviceOff; } private void routeToPort(int portId) { // TODO(AMYJOJO): route to specific input of the port mLocalActivePath = portId; } @VisibleForTesting protected int getLocalActivePath() { return mLocalActivePath; } } services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +33 −15 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { private int mMusicVolume; private int mMusicMaxVolume; private boolean mMusicMute; private int mAvrPhysicalAddress; @Before public void setUp() { Loading Loading @@ -145,6 +146,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); mNativeWrapper.clearResultMessages(); mAvrPhysicalAddress = 0x2000; mNativeWrapper.setPhysicalAddress(mAvrPhysicalAddress); SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true"); } Loading Loading @@ -386,42 +389,48 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test public void isPhysicalAddressMeOrBelow_isMe() throws Exception { public void pathToPort_isMe() throws Exception { int targetPhysicalAddress = 0x1000; mNativeWrapper.setPhysicalAddress(0x1000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isTrue(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(0); } @Test public void isPhysicalAddressMeOrBelow_isBelow() throws Exception { public void pathToPort_isBelow() throws Exception { int targetPhysicalAddress = 0x1100; mNativeWrapper.setPhysicalAddress(0x1000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isTrue(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(1); } @Test public void isPhysicalAddressMeOrBelow_neitherMeNorBelow() throws Exception { public void pathToPort_neitherMeNorBelow() throws Exception { int targetPhysicalAddress = 0x3000; mNativeWrapper.setPhysicalAddress(0x2000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2200; mNativeWrapper.setPhysicalAddress(0x3300); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2213; mNativeWrapper.setPhysicalAddress(0x2212); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2340; mNativeWrapper.setPhysicalAddress(0x2310); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); } @Test Loading Loading @@ -513,4 +522,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test public void handleSetStreamPath_underCurrentDevice() { assertThat(mHdmiCecLocalDeviceAudioSystem.getLocalActivePath()).isEqualTo(0); HdmiCecMessage message = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100); assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetStreamPath(message)).isTrue(); assertThat(mHdmiCecLocalDeviceAudioSystem.getLocalActivePath()).isEqualTo(1); } } Loading
services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +69 −16 Original line number Diff line number Diff line Loading @@ -60,6 +60,17 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { // AVR as audio receiver. @ServiceThreadOnly private boolean mArcEstablished = false; /** * Return value of {@link #getLocalPortFromPhysicalAddress(int)} */ private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1; private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0; // Local active port number used for Routing Control. // Default 0 means HOME is the current active path. Temp solution only. // TODO(amyjojo): adding system constants for Atom inputs port and TIF mapping. private int mLocalActivePath = 0; protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mSystemAudioControlFeatureEnabled = true; Loading Loading @@ -147,6 +158,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { return true; } @Override @ServiceThreadOnly protected boolean handleSetStreamPath(HdmiCecMessage message) { assertRunOnServiceThread(); int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); // If current device is the target path, playback device should handle it. // If the path is under the current device, should switch int port = getLocalPortFromPhysicalAddress(physicalAddress); if (port > 0) { routeToPort(port); } return true; } @Override @ServiceThreadOnly protected int getPreferredAddress() { Loading Loading @@ -396,7 +421,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mService.wakeUp(); } int targetPhysicalAddress = getActiveSource().physicalAddress; if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress); if (newSystemAudioMode && port >= 0) { switchToAudioInput(); } // TODO(b/80297700): Mute device when TV terminates the system audio control Loading @@ -411,27 +437,44 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { } /** * Method to check if the target device belongs to the subtree of the current device or not. * Method to parse target physical address to the port number on the current device. * * <p>Return true if it does or if the two devices share the same physical address. * <p>This check assumes target address is valid. * @param targetPhysicalAddress is the physical address of the target device * @return * <p>If the target device is under the current device, return the port number of current device * that the target device is connected to. * * <p>This check assumes both device physical address and target address are valid. * <p>If the target device has the same physical address as the current device, return * {@link #TARGET_SAME_PHYSICAL_ADDRESS}. * * @param targetPhysicalAddress is the physical address of the target device * <p>If the target device is not under the current device, return * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}. */ protected boolean isPhysicalAddressMeOrBelow(int targetPhysicalAddress) { protected int getLocalPortFromPhysicalAddress(int targetPhysicalAddress) { int myPhysicalAddress = mService.getPhysicalAddress(); int xor = targetPhysicalAddress ^ myPhysicalAddress; // Return true if two addresses are the same // or if they only differs for one byte, but not the first byte, // and myPhysicalAddress is 0 after that byte if (xor == 0 || ((xor & 0x0f00) == xor && (myPhysicalAddress & 0x0fff) == 0) || ((xor & 0x00f0) == xor && (myPhysicalAddress & 0x00ff) == 0) || ((xor & 0x000f) == xor && (myPhysicalAddress & 0x000f) == 0)) { return true; if (myPhysicalAddress == targetPhysicalAddress) { return TARGET_SAME_PHYSICAL_ADDRESS; } int finalMask = 0xF000; int mask; int port = 0; for (mask = 0x0F00; mask > 0x000F; mask >>= 4) { if ((myPhysicalAddress & mask) == 0) { port = mask & targetPhysicalAddress; break; } else { finalMask |= mask; } return false; } if (finalMask != 0xFFFF && (finalMask & targetPhysicalAddress) == myPhysicalAddress) { while (mask != 0x000F) { mask >>= 4; port >>= 4; } return port; } return TARGET_NOT_UNDER_LOCAL_DEVICE; } protected void switchToAudioInput() { Loading Loading @@ -529,4 +572,14 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { assertRunOnServiceThread(); mAutoDeviceOff = autoDeviceOff; } private void routeToPort(int portId) { // TODO(AMYJOJO): route to specific input of the port mLocalActivePath = portId; } @VisibleForTesting protected int getLocalActivePath() { return mLocalActivePath; } }
services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +33 −15 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { private int mMusicVolume; private int mMusicMaxVolume; private boolean mMusicMute; private int mAvrPhysicalAddress; @Before public void setUp() { Loading Loading @@ -145,6 +146,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); mNativeWrapper.clearResultMessages(); mAvrPhysicalAddress = 0x2000; mNativeWrapper.setPhysicalAddress(mAvrPhysicalAddress); SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true"); } Loading Loading @@ -386,42 +389,48 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test public void isPhysicalAddressMeOrBelow_isMe() throws Exception { public void pathToPort_isMe() throws Exception { int targetPhysicalAddress = 0x1000; mNativeWrapper.setPhysicalAddress(0x1000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isTrue(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(0); } @Test public void isPhysicalAddressMeOrBelow_isBelow() throws Exception { public void pathToPort_isBelow() throws Exception { int targetPhysicalAddress = 0x1100; mNativeWrapper.setPhysicalAddress(0x1000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isTrue(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(1); } @Test public void isPhysicalAddressMeOrBelow_neitherMeNorBelow() throws Exception { public void pathToPort_neitherMeNorBelow() throws Exception { int targetPhysicalAddress = 0x3000; mNativeWrapper.setPhysicalAddress(0x2000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2200; mNativeWrapper.setPhysicalAddress(0x3300); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2213; mNativeWrapper.setPhysicalAddress(0x2212); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2340; mNativeWrapper.setPhysicalAddress(0x2310); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) .isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); } @Test Loading Loading @@ -513,4 +522,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test public void handleSetStreamPath_underCurrentDevice() { assertThat(mHdmiCecLocalDeviceAudioSystem.getLocalActivePath()).isEqualTo(0); HdmiCecMessage message = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100); assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetStreamPath(message)).isTrue(); assertThat(mHdmiCecLocalDeviceAudioSystem.getLocalActivePath()).isEqualTo(1); } }