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

Commit 012520aa authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "hal: Audio HAL / APM changes for HDMI passthrough"

parents 6c1ac3f3 80a8cfb8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -167,6 +167,10 @@ ifneq ($(strip $(DOLBY_DDP)),true)
endif
endif

ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_PASSTHROUGH)),true)
    LOCAL_CFLAGS += -DHDMI_PASSTHROUGH_ENABLED
endif

LOCAL_SHARED_LIBRARIES := \
	liblog \
	libcutils \
+28 −1
Original line number Diff line number Diff line
@@ -270,7 +270,6 @@ void audio_extn_dolby_set_license(struct audio_device *adev);
void audio_extn_dolby_set_endpoint(struct audio_device *adev);
#endif


#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
bool audio_extn_is_dolby_format(audio_format_t format);
int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
@@ -288,6 +287,34 @@ int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
void audio_extn_ddp_set_parameters(struct audio_device *adev,
                                   struct str_parms *parms);
void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev);

#endif

#ifndef HDMI_PASSTHROUGH_ENABLED
#define audio_extn_dolby_update_passt_formats(adev, out)                   (0)
#define audio_extn_dolby_update_passt_stream_configuration(adev, out)      (0)
#define audio_extn_dolby_is_passt_convert_supported(adev, out)             (0)
#define audio_extn_dolby_is_passt_supported(adev, out)                     (0)
#define audio_extn_dolby_is_passthrough_stream(flags)                      (0)
#define audio_extn_dolby_set_hdmi_config(adev, out)                        (0)
#define audio_extn_dolby_get_passt_buffer_size(info)                       (0)
#define audio_extn_dolby_set_passt_volume(out, mute)                       (0)
#define audio_extn_dolby_set_passt_latency(out, latency)                   (0)
#else
int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
                                          struct stream_out *out);
bool audio_extn_dolby_is_passt_convert_supported(struct audio_device *adev,
                                                 struct stream_out *out);
bool audio_extn_dolby_is_passt_supported(struct audio_device *adev,
                                         struct stream_out *out);
void audio_extn_dolby_update_passt_stream_configuration(struct audio_device *adev,
                                                 struct stream_out *out);
bool audio_extn_dolby_is_passthrough_stream(int flags);
int audio_extn_dolby_set_hdmi_config(struct audio_device *adev,
                                     struct stream_out *out);
int audio_extn_dolby_get_passt_buffer_size(audio_offload_info_t* info);
int audio_extn_dolby_set_passt_volume(struct stream_out *out, int mute);
int audio_extn_dolby_set_passt_latency(struct stream_out *out, int latency);
#endif

#ifndef HFP_ENABLED
+112 −0
Original line number Diff line number Diff line
@@ -408,6 +408,118 @@ bool audio_extn_is_dolby_format(audio_format_t format)
}
#endif /* DS1_DOLBY_DDP_ENABLED || DS2_DOLBY_DAP_ENABLED */

#ifdef HDMI_PASSTHROUGH_ENABLED
int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
                                          struct stream_out *out) {
    int32_t i = 0, ret = -ENOSYS;

    if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3) ||
        platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_E_AC3)) {
        out->supported_formats[i++] = AUDIO_FORMAT_AC3;
        out->supported_formats[i++] = AUDIO_FORMAT_E_AC3;
        /* Reciever must support JOC and advertise, otherwise JOC is treated as DDP */
        out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
        ret = 0;
    }
    ALOGV("%s: ret = %d", __func__, ret);
    return ret;
}

bool audio_extn_dolby_is_passt_convert_supported(struct audio_device *adev,
                                                 struct stream_out *out) {

    bool convert = false;
    switch (out->format) {
    case AUDIO_FORMAT_E_AC3:
    case AUDIO_FORMAT_E_AC3_JOC:
        if (!platform_is_edid_supported_format(adev->platform,
            AUDIO_FORMAT_E_AC3)) {
            ALOGV("%s:PASSTHROUGH_CONVERT supported", __func__);
            convert = true;
        }
        break;
    default:
        ALOGE("%s: PASSTHROUGH_CONVERT not supported for format 0x%x",
              __func__, out->format);
        break;
    }
    ALOGE("%s: convert %d", __func__, convert);
    return convert;
}

bool audio_extn_dolby_is_passt_supported(struct audio_device *adev,
                                         struct stream_out *out) {
    bool passt = false;
    switch (out->format) {
    case AUDIO_FORMAT_E_AC3:
        if (platform_is_edid_supported_format(adev->platform, out->format)) {
            ALOGV("%s:PASSTHROUGH supported for format %x",
                   __func__, out->format);
            passt = true;
        }
        break;
    case AUDIO_FORMAT_AC3:
        if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)
            || platform_is_edid_supported_format(adev->platform,
            AUDIO_FORMAT_E_AC3)) {
            ALOGV("%s:PASSTHROUGH supported for format %x",
                   __func__, out->format);
            passt = true;
        }
        break;
    case AUDIO_FORMAT_E_AC3_JOC:
         /* Check for DDP capability in edid for JOC contents.*/
         if (platform_is_edid_supported_format(adev->platform,
             AUDIO_FORMAT_E_AC3)) {
             ALOGV("%s:PASSTHROUGH supported for format %x",
                   __func__, out->format);
             passt = true;
         }
    default:
        ALOGV("%s:Passthrough not supported", __func__);
    }
    return passt;
}

void audio_extn_dolby_update_passt_stream_configuration(
        struct audio_device *adev, struct stream_out *out) {
    if (audio_extn_dolby_is_passt_supported(adev, out)) {
        ALOGV("%s:PASSTHROUGH", __func__);
        out->compr_config.codec->compr_passthr = PASSTHROUGH;
    } else if (audio_extn_dolby_is_passt_convert_supported(adev, out)){
        ALOGV("%s:PASSTHROUGH CONVERT", __func__);
        out->compr_config.codec->compr_passthr = PASSTHROUGH_CONVERT;
    } else {
        ALOGV("%s:NO PASSTHROUGH", __func__);
        out->compr_config.codec->compr_passthr = LEGACY_PCM;
    }
}

bool audio_extn_dolby_is_passthrough_stream(int flags) {

    if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
        return true;
    return false;
}

int audio_extn_dolby_set_hdmi_config(struct audio_device *adev,
                                                    struct stream_out *out) {
    return platform_set_hdmi_config(out);
}

int audio_extn_dolby_get_passt_buffer_size(audio_offload_info_t* info) {
    return platform_get_compress_passthrough_buffer_size(info);
}

int audio_extn_dolby_set_passt_volume(struct stream_out *out,  int mute) {
    return platform_set_device_params(out, DEVICE_PARAM_MUTE_ID, mute);
}

int audio_extn_dolby_set_passt_latency(struct stream_out *out, int latency) {
    return platform_set_device_params(out, DEVICE_PARAM_LATENCY_ID, latency);
}
#endif /* HDMI_PASSTHROUGH_ENABLED */

#ifdef DS1_DOLBY_DAP_ENABLED
void audio_extn_dolby_set_endpoint(struct audio_device *adev)
{
+11 −3
Original line number Diff line number Diff line
@@ -64,12 +64,14 @@ const struct string_to_enum s_flag_name_to_enum_table[] = {
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
#ifdef INCALL_MUSIC_ENABLED
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
#endif
#ifdef COMPRESS_VOIP_ENABLED
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
#endif
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
};

const struct string_to_enum s_format_name_to_enum_table[] = {
@@ -98,6 +100,7 @@ const struct string_to_enum s_format_name_to_enum_table[] = {
    STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD),
    STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD),
    STRING_TO_ENUM(AUDIO_FORMAT_FLAC),
    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
#endif
};

@@ -404,6 +407,7 @@ static bool set_output_cfg(struct streams_output_cfg *so_info,
        ss_info = node_to_item(node_i, struct stream_sample_rate, list);
        if ((sample_rate <= ss_info->sample_rate) &&
            (bit_width == so_info->app_type_cfg.bit_width)) {

            app_type_cfg->app_type = so_info->app_type_cfg.app_type;
            app_type_cfg->sample_rate = ss_info->sample_rate;
            app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
@@ -509,7 +513,7 @@ int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase)
        (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY) &&
        (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
        (!is_offload_usecase(usecase->id))) {
        ALOGV("%s: a playback path where app type cfg is not required", __func__);
        ALOGV("%s: a playback path where app type cfg is not required %d", __func__, usecase->id);
        rc = 0;
        goto exit_send_app_type_cfg;
    }
@@ -548,8 +552,12 @@ int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase)

    app_type_cfg[len++] = out->app_type_cfg.app_type;
    app_type_cfg[len++] = acdb_dev_id;
    if (((out->format == AUDIO_FORMAT_E_AC3) ||
        (out->format == AUDIO_FORMAT_E_AC3_JOC)) &&
        (out->flags  & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
        app_type_cfg[len++] = sample_rate * 4;
    else
        app_type_cfg[len++] = sample_rate;

    mixer_ctl_set_array(ctl, app_type_cfg, len);
    ALOGI("%s app_type %d, acdb_dev_id %d, sample_rate %d",
           __func__, out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
+107 −31
Original line number Diff line number Diff line
@@ -1277,8 +1277,9 @@ static bool allow_hdmi_channel_config(struct audio_device *adev)
                break;
            } else if (is_offload_usecase(usecase->id) &&
                       audio_channel_count_from_out_mask(usecase->stream.out->channel_mask) > 2) {
                ALOGD("%s: multi-channel(%x) compress offload playback is active, "
                      "no change in HDMI channels", __func__, usecase->stream.out->channel_mask);
                ALOGD("%s:multi-channel(%x) compress offload playback is active"
                      ", no change in HDMI channels", __func__,
                      usecase->stream.out->channel_mask);
                ret = false;
                break;
            }
@@ -1309,6 +1310,7 @@ static int check_and_set_hdmi_channels(struct audio_device *adev,
        return 0;
    }

    /*TODO: CHECK for passthrough don't set channel map for passthrough*/
    platform_set_hdmi_channels(adev->platform, channels);
    platform_set_edid_channels_configuration(adev->platform, channels);
    adev->cur_hdmi_channels = channels;
@@ -1356,7 +1358,8 @@ static int stop_output_stream(struct stream_out *out)
        return -EINVAL;
    }

    if (is_offload_usecase(out->usecase)) {
    if (is_offload_usecase(out->usecase) &&
        !(audio_extn_dolby_is_passthrough_stream(out->flags))) {
        if (adev->visualizer_stop_output != NULL)
            adev->visualizer_stop_output(out->handle, out->pcm_device_id);
        if (adev->offload_effects_stop_output != NULL)
@@ -1372,6 +1375,15 @@ static int stop_output_stream(struct stream_out *out)
    list_remove(&uc_info->list);
    free(uc_info);

    if (is_offload_usecase(out->usecase) &&
        (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
        (audio_extn_dolby_is_passthrough_stream(out->flags))) {
        ALOGV("Disable passthrough , reset mixer to pcm");
        /* NO_PASSTHROUGH */
        out->compr_config.codec->compr_passthr = 0;
        audio_extn_dolby_set_hdmi_config(adev, out);
        audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
    }
    /* Must be called after removing the usecase from list */
    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
        check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
@@ -1409,7 +1421,7 @@ int start_output_stream(struct stream_out *out)
        ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
              __func__, out->pcm_device_id, out->usecase);
        ret = -EINVAL;
        goto error_config;
        goto error_open;
    }

    uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
@@ -1425,9 +1437,17 @@ int start_output_stream(struct stream_out *out)
    uc_info->devices = out->devices;
    uc_info->in_snd_device = SND_DEVICE_NONE;
    uc_info->out_snd_device = SND_DEVICE_NONE;

    /* This must be called before adding this usecase to the list */
    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
        if (is_offload_usecase(out->usecase)) {
            if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
                ret = audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_BYPASS);
                if(ret != 0) {
                    goto error_open;
                }
                audio_extn_dolby_update_passt_stream_configuration(adev, out);
            }
        }
        property_get("audio.use.hdmi.sink.cap", prop_value, NULL);
        if (!strncmp("true", prop_value, 4)) {
            sink_channels = platform_edid_get_max_channels(out->dev->platform);
@@ -1435,13 +1455,17 @@ int start_output_stream(struct stream_out *out)
                   __func__, sink_channels);
            check_and_set_hdmi_channels(adev, sink_channels);
        } else {
            if (is_offload_usecase(out->usecase))
                check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in);
            else
            if (is_offload_usecase(out->usecase)) {
                unsigned int ch_count =  out->compr_config.codec->ch_in;
                if (audio_extn_dolby_is_passthrough_stream(out->flags))
                    /* backend channel config for passthrough stream is stereo */
                    ch_count = 2;
                check_and_set_hdmi_channels(adev, ch_count);
            } else
                check_and_set_hdmi_channels(adev, out->config.channels);
        }
        audio_extn_dolby_set_hdmi_config(adev, out);
    }

    list_add_tail(&adev->usecase_list, &uc_info->list);

    select_devices(adev, out->usecase);
@@ -1498,12 +1522,13 @@ int start_output_stream(struct stream_out *out)
        if (audio_extn_is_dolby_format(out->format))
            audio_extn_dolby_send_ddp_endp_params(adev);
#endif

        if (!(audio_extn_dolby_is_passthrough_stream(out->flags))) {
            if (adev->visualizer_start_output != NULL)
                adev->visualizer_start_output(out->handle, out->pcm_device_id);
            if (adev->offload_effects_start_output != NULL)
                adev->offload_effects_start_output(out->handle, out->pcm_device_id);
        }
    }
    ALOGV("%s: exit", __func__);
    return 0;
error_open:
@@ -1891,6 +1916,28 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k
            str = strdup(keys);
        }
    }

    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
    if (ret >= 0) {
        value[0] = '\0';
        i = 0;
        first = true;
        while (out->supported_formats[i] != 0) {
            for (j = 0; j < ARRAY_SIZE(out_formats_name_to_enum_table); j++) {
                if (out_formats_name_to_enum_table[j].value == out->supported_formats[i]) {
                    if (!first) {
                        strcat(value, "|");
                    }
                    strlcat(value, out_formats_name_to_enum_table[j].name, sizeof(value));
                    first = false;
                    break;
                }
            }
            i++;
        }
        str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
        str = str_parms_to_str(reply);
    }
    str_parms_destroy(query);
    str_parms_destroy(reply);
    ALOGV("%s: exit: returns - %s", __func__, str);
@@ -1919,6 +1966,14 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
        out->muted = (left == 0.0f);
        return 0;
    } else if (is_offload_usecase(out->usecase)) {
        if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
            /*
             * Set mute or umute on HDMI passthrough stream.
             * Only take left channel into account.
             * Mute is 0 and unmute 1
             */
            audio_extn_dolby_set_passt_volume(out, (left == 0.0f));
        } else {
            char mixer_ctl_name[128];
            struct audio_device *adev = out->dev;
            struct mixer_ctl *ctl;
@@ -1938,6 +1993,7 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
            mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
            return 0;
        }
    }

    return -ENOSYS;
}
@@ -2633,6 +2689,18 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
            ret = -EINVAL;
            goto error_open;
        }

        if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
            ((audio_extn_dolby_is_passthrough_stream(out->flags)))) {
            ALOGV("read and update_pass through formats");
            ret = audio_extn_dolby_update_passt_formats(adev, out);
            if(ret != 0) {
                goto error_open;
            }
            if(config->offload_info.format == 0)
                config->offload_info.format = out->supported_formats[0];
        }

        if (!is_supported_format(config->offload_info.format) &&
                !audio_extn_is_dolby_format(config->offload_info.format)) {
            ALOGE("%s: Unsupported audio format", __func__);
@@ -2675,6 +2743,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        if (audio_is_offload_pcm(config->offload_info.format)) {
            out->compr_config.fragment_size =
               platform_get_pcm_offload_buffer_size(&config->offload_info);
        } else if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
            out->compr_config.fragment_size =
               audio_extn_dolby_get_passt_buffer_size(&config->offload_info);
        } else {
            out->compr_config.fragment_size =
               platform_get_compress_offload_buffer_size(&config->offload_info);
@@ -2688,6 +2759,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
                audio_channel_count_from_out_mask(config->channel_mask);
        out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
        out->bit_width = PCM_OUTPUT_BIT_WIDTH;
        /*TODO: Do we need to change it for passthrough */
        out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;

        if (config->offload_info.format == AUDIO_FORMAT_AAC)
            out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
@@ -2761,6 +2834,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev,

    ALOGV("%s devices %d,flags %x, format %x, out->sample_rate %d, out->bit_width %d",
           __func__, devices, flags, format, out->sample_rate, out->bit_width);
    /* TODO remove this hardcoding and check why width is zero*/
    if (out->bit_width == 0)
        out->bit_width = 16;
    audio_extn_utils_update_stream_app_type_cfg(adev->platform,
                                                &adev->streams_output_cfg_list,
                                                devices, flags, format, out->sample_rate,
Loading