Merge "Add several actions for ARC (Audio Return Channel)"
This commit is contained in:
committed by
Android (Google) Code Review
commit
e1a2e26a03
@@ -118,6 +118,11 @@ abstract class FeatureAction {
|
||||
* @param delayMillis amount of delay for the timer
|
||||
*/
|
||||
void sendTimerMessage(int state, long delayMillis);
|
||||
|
||||
/**
|
||||
* Removes any pending timer message.
|
||||
*/
|
||||
void clearTimerMessage();
|
||||
}
|
||||
|
||||
private class ActionTimerHandler extends Handler implements ActionTimer {
|
||||
@@ -131,6 +136,11 @@ abstract class FeatureAction {
|
||||
sendMessageDelayed(obtainMessage(MSG_TIMEOUT, state), delayMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTimerMessage() {
|
||||
removeMessages(MSG_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
@@ -154,15 +164,26 @@ abstract class FeatureAction {
|
||||
mActionTimer.sendTimerMessage(state, delayMillis);
|
||||
}
|
||||
|
||||
protected final void sendCommand(HdmiCecMessage cmd) {
|
||||
mService.sendCecCommand(cmd);
|
||||
protected final boolean sendCommand(HdmiCecMessage cmd) {
|
||||
return mService.sendCecCommand(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up action's state.
|
||||
*
|
||||
* <p>Declared as package-private. Only {@link HdmiControlService} can access it.
|
||||
*/
|
||||
void clear() {
|
||||
mState = STATE_NONE;
|
||||
// Clear all timers.
|
||||
mActionTimer.clearTimerMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish up the action. Reset the state, and remove itself from the action queue.
|
||||
*/
|
||||
protected void finish() {
|
||||
mState = STATE_NONE;
|
||||
clear();
|
||||
removeAction(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -442,9 +442,9 @@ final class HdmiCecController {
|
||||
|
||||
}
|
||||
|
||||
void sendCommand(HdmiCecMessage cecMessage) {
|
||||
boolean sendCommand(HdmiCecMessage cecMessage) {
|
||||
Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage);
|
||||
mIoHandler.sendMessage(message);
|
||||
return mIoHandler.sendMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,7 +465,9 @@ final class HdmiCecController {
|
||||
* Called by native when a hotplug event issues.
|
||||
*/
|
||||
private void handleHotplug(boolean connected) {
|
||||
// TODO: Delegate event to main message handler.
|
||||
// TODO: once add port number to cec HAL interface, pass port number
|
||||
// to the service.
|
||||
mService.onHotplug(0, connected);
|
||||
}
|
||||
|
||||
private static native long nativeInit(HdmiCecController handler);
|
||||
|
||||
@@ -185,6 +185,50 @@ public class HdmiCecMessageBuilder {
|
||||
return buildCommand(src, dest, HdmiCec.MESSAGE_CEC_VERSION, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build <Request Arc Initiation>
|
||||
*
|
||||
* @param src source address of command
|
||||
* @param dest destination address of command
|
||||
* @return newly created {@link HdmiCecMessage}
|
||||
*/
|
||||
static HdmiCecMessage buildRequestArcInitiation(int src, int dest) {
|
||||
return buildCommand(src, dest, HdmiCec.MESSAGE_REQUEST_ARC_INITIATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build <Request Arc Termination>
|
||||
*
|
||||
* @param src source address of command
|
||||
* @param dest destination address of command
|
||||
* @return newly created {@link HdmiCecMessage}
|
||||
*/
|
||||
static HdmiCecMessage buildRequestArcTermination(int src, int dest) {
|
||||
return buildCommand(src, dest, HdmiCec.MESSAGE_REQUEST_ARC_TERMINATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build <Report Arc Initiated>
|
||||
*
|
||||
* @param src source address of command
|
||||
* @param dest destination address of command
|
||||
* @return newly created {@link HdmiCecMessage}
|
||||
*/
|
||||
static HdmiCecMessage buildReportArcInitiated(int src, int dest) {
|
||||
return buildCommand(src, dest, HdmiCec.MESSAGE_REPORT_ARC_INITIATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build <Report Arc Terminated>
|
||||
*
|
||||
* @param src source address of command
|
||||
* @param dest destination address of command
|
||||
* @return newly created {@link HdmiCecMessage}
|
||||
*/
|
||||
static HdmiCecMessage buildReportArcTerminated(int src, int dest) {
|
||||
return buildCommand(src, dest, HdmiCec.MESSAGE_REPORT_ARC_TERMINATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link HdmiCecMessage} without extra parameter.
|
||||
*
|
||||
|
||||
@@ -21,12 +21,15 @@ import android.content.Context;
|
||||
import android.hardware.hdmi.HdmiCec;
|
||||
import android.hardware.hdmi.HdmiCecDeviceInfo;
|
||||
import android.hardware.hdmi.HdmiCecMessage;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
@@ -41,12 +44,23 @@ public final class HdmiControlService extends SystemService {
|
||||
// and sparse call it shares a thread to handle IO operations.
|
||||
private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread");
|
||||
|
||||
// A collection of FeatureAction.
|
||||
// Note that access to this collection should happen in service thread.
|
||||
private final LinkedList<FeatureAction> mActions = new LinkedList<>();
|
||||
|
||||
@Nullable
|
||||
private HdmiCecController mCecController;
|
||||
|
||||
@Nullable
|
||||
private HdmiMhlController mMhlController;
|
||||
|
||||
// Whether ARC is "enabled" or not.
|
||||
// TODO: it may need to hold lock if it's accessed from others.
|
||||
private boolean mArcStatusEnabled = false;
|
||||
|
||||
// Handler running on service thread. It's used to run a task in service thread.
|
||||
private Handler mHandler = new Handler();
|
||||
|
||||
public HdmiControlService(Context context) {
|
||||
super(context);
|
||||
}
|
||||
@@ -84,35 +98,83 @@ public final class HdmiControlService extends SystemService {
|
||||
* <p>Declared as package-private.
|
||||
*/
|
||||
Looper getServiceLooper() {
|
||||
return Looper.myLooper();
|
||||
return mHandler.getLooper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new {@link FeatureAction} to the action queue.
|
||||
* Add and start a new {@link FeatureAction} to the action queue.
|
||||
*
|
||||
* @param action {@link FeatureAction} to add
|
||||
* @param action {@link FeatureAction} to add and start
|
||||
*/
|
||||
void addAction(FeatureAction action) {
|
||||
// TODO: Implement this.
|
||||
void addAndStartAction(final FeatureAction action) {
|
||||
// TODO: may need to check the number of stale actions.
|
||||
runOnServiceThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mActions.add(action);
|
||||
action.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the given {@link FeatureAction} object from the action queue.
|
||||
*
|
||||
* @param action {@link FeatureAction} to add
|
||||
* @param action {@link FeatureAction} to remove
|
||||
*/
|
||||
void removeAction(FeatureAction action) {
|
||||
// TODO: Implement this.
|
||||
void removeAction(final FeatureAction action) {
|
||||
runOnServiceThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mActions.remove(action);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Remove all actions matched with the given Class type.
|
||||
private <T extends FeatureAction> void removeAction(final Class<T> clazz) {
|
||||
runOnServiceThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Iterator<FeatureAction> iter = mActions.iterator();
|
||||
while (iter.hasNext()) {
|
||||
FeatureAction action = iter.next();
|
||||
if (action.getClass().equals(clazz)) {
|
||||
action.clear();
|
||||
mActions.remove(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void runOnServiceThread(Runnable runnable) {
|
||||
mHandler.post(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change ARC status into the given {@code enabled} status.
|
||||
*
|
||||
* @return {@code true} if ARC was in "Enabled" status
|
||||
*/
|
||||
boolean setArcStatus(boolean enabled) {
|
||||
boolean oldStatus = mArcStatusEnabled;
|
||||
// 1. Enable/disable ARC circuit.
|
||||
// TODO: call set_audio_return_channel of hal interface.
|
||||
|
||||
// 2. Update arc status;
|
||||
mArcStatusEnabled = enabled;
|
||||
return oldStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit a CEC command to CEC bus.
|
||||
*
|
||||
* @param command CEC command to send out
|
||||
* @return {@code true} if succeeds to send command
|
||||
*/
|
||||
void sendCecCommand(HdmiCecMessage command) {
|
||||
mCecController.sendCommand(command);
|
||||
boolean sendCecCommand(HdmiCecMessage command) {
|
||||
return mCecController.sendCommand(command);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,6 +205,12 @@ public final class HdmiControlService extends SystemService {
|
||||
case HdmiCec.MESSAGE_GET_CEC_VERSION:
|
||||
handleGetCecVersion(message);
|
||||
return true;
|
||||
case HdmiCec.MESSAGE_INITIATE_ARC:
|
||||
handleInitiateArc(message);
|
||||
return true;
|
||||
case HdmiCec.MESSAGE_TERMINATE_ARC:
|
||||
handleTerminateArc(message);
|
||||
return true;
|
||||
// TODO: Add remaining system information query such as
|
||||
// <Give Device Power Status> and <Request Active Source> handler.
|
||||
default:
|
||||
@@ -151,6 +219,36 @@ public final class HdmiControlService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new hotplug event is issued.
|
||||
*
|
||||
* @param port hdmi port number where hot plug event issued.
|
||||
* @param connected whether to be plugged in or not
|
||||
*/
|
||||
void onHotplug(int portNo, boolean connected) {
|
||||
// TODO: Start "RequestArcInitiationAction" if ARC port.
|
||||
}
|
||||
|
||||
private void handleInitiateArc(HdmiCecMessage message){
|
||||
// In case where <Initiate Arc> is started by <Request ARC Initiation>
|
||||
// need to clean up RequestArcInitiationAction.
|
||||
removeAction(RequestArcInitiationAction.class);
|
||||
SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
|
||||
message.getDestination(), message.getSource(), true);
|
||||
addAndStartAction(action);
|
||||
}
|
||||
|
||||
private void handleTerminateArc(HdmiCecMessage message) {
|
||||
// In case where <Terminate Arc> is started by <Request ARC Termination>
|
||||
// need to clean up RequestArcInitiationAction.
|
||||
// TODO: check conditions of power status by calling is_connected api
|
||||
// to be added soon.
|
||||
removeAction(RequestArcTerminationAction.class);
|
||||
SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
|
||||
message.getDestination(), message.getSource(), false);
|
||||
addAndStartAction(action);
|
||||
}
|
||||
|
||||
private void handleGetCecVersion(HdmiCecMessage message) {
|
||||
int version = mCecController.getVersion();
|
||||
HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
|
||||
|
||||
100
services/core/java/com/android/server/hdmi/RequestArcAction.java
Normal file
100
services/core/java/com/android/server/hdmi/RequestArcAction.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.HdmiCec;
|
||||
import android.hardware.hdmi.HdmiCecMessage;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
* Base feature action class for <Request ARC Initiation>/<Request ARC Termination>.
|
||||
*/
|
||||
abstract class RequestArcAction extends FeatureAction {
|
||||
private static final String TAG = "RequestArcAction";
|
||||
|
||||
// State in which waits for ARC response.
|
||||
protected static final int STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE = 1;
|
||||
|
||||
// Logical address of AV Receiver.
|
||||
protected final int mAvrAddress;
|
||||
|
||||
/**
|
||||
* @Constructor
|
||||
*
|
||||
* @param service {@link HdmiControlService} instance
|
||||
* @param sourceAddress logical address to be used as source address. It should
|
||||
* TV type
|
||||
* @param avrAddress address of AV receiver. It should be AUDIO_SYSTEM type
|
||||
* @throw IllegalArugmentException if device type of sourceAddress and avrAddress
|
||||
* is invalid
|
||||
*/
|
||||
RequestArcAction(HdmiControlService service, int sourceAddress, int avrAddress) {
|
||||
super(service, sourceAddress);
|
||||
verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
|
||||
verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
|
||||
mAvrAddress = avrAddress;
|
||||
}
|
||||
|
||||
private static void verifyAddressType(int logicalAddress, int deviceType) {
|
||||
int actualDeviceType = HdmiCec.getTypeFromAddress(logicalAddress);
|
||||
if (actualDeviceType != deviceType) {
|
||||
throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType
|
||||
+ ", Actual:" + actualDeviceType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean processCommand(HdmiCecMessage cmd) {
|
||||
if (mState != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int src = cmd.getSource();
|
||||
if (src != mAvrAddress) {
|
||||
Slog.w(TAG, "Invalid source [Expected:" + mAvrAddress + ", Actual:" + src + "]");
|
||||
return false;
|
||||
}
|
||||
int opcode = cmd.getOpcode();
|
||||
switch (opcode) {
|
||||
// Handles only <Feature Abort> here and, both <Initiate ARC> and <Terminate ARC>
|
||||
// are handled in HdmiControlService itself because both can be
|
||||
// received wihtout <Request ARC Initiation> or <Request ARC Termination>.
|
||||
case HdmiCec.MESSAGE_FEATURE_ABORT:
|
||||
disableArcTransmission();
|
||||
finish();
|
||||
return true;
|
||||
default:
|
||||
Slog.w(TAG, "Unsupported opcode:" + cmd.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected final void disableArcTransmission() {
|
||||
// Start Set ARC Transmission State action.
|
||||
SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(mService,
|
||||
mSourceAddress, mAvrAddress, false);
|
||||
mService.addAndStartAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
final void handleTimerEvent(int state) {
|
||||
if (mState != state || state != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE) {
|
||||
return;
|
||||
}
|
||||
disableArcTransmission();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.util.Slog;
|
||||
|
||||
/**
|
||||
* Feature action that handles ARC action initiated by TV devices.
|
||||
*
|
||||
* <p>This action is created by TV's hot plug event of ARC port.
|
||||
*/
|
||||
final class RequestArcInitiationAction extends RequestArcAction {
|
||||
private static final String TAG = "RequestArcInitiationAction";
|
||||
|
||||
/**
|
||||
* @Constructor
|
||||
*
|
||||
* For more details look at {@link RequestArcAction#RequestArcAction}.
|
||||
*/
|
||||
RequestArcInitiationAction(HdmiControlService service, int sourceAddress, int avrAddress) {
|
||||
super(service, sourceAddress, avrAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean start() {
|
||||
if (sendCommand(
|
||||
HdmiCecMessageBuilder.buildRequestArcInitiation(mSourceAddress, mAvrAddress))) {
|
||||
mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
|
||||
addTimer(mState, TIMEOUT_MS);
|
||||
} else {
|
||||
Slog.w(TAG, "Failed to send <Request ARC Initiation>");
|
||||
// If failed to send <Request ARC Initiation>, start "Disabled" ARC transmission
|
||||
// action.
|
||||
disableArcTransmission();
|
||||
finish();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.util.Slog;
|
||||
|
||||
/**
|
||||
* Feature action to handle <Request ARC Termination>.
|
||||
*
|
||||
* <p>It's initiated by user's manual termination or ARC channel close from TV.
|
||||
*/
|
||||
final class RequestArcTerminationAction extends RequestArcAction {
|
||||
private static final String TAG = "RequestArcTerminationAction";
|
||||
|
||||
/**
|
||||
* @Constructor
|
||||
*
|
||||
* @see RequestArcAction#RequestArcAction
|
||||
*/
|
||||
RequestArcTerminationAction(HdmiControlService service, int sourceAddress, int avrAddress) {
|
||||
super(service, sourceAddress, avrAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean start() {
|
||||
if (sendCommand(
|
||||
HdmiCecMessageBuilder.buildRequestArcTermination(mSourceAddress, mAvrAddress))) {
|
||||
mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
|
||||
addTimer(mState, TIMEOUT_MS);
|
||||
} else {
|
||||
Slog.w(TAG, "Failed to send <Request ARC Initiation>");
|
||||
// If failed to send <Request ARC Termination>, start "Disabled" ARC transmission
|
||||
// action.
|
||||
disableArcTransmission();
|
||||
finish();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.HdmiCec;
|
||||
import android.hardware.hdmi.HdmiCecMessage;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
* Feature action that handles enabling/disabling of ARC transmission channel.
|
||||
* Once TV gets <Initiate ARC>, TV sends <Report ARC Initiated> to AV Receiver.
|
||||
* If it fails or it gets <Terminate ARC>, TV just disables ARC.
|
||||
*/
|
||||
final class SetArcTransmissionStateAction extends FeatureAction {
|
||||
private static final String TAG = "SetArcTransmissionStateAction";
|
||||
|
||||
// State in which the action sent <Rerpot Arc Initiated> and
|
||||
// is waiting for time out. If it receives <Feature Abort> within timeout
|
||||
// ARC should be disabled.
|
||||
private static final int STATE_WAITING_TIMEOUT = 1;
|
||||
|
||||
private final boolean mEnabled;
|
||||
private final int mAvrAddress;
|
||||
|
||||
/**
|
||||
* @Constructor
|
||||
*
|
||||
* @param service an instance of {@link HdmiControlService}
|
||||
* @param sourceAddress logical address to be used as source address
|
||||
* @param enabled whether to enable ARC Transmission channel
|
||||
*/
|
||||
SetArcTransmissionStateAction(HdmiControlService service, int sourceAddress, int avrAddress,
|
||||
boolean enabled) {
|
||||
super(service, sourceAddress);
|
||||
verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
|
||||
verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
|
||||
mAvrAddress = avrAddress;
|
||||
mEnabled = enabled;
|
||||
}
|
||||
|
||||
// TODO: extract it as separate utility class.
|
||||
private static void verifyAddressType(int logicalAddress, int deviceType) {
|
||||
int actualDeviceType = HdmiCec.getTypeFromAddress(logicalAddress);
|
||||
if (actualDeviceType != deviceType) {
|
||||
throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType
|
||||
+ ", Actual:" + actualDeviceType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean start() {
|
||||
if (mEnabled) {
|
||||
if (sendCommand(
|
||||
HdmiCecMessageBuilder.buildReportArcInitiated(mSourceAddress, mAvrAddress))) {
|
||||
// Enable ARC status immediately after sending <Report Arc Initiated>.
|
||||
// If AVR responds with <Feature Abort>, disable ARC status again.
|
||||
// This is different from spec that says that turns ARC status to "Enabled"
|
||||
// if <Report ARC Initiated> is acknowledged and no <Feature Abort> is received.
|
||||
// But implemented this way to save the time having to wait for <Feature Abort>.
|
||||
setArcStatus(true);
|
||||
// If succeeds to send <Report ARC Initiated>, wait general timeout
|
||||
// to check whether there is no <Feature Abort> for <Report ARC Initiated>.
|
||||
mState = STATE_WAITING_TIMEOUT;
|
||||
addTimer(mState, TIMEOUT_MS);
|
||||
} else {
|
||||
// If fails to send <Report ARC Initiated>, disable ARC and
|
||||
// send <Report ARC Terminated> directly.
|
||||
Slog.w(TAG, "Failed to send <Report ARC Initiated>:[source:" + mSourceAddress
|
||||
+ ", avr Address:" + mAvrAddress + "]");
|
||||
setArcStatus(false);
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
setArcStatus(false);
|
||||
finish();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setArcStatus(boolean enabled) {
|
||||
boolean wasEnabled = mService.setArcStatus(enabled);
|
||||
Slog.i(TAG, "Change arc status [old:" + wasEnabled + " ,new:" + enabled);
|
||||
|
||||
// If enabled before and set to "disabled" and send <Report Arc Terminated> to
|
||||
// av reciever.
|
||||
if (!enabled && wasEnabled) {
|
||||
sendCommand(
|
||||
HdmiCecMessageBuilder.buildReportArcTerminated(mSourceAddress, mAvrAddress));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean processCommand(HdmiCecMessage cmd) {
|
||||
if (mState != STATE_WAITING_TIMEOUT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int opcode = cmd.getOpcode();
|
||||
if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
|
||||
setArcStatus(false);
|
||||
}
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
void handleTimerEvent(int state) {
|
||||
if (mState != state || mState != STATE_WAITING_TIMEOUT) {
|
||||
return;
|
||||
}
|
||||
// Expire timeout for <Feature Abort>.
|
||||
finish();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user