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

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

Merge "policy_hal: Enable Direct PCM for 24 bit PCM playback"

parents 538657aa b7de4f18
Loading
Loading
Loading
Loading
+1 −12
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
 * Not a Contribution.
 *
 * Copyright (C) 2013 The Android Open Source Project
@@ -40,17 +40,6 @@

#include <cutils/str_parms.h>

#ifndef PCM_OFFLOAD_ENABLED
#define AUDIO_FORMAT_PCM_OFFLOAD 0x1A000000UL
#define AUDIO_FORMAT_PCM_16_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_16_BIT)
#define AUDIO_FORMAT_PCM_24_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_8_24_BIT)
#define AUDIO_OFFLOAD_CODEC_FORMAT  "music_offload_codec_format"
#define audio_is_offload_pcm(format) (0)
#define OFFLOAD_USE_SMALL_BUFFER false
#else
#define OFFLOAD_USE_SMALL_BUFFER ((info->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD)
#endif

#ifndef AFE_PROXY_ENABLED
#define AUDIO_DEVICE_OUT_PROXY 0x40000
#endif
+3 −4
Original line number Diff line number Diff line
@@ -76,6 +76,8 @@ const struct string_to_enum s_flag_name_to_enum_table[] = {

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_24_BIT_PACKED),
    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
    STRING_TO_ENUM(AUDIO_FORMAT_MP3),
    STRING_TO_ENUM(AUDIO_FORMAT_AAC),
@@ -97,8 +99,6 @@ const struct string_to_enum s_format_name_to_enum_table[] = {
    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),
    STRING_TO_ENUM(AUDIO_FORMAT_FLAC),
    STRING_TO_ENUM(AUDIO_FORMAT_ALAC),
    STRING_TO_ENUM(AUDIO_FORMAT_APE),
@@ -558,8 +558,7 @@ int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase)
        goto exit_send_app_type_cfg;
    }

    if ((24 == usecase->stream.out->bit_width) &&
        (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
    if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
        sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
    } else {
        sample_rate = out->app_type_cfg.sample_rate;
+147 −63
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@
#include "sound/asound.h"

#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
/*DIRECT PCM has same buffer sizes as DEEP Buffer*/
#define DIRECT_PCM_NUM_FRAGMENTS 2
/* ToDo: Check and update a proper value in msec */
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
@@ -168,8 +170,8 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = {
    [USECASE_AUDIO_PLAYBACK_ULL]         = "audio-ull-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",
#ifdef MULTIPLE_OFFLOAD_ENABLED
    [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5",
@@ -178,7 +180,6 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = {
    [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
    [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
#endif
    [USECASE_AUDIO_DIRECT_PCM_OFFLOAD] = "compress-offload-playback2",

    [USECASE_AUDIO_RECORD] = "audio-record",
    [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
@@ -213,8 +214,8 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = {

static const audio_usecase_t offload_usecases[] = {
    USECASE_AUDIO_PLAYBACK_OFFLOAD,
#ifdef MULTIPLE_OFFLOAD_ENABLED
    USECASE_AUDIO_PLAYBACK_OFFLOAD2,
#ifdef MULTIPLE_OFFLOAD_ENABLED
    USECASE_AUDIO_PLAYBACK_OFFLOAD3,
    USECASE_AUDIO_PLAYBACK_OFFLOAD4,
    USECASE_AUDIO_PLAYBACK_OFFLOAD5,
@@ -223,7 +224,6 @@ static const audio_usecase_t offload_usecases[] = {
    USECASE_AUDIO_PLAYBACK_OFFLOAD8,
    USECASE_AUDIO_PLAYBACK_OFFLOAD9,
#endif
    USECASE_AUDIO_DIRECT_PCM_OFFLOAD,
};

#define STRING_TO_ENUM(string) { #string, string }
@@ -254,17 +254,16 @@ static pthread_mutex_t adev_init_lock;
static unsigned int audio_device_ref_count;


static int check_and_set_gapless_mode(struct audio_device *adev) {


    char value[PROPERTY_VALUE_MAX] = {0};
static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless) {
    bool gapless_enabled = false;
    const char *mixer_ctl_name = "Compress Gapless Playback";
    struct mixer_ctl *ctl;

    ALOGV("%s:", __func__);
    property_get("audio.offload.gapless.enabled", value, NULL);
    gapless_enabled = atoi(value) || !strncmp("true", value, 4);
    gapless_enabled = property_get_bool("audio.offload.gapless.enabled", false);

    /*Disable gapless if its AV playback*/
    gapless_enabled = gapless_enabled && enable_gapless;

    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
    if (!ctl) {
@@ -287,8 +286,8 @@ static bool is_supported_format(audio_format_t format)
        format == AUDIO_FORMAT_AAC_LC ||
        format == AUDIO_FORMAT_AAC_HE_V1 ||
        format == AUDIO_FORMAT_AAC_HE_V2 ||
        format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
        format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD ||
        format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
        format == AUDIO_FORMAT_PCM_8_24_BIT ||
        format == AUDIO_FORMAT_PCM_16_BIT ||
        format == AUDIO_FORMAT_FLAC ||
        format == AUDIO_FORMAT_ALAC ||
@@ -312,7 +311,6 @@ static int get_snd_codec_id(audio_format_t format)
    case AUDIO_FORMAT_AAC:
        id = SND_AUDIOCODEC_AAC;
        break;
    case AUDIO_FORMAT_PCM_OFFLOAD:
    case AUDIO_FORMAT_PCM:
        id = SND_AUDIOCODEC_PCM;
        break;
@@ -1196,26 +1194,33 @@ bool is_offload_usecase(audio_usecase_t uc_id)
    return false;
}

static audio_usecase_t get_offload_usecase(struct audio_device *adev)
static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_direct_pcm)
{
    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 */
    audio_usecase_t ret_uc = USECASE_INVALID;
    unsigned int offload_uc_index;
    unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
    if (!adev->multi_offload_enable) {
        if (is_direct_pcm)
            ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2;
        else
            ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD;
        pthread_mutex_lock(&adev->lock);
        if (get_usecase_from_list(adev, ret_uc) != NULL)
           ret_uc = USECASE_INVALID;
        pthread_mutex_unlock(&adev->lock);
        return ret_uc;
    }

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

static void free_offload_usecase(struct audio_device *adev,
@@ -1647,7 +1652,7 @@ int start_output_stream(struct stream_out *out)
           for the default max poll time (20s) in the event of an SSR.
           Reduce the poll time to observe and deal with SSR faster.
        */
        if (out->use_small_bufs) {
        if (!out->non_blocking) {
            compress_set_max_poll_wait(out->compr, 1000);
        }

@@ -1664,7 +1669,7 @@ int start_output_stream(struct stream_out *out)
            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);
                adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer);
            audio_extn_check_and_set_dts_hpx_state(adev);
        }
    }
@@ -1743,6 +1748,37 @@ static size_t get_input_buffer_size(uint32_t sample_rate,
    return size;
}

static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out)
{
    uint64_t actual_frames_rendered = 0;
    size_t kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments;

    /* This adjustment accounts for buffering after app processor.
     * It is based on estimated DSP latency per use case, rather than exact.
     */
    int64_t platform_latency =  platform_render_latency(out->usecase) *
                                          out->sample_rate / 1000000LL;

    /* not querying actual state of buffering in kernel as it would involve an ioctl call
     * which then needs protection, this causes delay in TS query for pcm_offload usecase
     * hence only estimate.
     */
    int64_t signed_frames = out->written - kernel_buffer_size;

    signed_frames = signed_frames / (audio_bytes_per_sample(out->format) * popcount(out->channel_mask)) - platform_latency;

    if (signed_frames > 0)
        actual_frames_rendered = signed_frames;

     ALOGVV("%s signed frames %lld out_written %lld kernel_buffer_size %d"
            "bytes/sample %zu channel count %d", __func__,(long long int)signed_frames,
             (long long int)out->written, (int)kernel_buffer_size,
             audio_bytes_per_sample(out->compr_config.codec->format),
             popcount(out->channel_mask));

    return actual_frames_rendered;
}

static uint32_t out_get_sample_rate(const struct audio_stream *stream)
{
    struct stream_out *out = (struct stream_out *)stream;
@@ -2203,6 +2239,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
            out_standby(&out->stream.common);
            return ret;
        }
        if ( ret == (ssize_t)bytes && !out->non_blocking)
            out->written += bytes;

        if (!out->playback_started && ret >= 0) {
            compress_start(out->compr);
            audio_extn_dts_eagle_fade(adev, true, out);
@@ -2277,8 +2316,18 @@ static int out_get_render_position(const struct audio_stream_out *stream,
    *dsp_frames = 0;
    if (is_offload_usecase(out->usecase)) {
        ssize_t ret = 0;

        /* Below piece of code is not guarded against any lock beacuse audioFliner serializes
         * this operation and adev_close_output_stream(where out gets reset).
         */
        if (!out->non_blocking && (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) {
            *dsp_frames = get_actual_pcm_frames_rendered(out);
             ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate);
             return 0;
        }

        lock_output_stream(out);
        if (out->compr != NULL) {
        if (out->compr != NULL  && out->non_blocking) {
            ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
                    &out->sample_rate);
            if (ret < 0)
@@ -2329,19 +2378,36 @@ static int out_get_presentation_position(const struct audio_stream_out *stream,
    int ret = -1;
    unsigned long dsp_frames;

    /* below piece of code is not guarded against any lock because audioFliner serializes
     * this operation and adev_close_output_stream( where out gets reset).
     */
    if (is_offload_usecase(out->usecase) && !out->non_blocking &&
        (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) {
        *frames = get_actual_pcm_frames_rendered(out);
        /* this is the best we can do */
        clock_gettime(CLOCK_MONOTONIC, timestamp);
        ALOGVV("frames %lld playedat %lld",(long long int)*frames,
             timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000);
        return 0;
    }
    lock_output_stream(out);

    if (is_offload_usecase(out->usecase)) {
        if (out->compr != NULL) {
            compress_get_tstamp(out->compr, &dsp_frames,
    if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) {
        ret = compress_get_tstamp(out->compr, &dsp_frames,
                    &out->sample_rate);
        ALOGVV("%s rendered frames %ld sample_rate %d",
                   __func__, dsp_frames, out->sample_rate);
        *frames = dsp_frames;
        if (ret < 0)
            ret = -errno;
        if (-ENETRESET == ret) {
            ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
            set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
            ret = -EINVAL;
        } else
            ret = 0;
            /* this is the best we can do */
        clock_gettime(CLOCK_MONOTONIC, timestamp);
        }
    } else {
        if (out->pcm) {
            unsigned int avail;
@@ -2458,6 +2524,7 @@ static int out_flush(struct audio_stream_out* stream)
        ALOGD("copl(%p):calling compress flush", out);
        lock_output_stream(out);
        stop_compressed_output_l(out);
        out->written = 0;
        pthread_mutex_unlock(&out->lock);
        ALOGD("copl(%p):out of compress flush", out);
        return 0;
@@ -2853,7 +2920,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
    out->handle = handle;
    out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
    out->non_blocking = 0;
    out->use_small_bufs = false;

    /* Init use case and pcm_config */
    if ((out->flags & AUDIO_OUTPUT_FLAG_DIRECT) &&
@@ -2929,11 +2995,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        }

        if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
            ALOGV("%s:: inserting DIRECT_PCM _USECASE", __func__);
            out->usecase = USECASE_AUDIO_DIRECT_PCM_OFFLOAD;
            out->stream.pause = out_pause;
            out->stream.flush = out_flush;
            out->stream.resume = out_resume;
            out->usecase = get_offload_usecase(adev, true);
            ALOGV("DIRECT_PCM usecase ... usecase selected %d ", out->usecase);
        } else {
            ALOGV("%s:: inserting OFFLOAD_USECASE", __func__);
            out->usecase = get_offload_usecase(adev);
            out->usecase = get_offload_usecase(adev, false);

            out->stream.set_callback = out_set_callback;
            out->stream.pause = out_pause;
@@ -2941,6 +3010,19 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
            out->stream.drain = out_drain;
            out->stream.flush = out_flush;
        }

        if (out->usecase == USECASE_INVALID) {
            if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL &&
                    config->format == 0 && config->sample_rate == 0 &&
                    config->channel_mask == 0) {
                ALOGI("%s dummy open to query sink capability",__func__);
                out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
            } else {
                ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__);
                ret = -EEXIST;
                goto error_open;
            }
        }
        if (config->offload_info.channel_mask)
            out->channel_mask = config->offload_info.channel_mask;
        else if (config->channel_mask) {
@@ -2960,18 +3042,19 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
            out->compr_config.codec->id =
                get_snd_codec_id(config->offload_info.format);

        if (((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD)||
             ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM)) {
        if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) {
            out->compr_config.fragment_size =
               platform_get_pcm_offload_buffer_size(&config->offload_info);
            out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
        } 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);
            out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
        } else {
            out->compr_config.fragment_size =
               platform_get_compress_offload_buffer_size(&config->offload_info);
        }
            out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
        }
        out->compr_config.codec->sample_rate =
                    config->offload_info.sample_rate;
        out->compr_config.codec->bit_rate =
@@ -2985,16 +3068,12 @@ static int adev_open_output_stream(struct audio_hw_device *dev,

        if (config->offload_info.format == AUDIO_FORMAT_AAC)
            out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
        if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD)
            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
        if (config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
        if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT)
            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;

        if (out->bit_width == 24) {
        if (config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_3LE;
        if (config->offload_info.format == AUDIO_FORMAT_PCM_8_24_BIT)
            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
        }

        if (config->offload_info.format == AUDIO_FORMAT_FLAC)
            out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
@@ -3002,15 +3081,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
            out->non_blocking = 1;

        if (platform_use_small_buffer(&config->offload_info)) {
            //this flag is set from framework only if its for PCM formats
            //no need to check for PCM format again
            out->non_blocking = 0;
            out->use_small_bufs = true;
            ALOGI("Keep write blocking for small buff: non_blockling %d",
                  out->non_blocking);
        }

        out->send_new_metadata = 1;
        out->send_next_track_params = false;
        out->is_compr_metadata_avail = false;
@@ -3023,8 +3093,21 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
                __func__, config->offload_info.version,
                config->offload_info.bit_rate);
        //Decide if we need to use gapless mode by default
        check_and_set_gapless_mode(adev);
        /* Disable gapless if any of the following is true
         * passthrough playback
         * AV playback
         * Direct PCM playback
         */
        if (audio_extn_dolby_is_passthrough_stream(out->flags) ||
            config->offload_info.has_video ||
            out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
            check_and_set_gapless_mode(adev, false);
        } else
            check_and_set_gapless_mode(adev, true);

        if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
            out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
        }
    } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
        ret = voice_check_and_set_incall_music_usecase(adev, out);
        if (ret != 0) {
@@ -3812,7 +3895,7 @@ static int adev_open(const hw_module_t *module, const char *name,
            ALOGV("%s: DLOPEN successful for %s", __func__,
                  OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
            adev->offload_effects_start_output =
                        (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
                        (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib,
                                         "offload_effects_bundle_hal_start_output");
            adev->offload_effects_stop_output =
                        (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
@@ -3874,6 +3957,7 @@ static int adev_open(const hw_module_t *module, const char *name,
        }
    }

    adev->multi_offload_enable = property_get_bool("audio.offload.multiple.enabled", false);
    pthread_mutex_unlock(&adev_init_lock);

    if (adev->adm_init)
+3 −6
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
 * Not a contribution.
 *
 * Copyright (C) 2013 The Android Open Source Project
@@ -85,7 +85,6 @@ 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,
@@ -94,10 +93,8 @@ enum {
    USECASE_AUDIO_PLAYBACK_OFFLOAD7,
    USECASE_AUDIO_PLAYBACK_OFFLOAD8,
    USECASE_AUDIO_PLAYBACK_OFFLOAD9,
#endif
    USECASE_AUDIO_PLAYBACK_ULL,

    USECASE_AUDIO_DIRECT_PCM_OFFLOAD,

    /* FM usecase */
    USECASE_AUDIO_PLAYBACK_FM,
@@ -206,7 +203,6 @@ struct stream_out {
    struct stream_app_type_cfg app_type_cfg;

    int non_blocking;
    bool use_small_bufs;
    int playback_started;
    int offload_state;
    pthread_cond_t offload_cond;
@@ -334,7 +330,7 @@ struct audio_device {
    int (*visualizer_start_output)(audio_io_handle_t, int);
    int (*visualizer_stop_output)(audio_io_handle_t, int);
    void *offload_effects_lib;
    int (*offload_effects_start_output)(audio_io_handle_t, int);
    int (*offload_effects_start_output)(audio_io_handle_t, int, struct mixer *);
    int (*offload_effects_stop_output)(audio_io_handle_t, int);

    struct sound_card_status snd_card_status;
@@ -349,6 +345,7 @@ struct audio_device {
    adm_deregister_stream_t adm_deregister_stream;
    adm_request_focus_t adm_request_focus;
    adm_abandon_focus_t adm_abandon_focus;
    bool multi_offload_enable;
};

int select_devices(struct audio_device *adev,
+12 −13
Original line number Diff line number Diff line
@@ -522,6 +522,7 @@ static int msm_device_to_be_id_external_codec [][NO_COLS] = {


#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
#define PCM_OFFLOAD_PLATFORM_DELAY (30*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)

static void query_platform(const char *snd_card_name,
@@ -2392,7 +2393,7 @@ void platform_get_parameters(void *platform,
    free(kv_pairs);
}

/* Delay in Us */
/* Delay in Us, only to be used for PCM formats */
int64_t platform_render_latency(audio_usecase_t usecase)
{
    switch (usecase) {
@@ -2400,6 +2401,9 @@ int64_t platform_render_latency(audio_usecase_t usecase)
            return DEEP_BUFFER_PLATFORM_DELAY;
        case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
            return LOW_LATENCY_PLATFORM_DELAY;
        case USECASE_AUDIO_PLAYBACK_OFFLOAD:
        case USECASE_AUDIO_PLAYBACK_OFFLOAD2:
             return PCM_OFFLOAD_PLATFORM_DELAY;
        default:
            return 0;
    }
@@ -2435,7 +2439,6 @@ bool platform_listen_usecase_needs_event(audio_usecase_t uc_id)
    case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
    case USECASE_AUDIO_PLAYBACK_MULTI_CH:
    case USECASE_AUDIO_PLAYBACK_OFFLOAD:
    case USECASE_AUDIO_DIRECT_PCM_OFFLOAD:
        needs_event = true;
        break;
    /* concurrent playback in low latency allowed */
@@ -2497,7 +2500,6 @@ bool platform_sound_trigger_usecase_needs_event(audio_usecase_t uc_id)
    case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
    case USECASE_AUDIO_PLAYBACK_MULTI_CH:
    case USECASE_AUDIO_PLAYBACK_OFFLOAD:
    case USECASE_AUDIO_DIRECT_PCM_OFFLOAD:
        needs_event = true;
        break;
    /* concurrent playback in low latency allowed */
@@ -2569,19 +2571,17 @@ uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info)
uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
{
    uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
    uint32_t bits_per_sample = 16;
    uint32_t bytes_per_sample;
    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION;

    if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
        bits_per_sample = 32;
    }
    bytes_per_sample = audio_bytes_per_sample(info->format);

    //duration is set to 40 ms worth of stereo data at 48Khz
    //with 16 bit per sample, modify this when the channel
    //configuration is different
    fragment_size = (pcm_offload_time
                     * info->sample_rate
                     * (bits_per_sample >> 3)
                     * bytes_per_sample
                     * popcount(info->channel_mask))/1000;
    fragment_size = ALIGN( fragment_size, 1024);

@@ -2590,15 +2590,14 @@ uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
    else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;

    // To have same PCM samples for all channels, the buffer size requires to
    // be multiple of (number of channels * bytes per sample)
    // For writes to succeed, the buffer must be written at address which is multiple of 32
    fragment_size = ALIGN(fragment_size, ((bytes_per_sample) * popcount(info->channel_mask) * 32));
    ALOGV("%s: fragment_size %d", __func__, fragment_size);
    return fragment_size;
}

bool platform_use_small_buffer(audio_offload_info_t* info)
{
    return OFFLOAD_USE_SMALL_BUFFER;
}

void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
{
     *device_to_be_id = msm_device_to_be_id;
Loading