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

Commit 19dc03b5 authored by Subhash Chandra Bose Naripeddy's avatar Subhash Chandra Bose Naripeddy Committed by Gerrit - the friendly Code Review server
Browse files

hal: configure playback stream rendering based on output policy

For the usecases where individual streams have to be rendered
through different post processing chain on DSP an output policy
is defined. The output configuration is read from the
output policy file based on the stream atrributes to render the
playback appropriately.

Change-Id: I095592013ffa5b04bea69254026ebb78e2934822
parent 723c4b74
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -35,7 +35,8 @@ LOCAL_SRC_FILES := \
	platform_info.c \
	$(AUDIO_PLATFORM)/platform.c

LOCAL_SRC_FILES += audio_extn/audio_extn.c
LOCAL_SRC_FILES += audio_extn/audio_extn.c \
                   audio_extn/utils.c

ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PCM_OFFLOAD)),true)
    LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
@@ -91,6 +92,11 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_VOIP)),true)
    LOCAL_CFLAGS += -DCOMPRESS_VOIP_ENABLED
    LOCAL_SRC_FILES += voice_extn/compress_voip.c
endif

endif

ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FORMATS)),true)
LOCAL_CFLAGS += -DFORMATS_ENABLED
endif

ifneq ($(strip, $(AUDIO_FEATURE_DISABLED_SPKR_PROTECTION)),true)
+19 −0
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@ static inline bool audio_is_offload_pcm(audio_format_t format) {
#endif


#define MAX_LENGTH_MIXER_CONTROL_IN_INT                  (128)

void audio_extn_set_parameters(struct audio_device *adev,
                               struct str_parms *parms);

@@ -182,11 +184,15 @@ int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card,
#define audio_extn_spkr_prot_start_processing(snd_device)    (-EINVAL)
#define audio_extn_spkr_prot_stop_processing()     (0)
#define audio_extn_spkr_prot_is_enabled() (false)
#define audio_extn_spkr_prot_get_acdb_id(snd_device)         (-EINVAL)
#define audio_extn_get_spkr_prot_snd_device(snd_device) (SND_DEVICE_OUT_SPEAKER)
#else
void audio_extn_spkr_prot_init(void *adev);
int audio_extn_spkr_prot_start_processing(snd_device_t snd_device);
void audio_extn_spkr_prot_stop_processing();
bool audio_extn_spkr_prot_is_enabled();
int audio_extn_spkr_prot_get_acdb_id(snd_device_t snd_device);
int audio_extn_get_spkr_prot_snd_device(snd_device_t snd_device);
#endif

#ifndef COMPRESS_CAPTURE_ENABLED
@@ -246,4 +252,17 @@ bool audio_extn_hfp_is_active(struct audio_device *adev);
audio_usecase_t audio_extn_hfp_get_usecase();
#endif

void audio_extn_utils_update_streams_output_cfg_list(void *platform,
                                  struct mixer *mixer,
                                  struct listnode *streams_output_cfg_list);
void audio_extn_utils_dump_streams_output_cfg_list(
                                  struct listnode *streams_output_cfg_list);
void audio_extn_utils_release_streams_output_cfg_list(
                                  struct listnode *streams_output_cfg_list);
void audio_extn_utils_update_stream_app_type_cfg(void *platform,
                                  struct listnode *streams_output_cfg_list,
                                  audio_output_flags_t flags,
                                  audio_format_t format,
                                  struct stream_app_type_cfg *app_type_cfg);
int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase);
#endif /* AUDIO_EXTN_H */
+19 −0
Original line number Diff line number Diff line
@@ -577,6 +577,25 @@ void audio_extn_spkr_prot_init(void *adev)
    }
}

int audio_extn_spkr_prot_get_acdb_id(snd_device_t snd_device)
{
    int acdb_id;

    acdb_id = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
              platform_get_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED) :
              -EINVAL;

    return acdb_id;
}

int audio_extn_get_spkr_prot_snd_device(snd_device_t snd_device)
{
    if ((snd_device == SND_DEVICE_OUT_SPEAKER) && handle.spkr_prot_enable)
        return SND_DEVICE_OUT_SPEAKER_PROTECTED;
    else
        return snd_device;
}

int audio_extn_spkr_prot_start_processing(snd_device_t snd_device)
{
    struct audio_usecase uc_info_tx;

hal/audio_extn/utils.c

0 → 100644
+446 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
 * Not a Contribution.
 *
 * 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.
 */

#define LOG_TAG "audio_hw_utils"
/* #define LOG_NDEBUG 0 */

#include <errno.h>
#include <cutils/properties.h>
#include <cutils/config_utils.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <cutils/str_parms.h>
#include <cutils/log.h>
#include <cutils/misc.h>

#include "audio_hw.h"
#include "platform.h"
#include "platform_api.h"
#include "audio_extn.h"

#define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"

#define OUTPUTS_TAG "outputs"

#define DYNAMIC_VALUE_TAG "dynamic"
#define FLAGS_TAG "flags"
#define FORMATS_TAG "formats"
#define SAMPLING_RATES_TAG "sampling_rates"
#define BIT_WIDTH_TAG "bit_width"
#define APP_TYPE_TAG "app_type"

#define STRING_TO_ENUM(string) { #string, string }
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

struct string_to_enum {
    const char *name;
    uint32_t value;
};

const struct string_to_enum s_flag_name_to_enum_table[] = {
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
#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
};

const struct string_to_enum s_format_name_to_enum_table[] = {
    STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
    STRING_TO_ENUM(AUDIO_FORMAT_MP3),
    STRING_TO_ENUM(AUDIO_FORMAT_AAC),
    STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
#ifdef FORMATS_ENABLED
    STRING_TO_ENUM(AUDIO_FORMAT_AC3),
    STRING_TO_ENUM(AUDIO_FORMAT_EAC3),
    STRING_TO_ENUM(AUDIO_FORMAT_DTS),
    STRING_TO_ENUM(AUDIO_FORMAT_DTS_LBR),
    STRING_TO_ENUM(AUDIO_FORMAT_WMA),
    STRING_TO_ENUM(AUDIO_FORMAT_WMA_PRO),
    STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADIF),
    STRING_TO_ENUM(AUDIO_FORMAT_AMR_NB),
    STRING_TO_ENUM(AUDIO_FORMAT_AMR_WB),
    STRING_TO_ENUM(AUDIO_FORMAT_AMR_WB_PLUS),
    STRING_TO_ENUM(AUDIO_FORMAT_EVRC),
    STRING_TO_ENUM(AUDIO_FORMAT_EVRCB),
    STRING_TO_ENUM(AUDIO_FORMAT_EVRCWB),
    STRING_TO_ENUM(AUDIO_FORMAT_QCELP),
    STRING_TO_ENUM(AUDIO_FORMAT_MP2),
    STRING_TO_ENUM(AUDIO_FORMAT_EVRCNW),
    STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD),
    STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD),
#endif
};

static uint32_t string_to_enum(const struct string_to_enum *table, size_t size,
                               const char *name)
{
    size_t i;
    for (i = 0; i < size; i++) {
        if (strcmp(table[i].name, name) == 0) {
            ALOGV("%s found %s", __func__, table[i].name);
            return table[i].value;
        }
    }
    return 0;
}

static audio_output_flags_t parse_flag_names(char *name)
{
    uint32_t flag = 0;
    char *flag_name = strtok(name, "|");
    while (flag_name != NULL) {
        if (strlen(flag_name) != 0) {
            flag |= string_to_enum(s_flag_name_to_enum_table,
                               ARRAY_SIZE(s_flag_name_to_enum_table),
                               flag_name);
        }
        flag_name = strtok(NULL, "|");
    }

    ALOGV("parse_flag_names: flag - %d", flag);
    return (audio_output_flags_t)flag;
}

static void parse_format_names(char *name, struct streams_output_cfg *so_info)
{
    struct stream_format *sf_info = NULL;
    char *str = strtok(name, "|");

    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0)
        return;

    list_init(&so_info->format_list);
    while (str != NULL) {
        audio_format_t format = (audio_format_t)string_to_enum(s_format_name_to_enum_table,
                                              ARRAY_SIZE(s_format_name_to_enum_table), str);
        ALOGV("%s: format - %d", __func__, format);
        if (format != 0) {
            sf_info = (struct stream_format *)calloc(1, sizeof(struct stream_format));
            sf_info->format = format;
            list_add_tail(&so_info->format_list, &sf_info->list);
        }
        str = strtok(NULL, "|");
    }
}

static int parse_sample_rate_names(char *name)
{
    int sample_rate = 48000;
    char *str = strtok(name, "|");

    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG))
        sample_rate = (int)strtol(str, (char **)NULL, 10);

    ALOGV("%s: sample_rate - %d", __func__, sample_rate);
    return sample_rate;
}

static int parse_bit_width_names(char *name)
{
    int bit_width = 16;
    char *str = strtok(name, "|");

    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG))
        bit_width = (int)strtol(str, (char **)NULL, 10);

    ALOGV("%s: bit_width - %d", __func__, bit_width);
    return bit_width;
}

static int parse_app_type_names(void *platform, char *name)
{
    int app_type = 0; /* TODO: default app type from acdb when exposed using "platform" */
    char *str = strtok(name, "|");

    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG))
        app_type = (int)strtol(str, (char **)NULL, 10);

    ALOGV("%s: app_type - %d", __func__, app_type);
    return app_type;
}

static void update_streams_output_cfg_list(cnode *root, void *platform,
                                           struct listnode *streams_output_cfg_list)
{
    cnode *node = root->first_child;
    struct streams_output_cfg *so_info;

    ALOGV("%s", __func__);
    so_info = (struct streams_output_cfg *)calloc(1, sizeof(struct streams_output_cfg));
    while (node) {
        if (strcmp(node->name, FLAGS_TAG) == 0) {
            so_info->flags = parse_flag_names((char *)node->value);
        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
            parse_format_names((char *)node->value, so_info);
        } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
            so_info->app_type_cfg.sample_rate = parse_sample_rate_names((char *)node->value);
        } else if (strcmp(node->name, BIT_WIDTH_TAG) == 0) {
            so_info->app_type_cfg.bit_width = parse_bit_width_names((char *)node->value);
        } else if (strcmp(node->name, APP_TYPE_TAG) == 0) {
            so_info->app_type_cfg.app_type = parse_app_type_names(platform, (char *)node->value);
        }
        node = node->next;
    }
    list_add_tail(streams_output_cfg_list, &so_info->list);
}

static void load_output(cnode *root, void *platform,
                        struct listnode *streams_output_cfg_list)
{
    cnode *node = config_find(root, OUTPUTS_TAG);
    if (node == NULL) {
        ALOGE("%s: could not load output, node is NULL", __func__);
        return;
    }

    node = node->first_child;
    while (node) {
        ALOGV("%s: loading output %s", __func__, node->name);
        update_streams_output_cfg_list(node, platform, streams_output_cfg_list);
        node = node->next;
    }
}

static void send_app_type_cfg(void *platform, struct mixer *mixer,
                              struct listnode *streams_output_cfg_list)
{
    int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {-1};
    int length = 0, i, num_app_types = 0;
    struct listnode *node;
    bool update;
    struct mixer_ctl *ctl = NULL;
    const char *mixer_ctl_name = "App Type Config";
    struct streams_output_cfg *so_info;

    if (!mixer) {
        ALOGE("%s: mixer is null",__func__);
        return;
    }
    ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
    if (!ctl) {
        ALOGE("%s: Could not get ctl for mixer cmd - %s",__func__, mixer_ctl_name);
        return;
    }
    if (streams_output_cfg_list == NULL) {
        app_type_cfg[length++] = 1;
        app_type_cfg[length++] = 0; /* TODO: default app type from acdb when exposed from "platform" */
        app_type_cfg[length++] = 48000;
        app_type_cfg[length++] = 16;
        mixer_ctl_set_array(ctl, app_type_cfg, length);
        return;
    }

    app_type_cfg[length++] = num_app_types;
    list_for_each(node, streams_output_cfg_list) {
        so_info = node_to_item(node, struct streams_output_cfg, list);
        update = true;
        for (i=0; i<length; i=i+3) {
            if (app_type_cfg[i+1] == -1)
                break;
            else if (app_type_cfg[i+1] == so_info->app_type_cfg.app_type) {
                update = false;
                break;
            }
        }
        if (update && ((length + 3) <= MAX_LENGTH_MIXER_CONTROL_IN_INT)) {
            num_app_types += 1 ;
            app_type_cfg[length++] = so_info->app_type_cfg.app_type;
            app_type_cfg[length++] = so_info->app_type_cfg.sample_rate;
            app_type_cfg[length++] = so_info->app_type_cfg.bit_width;
        }
    }
    ALOGV("%s: num_app_types: %d", __func__, num_app_types);
    if (num_app_types) {
        app_type_cfg[0] = num_app_types;
        mixer_ctl_set_array(ctl, app_type_cfg, length);
    }
}

void audio_extn_utils_update_streams_output_cfg_list(void *platform,
                                       struct mixer *mixer,
                                       struct listnode *streams_output_cfg_list)
{
    cnode *root;
    char *data;

    ALOGV("%s", __func__);
    list_init(streams_output_cfg_list);
    data = (char *)load_file(AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE, NULL);
    if (data == NULL) {
        send_app_type_cfg(platform, mixer, NULL);
        ALOGE("%s: could not load output policy config file", __func__);
        return;
    }

    root = config_node("", "");
    config_load(root, data);
    load_output(root, platform, streams_output_cfg_list);

    send_app_type_cfg(platform, mixer, streams_output_cfg_list);
}

void audio_extn_utils_dump_streams_output_cfg_list(
                                       struct listnode *streams_output_cfg_list)
{
    int i=0;
    struct listnode *node_i, *node_j;
    struct streams_output_cfg *so_info;
    struct stream_format *sf_info;
    ALOGV("%s", __func__);
    list_for_each(node_i, streams_output_cfg_list) {
        so_info = node_to_item(node_i, struct streams_output_cfg, list);
        ALOGV("%d: flags-%d, output_sample_rate-%d, output_bit_width-%d, app_type-%d",
               i++, so_info->flags, so_info->app_type_cfg.sample_rate,
               so_info->app_type_cfg.bit_width, so_info->app_type_cfg.app_type);
        list_for_each(node_j, &so_info->format_list) {
            sf_info = node_to_item(node_j, struct stream_format, list);
            ALOGV("format-%x", sf_info->format);
        }
    }
}

void audio_extn_utils_release_streams_output_cfg_list(
                                       struct listnode *streams_output_cfg_list)
{
    struct listnode *node_i, *node_j;
    struct streams_output_cfg *so_info;
    struct stream_format *sf_info;

    ALOGV("%s", __func__);
    while (!list_empty(streams_output_cfg_list)) {
        node_i = list_head(streams_output_cfg_list);
        so_info = node_to_item(node_i, struct streams_output_cfg, list);
        while (!list_empty(&so_info->format_list)) {
            node_j = list_head(&so_info->format_list);
            list_remove(node_j);
            free(node_to_item(node_j, struct stream_format, list));
        }
        list_remove(node_i);
        free(node_to_item(node_i, struct streams_output_cfg, list));
    }
}

void audio_extn_utils_update_stream_app_type_cfg(void *platform,
                                  struct listnode *streams_output_cfg_list,
                                  audio_output_flags_t flags,
                                  audio_format_t format,
                                  struct stream_app_type_cfg *app_type_cfg)
{
    struct listnode *node_i, *node_j;
    struct streams_output_cfg *so_info;
    struct stream_format *sf_info;

    ALOGV("%s: flags: %x, format: %x", __func__, flags, format);
    list_for_each(node_i, streams_output_cfg_list) {
        so_info = node_to_item(node_i, struct streams_output_cfg, list);
        if (so_info->flags == flags) {
            list_for_each(node_j, &so_info->format_list) {
                sf_info = node_to_item(node_j, struct stream_format, list);
                if (sf_info->format == format) {
                    ALOGV("App type: %d", so_info->app_type_cfg.app_type);
                    app_type_cfg->app_type = so_info->app_type_cfg.app_type;
                    app_type_cfg->sample_rate = so_info->app_type_cfg.sample_rate;
                    app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
                    return;
                }
            }
        }
    }
    list_for_each(node_i, streams_output_cfg_list) {
        so_info = node_to_item(node_i, struct streams_output_cfg, list);
        if (so_info->flags == AUDIO_OUTPUT_FLAG_PRIMARY) {
            ALOGV("Compatible output profile not found.");
            ALOGV("App type default to primary output: %d", so_info->app_type_cfg.app_type);
            app_type_cfg->app_type = so_info->app_type_cfg.app_type;
            app_type_cfg->sample_rate = so_info->app_type_cfg.sample_rate;
            app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
            return;
        }
    }
    ALOGW("%s: App type could not be selected. Falling back to default", __func__);
    app_type_cfg->app_type = 0; /* TODO: default app type from acdb when exposed from "platform" */
    app_type_cfg->sample_rate = 48000;
    app_type_cfg->bit_width = 16;
}

int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase)
{
    char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
    int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc;
    struct stream_out *out = usecase->stream.out;
    struct audio_device *adev = out->dev;
    struct mixer_ctl *ctl;
    int pcm_device_id, acdb_dev_id, snd_device = usecase->out_snd_device;

    ALOGV("%s", __func__);

    if (usecase->type != PCM_PLAYBACK) {
        ALOGV("%s: not a playback path, no need to cfg app type", __func__);
        rc = 0;
        goto exit_send_app_type_cfg;
    }
    if ((usecase->id != USECASE_AUDIO_PLAYBACK_DEEP_BUFFER) &&
        (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY) &&
        (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
        (usecase->id != USECASE_AUDIO_PLAYBACK_OFFLOAD)) {
        ALOGV("%s: a playback path where app type cfg is not required", __func__);
        rc = 0;
        goto exit_send_app_type_cfg;
    }

    snd_device = usecase->out_snd_device;

    pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);

    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
             "Audio Stream %d App Type Cfg", pcm_device_id);

    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
    if (!ctl) {
        ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
              mixer_ctl_name);
        rc = -EINVAL;
        goto exit_send_app_type_cfg;
    }
    snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
                 audio_extn_get_spkr_prot_snd_device(snd_device) : snd_device;
    acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
    if (acdb_dev_id < 0) {
        ALOGE("%s: Couldn't get the acdb dev id", __func__);
        rc = -EINVAL;
        goto exit_send_app_type_cfg;
    }
    app_type_cfg[len++] = out->app_type_cfg.app_type;
    app_type_cfg[len++] = acdb_dev_id;

    mixer_ctl_set_array(ctl, app_type_cfg, len);

    rc = 0;
exit_send_app_type_cfg:
    return rc;
}
+13 −2
Original line number Diff line number Diff line
@@ -257,6 +257,7 @@ int enable_audio_route(struct audio_device *adev,
    audio_extn_dolby_set_dmid(adev);
    audio_extn_dolby_set_endpoint(adev);
#endif
    audio_extn_utils_send_app_type_cfg(usecase);
    strcpy(mixer_path, use_case_table[usecase->id]);
    platform_add_backend_name(mixer_path, snd_device);
    ALOGV("%s: apply mixer and update path: %s", __func__, mixer_path);
@@ -2218,6 +2219,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
    struct audio_device *adev = (struct audio_device *)dev;
    struct stream_out *out;
    int i, ret = 0;
    audio_format_t format;

    *stream_out = NULL;
    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
@@ -2240,7 +2242,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
    out->flags = flags;
    out->devices = devices;
    out->dev = adev;
    out->format = config->format;
    format = out->format = config->format;
    out->sample_rate = config->sample_rate;
    out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
    out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
@@ -2306,7 +2308,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
            out->channel_mask = config->channel_mask;
            config->offload_info.channel_mask = config->channel_mask;
        }
        out->format = config->offload_info.format;
        format = out->format = config->offload_info.format;
        out->sample_rate = config->offload_info.sample_rate;

        out->stream.set_callback = out_set_callback;
@@ -2366,16 +2368,21 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
            goto error_open;
        }
    } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
        format = AUDIO_FORMAT_PCM_16_BIT;
        out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
        out->config = pcm_config_low_latency;
        out->sample_rate = out->config.rate;
    } else {
        /* primary path is the default path selected if no other outputs are available/suitable */
        format = AUDIO_FORMAT_PCM_16_BIT;
        out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY;
        out->config = pcm_config_deep_buffer;
        out->sample_rate = out->config.rate;
    }

    audio_extn_utils_update_stream_app_type_cfg(adev->platform,
                                                &adev->streams_output_cfg_list,
                                                flags, format, &out->app_type_cfg);
    if ((out->usecase == USECASE_AUDIO_PLAYBACK_PRIMARY) ||
        (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
        /* Ensure the default output is not selected twice */
@@ -2788,6 +2795,7 @@ static int adev_close(hw_device_t *device)

    if ((--audio_device_ref_count) == 0) {
        audio_extn_listen_deinit(adev);
        audio_extn_utils_release_streams_output_cfg_list(&adev->streams_output_cfg_list);
        audio_route_free(adev->audio_route);
        free(adev->snd_dev_ref_cnt);
        platform_deinit(adev->platform);
@@ -2907,6 +2915,9 @@ static int adev_open(const hw_module_t *module, const char *name,

    *device = &adev->device.common;

    audio_extn_utils_update_streams_output_cfg_list(adev->platform, adev->mixer,
                                                    &adev->streams_output_cfg_list);

    audio_device_ref_count++;
    pthread_mutex_unlock(&adev_init_lock);

Loading