blob: 3ededfdd2fb364b74335e7e9a7b1bc539d4dfda9 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.AudioManager;
import android.os.SystemProperties;
import android.provider.Settings.Global;
import com.android.internal.annotations.GuardedBy;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
/**
* Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in
* Android system.
*/
public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
private static final String TAG = "HdmiCecLocalDeviceAudioSystem";
// Whether System audio mode is activated or not.
// This becomes true only when all system audio sequences are finished.
@GuardedBy("mLock")
private boolean mSystemAudioActivated;
// Whether the System Audio Control feature is enabled or not. True by default.
@GuardedBy("mLock")
private boolean mSystemAudioControlFeatureEnabled;
protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
mSystemAudioControlFeatureEnabled = true;
// TODO(amyjojo) make System Audio Control controllable by users
/*mSystemAudioControlFeatureEnabled =
mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
}
@Override
@ServiceThreadOnly
protected void onAddressAllocated(int logicalAddress, int reason) {
assertRunOnServiceThread();
mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
mAddress, mService.getPhysicalAddress(), mDeviceType));
mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
mAddress, mService.getVendorId()));
startQueuedActions();
}
@Override
@ServiceThreadOnly
protected int getPreferredAddress() {
assertRunOnServiceThread();
return SystemProperties.getInt(Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM,
Constants.ADDR_UNREGISTERED);
}
@Override
@ServiceThreadOnly
protected void setPreferredAddress(int addr) {
assertRunOnServiceThread();
SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM,
String.valueOf(addr));
}
@Override
@ServiceThreadOnly
protected boolean handleReportAudioStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
// TODO(amyjojo): implement report audio status handler
HdmiLogger.debug(TAG + "Stub handleReportAudioStatus");
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleInitiateArc(HdmiCecMessage message) {
assertRunOnServiceThread();
// TODO(amyjojo): implement initiate arc handler
HdmiLogger.debug(TAG + "Stub handleInitiateArc");
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleReportArcInitiate(HdmiCecMessage message) {
assertRunOnServiceThread();
// TODO(amyjojo): implement report arc initiate handler
HdmiLogger.debug(TAG + "Stub handleReportArcInitiate");
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleReportArcTermination(HdmiCecMessage message) {
assertRunOnServiceThread();
// TODO(amyjojo): implement report arc terminate handler
HdmiLogger.debug(TAG + "Stub handleReportArcTermination");
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleGiveAudioStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
reportAudioStatus(message);
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleGiveSystemAudioModeStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
mService.sendCecCommand(HdmiCecMessageBuilder
.buildReportSystemAudioMode(mAddress, message.getSource(), mSystemAudioActivated));
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleRequestArcInitiate(HdmiCecMessage message) {
assertRunOnServiceThread();
// TODO(b/80296911): Check if ARC supported.
// TODO(b/80296911): Check if port is ready to accept.
// TODO(b/80296911): if both true, activate ARC functinality and
mService.sendCecCommand(HdmiCecMessageBuilder
.buildInitiateArc(mAddress, message.getSource()));
// TODO(b/80296911): else, send <Feature Abort>["Unrecongnized opcode"]
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleRequestArcTermination(HdmiCecMessage message) {
assertRunOnServiceThread();
// TODO(b/80297105): Check if ARC supported.
// TODO(b/80297105): Check is currently in arc.
// TODO(b/80297105): If both true, deactivate ARC functionality and
mService.sendCecCommand(HdmiCecMessageBuilder
.buildTerminateArc(mAddress, message.getSource()));
// TODO(b/80297105): else, send <Feature Abort>["Unrecongnized opcode"]
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleSystemAudioModeRequest(HdmiCecMessage message) {
assertRunOnServiceThread();
boolean systemAudioStatusOn = message.getParams().length != 0;
if (!setSystemAudioMode(systemAudioStatusOn)) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
return true;
}
if (systemAudioStatusOn) {
// TODO(amyjojo): Bring up device when it's on standby mode
// TODO(amyjojo): Switch to the corresponding input
}
// Mute device when feature is turned off and unmute device when feature is turned on
boolean currentMuteStatus =
mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
if (currentMuteStatus == systemAudioStatusOn) {
mService.getAudioManager().adjustStreamVolume(AudioManager.STREAM_MUSIC,
systemAudioStatusOn ? AudioManager.ADJUST_UNMUTE : AudioManager.ADJUST_MUTE, 0);
}
mService.sendCecCommand(HdmiCecMessageBuilder
.buildSetSystemAudioMode(mAddress, Constants.ADDR_BROADCAST, systemAudioStatusOn));
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
assertRunOnServiceThread();
if (!setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
}
return true;
}
@Override
@ServiceThreadOnly
protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
if (!setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
}
return true;
}
private void reportAudioStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
int volume = mService.getAudioManager().getStreamVolume(AudioManager.STREAM_MUSIC);
boolean mute = mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
int maxVolume = mService.getAudioManager().getStreamMaxVolume(AudioManager.STREAM_MUSIC);
int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
mService.sendCecCommand(HdmiCecMessageBuilder
.buildReportAudioStatus(mAddress, message.getSource(), scaledVolume, mute));
}
protected boolean setSystemAudioMode(boolean newSystemAudioMode) {
if (!isSystemAudioControlFeatureEnabled()) {
HdmiLogger.debug("Cannot turn " +
(newSystemAudioMode ? "on" : "off") + "system audio mode " +
"because the System Audio Control feature is disabled.");
return false;
}
HdmiLogger.debug("System Audio Mode change[old:%b new:%b]",
mSystemAudioActivated, newSystemAudioMode);
updateAudioManagerForSystemAudio(newSystemAudioMode);
synchronized (mLock) {
if (mSystemAudioActivated != newSystemAudioMode) {
mSystemAudioActivated = newSystemAudioMode;
mService.announceSystemAudioModeChange(newSystemAudioMode);
}
}
return true;
}
private void updateAudioManagerForSystemAudio(boolean on) {
int device = mService.getAudioManager().setHdmiSystemAudioSupported(on);
HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device);
}
protected boolean isSystemAudioControlFeatureEnabled() {
synchronized (mLock) {
return mSystemAudioControlFeatureEnabled;
}
}
}