Loading services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +69 −16 Original line number Original line Diff line number Diff line Loading @@ -60,6 +60,17 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { // AVR as audio receiver. // AVR as audio receiver. @ServiceThreadOnly private boolean mArcEstablished = false; @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) { protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mSystemAudioControlFeatureEnabled = true; mSystemAudioControlFeatureEnabled = true; Loading Loading @@ -147,6 +158,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { return true; 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 @Override @ServiceThreadOnly @ServiceThreadOnly protected int getPreferredAddress() { protected int getPreferredAddress() { Loading Loading @@ -396,7 +421,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mService.wakeUp(); mService.wakeUp(); } } int targetPhysicalAddress = getActiveSource().physicalAddress; int targetPhysicalAddress = getActiveSource().physicalAddress; if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress); if (newSystemAudioMode && port >= 0) { switchToAudioInput(); switchToAudioInput(); } } // TODO(b/80297700): Mute device when TV terminates the system audio control // 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 myPhysicalAddress = mService.getPhysicalAddress(); int xor = targetPhysicalAddress ^ myPhysicalAddress; if (myPhysicalAddress == targetPhysicalAddress) { // Return true if two addresses are the same return TARGET_SAME_PHYSICAL_ADDRESS; // or if they only differs for one byte, but not the first byte, } // and myPhysicalAddress is 0 after that byte int finalMask = 0xF000; if (xor == 0 int mask; || ((xor & 0x0f00) == xor && (myPhysicalAddress & 0x0fff) == 0) int port = 0; || ((xor & 0x00f0) == xor && (myPhysicalAddress & 0x00ff) == 0) for (mask = 0x0F00; mask > 0x000F; mask >>= 4) { || ((xor & 0x000f) == xor && (myPhysicalAddress & 0x000f) == 0)) { if ((myPhysicalAddress & mask) == 0) { return true; 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() { protected void switchToAudioInput() { Loading Loading @@ -529,4 +572,14 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { assertRunOnServiceThread(); assertRunOnServiceThread(); mAutoDeviceOff = autoDeviceOff; 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 Original line Diff line number Diff line Loading @@ -60,6 +60,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { private int mMusicVolume; private int mMusicVolume; private int mMusicMaxVolume; private int mMusicMaxVolume; private boolean mMusicMute; private boolean mMusicMute; private int mAvrPhysicalAddress; @Before @Before public void setUp() { public void setUp() { Loading Loading @@ -145,6 +146,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); mTestLooper.dispatchAll(); mNativeWrapper.clearResultMessages(); mNativeWrapper.clearResultMessages(); mAvrPhysicalAddress = 0x2000; mNativeWrapper.setPhysicalAddress(mAvrPhysicalAddress); SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true"); SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true"); } } Loading Loading @@ -386,42 +389,48 @@ public class HdmiCecLocalDeviceAudioSystemTest { } } @Test @Test public void isPhysicalAddressMeOrBelow_isMe() throws Exception { public void pathToPort_isMe() throws Exception { int targetPhysicalAddress = 0x1000; int targetPhysicalAddress = 0x1000; mNativeWrapper.setPhysicalAddress(0x1000); mNativeWrapper.setPhysicalAddress(0x1000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isTrue(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(0); } } @Test @Test public void isPhysicalAddressMeOrBelow_isBelow() throws Exception { public void pathToPort_isBelow() throws Exception { int targetPhysicalAddress = 0x1100; int targetPhysicalAddress = 0x1100; mNativeWrapper.setPhysicalAddress(0x1000); mNativeWrapper.setPhysicalAddress(0x1000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isTrue(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(1); } } @Test @Test public void isPhysicalAddressMeOrBelow_neitherMeNorBelow() throws Exception { public void pathToPort_neitherMeNorBelow() throws Exception { int targetPhysicalAddress = 0x3000; int targetPhysicalAddress = 0x3000; mNativeWrapper.setPhysicalAddress(0x2000); mNativeWrapper.setPhysicalAddress(0x2000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isFalse(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2200; targetPhysicalAddress = 0x2200; mNativeWrapper.setPhysicalAddress(0x3300); mNativeWrapper.setPhysicalAddress(0x3300); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isFalse(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2213; targetPhysicalAddress = 0x2213; mNativeWrapper.setPhysicalAddress(0x2212); mNativeWrapper.setPhysicalAddress(0x2212); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isFalse(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2340; targetPhysicalAddress = 0x2340; mNativeWrapper.setPhysicalAddress(0x2310); mNativeWrapper.setPhysicalAddress(0x2310); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isFalse(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); } } @Test @Test Loading Loading @@ -513,4 +522,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { mTestLooper.dispatchAll(); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); 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 Original line Diff line number Diff line Loading @@ -60,6 +60,17 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { // AVR as audio receiver. // AVR as audio receiver. @ServiceThreadOnly private boolean mArcEstablished = false; @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) { protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mSystemAudioControlFeatureEnabled = true; mSystemAudioControlFeatureEnabled = true; Loading Loading @@ -147,6 +158,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { return true; 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 @Override @ServiceThreadOnly @ServiceThreadOnly protected int getPreferredAddress() { protected int getPreferredAddress() { Loading Loading @@ -396,7 +421,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mService.wakeUp(); mService.wakeUp(); } } int targetPhysicalAddress = getActiveSource().physicalAddress; int targetPhysicalAddress = getActiveSource().physicalAddress; if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress); if (newSystemAudioMode && port >= 0) { switchToAudioInput(); switchToAudioInput(); } } // TODO(b/80297700): Mute device when TV terminates the system audio control // 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 myPhysicalAddress = mService.getPhysicalAddress(); int xor = targetPhysicalAddress ^ myPhysicalAddress; if (myPhysicalAddress == targetPhysicalAddress) { // Return true if two addresses are the same return TARGET_SAME_PHYSICAL_ADDRESS; // or if they only differs for one byte, but not the first byte, } // and myPhysicalAddress is 0 after that byte int finalMask = 0xF000; if (xor == 0 int mask; || ((xor & 0x0f00) == xor && (myPhysicalAddress & 0x0fff) == 0) int port = 0; || ((xor & 0x00f0) == xor && (myPhysicalAddress & 0x00ff) == 0) for (mask = 0x0F00; mask > 0x000F; mask >>= 4) { || ((xor & 0x000f) == xor && (myPhysicalAddress & 0x000f) == 0)) { if ((myPhysicalAddress & mask) == 0) { return true; 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() { protected void switchToAudioInput() { Loading Loading @@ -529,4 +572,14 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { assertRunOnServiceThread(); assertRunOnServiceThread(); mAutoDeviceOff = autoDeviceOff; 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 Original line Diff line number Diff line Loading @@ -60,6 +60,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { private int mMusicVolume; private int mMusicVolume; private int mMusicMaxVolume; private int mMusicMaxVolume; private boolean mMusicMute; private boolean mMusicMute; private int mAvrPhysicalAddress; @Before @Before public void setUp() { public void setUp() { Loading Loading @@ -145,6 +146,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); mTestLooper.dispatchAll(); mNativeWrapper.clearResultMessages(); mNativeWrapper.clearResultMessages(); mAvrPhysicalAddress = 0x2000; mNativeWrapper.setPhysicalAddress(mAvrPhysicalAddress); SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true"); SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true"); } } Loading Loading @@ -386,42 +389,48 @@ public class HdmiCecLocalDeviceAudioSystemTest { } } @Test @Test public void isPhysicalAddressMeOrBelow_isMe() throws Exception { public void pathToPort_isMe() throws Exception { int targetPhysicalAddress = 0x1000; int targetPhysicalAddress = 0x1000; mNativeWrapper.setPhysicalAddress(0x1000); mNativeWrapper.setPhysicalAddress(0x1000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isTrue(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(0); } } @Test @Test public void isPhysicalAddressMeOrBelow_isBelow() throws Exception { public void pathToPort_isBelow() throws Exception { int targetPhysicalAddress = 0x1100; int targetPhysicalAddress = 0x1100; mNativeWrapper.setPhysicalAddress(0x1000); mNativeWrapper.setPhysicalAddress(0x1000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isTrue(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(1); } } @Test @Test public void isPhysicalAddressMeOrBelow_neitherMeNorBelow() throws Exception { public void pathToPort_neitherMeNorBelow() throws Exception { int targetPhysicalAddress = 0x3000; int targetPhysicalAddress = 0x3000; mNativeWrapper.setPhysicalAddress(0x2000); mNativeWrapper.setPhysicalAddress(0x2000); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isFalse(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2200; targetPhysicalAddress = 0x2200; mNativeWrapper.setPhysicalAddress(0x3300); mNativeWrapper.setPhysicalAddress(0x3300); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isFalse(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2213; targetPhysicalAddress = 0x2213; mNativeWrapper.setPhysicalAddress(0x2212); mNativeWrapper.setPhysicalAddress(0x2212); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isFalse(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); targetPhysicalAddress = 0x2340; targetPhysicalAddress = 0x2340; mNativeWrapper.setPhysicalAddress(0x2310); mNativeWrapper.setPhysicalAddress(0x2310); assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) assertThat(mHdmiCecLocalDeviceAudioSystem .isFalse(); .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) .isEqualTo(-1); } } @Test @Test Loading Loading @@ -513,4 +522,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { mTestLooper.dispatchAll(); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); 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); } } }