SystemAudioAction.java revision 16321b80077815eebeceee249ff7a29e336e04a4
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.hardware.hdmi.HdmiCec;
20import android.hardware.hdmi.HdmiCecMessage;
21
22/**
23 * Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr.
24 */
25abstract class SystemAudioAction extends FeatureAction {
26    private static final String TAG = "SystemAudioAction";
27
28    // State in which waits for <SetSystemAudioMode>.
29    private static final int STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE = 1;
30
31    private static final int MAX_SEND_RETRY_COUNT = 2;
32
33    private static final int ON_TIMEOUT_MS = 5000;
34    private static final int OFF_TIMEOUT_MS = TIMEOUT_MS;
35
36    // Logical address of AV Receiver.
37    protected final int mAvrLogicalAddress;
38
39    // The target audio status of the action, whether to enable the system audio mode or not.
40    protected boolean mTargetAudioStatus;
41
42    private int mSendRetryCount = 0;
43
44    /**
45     * Constructor
46     *
47     * @param source {@link HdmiCecLocalDevice} instance
48     * @param avrAddress logical address of AVR device
49     * @param targetStatus Whether to enable the system audio mode or not
50     * @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid
51     */
52    SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus) {
53        super(source);
54        HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
55        mAvrLogicalAddress = avrAddress;
56        mTargetAudioStatus = targetStatus;
57    }
58
59    protected void sendSystemAudioModeRequest() {
60        int avrPhysicalAddress = tv().getAvrDeviceInfo().getPhysicalAddress();
61        HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest(
62                getSourceAddress(),
63                mAvrLogicalAddress, avrPhysicalAddress, mTargetAudioStatus);
64        sendCommand(command, new HdmiControlService.SendMessageCallback() {
65            @Override
66            public void onSendCompleted(int error) {
67                if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
68                    mState = STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE;
69                    addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
70                } else {
71                    setSystemAudioMode(false);
72                    finish();
73                }
74            }
75        });
76    }
77
78    private void handleSendSystemAudioModeRequestTimeout() {
79        if (!mTargetAudioStatus  // Don't retry for Off case.
80                || mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) {
81            setSystemAudioMode(false);
82            finish();
83            return;
84        }
85        sendSystemAudioModeRequest();
86    }
87
88    protected void setSystemAudioMode(boolean mode) {
89        tv().setSystemAudioMode(mode);
90    }
91
92    @Override
93    final boolean processCommand(HdmiCecMessage cmd) {
94        switch (mState) {
95            case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
96                // TODO: Handle <FeatureAbort> of <SystemAudioModeRequest>
97                if (cmd.getOpcode() != HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE
98                        || !HdmiUtils.checkCommandSource(cmd, mAvrLogicalAddress, TAG)) {
99                    return false;
100                }
101                boolean receivedStatus = HdmiUtils.parseCommandParamSystemAudioStatus(cmd);
102                if (receivedStatus == mTargetAudioStatus) {
103                    setSystemAudioMode(receivedStatus);
104                    startAudioStatusAction();
105                    return true;
106                } else {
107                    // Unexpected response, consider the request is newly initiated by AVR.
108                    // To return 'false' will initiate new SystemAudioActionFromAvr by the control
109                    // service.
110                    finish();
111                    return false;
112                }
113            default:
114                return false;
115        }
116    }
117
118    protected void startAudioStatusAction() {
119        addAndStartAction(new SystemAudioStatusAction(tv(), mAvrLogicalAddress));
120        finish();
121    }
122
123    protected void removeSystemAudioActionInProgress() {
124        removeActionExcept(SystemAudioActionFromTv.class, this);
125        removeActionExcept(SystemAudioActionFromAvr.class, this);
126    }
127
128    @Override
129    final void handleTimerEvent(int state) {
130        if (mState != state) {
131            return;
132        }
133        switch (mState) {
134            case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
135                handleSendSystemAudioModeRequestTimeout();
136                return;
137        }
138    }
139}
140