SystemAudioStatusAction.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;
21import android.util.Slog;
22
23import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
24
25/**
26 * Action to update audio status (volume or mute) of audio amplifier
27 */
28final class SystemAudioStatusAction extends FeatureAction {
29    private static final String TAG = "SystemAudioStatusAction";
30
31    // State that waits for <ReportAudioStatus>.
32    private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 1;
33
34    private final int mAvrAddress;
35
36    SystemAudioStatusAction(HdmiCecLocalDevice source, int avrAddress) {
37        super(source);
38        mAvrAddress = avrAddress;
39    }
40
41    @Override
42    boolean start() {
43        mState = STATE_WAIT_FOR_REPORT_AUDIO_STATUS;
44        addTimer(mState, TIMEOUT_MS);
45        sendGiveAudioStatus();
46        return true;
47    }
48
49    private void sendGiveAudioStatus() {
50        sendCommand(HdmiCecMessageBuilder.buildGiveAudioStatus(getSourceAddress(), mAvrAddress),
51                new SendMessageCallback() {
52            @Override
53            public void onSendCompleted(int error) {
54                if (error != HdmiConstants.SEND_RESULT_SUCCESS) {
55                    handleSendGiveAudioStatusFailure();
56                }
57            }
58        });
59    }
60
61    private void handleSendGiveAudioStatusFailure() {
62        // Inform to all application that the audio status (volumn, mute) of
63        // the audio amplifier is unknown.
64        tv().setAudioStatus(false, HdmiConstants.UNKNOWN_VOLUME);
65
66        int uiCommand = tv().getSystemAudioMode()
67                ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION  // SystemAudioMode: ON
68                : HdmiConstants.UI_COMMAND_MUTE_FUNCTION;           // SystemAudioMode: OFF
69        sendUserControlPressedAndReleased(uiCommand);
70        finish();
71    }
72
73    private void sendUserControlPressedAndReleased(int uiCommand) {
74        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
75                getSourceAddress(), mAvrAddress, uiCommand));
76        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
77                getSourceAddress(), mAvrAddress));
78    }
79
80    @Override
81    boolean processCommand(HdmiCecMessage cmd) {
82        if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS) {
83            return false;
84        }
85
86        switch (cmd.getOpcode()) {
87            case HdmiCec.MESSAGE_REPORT_AUDIO_STATUS:
88                handleReportAudioStatus(cmd);
89                return true;
90        }
91
92        return false;
93    }
94
95    private void handleReportAudioStatus(HdmiCecMessage cmd) {
96        byte[] params = cmd.getParams();
97        if (params.length > 0) {
98            boolean mute = (params[0] & 0x80) == 0x80;
99            int volume = params[0] & 0x7F;
100            tv().setAudioStatus(mute, volume);
101
102            if ((tv().getSystemAudioMode() && mute) || (!tv().getSystemAudioMode() && !mute)) {
103                // Toggle AVR's mute status to match with the system audio status.
104                sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
105            }
106            finish();
107        } else {
108            Slog.e(TAG, "Invalid <Report Audio Status> message:" + cmd);
109            handleSendGiveAudioStatusFailure();
110            return;
111        }
112    }
113
114    @Override
115    void handleTimerEvent(int state) {
116        if (mState != state) {
117            return;
118        }
119
120        handleSendGiveAudioStatusFailure();
121    }
122}
123