SystemAudioAction.java revision d05f67f9721e1f9194a1f57cf7481b4be65366b3
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.hdmi; 18 19import android.annotation.Nullable; 20import android.hardware.hdmi.HdmiCecDeviceInfo; 21import android.hardware.hdmi.HdmiControlManager; 22import android.hardware.hdmi.IHdmiControlCallback; 23import android.os.RemoteException; 24import android.util.Slog; 25 26/** 27 * Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr. 28 */ 29abstract class SystemAudioAction extends FeatureAction { 30 private static final String TAG = "SystemAudioAction"; 31 32 // State in which waits for <SetSystemAudioMode>. 33 private static final int STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE = 1; 34 35 private static final int MAX_SEND_RETRY_COUNT = 2; 36 37 private static final int ON_TIMEOUT_MS = 5000; 38 private static final int OFF_TIMEOUT_MS = HdmiConfig.TIMEOUT_MS; 39 40 // Logical address of AV Receiver. 41 protected final int mAvrLogicalAddress; 42 43 // The target audio status of the action, whether to enable the system audio mode or not. 44 protected boolean mTargetAudioStatus; 45 46 @Nullable private final IHdmiControlCallback mCallback; 47 48 private int mSendRetryCount = 0; 49 50 /** 51 * Constructor 52 * 53 * @param source {@link HdmiCecLocalDevice} instance 54 * @param avrAddress logical address of AVR device 55 * @param targetStatus Whether to enable the system audio mode or not 56 * @param callback callback interface to be notified when it's done 57 * @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid 58 */ 59 SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus, 60 IHdmiControlCallback callback) { 61 super(source); 62 HdmiUtils.verifyAddressType(avrAddress, HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM); 63 mAvrLogicalAddress = avrAddress; 64 mTargetAudioStatus = targetStatus; 65 mCallback = callback; 66 } 67 68 protected void sendSystemAudioModeRequest() { 69 int avrPhysicalAddress = tv().getAvrDeviceInfo().getPhysicalAddress(); 70 HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest( 71 getSourceAddress(), 72 mAvrLogicalAddress, avrPhysicalAddress, mTargetAudioStatus); 73 sendCommand(command, new HdmiControlService.SendMessageCallback() { 74 @Override 75 public void onSendCompleted(int error) { 76 if (error == Constants.SEND_RESULT_SUCCESS) { 77 mState = STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE; 78 addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS); 79 } else { 80 setSystemAudioMode(false); 81 finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED); 82 } 83 } 84 }); 85 } 86 87 private void handleSendSystemAudioModeRequestTimeout() { 88 if (!mTargetAudioStatus // Don't retry for Off case. 89 || mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) { 90 setSystemAudioMode(false); 91 finishWithCallback(HdmiControlManager.RESULT_TIMEOUT); 92 return; 93 } 94 sendSystemAudioModeRequest(); 95 } 96 97 protected void setSystemAudioMode(boolean mode) { 98 tv().setSystemAudioMode(mode, true); 99 } 100 101 @Override 102 final boolean processCommand(HdmiCecMessage cmd) { 103 switch (mState) { 104 case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE: 105 if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT 106 && cmd.getParams()[0] == Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST) { 107 setSystemAudioMode(false); 108 finishWithCallback(HdmiControlManager.RESULT_EXCEPTION); 109 return true; 110 } 111 if (cmd.getOpcode() != Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE 112 || !HdmiUtils.checkCommandSource(cmd, mAvrLogicalAddress, TAG)) { 113 return false; 114 } 115 boolean receivedStatus = HdmiUtils.parseCommandParamSystemAudioStatus(cmd); 116 if (receivedStatus == mTargetAudioStatus) { 117 setSystemAudioMode(receivedStatus); 118 startAudioStatusAction(); 119 return true; 120 } else { 121 // Unexpected response, consider the request is newly initiated by AVR. 122 // To return 'false' will initiate new SystemAudioActionFromAvr by the control 123 // service. 124 finishWithCallback(HdmiControlManager.RESULT_EXCEPTION); 125 return false; 126 } 127 default: 128 return false; 129 } 130 } 131 132 protected void startAudioStatusAction() { 133 addAndStartAction(new SystemAudioStatusAction(tv(), mAvrLogicalAddress, mCallback)); 134 finish(); 135 } 136 137 protected void removeSystemAudioActionInProgress() { 138 removeActionExcept(SystemAudioActionFromTv.class, this); 139 removeActionExcept(SystemAudioActionFromAvr.class, this); 140 } 141 142 @Override 143 final void handleTimerEvent(int state) { 144 if (mState != state) { 145 return; 146 } 147 switch (mState) { 148 case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE: 149 handleSendSystemAudioModeRequestTimeout(); 150 return; 151 } 152 } 153 154 // TODO: if IHdmiControlCallback is general to other FeatureAction, 155 // move it into FeatureAction. 156 protected void finishWithCallback(int returnCode) { 157 if (mCallback != null) { 158 try { 159 mCallback.onComplete(returnCode); 160 } catch (RemoteException e) { 161 Slog.e(TAG, "Failed to invoke callback.", e); 162 } 163 } 164 finish(); 165 } 166} 167