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

Change-Id: I2064d646b66e8283fce2cc736e96fb93cba0a552
This commit is contained in:
ApurupaPattapu 2014-01-10 14:46:02 -08:00
parent c4ad7c0214
commit c6a3a9e6ed
4 changed files with 168 additions and 63 deletions

View File

@ -53,16 +53,14 @@
#include "voice_extn.h"
#include "sound/compress_params.h"
#include "sound/asound.h"
#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)
#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 = {
@ -155,35 +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(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;
//ring buffer size needs to be 4k aligned.
CHECK(!(fragment_size * COMPRESS_OFFLOAD_NUM_FRAGMENTS % 4096));
}
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);
}
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) {
@ -214,8 +183,10 @@ 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)
return true;
format == AUDIO_FORMAT_AAC ||
format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
return true;
return false;
}
@ -231,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);
}
@ -2161,8 +2136,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;
@ -2179,7 +2156,13 @@ 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(&config->offload_info);
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);
@ -2190,6 +2173,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
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;
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;

View File

@ -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:
*
@ -1694,3 +1712,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;
}

View File

@ -62,4 +62,8 @@ bool platform_listen_update_status(snd_device_t snd_device);
/* From platform_info_parser.c */
int platform_info_init(void);
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

View File

@ -1116,16 +1116,6 @@ bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadI
return false;
}
#endif
// Check if offload has been disabled
char propValue[PROPERTY_VALUE_MAX];
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 stream type is music, then only allow offload as of now.
if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
{
@ -1133,26 +1123,65 @@ bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadI
return false;
}
//TODO: enable audio offloading with video when ready
if (offloadInfo.has_video)
{
if(property_get("av.offload.enable", propValue, NULL)) {
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("offload disabled by av.offload.enable = %s ", propValue );
return false;
if (prop_enabled) {
ALOGW("PCM offload property is enabled");
pcmOffload = true;
}
}
if(offloadInfo.is_streaming &&
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;
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;
}
}
ALOGV("isOffloadSupported: has_video == true, property\
set to enable offload");
//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
@ -1165,7 +1194,7 @@ bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadI
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)
if (offloadInfo.format == AUDIO_FORMAT_MP3 || offloadInfo.format == AUDIO_FORMAT_AAC || pcmOffload)
return false;
}