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

Commit 39fc6a26 authored by Vignesh Kulothungan's avatar Vignesh Kulothungan
Browse files

hal: add multi stream support for display port

Add support to switch audio stream between multiple
display ports.

CRs-Fixed: 2504445
Change-Id: I6ff80d12ea92b83b765faaf93b94ced98ea10d35
parent 8b39fcc9
Loading
Loading
Loading
Loading
+46 −13
Original line number Diff line number Diff line
@@ -217,6 +217,8 @@ static bool audio_extn_audiozoom_enabled = false;
#define IS_BIT_SET(NUM, bitno) (NUM & (1 << bitno))

#define EXT_DISPLAY_PLUG_STATUS_NOTIFY_ENABLE      0x30
#define EXT_DISPLAY_PLUG_STATUS_NOTIFY_CONNECT     0x01
#define EXT_DISPLAY_PLUG_STATUS_NOTIFY_DISCONNECT  0x00

static ssize_t update_sysfs_node(const char *path, const char *data, size_t len)
{
@@ -276,12 +278,14 @@ static int get_ext_disp_sysfs_node_index(int ext_disp_type)
    return -1;
}

static int update_ext_disp_sysfs_node(const struct audio_device *adev, int node_value)
static int update_ext_disp_sysfs_node(const struct audio_device *adev,
                                      int node_value, int controller, int stream)
{
    char ext_disp_ack_path[80] = {0};
    char ext_disp_ack_value[3] = {0};
    int index, ret = -1;
    int ext_disp_type = platform_get_ext_disp_type(adev->platform);
    int ext_disp_type = platform_get_ext_disp_type_v2(adev->platform, controller,
                                                      stream);

    if (ext_disp_type < 0) {
        ALOGE("%s, Unable to get the external display type, err:%d",
@@ -305,26 +309,47 @@ static int update_ext_disp_sysfs_node(const struct audio_device *adev, int node_
    return ret;
}

static int update_audio_ack_state(const struct audio_device *adev, int node_value)
static int update_audio_ack_state(const struct audio_device *adev,
                                  int node_value,
                                  int controller,
                                  int stream)
{
    const char *mixer_ctl_name = "External Display Audio Ack";
    struct mixer_ctl *ctl;
    int ret = 0;
    int ctl_index = 0;
    struct mixer_ctl *ctl = NULL;
    const char *ctl_prefix = "External Display";
    const char *ctl_suffix = "Audio Ack";
    char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};

    ctl_index = platform_get_display_port_ctl_index(controller, stream);
    if (-EINVAL == ctl_index) {
        ALOGE("%s: Unknown controller/stream %d/%d",
              __func__, controller, stream);
        return -EINVAL;
    }

    if (0 == ctl_index)
        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
                 "%s %s", ctl_prefix, ctl_suffix);
    else
        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
                 "%s%d %s", ctl_prefix, ctl_index, ctl_suffix);

    ALOGV("%s: mixer ctl name: %s", __func__, mixer_ctl_name);
    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
    /* If no mixer command support, fall back to sysfs node approach */
    if (!ctl) {
        ALOGI("%s: could not get ctl for mixer cmd(%s), use sysfs node instead\n",
              __func__, mixer_ctl_name);
        ret = update_ext_disp_sysfs_node(adev, node_value);
        ret = update_ext_disp_sysfs_node(adev, node_value, controller, stream);
    } else {
        char *ack_str = NULL;

        if (node_value == EXT_DISPLAY_PLUG_STATUS_NOTIFY_ENABLE)
            ack_str = "Ack_Enable";
        else if (node_value == 1)
        else if (node_value == EXT_DISPLAY_PLUG_STATUS_NOTIFY_CONNECT)
            ack_str = "Connect";
        else if (node_value == 0)
        else if (node_value == EXT_DISPLAY_PLUG_STATUS_NOTIFY_DISCONNECT)
            ack_str = "Disconnect";
        else {
            ALOGE("%s: Invalid input parameter - 0x%x\n",
@@ -343,24 +368,32 @@ static int update_audio_ack_state(const struct audio_device *adev, int node_valu
static void audio_extn_ext_disp_set_parameters(const struct audio_device *adev,
                                                     struct str_parms *parms)
{
    int controller = 0;
    int stream = 0;
    char value[32] = {0};
    static bool is_hdmi_sysfs_node_init = false;

    if (str_parms_get_str(parms, "connect", value, sizeof(value)) >= 0
            && (atoi(value) & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
        //params = "connect=1024" for external display connection.
        platform_get_controller_stream_from_params(parms, &controller, &stream);
        if (is_hdmi_sysfs_node_init == false) {
            //check if this is different for dp and hdmi
            is_hdmi_sysfs_node_init = true;
            update_audio_ack_state(adev, EXT_DISPLAY_PLUG_STATUS_NOTIFY_ENABLE);
            update_audio_ack_state(adev,
                                   EXT_DISPLAY_PLUG_STATUS_NOTIFY_ENABLE,
                                   controller, stream);
        }
        update_audio_ack_state(adev, 1);
        update_audio_ack_state(adev, EXT_DISPLAY_PLUG_STATUS_NOTIFY_CONNECT,
                               controller, stream);
    } else if(str_parms_get_str(parms, "disconnect", value, sizeof(value)) >= 0
            && (atoi(value) & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
        //params = "disconnect=1024" for external display disconnection.
        update_audio_ack_state(adev, 0);
        platform_get_controller_stream_from_params(parms, &controller, &stream);
        update_audio_ack_state(adev, EXT_DISPLAY_PLUG_STATUS_NOTIFY_DISCONNECT,
                               controller, stream);
        ALOGV("invalidate cached edid");
        platform_invalidate_hdmi_config(adev->platform);
        platform_invalidate_hdmi_config_v2(adev->platform, controller, stream);
    } else {
        // handle ext disp devices only
        return;
+6 −0
Original line number Diff line number Diff line
@@ -594,6 +594,12 @@ enum {
    EXT_DISPLAY_TYPE_HDMI,
    EXT_DISPLAY_TYPE_DP
};

// START: MST ==================================================
#define MAX_CONTROLLERS 1
#define MAX_STREAMS_PER_CONTROLLER 2
// END: MST ==================================================

// START: HDMI_PASSTHROUGH ==================================================
/* Used to limit sample rate for TrueHD & EC3 */
#define HDMI_PASSTHROUGH_MAX_SAMPLE_RATE 192000
+47 −11
Original line number Diff line number Diff line
@@ -1836,12 +1836,16 @@ static void reset_hdmi_sink_caps(struct stream_out *out) {
static int read_hdmi_sink_caps(struct stream_out *out)
{
    int ret = 0, i = 0, j = 0;
    int channels = platform_edid_get_max_channels(out->dev->platform);
    int channels = platform_edid_get_max_channels_v2(out->dev->platform,
                                                     out->extconn.cs.controller,
                                                     out->extconn.cs.stream);

    reset_hdmi_sink_caps(out);

    /* Cache ext disp type */
    if (platform_get_ext_disp_type(adev->platform) <= 0) {
    if (platform_get_ext_disp_type_v2(adev->platform,
                                      out->extconn.cs.controller,
                                      out->extconn.cs.stream <= 0)) {
        ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
        return -EINVAL;
    }
@@ -1867,7 +1871,9 @@ static int read_hdmi_sink_caps(struct stream_out *out)

    // check channel format caps
    i = 0;
    if (platform_is_edid_supported_format(out->dev->platform, AUDIO_FORMAT_AC3)) {
    if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_AC3,
                                             out->extconn.cs.controller,
                                             out->extconn.cs.stream)) {
        ALOGV(":%s HDMI supports AC3/EAC3 formats", __func__);
        out->supported_formats[i++] = AUDIO_FORMAT_AC3;
        //Adding EAC3/EAC3_JOC formats if AC3 is supported by the sink.
@@ -1876,22 +1882,30 @@ static int read_hdmi_sink_caps(struct stream_out *out)
        out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
    }

    if (platform_is_edid_supported_format(out->dev->platform, AUDIO_FORMAT_DOLBY_TRUEHD)) {
    if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DOLBY_TRUEHD,
                                             out->extconn.cs.controller,
                                             out->extconn.cs.stream)) {
        ALOGV(":%s HDMI supports TRUE HD format", __func__);
        out->supported_formats[i++] = AUDIO_FORMAT_DOLBY_TRUEHD;
    }

    if (platform_is_edid_supported_format(out->dev->platform, AUDIO_FORMAT_DTS)) {
    if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS,
                                             out->extconn.cs.controller,
                                             out->extconn.cs.stream)) {
        ALOGV(":%s HDMI supports DTS format", __func__);
        out->supported_formats[i++] = AUDIO_FORMAT_DTS;
    }

    if (platform_is_edid_supported_format(out->dev->platform, AUDIO_FORMAT_DTS_HD)) {
    if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS_HD,
                                             out->extconn.cs.controller,
                                             out->extconn.cs.stream)) {
        ALOGV(":%s HDMI supports DTS HD format", __func__);
        out->supported_formats[i++] = AUDIO_FORMAT_DTS_HD;
    }

    if (platform_is_edid_supported_format(out->dev->platform, AUDIO_FORMAT_IEC61937)) {
    if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_IEC61937,
                                             out->extconn.cs.controller,
                                             out->extconn.cs.stream)) {
        ALOGV(":%s HDMI supports IEC61937 format", __func__);
        out->supported_formats[i++] = AUDIO_FORMAT_IEC61937;
    }
@@ -1900,7 +1914,9 @@ static int read_hdmi_sink_caps(struct stream_out *out)
    // check sample rate caps
    i = 0;
    for (j = 0; j < MAX_SUPPORTED_SAMPLE_RATES; j++) {
        if (platform_is_edid_supported_sample_rate(out->dev->platform, out_hdmi_sample_rates[j])) {
        if (platform_is_edid_supported_sample_rate_v2(out->dev->platform, out_hdmi_sample_rates[j],
                                                      out->extconn.cs.controller,
                                                      out->extconn.cs.stream)) {
            ALOGV(":%s HDMI supports sample rate:%d", __func__, out_hdmi_sample_rates[j]);
            out->supported_sample_rates[i++] = out_hdmi_sample_rates[j];
        }
@@ -4431,6 +4447,8 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
    struct str_parms *parms;
    char value[32];
    int ret = 0, val = 0, err;
    int ext_controller = -1;
    int ext_stream = -1;
    bool bypass_a2dp = false;
    bool reconfig = false;
    unsigned long service_interval = 0;
@@ -4440,6 +4458,17 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
    parms = str_parms_create_str(kvpairs);
    if (!parms)
        goto error;

    err = platform_get_controller_stream_from_params(parms, &ext_controller,
                                                       &ext_stream);
    if (err >= 0) {
        out->extconn.cs.controller = ext_controller;
        out->extconn.cs.stream = ext_stream;
        ALOGD("%s: usecase(%s) new controller/stream (%d/%d)", __func__,
              use_case_table[out->usecase], out->extconn.cs.controller,
              out->extconn.cs.stream);
    }

    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
    if (err >= 0) {
        val = atoi(value);
@@ -4456,7 +4485,10 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
        if ((out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
                (val == AUDIO_DEVICE_NONE) &&
                !audio_extn_passthru_is_passthrough_stream(out) &&
                (platform_get_edid_info(adev->platform) != 0) /* HDMI disconnected */) {
                (platform_get_edid_info_v2(adev->platform,
                                           out->extconn.cs.controller,
                                           out->extconn.cs.stream) != 0)) {
            out->extconn.cs.controller = out->extconn.cs.stream = -1;
            val = AUDIO_DEVICE_OUT_SPEAKER;
        }
        /*
@@ -4683,6 +4715,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
            pthread_mutex_unlock(&out->lock);
        }
    }

    //end suspend, resume handling block
    str_parms_destroy(parms);
error:
@@ -8116,6 +8149,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
    bool a2dp_reconfig = false;
    struct listnode *node;
    struct audio_usecase *usecase = NULL;
    int controller = -1, stream = -1;

    ALOGD("%s: enter: %s", __func__, kvpairs);
    parms = str_parms_create_str(kvpairs);
@@ -8243,11 +8277,13 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
        if (audio_is_output_device(val) &&
            (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
            ALOGV("cache new ext disp type and edid");
            ret = platform_get_ext_disp_type(adev->platform);
            platform_get_controller_stream_from_params(parms, &controller, &stream);
            platform_set_ext_display_device_v2(adev->platform, controller, stream);
            ret = platform_get_ext_disp_type_v2(adev->platform, controller, stream);
            if (ret < 0) {
                ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
            } else {
                platform_cache_edid(adev->platform);
                platform_cache_edid_v2(adev->platform, controller, stream);
            }
        } else if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
            /*
+8 −0
Original line number Diff line number Diff line
@@ -435,6 +435,14 @@ struct stream_out {

    char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
    int car_audio_stream;

    union {
        char *addr;
        struct {
            int controller;
            int stream;
        } cs;
    } extconn;
};

struct stream_in {
+90 −0
Original line number Diff line number Diff line
@@ -8610,3 +8610,93 @@ end:
    *mic_count = actual_mic_count;
    return 0;
}

int platform_get_edid_info_v2(void *platform,
                              int controller __unused,
                              int stream __unused)
{
    return platform_get_edid_info(platform);
}

int platform_edid_get_max_channels_v2(void *platform,
                                      int controller __unused,
                                      int stream __unused)
{
    return platform_edid_get_max_channels(platform);
}

bool platform_is_edid_supported_format_v2(void *platform, int format,
                                          int controller __unused,
                                          int stream __unused)
{
    return platform_is_edid_supported_format(platform, format);
}

bool platform_is_edid_supported_sample_rate_v2(void *platform, int format,
                                          int controller __unused,
                                          int stream __unused)
{
    return platform_is_edid_supported_sample_rate(platform, format);
}

void platform_cache_edid_v2(void * platform,
                            int controller __unused,
                            int stream __unused)
{
    return platform_cache_edid(platform);
}

void platform_invalidate_hdmi_config_v2(void * platform,
                                        int controller __unused,
                                        int stream __unused)
{
    return platform_invalidate_hdmi_config(platform);
}

int platform_set_ext_display_device(void *platform, int controller, int stream)
{
    return -1;
}

int platform_get_controller_stream_from_params(struct str_parms *parms,
                                               int *controller, int *stream);
{
    return -1;
}

int platform_get_ext_disp_type_v2(void *platform,
                                  int controller __unused,
                                  int stream __unused)
{
    return platform_get_ext_disp_type(platform);
}

int platform_set_edid_channels_configuration_v2(void *platform, int channels,
                                             int backend_idx,
                                             snd_device_t snd_device,
                                             int controller __unused,
                                             int stream __unused)
{
    return platform_set_edid_channels_configuration(platform, channels,
                                                    backend_idx, snd_device);
}

int platform_set_channel_allocation_v2(void *platform,
                                        int controller __unused,
                                        int stream __unused)
{
    return platform_set_channel_allocation(platform);
}

int platform_set_hdmi_channels_v2(void *platform, int channel_count,
                                  int controller __unused,
                                  int stream __unused)
{
    return platform_set_hdmi_channels(platform, channel_count);
}

int platform_get_display_port_ctl_index(int controller __unused,
                                        int stream __unused)
{
    return -EINVAL;
}
Loading