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

Commit ccc138ad authored by Nathalie Le Clair's avatar Nathalie Le Clair
Browse files

Process eARC capabilities reported by the HAL

Test: atest
Bug: 260547656
Change-Id: Iec7435316194c51ffea41596bbdaeb308d61cdba
parent 3814f1e2
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -1320,7 +1320,6 @@ public class HdmiControlService extends SystemService {
     * Returns {@link Looper} of main thread. Use this {@link Looper} instance
     * for tasks that are running on main service thread.
     */
    @VisibleForTesting
    protected Looper getServiceLooper() {
        return mHandler.getLooper();
    }
@@ -4526,4 +4525,19 @@ public class HdmiControlService extends SystemService {
            mEarcLocalDevice.handleEarcStateChange(status);
        }
    }

    @ServiceThreadOnly
    void handleEarcCapabilitiesReported(List<byte[]> capabilities, int portId) {
        assertRunOnServiceThread();
        if (!getPortInfo(portId).isEarcSupported()) {
            Slog.w(TAG,
                    "Tried to process eARC capabilities from a port that doesn't support eARC.");
            return;
        }
        // If eARC is disabled, the local device is null. In this case, the HAL shouldn't have
        // reported eARC capabilities, but even if it did, it won't take effect.
        if (mEarcLocalDevice != null) {
            mEarcLocalDevice.handleEarcCapabilitiesReported(capabilities);
        }
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.os.Looper;

import com.android.internal.annotations.VisibleForTesting;

import java.util.List;

final class HdmiEarcController {
    private static final String TAG = "HdmiEarcController";

@@ -91,11 +93,26 @@ final class HdmiEarcController {
        return Constants.HDMI_EARC_STATUS_IDLE;
    }

     /**
     * Ask the HAL to report the last eARC capabilities that the connected audio system reported.
     * @return the raw eARC capabilities
     */
    @HdmiAnnotations.ServiceThreadOnly
    byte[] getLastReportedCaps() {
        // Stub. TODO: bind to native.
        return new byte[] {};
    }

    final class EarcCallback {
        public void onStateChange(@Constants.EarcStatus int status, int portId) {
            runOnServiceThread(
                    () -> mService.handleEarcStateChange(status, portId));
        }

        public void onCapabilitiesReported(List<byte[]> capabilities, int portId) {
            runOnServiceThread(
                    () -> mService.handleEarcCapabilitiesReported(capabilities, portId));
        }
    }

    // TODO: bind to native.
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.util.IndentingPrintWriter;

import com.android.internal.annotations.GuardedBy;

import java.util.List;

/**
 * Class that models a local eARC device hosted in this system.
 * The class contains methods that are common between eARC TX and eARC RX devices.
@@ -49,6 +51,7 @@ abstract class HdmiEarcLocalDevice extends HdmiLocalDevice {

    protected abstract void handleEarcStateChange(@Constants.EarcStatus int status);

    protected abstract void handleEarcCapabilitiesReported(List<byte[]> capabilities);

    protected void disableDevice() {
    }
+51 −5
Original line number Diff line number Diff line
@@ -25,9 +25,12 @@ import android.media.AudioDescriptor;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioProfile;
import android.os.Handler;
import android.util.IndentingPrintWriter;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Represents a local eARC device of type TX residing in the Android system.
@@ -36,8 +39,19 @@ import java.util.ArrayList;
public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice {
    private static final String TAG = "HdmiEarcLocalDeviceTx";

    // How long to wait for the audio system to report its capabilities after eARC was connected
    static final long REPORT_CAPS_MAX_DELAY_MS = 2_000;

    // Handler and runnable for waiting for the audio system to report its capabilities after eARC
    // was connected
    private Handler mReportCapsHandler;
    private ReportCapsRunnable mReportCapsRunnable;

    HdmiEarcLocalDeviceTx(HdmiControlService service) {
        super(service, HdmiDeviceInfo.DEVICE_TV);

        mReportCapsHandler = new Handler(service.getServiceLooper());
        mReportCapsRunnable = new ReportCapsRunnable();
    }

    protected void handleEarcStateChange(@Constants.EarcStatus int status) {
@@ -46,22 +60,54 @@ public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice {
                    status);
            mEarcStatus = status;
        }

        mReportCapsHandler.removeCallbacksAndMessages(null);
        if (status == HDMI_EARC_STATUS_IDLE) {
            notifyEarcStatusToAudioService(false);
            notifyEarcStatusToAudioService(false, new ArrayList<>());
        } else if (status == HDMI_EARC_STATUS_ARC_PENDING) {
            notifyEarcStatusToAudioService(false);
            notifyEarcStatusToAudioService(false, new ArrayList<>());
        } else if (status == HDMI_EARC_STATUS_EARC_CONNECTED) {
            notifyEarcStatusToAudioService(true);
            mReportCapsHandler.postDelayed(mReportCapsRunnable, REPORT_CAPS_MAX_DELAY_MS);
        }
    }

    protected void handleEarcCapabilitiesReported(List<byte[]> capabilities) {
        synchronized (mLock) {
            if (mEarcStatus == HDMI_EARC_STATUS_EARC_CONNECTED
                    && mReportCapsHandler.hasCallbacks(mReportCapsRunnable)) {
                mReportCapsHandler.removeCallbacksAndMessages(null);
                notifyEarcStatusToAudioService(true, capabilities);
            }
        }
    }

    private void notifyEarcStatusToAudioService(boolean enabled) {
    private void notifyEarcStatusToAudioService(boolean enabled, List<byte[]> capabilities) {
        AudioDeviceAttributes attributes = new AudioDeviceAttributes(
                AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_EARC, "", "",
                new ArrayList<AudioProfile>(), new ArrayList<AudioDescriptor>());
                new ArrayList<AudioProfile>(), capabilities.stream()
                .map(cap -> new AudioDescriptor(AudioDescriptor.STANDARD_EDID,
                        AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, cap))
                .collect(Collectors.toList()));
        mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
    }

    /**
     * Runnable for waiting for a certain amount of time for the audio system to report its
     * capabilities after eARC was connected. If the audio system doesn´t report its capabilities in
     * this time, we inform AudioService about the connection state only, without any specified
     * capabilities.
     */
    private class ReportCapsRunnable implements Runnable {
        @Override
        public void run() {
            synchronized (mLock) {
                if (mEarcStatus == HDMI_EARC_STATUS_EARC_CONNECTED) {
                    notifyEarcStatusToAudioService(true, new ArrayList<>());
                }
            }
        }
    }

    /** Dump internal status of HdmiEarcLocalDeviceTx object */
    protected void dump(final IndentingPrintWriter pw) {
        synchronized (mLock) {
+0 −3
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package com.android.server.hdmi;

import com.android.internal.annotations.VisibleForTesting;

/**
 * Class that models an HDMI device hosted in this system.
 * Can be used to share methods between CEC and eARC local devices.
@@ -29,7 +27,6 @@ abstract class HdmiLocalDevice {
    protected final HdmiControlService mService;
    protected final int mDeviceType;

    @VisibleForTesting
    protected final Object mLock;

    protected HdmiLocalDevice(HdmiControlService service, int deviceType) {
Loading