Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bce52713 authored by Jungshik Jang's avatar Jungshik Jang Committed by Android (Google) Code Review
Browse files

Merge "Add SystemAudioAutoInitiationAction and SystemAudioStatusAction"

parents 128be2a9 187d0176
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {

    HdmiCecLocalDeviceTv(HdmiControlService service) {
        super(service, HdmiCec.DEVICE_TV);

        // TODO: load system audio mode and set it to mSystemAudioMode.
    }

    @Override
@@ -174,6 +176,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
                        }

                        addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));

                        // If there is AVR, initiate System Audio Auto initiation action,
                        // which turns on and off system audio according to last system
                        // audio setting.
                        HdmiCecDeviceInfo avrInfo = getAvrDeviceInfo();
                        if (avrInfo != null) {
                            addAndStartAction(new SystemAudioAutoInitiationAction(
                                    HdmiCecLocalDeviceTv.this, avrInfo.getLogicalAddress()));
                        }
                    }
                });
        addAndStartAction(action);
@@ -456,4 +467,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            hotplugActions.get(0).pollAllDevicesNow();
        }
    }

    boolean canChangeSystemAudio() {
        // TODO: implement this.
        // return true if no system audio control sequence is running.
        return false;
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -377,6 +377,17 @@ public class HdmiCecMessageBuilder {
        return buildCommand(src, dest, HdmiCec.MESSAGE_USER_CONTROL_RELEASED);
    }

    /**
     * Build <Give System Audio Mode Status> command.
     *
     * @param src source address of command
     * @param dest destination address of command
     * @return newly created {@link HdmiCecMessage}
     */
    static HdmiCecMessage buildGiveSystemAudioModeStatus(int src, int dest) {
        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS);
    }

    /***** Please ADD new buildXXX() methods above. ******/

    /**
+2 −0
Original line number Diff line number Diff line
@@ -95,5 +95,7 @@ final class HdmiConstants {
    static final int POLL_ITERATION_IN_ORDER = 0x10000;
    static final int POLL_ITERATION_REVERSE_ORDER = 0x20000;

    static final int UNKNOWN_VOLUME = -1;

    private HdmiConstants() { /* cannot be instantiated */ }
}
+120 −0
Original line number Diff line number Diff line
/*
 * 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 com.android.server.hdmi.HdmiControlService.SendMessageCallback;

/**
 * Action to initiate system audio once AVR is detected on Device discovery action.
 */
final class SystemAudioAutoInitiationAction extends FeatureAction {
    private final int mAvrAddress;

    // State that waits for <System Audio Mode Status> once send
    // <Give System Audio Mode Status> to AV Receiver.
    private static final int STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS = 1;

    SystemAudioAutoInitiationAction(HdmiCecLocalDevice source, int avrAddress) {
        super(source);
        mAvrAddress = avrAddress;
    }

    @Override
    boolean start() {
        mState = STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS;

        addTimer(mState, TIMEOUT_MS);
        sendGiveSystemAudioModeStatus();
        return true;
    }

    private void sendGiveSystemAudioModeStatus() {
        sendCommand(HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(getSourceAddress(),
                mAvrAddress), new SendMessageCallback() {
            @Override
            public void onSendCompleted(int error) {
                if (error != HdmiConstants.SEND_RESULT_SUCCESS) {
                    tv().setSystemAudioMode(false);
                    finish();
                }
            }
        });
    }

    @Override
    boolean processCommand(HdmiCecMessage cmd) {
        if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS) {
            return false;
        }

        switch (cmd.getOpcode()) {
            case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
                handleSystemAudioModeStatusMessage();
                return true;
            default:
                return false;
        }
    }

    private void handleSystemAudioModeStatusMessage() {
        // If the last setting is system audio, turn on system audio whatever AVR status is.
        if (tv().getSystemAudioMode()) {
            if (canChangeSystemAudio()) {
                addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true));
            }
        } else {
            // If the last setting is non-system audio, turn off system audio mode
            // and update system audio status (volume or mute).
            tv().setSystemAudioMode(false);
            if (canChangeSystemAudio()) {
                addAndStartAction(new SystemAudioStatusAction(tv(), mAvrAddress));
            }
        }
        finish();
    }

    @Override
    void handleTimerEvent(int state) {
        if (mState != state) {
            return;
        }

        switch (mState) {
            case STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS:
                handleSystemAudioModeStatusTimeout();
                break;
        }
    }

    private void handleSystemAudioModeStatusTimeout() {
        if (tv().getSystemAudioMode()) {
            if (canChangeSystemAudio()) {
                addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true));
            }
        } else {
            tv().setSystemAudioMode(false);
        }
        finish();
    }

    private boolean canChangeSystemAudio() {
        return tv().canChangeSystemAudio();
    }
}
+123 −0
Original line number Diff line number Diff line
/*
 * 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;

import com.android.server.hdmi.HdmiControlService.SendMessageCallback;

/**
 * Action to update audio status (volume or mute) of audio amplifier
 */
// TODO: refactor SystemAudioMode so that it uses this class instead of internal state.
final class SystemAudioStatusAction extends FeatureAction {
    private static final String TAG = "SystemAudioStatusAction";

    // State that waits for <ReportAudioStatus>.
    private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 1;

    private final int mAvrAddress;

    SystemAudioStatusAction(HdmiCecLocalDevice source, int avrAddress) {
        super(source);
        mAvrAddress = avrAddress;
    }

    @Override
    boolean start() {
        mState = STATE_WAIT_FOR_REPORT_AUDIO_STATUS;
        addTimer(mState, TIMEOUT_MS);
        sendGiveAudioStatus();
        return true;
    }

    private void sendGiveAudioStatus() {
        sendCommand(HdmiCecMessageBuilder.buildGiveAudioStatus(getSourceAddress(), mAvrAddress),
                new SendMessageCallback() {
            @Override
            public void onSendCompleted(int error) {
                if (error != HdmiConstants.SEND_RESULT_SUCCESS) {
                    handleSendGiveAudioStatusFailure();
                }
            }
        });
    }

    private void handleSendGiveAudioStatusFailure() {
        // Inform to all application that the audio status (volumn, mute) of
        // the audio amplifier is unknown.
        tv().setAudioStatus(false, HdmiConstants.UNKNOWN_VOLUME);

        int uiCommand = tv().getSystemAudioMode()
                ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION  // SystemAudioMode: ON
                : HdmiConstants.UI_COMMAND_MUTE_FUNCTION;           // SystemAudioMode: OFF
        sendUserControlPressedAndReleased(uiCommand);
        finish();
    }

    private void sendUserControlPressedAndReleased(int uiCommand) {
        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
                getSourceAddress(), mAvrAddress, uiCommand));
        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
                getSourceAddress(), mAvrAddress));
    }

    @Override
    boolean processCommand(HdmiCecMessage cmd) {
        if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS) {
            return false;
        }

        switch (cmd.getOpcode()) {
            case HdmiCec.MESSAGE_REPORT_AUDIO_STATUS:
                handleReportAudioStatus(cmd);
                return true;
        }

        return false;
    }

    private void handleReportAudioStatus(HdmiCecMessage cmd) {
        byte[] params = cmd.getParams();
        if (params.length > 0) {
            boolean mute = (params[0] & 0x80) == 0x80;
            int volume = params[0] & 0x7F;
            tv().setAudioStatus(mute, volume);

            if ((tv().getSystemAudioMode() && mute) || (!tv().getSystemAudioMode() && !mute)) {
                // Toggle AVR's mute status to match with the system audio status.
                sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
            }
            finish();
        } else {
            Slog.e(TAG, "Invalid <Report Audio Status> message:" + cmd);
            handleSendGiveAudioStatusFailure();
            return;
        }
    }

    @Override
    void handleTimerEvent(int state) {
        if (mState != state) {
            return;
        }

        handleSendGiveAudioStatusFailure();
    }
}