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

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

Merge "hal: Add support for multiple instances of offload playback"

parents 2bd2c9e6 16ff4f86
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -126,6 +126,9 @@ ifeq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DDP)),true)
endif
endif

ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTIPLE_TUNNEL)), true)
    LOCAL_CFLAGS += -DMULTIPLE_OFFLOAD_ENABLED
endif

LOCAL_SHARED_LIBRARIES := \
	liblog \
+27 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ static struct audio_extn_module aextnmod = {
#define AUDIO_PARAMETER_KEY_WFD        "wfd_channel_cap"
#define AUDIO_PARAMETER_CAN_OPEN_PROXY "can_open_proxy"
#define AUDIO_PARAMETER_CUSTOM_STEREO  "stereo_as_dual_mono"
/* Query offload playback instances count */
#define AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE "offload_num_active"

#ifndef FM_ENABLED
#define audio_extn_fm_set_parameters(adev, parms) (0)
@@ -424,6 +426,30 @@ int32_t audio_extn_get_afe_proxy_channel_count()

#endif /* AFE_PROXY_ENABLED */

static int get_active_offload_usecases(const struct audio_device *adev,
                                       struct str_parms *query,
                                       struct str_parms *reply)
{
    int ret, count = 0;
    char value[32]={0};
    struct listnode *node;
    struct audio_usecase *usecase;

    ALOGV("%s", __func__);
    ret = str_parms_get_str(query, AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE, value,
                            sizeof(value));
    if (ret >= 0) {
        list_for_each(node, &adev->usecase_list) {
            usecase = node_to_item(node, struct audio_usecase, list);
            if (is_offload_usecase(usecase->id))
                count++;
        }
        ALOGV("%s, number of active offload usecases: %d", __func__, count);
        str_parms_add_int(reply, AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE, count);
    }
    return ret;
}

void audio_extn_set_parameters(struct audio_device *adev,
                               struct str_parms *parms)
{
@@ -444,6 +470,7 @@ void audio_extn_get_parameters(const struct audio_device *adev,
    char *kv_pairs = NULL;
    audio_extn_get_afe_proxy_parameters(query, reply);
    audio_extn_get_fluence_parameters(adev, query, reply);
    get_active_offload_usecases(adev, query, reply);

    kv_pairs = str_parms_to_str(reply);
    ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
+88 −20
Original line number Diff line number Diff line
@@ -107,6 +107,16 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = {
    [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
#ifdef MULTIPLE_OFFLOAD_ENABLED
    [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD6] = "compress-offload-playback6",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
#endif
    [USECASE_AUDIO_RECORD] = "audio-record",
    [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
    [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
@@ -134,6 +144,19 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = {
    [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
};

static const audio_usecase_t offload_usecases[] = {
    USECASE_AUDIO_PLAYBACK_OFFLOAD,
#ifdef MULTIPLE_OFFLOAD_ENABLED
    USECASE_AUDIO_PLAYBACK_OFFLOAD2,
    USECASE_AUDIO_PLAYBACK_OFFLOAD3,
    USECASE_AUDIO_PLAYBACK_OFFLOAD4,
    USECASE_AUDIO_PLAYBACK_OFFLOAD5,
    USECASE_AUDIO_PLAYBACK_OFFLOAD6,
    USECASE_AUDIO_PLAYBACK_OFFLOAD7,
    USECASE_AUDIO_PLAYBACK_OFFLOAD8,
    USECASE_AUDIO_PLAYBACK_OFFLOAD9,
#endif
};

#define STRING_TO_ENUM(string) { #string, string }

@@ -877,6 +900,51 @@ static void stop_compressed_output_l(struct stream_out *out)
    }
}

bool is_offload_usecase(audio_usecase_t uc_id)
{
    unsigned int i;
    for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
        if (uc_id == offload_usecases[i])
            return true;
    }
    return false;
}

static audio_usecase_t get_offload_usecase(struct audio_device *adev)
{
    audio_usecase_t ret = USECASE_AUDIO_PLAYBACK_OFFLOAD;
    unsigned int i, num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
    char value[PROPERTY_VALUE_MAX] = {0};

    property_get("audio.offload.multiple.enabled", value, NULL);
    if (!(atoi(value) || !strncmp("true", value, 4)))
        num_usecase = 1; /* If prop is not set, limit the num of offload usecases to 1 */

    ALOGV("%s: num_usecase: %d", __func__, num_usecase);
    for (i = 0; i < num_usecase; i++) {
        if (!(adev->offload_usecases_state & (0x1<<i))) {
            adev->offload_usecases_state |= 0x1 << i;
            ret = offload_usecases[i];
            break;
        }
    }
    ALOGV("%s: offload usecase is %d", __func__, ret);
    return ret;
}

static void free_offload_usecase(struct audio_device *adev,
                                 audio_usecase_t uc_id)
{
    unsigned int i;
    for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
        if (offload_usecases[i] == uc_id) {
            adev->offload_usecases_state &= ~(0x1<<i);
            break;
        }
    }
    ALOGV("%s: free offload usecase %d", __func__, uc_id);
}

static void *offload_thread_loop(void *context)
{
    struct stream_out *out = (struct stream_out *) context;
@@ -1024,7 +1092,7 @@ static bool allow_hdmi_channel_config(struct audio_device *adev)
                      "no change in HDMI channels", __func__);
                ret = false;
                break;
            } else if (usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD &&
            } else if (is_offload_usecase(usecase->id) &&
                       popcount(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);
@@ -1097,7 +1165,7 @@ static int stop_output_stream(struct stream_out *out)
        return -EINVAL;
    }

    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        if (adev->visualizer_stop_output != NULL)
            adev->visualizer_stop_output(out->handle, out->pcm_device_id);
        if (adev->offload_effects_stop_output != NULL)
@@ -1147,7 +1215,7 @@ int start_output_stream(struct stream_out *out)

    /* This must be called before adding this usecase to the list */
    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
        if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
        if (is_offload_usecase(out->usecase))
            check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in);
        else
            check_and_set_hdmi_channels(adev, out->config.channels);
@@ -1159,7 +1227,7 @@ int start_output_stream(struct stream_out *out)

    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)",
          __func__, 0, out->pcm_device_id);
    if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (!is_offload_usecase(out->usecase)) {
        out->pcm = pcm_open(adev->snd_card,
                            out->pcm_device_id,
                            PCM_OUT | PCM_MONOTONIC, &out->config);
@@ -1277,7 +1345,7 @@ static size_t out_get_buffer_size(const struct audio_stream *stream)
{
    struct stream_out *out = (struct stream_out *)stream;

    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
    if (is_offload_usecase(out->usecase))
        return out->compr_config.fragment_size;
    else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
        return voice_extn_compress_voip_out_get_buffer_size(out);
@@ -1323,7 +1391,7 @@ static int out_standby(struct audio_stream *stream)
    if (!out->standby) {
        pthread_mutex_lock(&adev->lock);
        out->standby = true;
        if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
        if (!is_offload_usecase(out->usecase)) {
            if (out->pcm) {
                pcm_close(out->pcm);
                out->pcm = NULL;
@@ -1490,7 +1558,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
        audio_extn_set_parameters(adev, parms);
        pthread_mutex_unlock(&adev->lock);
    }
    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        pthread_mutex_lock(&out->lock);
        parse_compress_metadata(out, parms);
        pthread_mutex_unlock(&out->lock);
@@ -1549,7 +1617,7 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream)
{
    struct stream_out *out = (struct stream_out *)stream;

    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
    if (is_offload_usecase(out->usecase))
        return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;

    return (out->config.period_count * out->config.period_size * 1000) /
@@ -1566,7 +1634,7 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
        /* only take left channel into account: the API is for stereo anyway */
        out->muted = (left == 0.0f);
        return 0;
    } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    } else if (is_offload_usecase(out->usecase)) {
        char mixer_ctl_name[128];
        struct audio_device *adev = out->dev;
        struct mixer_ctl *ctl;
@@ -1613,7 +1681,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
        }
    }

    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        ALOGD("copl(%x): writing buffer (%d bytes) to compress device", (unsigned int)out, bytes);
        if (out->send_new_metadata) {
            ALOGD("copl(%x):send new gapless metadata", (unsigned int)out);
@@ -1663,7 +1731,7 @@ static int out_get_render_position(const struct audio_stream_out *stream,
{
    struct stream_out *out = (struct stream_out *)stream;
    *dsp_frames = 0;
    if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
    if (is_offload_usecase(out->usecase) && (dsp_frames != NULL)) {
        pthread_mutex_lock(&out->lock);
        if (out->compr != NULL) {
            compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
@@ -1702,7 +1770,7 @@ static int out_get_presentation_position(const struct audio_stream_out *stream,

    pthread_mutex_lock(&out->lock);

    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        if (out->compr != NULL) {
            compress_get_tstamp(out->compr, &dsp_frames,
                    &out->sample_rate);
@@ -1756,7 +1824,7 @@ static int out_pause(struct audio_stream_out* stream)
    struct stream_out *out = (struct stream_out *)stream;
    int status = -ENOSYS;
    ALOGV("%s", __func__);
    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        ALOGD("copl(%x):pause compress driver", (unsigned int)out);
        pthread_mutex_lock(&out->lock);
        if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
@@ -1773,7 +1841,7 @@ static int out_resume(struct audio_stream_out* stream)
    struct stream_out *out = (struct stream_out *)stream;
    int status = -ENOSYS;
    ALOGV("%s", __func__);
    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        ALOGD("copl(%x):resume compress driver", (unsigned int)out);
        status = 0;
        pthread_mutex_lock(&out->lock);
@@ -1791,7 +1859,7 @@ static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
    struct stream_out *out = (struct stream_out *)stream;
    int status = -ENOSYS;
    ALOGV("%s", __func__);
    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        pthread_mutex_lock(&out->lock);
        if (type == AUDIO_DRAIN_EARLY_NOTIFY)
            status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
@@ -1806,7 +1874,7 @@ static int out_flush(struct audio_stream_out* stream)
{
    struct stream_out *out = (struct stream_out *)stream;
    ALOGV("%s", __func__);
    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        ALOGD("copl(%x):calling compress flush", (unsigned int)out);
        pthread_mutex_lock(&out->lock);
        stop_compressed_output_l(out);
@@ -2169,7 +2237,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        out->compr_config.codec = (struct snd_codec *)
                                    calloc(1, sizeof(struct snd_codec));

        out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
        out->usecase = get_offload_usecase(adev);
        if (config->offload_info.channel_mask)
            out->channel_mask = config->offload_info.channel_mask;
        else if (config->channel_mask) {
@@ -2324,9 +2392,9 @@ static void adev_close_output_stream(struct audio_hw_device *dev,
    else
        out_standby(&stream->common);

    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
    if (is_offload_usecase(out->usecase)) {
        destroy_offload_callback_thread(out);

        free_offload_usecase(adev, out->usecase);
        if (out->compr_config.codec != NULL)
            free(out->compr_config.codec);
    }
@@ -2702,7 +2770,7 @@ static int adev_open(const hw_module_t *module, const char *name,
    voice_init(adev);
    list_init(&adev->usecase_list);
    adev->cur_wfd_channels = 2;

    adev->offload_usecases_state = 0;
    /* Loads platform specific libraries dynamically */
    adev->platform = platform_init(adev);
    if (!adev->platform) {
+14 −2
Original line number Diff line number Diff line
@@ -65,6 +65,16 @@ typedef enum {
    USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
    USECASE_AUDIO_PLAYBACK_MULTI_CH,
    USECASE_AUDIO_PLAYBACK_OFFLOAD,
#ifdef MULTIPLE_OFFLOAD_ENABLED
    USECASE_AUDIO_PLAYBACK_OFFLOAD2,
    USECASE_AUDIO_PLAYBACK_OFFLOAD3,
    USECASE_AUDIO_PLAYBACK_OFFLOAD4,
    USECASE_AUDIO_PLAYBACK_OFFLOAD5,
    USECASE_AUDIO_PLAYBACK_OFFLOAD6,
    USECASE_AUDIO_PLAYBACK_OFFLOAD7,
    USECASE_AUDIO_PLAYBACK_OFFLOAD8,
    USECASE_AUDIO_PLAYBACK_OFFLOAD9,
#endif

    /* FM usecase */
    USECASE_AUDIO_PLAYBACK_FM,
@@ -234,7 +244,7 @@ struct audio_device {

    int snd_card;
    void *platform;

    unsigned int offload_usecases_state;
    void *visualizer_lib;
    int (*visualizer_start_output)(audio_io_handle_t, int);
    int (*visualizer_stop_output)(audio_io_handle_t, int);
@@ -260,6 +270,8 @@ int enable_audio_route(struct audio_device *adev,
struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
                                                   audio_usecase_t uc_id);

bool is_offload_usecase(audio_usecase_t uc_id);

#define LITERAL_TO_STRING(x) #x
#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
            __FILE__ ":" LITERAL_TO_STRING(__LINE__)\
+18 −0
Original line number Diff line number Diff line
@@ -139,6 +139,24 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
                                        MULTIMEDIA2_PCM_DEVICE},
    [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
                     {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
#ifdef MULTIPLE_OFFLOAD_ENABLED
    [USECASE_AUDIO_PLAYBACK_OFFLOAD2] =
                     {PLAYBACK_OFFLOAD_DEVICE2, PLAYBACK_OFFLOAD_DEVICE2},
    [USECASE_AUDIO_PLAYBACK_OFFLOAD3] =
                     {PLAYBACK_OFFLOAD_DEVICE3, PLAYBACK_OFFLOAD_DEVICE3},
    [USECASE_AUDIO_PLAYBACK_OFFLOAD4] =
                     {PLAYBACK_OFFLOAD_DEVICE4, PLAYBACK_OFFLOAD_DEVICE4},
    [USECASE_AUDIO_PLAYBACK_OFFLOAD5] =
                     {PLAYBACK_OFFLOAD_DEVICE5, PLAYBACK_OFFLOAD_DEVICE5},
    [USECASE_AUDIO_PLAYBACK_OFFLOAD6] =
                     {PLAYBACK_OFFLOAD_DEVICE6, PLAYBACK_OFFLOAD_DEVICE6},
    [USECASE_AUDIO_PLAYBACK_OFFLOAD7] =
                     {PLAYBACK_OFFLOAD_DEVICE7, PLAYBACK_OFFLOAD_DEVICE7},
    [USECASE_AUDIO_PLAYBACK_OFFLOAD8] =
                     {PLAYBACK_OFFLOAD_DEVICE8, PLAYBACK_OFFLOAD_DEVICE8},
    [USECASE_AUDIO_PLAYBACK_OFFLOAD9] =
                     {PLAYBACK_OFFLOAD_DEVICE9, PLAYBACK_OFFLOAD_DEVICE9},
#endif
    [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
    [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
    [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
Loading