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

Commit 57c030e7 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 PCM in offload path"

parents 15d877ab 0c566872
Loading
Loading
Loading
Loading
+27 −29
Original line number Diff line number Diff line
@@ -53,14 +53,14 @@
#include "voice_extn.h"

#include "sound/compress_params.h"
#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (8 * 1024)
#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
#include "sound/asound.h"

#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
/* ToDo: Check and update a proper value in msec */
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000


#define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER

struct pcm_config pcm_config_deep_buffer = {
@@ -153,28 +153,6 @@ static unsigned int audio_device_ref_count;

static int set_voice_volume_l(struct audio_device *adev, float volume);

/* Read  offload buffer size from a property.
 * If value is not power of 2  round it to
 * power of 2.
 */
static uint32_t get_offload_buffer_size()
{
    char value[PROPERTY_VALUE_MAX] = {0};
    uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
    if((property_get("audio.offload.buffer.size.kb", value, "")) &&
            atoi(value)) {
        fragment_size =  atoi(value) * 1024;
        //ring buffer size needs to be 4k aligned.
        CHECK(!(fragment_size * COMPRESS_OFFLOAD_NUM_FRAGMENTS % 4096));
    }
    if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
        fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
    else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
        fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
    ALOGVV("%s: fragment_size %d", __func__, fragment_size);
    return fragment_size;
}

static int check_and_set_gapless_mode(struct audio_device *adev) {


@@ -205,7 +183,9 @@ static int check_and_set_gapless_mode(struct audio_device *adev) {
static bool is_supported_format(audio_format_t format)
{
    if (format == AUDIO_FORMAT_MP3 ||
            format == AUDIO_FORMAT_AAC)
        format == AUDIO_FORMAT_AAC ||
        format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
        format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
           return true;

    return false;
@@ -222,6 +202,10 @@ static int get_snd_codec_id(audio_format_t format)
    case AUDIO_FORMAT_AAC:
        id = SND_AUDIOCODEC_AAC;
        break;
    case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD:
    case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD:
        id = SND_AUDIOCODEC_PCM;
        break;
    default:
        ALOGE("%s: Unsupported audio format :%x", __func__, format);
    }
@@ -2147,8 +2131,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;

@@ -2165,7 +2151,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
        else
            out->compr_config.codec->id =
                get_snd_codec_id(config->offload_info.format);
        out->compr_config.fragment_size = get_offload_buffer_size();

        if (audio_is_offload_pcm(config->offload_info.format)) {
            out->compr_config.fragment_size =
                       platform_get_pcm_offload_buffer_size(&config->offload_info);
        } 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 =
                    compress_get_alsa_rate(config->offload_info.sample_rate);
@@ -2175,6 +2168,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
                    popcount(config->channel_mask);
        out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;

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

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

+84 −0
Original line number Diff line number Diff line
@@ -31,12 +31,30 @@
#include "platform.h"
#include "audio_extn.h"
#include "voice_extn.h"
#include "sound/compress_params.h"

#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
#define LIB_ACDB_LOADER "libacdbloader.so"
#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"

#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
#define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)

/* Used in calculating fragment size for pcm offload */
#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 2000 /* 2 secs */
#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 100 /* 100 millisecs */

/* MAX PCM fragment size cannot be increased  further due
 * to flinger's cblk size of 1mb,and it has to be a multiple of
 * 24 - lcm of channels supported by DSP
 */
#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (32 * 1024)

#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1)))
/*
 * This file will have a maximum of 38 bytes:
 *
@@ -1579,3 +1597,69 @@ bool platform_listen_update_status(snd_device_t snd_device)
    else
        return false;
}

/* Read  offload buffer size from a property.
 * If value is not power of 2  round it to
 * power of 2.
 */
uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info)
{
    char value[PROPERTY_VALUE_MAX] = {0};
    uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
    if((property_get("audio.offload.buffer.size.kb", value, "")) &&
            atoi(value)) {
        fragment_size =  atoi(value) * 1024;
    }

    if (info != NULL && info->has_video && info->is_streaming) {
        fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
        ALOGV("%s: offload fragment size reduced for AV streaming to %d",
               __func__, out->compr_config.fragment_size);
    }

    fragment_size = ALIGN( fragment_size, 1024);

    if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
        fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
    else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
        fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
    ALOGV("%s: fragment_size %d", __func__, fragment_size);
    return fragment_size;
}

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;

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

    if (!info->has_video) {
        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;

    } else if (info->has_video && info->is_streaming) {
        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING
                                     * info->sample_rate
                                     * bits_per_sample
                                     * popcount(info->channel_mask))/1000;

    } else if (info->has_video) {
        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
                                     * info->sample_rate
                                     * bits_per_sample
                                     * popcount(info->channel_mask))/1000;
    }

    fragment_size = ALIGN( fragment_size, 1024);

    if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
        fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
    else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;

    ALOGV("%s: fragment_size %d", __func__, fragment_size);
    return fragment_size;
}
+5 −1
Original line number Diff line number Diff line
@@ -57,4 +57,8 @@ int platform_update_usecase_from_source(int source, audio_usecase_t usecase);

bool platform_listen_update_status(snd_device_t snd_device);

#endif // QCOM_AUDIO_PLATFORM_API_H
struct audio_offload_info_t;
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);

#endif // AUDIO_PLATFORM_API_H
+123 −0
Original line number Diff line number Diff line
@@ -881,6 +881,129 @@ float AudioPolicyManager::computeVolume(int stream,
#endif
    return AudioPolicyManagerBase::computeVolume(stream, index, output, device);
}

// This function checks for the parameters which can be offloaded.
// This can be enhanced depending on the capability of the DSP and policy
// of the system.
bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadInfo)
{
    ALOGV(" isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d,"
     " BitRate=%u, duration=%lld us, has_video=%d",
     offloadInfo.sample_rate, offloadInfo.channel_mask,
     offloadInfo.format,
     offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
     offloadInfo.has_video);

#ifdef VOICE_CONCURRENCY
    if(isInCall())
    {
        ALOGD("\n  blocking  compress offload on call mode\n");
        return false;
    }
#endif
    // Check if stream type is music, then only allow offload as of now.
    if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
    {
        ALOGV("isOffloadSupported: stream_type != MUSIC, returning false");
        return false;
    }

    char propValue[PROPERTY_VALUE_MAX];
    bool pcmOffload = false;
    if (audio_is_offload_pcm(offloadInfo.format)) {
        if(property_get("audio.offload.pcm.enable", propValue, NULL)) {
            bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4);
            if (prop_enabled) {
                ALOGW("PCM offload property is enabled");
                pcmOffload = true;
            }
        }
        if (!pcmOffload) {
            ALOGV("PCM offload disabled by property audio.offload.pcm.enable");
            return false;
        }
    }

    if (!pcmOffload) {
        // Check if offload has been disabled
        if (property_get("audio.offload.disable", propValue, "0")) {
            if (atoi(propValue) != 0) {
                ALOGV("offload disabled by audio.offload.disable=%s", propValue );
                return false;
            }
        }

        //check if it's multi-channel AAC format
        if (AudioSystem::popCount(offloadInfo.channel_mask) > 2
              && offloadInfo.format == AUDIO_FORMAT_AAC) {
            ALOGV("offload disabled for multi-channel AAC format");
            return false;
        }

        if (offloadInfo.has_video)
        {
            if(property_get("av.offload.enable", propValue, NULL)) {
                bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4);
                if (!prop_enabled) {
                    ALOGW("offload disabled by av.offload.enable = %s ", propValue );
                    return false;
                }
            } else {
                return false;
            }

            if(offloadInfo.is_streaming) {
                if (property_get("av.streaming.offload.enable", propValue, NULL)) {
                    bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4);
                    if (!prop_enabled) {
                       ALOGW("offload disabled by av.streaming.offload.enable = %s ", propValue );
                       return false;
                    }
                } else {
                    //Do not offload AV streamnig if the property is not defined
                    return false;
                }
            }
            ALOGV("isOffloadSupported: has_video == true, property\
                    set to enable offload");
        }
    }

    //If duration is less than minimum value defined in property, return false
    if (property_get("audio.offload.min.duration.secs", propValue, NULL)) {
        if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) {
            ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue);
            return false;
        }
    } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
        ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS);
        //duration checks only valid for MP3/AAC formats,
        //do not check duration for other audio formats, e.g. dolby AAC/AC3 and amrwb+ formats
        if (offloadInfo.format == AUDIO_FORMAT_MP3 || offloadInfo.format == AUDIO_FORMAT_AAC || pcmOffload)
            return false;
    }

    // Do not allow offloading if one non offloadable effect is enabled. This prevents from
    // creating an offloaded track and tearing it down immediately after start when audioflinger
    // detects there is an active non offloadable effect.
    // FIXME: We should check the audio session here but we do not have it in this context.
    // This may prevent offloading in rare situations where effects are left active by apps
    // in the background.
    if (isNonOffloadableEffectEnabled()) {
        return false;
    }

    // See if there is a profile to support this.
    // AUDIO_DEVICE_NONE
    IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
                                            offloadInfo.sample_rate,
                                            offloadInfo.format,
                                            offloadInfo.channel_mask,
                                            AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
    ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT ");
    return (profile != NULL);
}

extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
    return new AudioPolicyManager(clientInterface);
+2 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ public:
                                            uint32_t format,
                                            uint32_t channels,
                                            AudioSystem::audio_in_acoustics acoustics);
        virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);

protected:
        // return the strategy corresponding to a given stream type
        static routing_strategy getStrategy(AudioSystem::stream_type stream);