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

Commit b56a2b2f authored by Steve Kondik's avatar Steve Kondik
Browse files

hal: Squashed support for new offload features

hal: add extended audio definitions in hal

- Add audio_defs.h in hal for extended audio
  definitions.

hal: Add support for PCM in offload path

- Translate PCM Offload format to pcm codec id
- Set 16/24 sub format id in compress params format
- Calculate offload fragment size for pcm
- Move offload calculation functions to platform file
- Update audio policy manager isOffloadSupported
  for pcm offload profile. Use audio.offload.pcm.enable

hal: set gapless metadata for compress  offload playback

-If any of the  metadata parameters are set from the framework.
 set the gapless metadata to one.

CRs-Fixed: 588353

hal: Support for FLAC 24 bit format in offload path

- Add flac in supported codecs list
- Set FLAC codec specific parameters
- Set fragment size based on bit width and sampling rate
  for flac
- Configure backend to 24/16 bit based on the current
  usecases running

hal: Fix backend configuration for 24 bit offload playback

Backend sample rate configuration follows:
16 bit playback - 48khz for streams at any valid sample rate
24 bit playback - 48khz for stream sample rate upto 48khz
24 bit playback - 96khz for sample rate range of 48khz to 96khz
24 bit playback - 192khz for sample rate range of 96khz to 192 khz
For invalid or out of range sample rate, default rate is 48K
Upper limit is inclusive in the sample rate range

 audio: Update error number in HAL

- Error number is not propagated from pcm/compress driver on
  pcm/compress error
- Read error number in HAL from errno define

hal: Fix backend configuration during stream switch

-Currently, input stream sample rate and/or bit width is compared
with current backend sample rate and/or bit width. Backend is
re-configured only if input stream's rate/width is higher. This
causes incorrect sampling rate during stream switch of varying
sample rates.
-The backend is configured at highest bit width and/or sample rate
amongst all active playback usecases.
-By setting the backend re-configuration flag only when the selected
sample rate and/or bit width differ with current backend sample rate
and/or bit width, re-routing is enabled and backend is re-configured.
-Exception: 16 bit playbacks is allowed through 16/48 backend only.
-Enable logs for app type, acdb id and sample rate.

hal: fix 24bit compilation error with extended flag disabled

- use PCM_OUTPUT_BIT_WIDTH instead of out->bit_width to fix
  compilation errors while it is not defined in audio.h

hal: Fix backend for 24 bit playback on speaker

Configure backend at 48khz for 24 bit playback on speakers.
Currently, ADM can be configured only at the begining of stream
playback. During device switch, in the middle of a playback, the
backend remains at the previous configuration.
By allowing ADM and backend re-configuration during playback, 24-bit
playback is enforced on appropriate backend.

hal: Fix combo device configuration for 24 bit playback on speaker

-Fix combo device configuration for 24 bit playback on speaker
-Move exception hadndling code to audio_extn

hal: Remove checks for 24 bit platform support

Check for 24 bit in HAL is not needed as the check for 24 bit
platform support is achieved through flags in frameworks.

hal: fix voice call mute issue

The backend is always configured with default bit width and sample
rate for voice calls. The backend reconfiguration should not be done
when a new stream starts during voice call.

CRs-fixed: 747001

hal: bug fixes for PCM offload

When pcm offload is done, override the buffer size
that was calculated and use the value from the system property
Make write call blocking if small buffers are used in offload
Update latency value for pcm offload with small buffer hint based
on period size and period count.

hal: send additional param for gapless flac

Currently, metadata such as min/max block size is sent only for first
stream in FLAC gapless playback. This causes incorrect configuration
and, subsequently, framedrops in decoding of second stream and onwards
Sending additional parameters

CRs-Fixed: 781837

hal: align fragment size to 24 instead of 1024 for PCM offload

Aligning PCM buffer size to 1024 bytes is not required in case
of PCM offloading. It actually creates problem when playing
6 ch, 96KHz, 16-bit stream PCM in offload mode, due to aligning
PCM data becomes unequal for the six channels.
Align the buffer to LCM of 2, 4, 6, 8 i.e. 24.

CRs-fixed: 780001

hal: Fix bit width for 24 bit PCM offload playback

PCM offload bit width is selected as 16 bit even for 24 bit pcm offload
playback streams if QTI_FLAC_DECODER flag is not defined. Fix this issue
by defining appropriate flag PCM_OFFLOAD_ENABLED_24.

hal: Reduce offload latency and log spam

Offload latency is set to 96. Change
it to 50 to reflect the rendering latency more correctly
Modify pcm offload latency to return offload
latency rather than the latency based on buffering
since volume is applied immediately for offload use
cases. Also reduce log spam in offload use cases

CRs-Fixed: 787448

hal: Fix alignement of of buffer sent to DSP

Currently, ALIGN macro can align properly only if the buffer size
is a power of 2.
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.
Alignment of 96 satsfies both of the above requirements.

CRs-Fixed: 795936

hal : Avoid use of small buf flag and bit width info.

 -small buf flag and bit width info are not member of offload into
  structure.
 -avoid use of small buf flag and bit width info, use PCM offload
  format.

audio: hal: Add support to send codec specific data in gapless

Codec specific metadata is sent only for first stream in gapless
playback.
This causes incorrect configuration to be set for second
stream and distortions are observed due to framedrops in adsp.
Add support to send codec specific format data of second stream
during gapless playback.

Use vorbis bitstream format info from metadata instead of hardcoding.
This avoids sending gapless metadata each time set parameters
is called during vorbis playback.

Set flag to send new metadata at start of session for first track
and for the next stream in gapless after return from partial drain.

hal: set output bitwidth to 24 bit for 32 bit data.

 - parser gives 32 bit data for 24 bit AIFF playback and same
   is sent down to HAL.
 - So update bit width to 24 bit if offload info bit width is 32 bit
   to configure back end to 24 bit for 24 bit e2e playback.

hal: check offload_callback not NULL before calling

- in case when offload o/p stream is created in blocking mode
  flinger do not sets the callback pointer. So check for offload
  callback pointer before calling.

hal: Increase PCM offload buffering

Increase PCM offload buffering to 40ms

Change-Id: I13fbab3518a1e7e4314ce112d673469f0a30d457
CRs-Fixed: 924443
parent 9f78676f
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -108,6 +108,19 @@ ifneq ($(filter msm8992 msm8994,$(TARGET_BOARD_PLATFORM)),)
  LOCAL_SRC_FILES += audio_extn/hwdep_cal.c
endif

ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true)
    LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
endif

ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FLAC_OFFLOAD)),true)
    LOCAL_CFLAGS += -DFLAC_OFFLOAD_ENABLED
    LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
endif

LOCAL_COPY_HEADERS_TO   := mm-audio
LOCAL_COPY_HEADERS      := audio_extn/audio_defs.h

LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)

LOCAL_MODULE_RELATIVE_PATH := hw
+78 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following
 *      disclaimer in the documentation and/or other materials provided
 *      with the distribution.
 *    * Neither the name of The Linux Foundation nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef AUDIO_DEFS_H
#define AUDIO_DEFS_H


/**
 * extended audio codec parameters
 */

#define AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG "music_offload_wma_format_tag"
#define AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN "music_offload_wma_block_align"
#define AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE "music_offload_wma_bit_per_sample"
#define AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK "music_offload_wma_channel_mask"
#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION "music_offload_wma_encode_option"
#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1 "music_offload_wma_encode_option1"
#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2 "music_offload_wma_encode_option2"
#define AUDIO_OFFLOAD_CODEC_FORMAT  "music_offload_codec_format"
#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE "music_offload_flac_min_blk_size"
#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE "music_offload_flac_max_blk_size"
#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size"
#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size"

/* Query handle fm parameter*/
#define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm"

/* Query fm volume */
#define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume"

/* Query Fluence type */
#define AUDIO_PARAMETER_KEY_FLUENCE "fluence"
#define AUDIO_PARAMETER_VALUE_QUADMIC "quadmic"
#define AUDIO_PARAMETER_VALUE_DUALMIC "dualmic"
#define AUDIO_PARAMETER_KEY_NO_FLUENCE "none"

/* Query if surround sound recording is supported */
#define AUDIO_PARAMETER_KEY_SSR "ssr"

/* Query if a2dp  is supported */
#define AUDIO_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported"

/* Query ADSP Status */
#define AUDIO_PARAMETER_KEY_ADSP_STATUS "ADSP_STATUS"

/* Query Sound Card Status */
#define AUDIO_PARAMETER_KEY_SND_CARD_STATUS "SND_CARD_STATUS"

/* Query if Proxy can be Opend */
#define AUDIO_PARAMETER_KEY_CAN_OPEN_PROXY "can_open_proxy"

#endif /* AUDIO_DEFS_H */
+43 −0
Original line number Diff line number Diff line
@@ -29,7 +29,50 @@
#include "platform.h"
#include "platform_api.h"

#include "sound/compress_params.h"

#ifndef COMPRESS_METADATA_NEEDED
#define audio_extn_parse_compress_metadata(out, parms) (0)
#else
int audio_extn_parse_compress_metadata(struct stream_out *out,
                                       struct str_parms *parms)
{
    int ret = 0;
    char value[32];

#ifdef FLAC_OFFLOAD_ENABLED
    if (out->format == AUDIO_FORMAT_FLAC) {
        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE, value, sizeof(value));
        if (ret >= 0) {
            out->compr_config.codec->options.flac_dec.min_blk_size = atoi(value);
            out->is_compr_metadata_avail = true;
        }
        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value));
        if (ret >= 0) {
            out->compr_config.codec->options.flac_dec.max_blk_size = atoi(value);
            out->is_compr_metadata_avail = true;
        }
        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value));
        if (ret >= 0) {
            out->compr_config.codec->options.flac_dec.min_frame_size = atoi(value);
            out->is_compr_metadata_avail = true;
        }
        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value));
        if (ret >= 0) {
            out->compr_config.codec->options.flac_dec.max_frame_size = atoi(value);
            out->is_compr_metadata_avail = true;
        }
        ALOGV("FLAC metadata: min_blk_size %d, max_blk_size %d min_frame_size %d max_frame_size %d",
              out->compr_config.codec->options.flac_dec.min_blk_size,
              out->compr_config.codec->options.flac_dec.max_blk_size,
              out->compr_config.codec->options.flac_dec.min_frame_size,
              out->compr_config.codec->options.flac_dec.max_frame_size);
    }
#endif

    return ret;
}
#endif

#ifdef KPI_OPTIMIZE_ENABLED
typedef int (*perf_lock_acquire_t)(int, int, int*, int);
+22 −0
Original line number Diff line number Diff line
@@ -25,6 +25,28 @@ void audio_extn_extspk_update(void* extn);
void audio_extn_extspk_set_mode(void* extn, audio_mode_t mode);
void audio_extn_extspk_set_voice_vol(void* extn, float vol);

#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)
#endif

#ifndef FLAC_OFFLOAD_ENABLED
#define AUDIO_FORMAT_FLAC 0x1B000000UL
#endif

#ifndef COMPRESS_METADATA_NEEDED
#define audio_extn_parse_compress_metadata(out, parms) (0)
#else
int audio_extn_parse_compress_metadata(struct stream_out *out,
                                       struct str_parms *parms);
#endif

#define AUDIO_OUTPUT_BIT_WIDTH ((config->offload_info.bit_width == 32) ? 24\
                                   :config->offload_info.bit_width)

#ifndef SPKR_PROT_ENABLED
#define audio_extn_spkr_prot_init(adev)       (0)
#define audio_extn_spkr_prot_start_processing(snd_device)    (-EINVAL)
+156 −39
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013-2014 The Android Open Source Project
 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
 * Not a Contribution.
 *
 * Copyright (C) 2013 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.
@@ -51,12 +54,13 @@
#include "voice_extn.h"

#include "sound/compress_params.h"
#include "sound/asound.h"

#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
// 2 buffers causes problems with high bitrate files
#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 3
/* ToDo: Check and update a proper value in msec */
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000

#define PROXY_OPEN_RETRY_COUNT           100
@@ -222,15 +226,24 @@ bool audio_hw_send_gain_dep_calibration(int level) {

static bool is_supported_format(audio_format_t format)
{
    switch (format) {
        case AUDIO_FORMAT_MP3:
        case AUDIO_FORMAT_AAC_LC:
        case AUDIO_FORMAT_AAC_HE_V1:
        case AUDIO_FORMAT_AAC_HE_V2:
    if (format == AUDIO_FORMAT_MP3 ||
        format == AUDIO_FORMAT_AAC ||
        format == AUDIO_FORMAT_AAC_LC ||
        format == AUDIO_FORMAT_AAC_HE_V1 ||
        format == AUDIO_FORMAT_AAC_HE_V2)
        return true;
        default:
            break;
    }

#ifdef PCM_OFFLOAD_ENABLED
    if (format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
        format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
        return true;
#endif

#ifdef FLAC_OFFLOAD_ENABLED
    if (format == AUDIO_FORMAT_FLAC)
        return true;
#endif

    return false;
}

@@ -245,8 +258,19 @@ static int get_snd_codec_id(audio_format_t format)
    case AUDIO_FORMAT_AAC:
        id = SND_AUDIOCODEC_AAC;
        break;
#ifdef PCM_OFFLOAD_ENABLED
    case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD:
    case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD:
        id = SND_AUDIOCODEC_PCM;
        break;
#endif
#ifdef FLAC_OFFLOAD_ENABLED
    case AUDIO_FORMAT_FLAC:
        id = SND_AUDIOCODEC_FLAC;
        break;
#endif
    default:
        ALOGE("%s: Unsupported audio format", __func__);
        ALOGE("%s: Unsupported audio format %x", __func__, format);
    }

    return id;
@@ -415,6 +439,15 @@ static void check_and_route_playback_usecases(struct audio_device *adev,
     * because of the limitation that both the devices cannot be enabled
     * at the same time as they share the same backend.
     */
    /*
     * This call is to check if we need to force routing for a particular stream
     * If there is a backend configuration change for the device when a
     * new stream starts, then ADM needs to be closed and re-opened with the new
     * configuraion. This call check if we need to re-route all the streams
     * associated with the backend. Touch tone + 24 bit playback.
     */
    bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info);

    /* Disable all the usecases on the shared backend other than the
       specified usecase */
    for (i = 0; i < AUDIO_USECASE_MAX; i++)
@@ -424,7 +457,7 @@ static void check_and_route_playback_usecases(struct audio_device *adev,
        usecase = node_to_item(node, struct audio_usecase, list);
        if (usecase->type != PCM_CAPTURE &&
                usecase != uc_info &&
                usecase->out_snd_device != snd_device &&
                (usecase->out_snd_device != snd_device || force_routing) &&
                usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND &&
                platform_check_backends_match(snd_device, usecase->out_snd_device)) {
            ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
@@ -909,6 +942,7 @@ static void *offload_thread_loop(void *context)
{
    struct stream_out *out = (struct stream_out *) context;
    struct listnode *item;
    int ret = 0;

    out->offload_state = OFFLOAD_STATE_IDLE;
    out->playback_started = 0;
@@ -961,12 +995,24 @@ static void *offload_thread_loop(void *context)
            event = STREAM_CBK_EVENT_WRITE_READY;
            break;
        case OFFLOAD_CMD_PARTIAL_DRAIN:
            compress_next_track(out->compr);
            ret = compress_next_track(out->compr);
            if(ret == 0) {
                ALOGD("copl(%p):calling compress_partial_drain", out);
                compress_partial_drain(out->compr);
                ALOGD("copl(%p):out of compress_partial_drain", out);
            }
            else if(ret == -ETIMEDOUT)
                compress_drain(out->compr);
            else
                ALOGE("%s: Next track returned error %d",__func__, ret);

            send_callback = true;
            event = STREAM_CBK_EVENT_DRAIN_READY;
            pthread_mutex_lock(&out->lock);
            /* Resend the metadata for next iteration */
            out->send_new_metadata = 1;
            out->send_next_track_params = true;
            pthread_mutex_unlock(&out->lock);
            break;
        case OFFLOAD_CMD_DRAIN:
            compress_drain(out->compr);
@@ -980,7 +1026,7 @@ static void *offload_thread_loop(void *context)
        lock_output_stream(out);
        out->offload_thread_blocked = false;
        pthread_cond_signal(&out->cond);
        if (send_callback) {
        if (send_callback && out->offload_callback) {
            ALOGVV("%s: sending offload_callback event %d", __func__, event);
            out->offload_callback(event, NULL, out->offload_cookie);
        }
@@ -1218,6 +1264,9 @@ int start_output_stream(struct stream_out *out)
            ret = -EIO;
            goto error_open;
        }
        /* compress_open sends params of the track, so reset the flag here */
        out->is_compr_metadata_avail = false;

        if (out->offload_callback)
            compress_nonblock(out->compr, out->non_blocking);

@@ -1362,6 +1411,8 @@ static int out_standby(struct audio_stream *stream)
            }
        } else {
            stop_compressed_output_l(out);
            out->send_next_track_params = false;
            out->is_compr_metadata_avail = false;
            out->gapless_mdata.encoder_delay = 0;
            out->gapless_mdata.encoder_padding = 0;
            if (out->compr != NULL) {
@@ -1386,28 +1437,23 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par
{
    int ret = 0;
    char value[32];
    struct compr_gapless_mdata tmp_mdata;

    if (!out || !parms) {
        ALOGE("%s: return invalid ",__func__);
        return -EINVAL;
    }

    ret = audio_extn_parse_compress_metadata(out, parms);

    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
    if (ret >= 0) {
        tmp_mdata.encoder_delay = atoi(value); //whats a good limit check?
    } else {
        return -EINVAL;
        out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
    }

    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
    if (ret >= 0) {
        tmp_mdata.encoder_padding = atoi(value);
    } else {
        return -EINVAL;
        out->gapless_mdata.encoder_padding = atoi(value);
    }

    out->gapless_mdata = tmp_mdata;
    out->send_new_metadata = 1;
    ALOGV("%s new encoder delay %u and padding %u", __func__,
          out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);

@@ -1497,7 +1543,9 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
    }

    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
        pthread_mutex_lock(&out->lock);
        parse_compress_metadata(out, parms);
        pthread_mutex_unlock(&out->lock);
    }

    str_parms_destroy(parms);
@@ -1547,14 +1595,19 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k
static uint32_t out_get_latency(const struct audio_stream_out *stream)
{
    struct stream_out *out = (struct stream_out *)stream;
    uint32_t latency = 0;

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

    return (out->config.period_count * out->config.period_size * 1000) /
    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
        latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
    } else {
        latency = (out->config.period_count * out->config.period_size * 1000) /
           (out->config.rate);
    }

    ALOGV("%s: Latency %d", __func__, latency);
    return latency;
}

static int out_set_volume(struct audio_stream_out *stream, float left,
                          float right)
{
@@ -1632,14 +1685,22 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
    }

    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
        ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes);
        ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
        if (out->send_new_metadata) {
            ALOGVV("send new gapless metadata");
            compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
            out->send_new_metadata = 0;
            if (out->send_next_track_params && out->is_compr_metadata_avail) {
                ALOGD("copl(%p):send next track params in gapless", out);
                compress_set_next_track_param(out->compr, &(out->compr_config.codec->options));
                out->send_next_track_params = false;
                out->is_compr_metadata_avail = false;
            }
        }

        ret = compress_write(out->compr, buffer, bytes);
        if (ret < 0)
            ret = -errno;
        ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret);
        if (ret >= 0 && ret < (ssize_t)bytes) {
            send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
@@ -1666,7 +1727,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
            else
                ret = pcm_write(out->pcm, (void *)buffer, bytes);

            if (ret == 0)
            if (ret < 0)
                ret = -errno;
            else if (ret == 0)
                out->written += bytes / (out->config.channels * sizeof(short));

            if (adev->adm_abandon_focus)
@@ -1691,19 +1754,22 @@ static int out_get_render_position(const struct audio_stream_out *stream,
                                   uint32_t *dsp_frames)
{
    struct stream_out *out = (struct stream_out *)stream;
    ssize_t ret = 0;
    *dsp_frames = 0;
    if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
        lock_output_stream(out);
        if (out->compr != NULL) {
            compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
            ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
                    &out->sample_rate);
            if (ret < 0)
                ret = -errno;
            ALOGVV("%s rendered frames %d sample_rate %d",
                   __func__, *dsp_frames, out->sample_rate);
        }
        pthread_mutex_unlock(&out->lock);
        return 0;
    } else
        return -EINVAL;
    }
    return ret;
}

static int out_add_audio_effect(const struct audio_stream *stream __unused,
@@ -2016,6 +2082,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
            ret = pcm_mmap_read(in->pcm, buffer, bytes);
        } else
            ret = pcm_read(in->pcm, buffer, bytes);
        if (ret < 0)
            ret = -errno;
    }

    if (adev->adm_abandon_focus)
@@ -2117,7 +2185,8 @@ 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;
    int i, ret = 0;
    int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;

    ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)",
          __func__, config->sample_rate, config->channel_mask, devices, flags);
@@ -2135,6 +2204,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
    out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
    out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
    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 &&
@@ -2177,8 +2249,10 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
        if (config->offload_info.channel_mask)
            out->channel_mask = config->offload_info.channel_mask;
        else if (config->channel_mask)
        else if (config->channel_mask) {
            out->channel_mask = config->channel_mask;
            config->offload_info.channel_mask = config->channel_mask;
        }
        out->format = config->offload_info.format;
        out->sample_rate = config->offload_info.sample_rate;

@@ -2187,10 +2261,18 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        out->stream.resume = out_resume;
        out->stream.drain = out_drain;
        out->stream.flush = out_flush;
        out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;

        out->compr_config.codec->id =
                get_snd_codec_id(config->offload_info.format);
        out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
#ifdef PCM_OFFLOAD_ENABLED
        if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD)
            out->compr_config.fragment_size =
                       platform_get_pcm_offload_buffer_size(&config->offload_info);
        else
#endif
            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 =
@@ -2198,11 +2280,35 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        out->compr_config.codec->ch_in =
                audio_channel_count_from_out_mask(config->channel_mask);
        out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
        out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;

        if (config->offload_info.format == AUDIO_FORMAT_AAC)
            out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;

#ifdef PCM_OFFLOAD_ENABLED
        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 (out->bit_width == 24) {
            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
        }
#endif

#ifdef FLAC_OFFLOAD_ENABLED
        if (config->offload_info.format == AUDIO_FORMAT_FLAC)
            out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
#endif

        if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
            out->non_blocking = 1;

        out->send_new_metadata = 1;
        out->send_next_track_params = false;
        out->is_compr_metadata_avail = false;
        out->offload_state = OFFLOAD_STATE_IDLE;
        out->playback_started = 0;

        create_offload_callback_thread(out);
        ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
                __func__, config->offload_info.version,
@@ -2263,6 +2369,15 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
    ALOGV("%s: Usecase(%s) config->format %#x  out->config.format %#x\n",
            __func__, use_case_table[out->usecase], config->format, out->config.format);

    if ((24 == out->bit_width) &&
        (devices == AUDIO_DEVICE_OUT_SPEAKER)) {
        sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
        ALOGI("%s 24-bit playback on Speaker is allowed ONLY at 48khz. Hence changing sample rate to: %d",
               __func__, sample_rate);
    } else {
        sample_rate = out->sample_rate;
    }

    if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
        if(adev->primary_output == NULL)
            adev->primary_output = out;
@@ -2891,6 +3006,8 @@ static int adev_open(const hw_module_t *module, const char *name,
    adev->bluetooth_nrec = true;
    adev->acdb_settings = TTY_MODE_OFF;
    /* adev->cur_hdmi_channels = 0;  by calloc() */
    adev->cur_codec_backend_samplerate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
    adev->cur_codec_backend_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
    adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
    voice_init(adev);
    list_init(&adev->usecase_list);
Loading