Loading services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +70 −18 Original line number Diff line number Diff line Loading @@ -19,12 +19,16 @@ import static com.android.server.hdmi.Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_P import static com.android.server.hdmi.Constants.PROPERTY_SYSTEM_AUDIO_CONTROL_ON_POWER_ON; import static com.android.server.hdmi.Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON; import android.annotation.Nullable; import android.hardware.hdmi.HdmiDeviceInfo; import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.AudioSystem; import android.os.SystemProperties; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.Constants.AudioCodec; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; /** Loading @@ -48,8 +52,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { // Whether ARC is available or not. "true" means that ARC is established between TV and // AVR as audio receiver. @ServiceThreadOnly private boolean mArcEstablished = false; @ServiceThreadOnly private boolean mArcEstablished = false; protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); Loading Loading @@ -218,11 +221,55 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleRequestShortAudioDescriptor(HdmiCecMessage message) { assertRunOnServiceThread(); // TODO(b/80297701): implement request short audio descriptor HdmiLogger.debug(TAG + "Stub handleRequestShortAudioDescriptor"); if (!isSystemAudioControlFeatureEnabled()) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); return true; } if (!isSystemAudioActivated()) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE); return true; } AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo(); if (deviceInfo == null) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE); return true; } @AudioCodec int[] audioFormatCodes = parseAudioFormatCodes(message.getParams()); byte[] sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes); if (sadBytes.length == 0) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND); } else { mService.sendCecCommand( HdmiCecMessageBuilder.buildReportShortAudioDescriptor( mAddress, message.getSource(), sadBytes)); } return true; } private byte[] getSupportedShortAudioDescriptors( AudioDeviceInfo deviceInfo, @AudioCodec int[] audioFormatCodes) { // TODO(b/80297701) implement return new byte[] {}; } @Nullable private AudioDeviceInfo getSystemAudioDeviceInfo() { // TODO(b/80297701) implement // Get the audio device used for system audio mode. return null; } @AudioCodec private int[] parseAudioFormatCodes(byte[] params) { @AudioCodec int[] audioFormatCodes = new int[params.length]; for (int i = 0; i < params.length; i++) { byte val = params[i]; audioFormatCodes[i] = val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE; } return audioFormatCodes; } @Override @ServiceThreadOnly Loading Loading @@ -274,23 +321,19 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mArcEstablished = enabled; } /** * Switch hardware ARC circuit in the system. */ /** Switch hardware ARC circuit in the system. */ @ServiceThreadOnly private void enableAudioReturnChannel(boolean enabled) { assertRunOnServiceThread(); mService.enableAudioReturnChannel( SystemProperties.getInt( Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, 0), SystemProperties.getInt(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, 0), enabled); } private void notifyArcStatusToAudioService(boolean enabled) { // Note that we don't set any name to ARC. mService.getAudioManager().setWiredDeviceConnectionState( AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", ""); mService.getAudioManager() .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", ""); } private void reportAudioStatus(HdmiCecMessage message) { Loading Loading @@ -323,8 +366,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mService.wakeUp(); } int targetPhysicalAddress = getActiveSource().physicalAddress; if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { switchToAudioInput(); } // TODO(b/80297700): Mute device when TV terminates the system audio control Loading @@ -340,9 +382,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { /** * Method to check if the target device belongs to the subtree of the current device or not. * * <p>Return true if it does or if the two devices share the same physical address. * * <p>This check assumes both device physical address and target address are valid. * * @param targetPhysicalAddress is the physical address of the target device */ protected boolean isPhysicalAddressMeOrBelow(int targetPhysicalAddress) { Loading Loading @@ -374,7 +418,15 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device); } protected boolean isSystemAudioControlFeatureEnabled() { @ServiceThreadOnly void setSystemAudioControlFeatureEnabled(boolean enabled) { assertRunOnServiceThread(); synchronized (mLock) { mSystemAudioControlFeatureEnabled = enabled; } } boolean isSystemAudioControlFeatureEnabled() { synchronized (mLock) { return mSystemAudioControlFeatureEnabled; } Loading services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +15 −1 Original line number Diff line number Diff line Loading @@ -16,9 +16,10 @@ package com.android.server.hdmi; import com.android.server.hdmi.Constants.AudioCodec; import java.io.UnsupportedEncodingException; import java.util.Arrays; import com.android.server.hdmi.Constants.AudioCodec; /** * A helper class to build {@link HdmiCecMessage} from various cec commands. Loading Loading @@ -451,6 +452,19 @@ public class HdmiCecMessageBuilder { ); } /** * Build <Report Short Audio Descriptor> command. * * @param src source address of command * @param des destination address of command * @param sadBytes Short Audio Descriptor in bytes * @return newly created {@link HdmiCecMessage} */ static HdmiCecMessage buildReportShortAudioDescriptor(int src, int des, byte[] sadBytes) { // TODO(b/80297701) validate. return buildCommand(src, des, Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, sadBytes); } /** * Build <Give Audio Status> command. * Loading services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +58 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,10 @@ import java.util.ArrayList; /** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */ public class HdmiCecLocalDeviceAudioSystemTest { private static final HdmiCecMessage MESSAGE_REQUEST_SAD_LCPM = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor( ADDR_TV, ADDR_AUDIO_SYSTEM, new int[] {Constants.AUDIO_CODEC_LPCM}); private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem; Loading Loading @@ -169,6 +173,60 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Ignore("b/80297700") @Test public void handleRequestShortAudioDescriptor_featureDisabled() throws Exception { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( ADDR_AUDIO_SYSTEM, ADDR_TV, Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, Constants.ABORT_REFUSED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(false); assertThat( mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( MESSAGE_REQUEST_SAD_LCPM)) .isTrue(); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test public void handleRequestShortAudioDescriptor_samOff() throws Exception { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( ADDR_AUDIO_SYSTEM, ADDR_TV, Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, Constants.ABORT_NOT_IN_CORRECT_MODE); mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false); assertThat( mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( MESSAGE_REQUEST_SAD_LCPM)) .isEqualTo(true); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test public void handleRequestShortAudioDescriptor_noAudioDeviceInfo() throws Exception { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( ADDR_AUDIO_SYSTEM, ADDR_TV, Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, Constants.ABORT_UNABLE_TO_DETERMINE); mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true); assertThat( mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( MESSAGE_REQUEST_SAD_LCPM)) .isEqualTo(true); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test public void handleSetSystemAudioMode_setOn_orignalOff() { mMusicMute = true; Loading Loading
services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +70 −18 Original line number Diff line number Diff line Loading @@ -19,12 +19,16 @@ import static com.android.server.hdmi.Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_P import static com.android.server.hdmi.Constants.PROPERTY_SYSTEM_AUDIO_CONTROL_ON_POWER_ON; import static com.android.server.hdmi.Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON; import android.annotation.Nullable; import android.hardware.hdmi.HdmiDeviceInfo; import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.AudioSystem; import android.os.SystemProperties; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.Constants.AudioCodec; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; /** Loading @@ -48,8 +52,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { // Whether ARC is available or not. "true" means that ARC is established between TV and // AVR as audio receiver. @ServiceThreadOnly private boolean mArcEstablished = false; @ServiceThreadOnly private boolean mArcEstablished = false; protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); Loading Loading @@ -218,11 +221,55 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleRequestShortAudioDescriptor(HdmiCecMessage message) { assertRunOnServiceThread(); // TODO(b/80297701): implement request short audio descriptor HdmiLogger.debug(TAG + "Stub handleRequestShortAudioDescriptor"); if (!isSystemAudioControlFeatureEnabled()) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); return true; } if (!isSystemAudioActivated()) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE); return true; } AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo(); if (deviceInfo == null) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE); return true; } @AudioCodec int[] audioFormatCodes = parseAudioFormatCodes(message.getParams()); byte[] sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes); if (sadBytes.length == 0) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND); } else { mService.sendCecCommand( HdmiCecMessageBuilder.buildReportShortAudioDescriptor( mAddress, message.getSource(), sadBytes)); } return true; } private byte[] getSupportedShortAudioDescriptors( AudioDeviceInfo deviceInfo, @AudioCodec int[] audioFormatCodes) { // TODO(b/80297701) implement return new byte[] {}; } @Nullable private AudioDeviceInfo getSystemAudioDeviceInfo() { // TODO(b/80297701) implement // Get the audio device used for system audio mode. return null; } @AudioCodec private int[] parseAudioFormatCodes(byte[] params) { @AudioCodec int[] audioFormatCodes = new int[params.length]; for (int i = 0; i < params.length; i++) { byte val = params[i]; audioFormatCodes[i] = val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE; } return audioFormatCodes; } @Override @ServiceThreadOnly Loading Loading @@ -274,23 +321,19 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mArcEstablished = enabled; } /** * Switch hardware ARC circuit in the system. */ /** Switch hardware ARC circuit in the system. */ @ServiceThreadOnly private void enableAudioReturnChannel(boolean enabled) { assertRunOnServiceThread(); mService.enableAudioReturnChannel( SystemProperties.getInt( Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, 0), SystemProperties.getInt(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, 0), enabled); } private void notifyArcStatusToAudioService(boolean enabled) { // Note that we don't set any name to ARC. mService.getAudioManager().setWiredDeviceConnectionState( AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", ""); mService.getAudioManager() .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", ""); } private void reportAudioStatus(HdmiCecMessage message) { Loading Loading @@ -323,8 +366,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mService.wakeUp(); } int targetPhysicalAddress = getActiveSource().physicalAddress; if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { switchToAudioInput(); } // TODO(b/80297700): Mute device when TV terminates the system audio control Loading @@ -340,9 +382,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { /** * Method to check if the target device belongs to the subtree of the current device or not. * * <p>Return true if it does or if the two devices share the same physical address. * * <p>This check assumes both device physical address and target address are valid. * * @param targetPhysicalAddress is the physical address of the target device */ protected boolean isPhysicalAddressMeOrBelow(int targetPhysicalAddress) { Loading Loading @@ -374,7 +418,15 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device); } protected boolean isSystemAudioControlFeatureEnabled() { @ServiceThreadOnly void setSystemAudioControlFeatureEnabled(boolean enabled) { assertRunOnServiceThread(); synchronized (mLock) { mSystemAudioControlFeatureEnabled = enabled; } } boolean isSystemAudioControlFeatureEnabled() { synchronized (mLock) { return mSystemAudioControlFeatureEnabled; } Loading
services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +15 −1 Original line number Diff line number Diff line Loading @@ -16,9 +16,10 @@ package com.android.server.hdmi; import com.android.server.hdmi.Constants.AudioCodec; import java.io.UnsupportedEncodingException; import java.util.Arrays; import com.android.server.hdmi.Constants.AudioCodec; /** * A helper class to build {@link HdmiCecMessage} from various cec commands. Loading Loading @@ -451,6 +452,19 @@ public class HdmiCecMessageBuilder { ); } /** * Build <Report Short Audio Descriptor> command. * * @param src source address of command * @param des destination address of command * @param sadBytes Short Audio Descriptor in bytes * @return newly created {@link HdmiCecMessage} */ static HdmiCecMessage buildReportShortAudioDescriptor(int src, int des, byte[] sadBytes) { // TODO(b/80297701) validate. return buildCommand(src, des, Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, sadBytes); } /** * Build <Give Audio Status> command. * Loading
services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +58 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,10 @@ import java.util.ArrayList; /** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */ public class HdmiCecLocalDeviceAudioSystemTest { private static final HdmiCecMessage MESSAGE_REQUEST_SAD_LCPM = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor( ADDR_TV, ADDR_AUDIO_SYSTEM, new int[] {Constants.AUDIO_CODEC_LPCM}); private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem; Loading Loading @@ -169,6 +173,60 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Ignore("b/80297700") @Test public void handleRequestShortAudioDescriptor_featureDisabled() throws Exception { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( ADDR_AUDIO_SYSTEM, ADDR_TV, Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, Constants.ABORT_REFUSED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(false); assertThat( mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( MESSAGE_REQUEST_SAD_LCPM)) .isTrue(); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test public void handleRequestShortAudioDescriptor_samOff() throws Exception { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( ADDR_AUDIO_SYSTEM, ADDR_TV, Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, Constants.ABORT_NOT_IN_CORRECT_MODE); mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false); assertThat( mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( MESSAGE_REQUEST_SAD_LCPM)) .isEqualTo(true); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test public void handleRequestShortAudioDescriptor_noAudioDeviceInfo() throws Exception { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( ADDR_AUDIO_SYSTEM, ADDR_TV, Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, Constants.ABORT_UNABLE_TO_DETERMINE); mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true); assertThat( mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( MESSAGE_REQUEST_SAD_LCPM)) .isEqualTo(true); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test public void handleSetSystemAudioMode_setOn_orignalOff() { mMusicMute = true; Loading