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.

Change-Id: Ic74caa6bd172c8e4554384e9fa98a5137117f07c
This commit is contained in:
Alexy Joseph 2014-12-03 02:46:47 -08:00
parent a8646d9d71
commit aa54c87a7e
3 changed files with 50 additions and 27 deletions

View File

@ -1944,12 +1944,23 @@ 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) static uint32_t out_get_latency(const struct audio_stream_out *stream)
{ {
struct stream_out *out = (struct stream_out *)stream; struct stream_out *out = (struct stream_out *)stream;
uint32_t latency = 0;
if (is_offload_usecase(out->usecase)) if (is_offload_usecase(out->usecase)) {
return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; if (out->use_small_bufs == true)
latency = ((out->compr_config.fragments *
return (out->config.period_count * out->config.period_size * 1000) / out->compr_config.fragment_size * 1000) /
(out->sample_rate * out->compr_config.codec->ch_in *
audio_bytes_per_sample(out->format)));
else
latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
} else {
latency = (out->config.period_count * out->config.period_size * 1000) /
(out->config.rate); (out->config.rate);
}
ALOGV("%s: Latency %d", latency);
return latency;
} }
static int out_set_volume(struct audio_stream_out *stream, float left, static int out_set_volume(struct audio_stream_out *stream, float left,
@ -2642,6 +2653,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
out->handle = handle; out->handle = handle;
out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
out->non_blocking = 0;
out->use_small_bufs = false;
/* Init use case and pcm_config */ /* Init use case and pcm_config */
if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) && if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
@ -2776,6 +2789,15 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
out->non_blocking = 1; out->non_blocking = 1;
if (config->offload_info.use_small_bufs) {
//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_new_metadata = 1;
out->offload_state = OFFLOAD_STATE_IDLE; out->offload_state = OFFLOAD_STATE_IDLE;
out->playback_started = 0; out->playback_started = 0;

View File

@ -181,6 +181,7 @@ struct stream_out {
struct stream_app_type_cfg app_type_cfg; struct stream_app_type_cfg app_type_cfg;
int non_blocking; int non_blocking;
bool use_small_bufs;
int playback_started; int playback_started;
int offload_state; int offload_state;
pthread_cond_t offload_cond; pthread_cond_t offload_cond;

View File

@ -63,6 +63,8 @@
/* Used in calculating fragment size for pcm offload */ /* Used in calculating fragment size for pcm offload */
#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */ #define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */
#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */ #define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */
#define PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS 20 /* 20 millisecs */
#define PCM_OFFLOAD_BUFFER_DURATION_MAX 1200 /* 1200 millisecs */
/* MAX PCM fragment size cannot be increased further due /* MAX PCM fragment size cannot be increased further due
* to flinger's cblk size of 1mb,and it has to be a multiple of * to flinger's cblk size of 1mb,and it has to be a multiple of
@ -2898,44 +2900,42 @@ 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 platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
{ {
uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; uint32_t fragment_size = 0;
uint32_t bits_per_sample = 16; uint32_t bits_per_sample = 16;
uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
bits_per_sample = 32; bits_per_sample = 32;
} }
if (!info->has_video) { if (info->use_small_bufs) {
fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE; pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
} else {
} else if (info->has_video && info->is_streaming) { if (!info->has_video) {
fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_MAX;
* info->sample_rate } else if (info->has_video && info->is_streaming) {
* (bits_per_sample >> 3) pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING;
* popcount(info->channel_mask))/1000; } else if (info->has_video) {
pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV;
} else if (info->has_video) { }
fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
* info->sample_rate
* (bits_per_sample >> 3)
* popcount(info->channel_mask))/1000;
} }
char value[PROPERTY_VALUE_MAX] = {0}; //duration is set to 20 ms worth of stereo data at 48Khz
if((property_get("audio.offload.pcm.buffer.size", value, "")) && //with 16 bit per sample, modify this when the channel
atoi(value)) { //configuration is different
fragment_size = atoi(value) * 1024; fragment_size = (pcm_offload_time
ALOGV("Using buffer size from sys prop %d", fragment_size); * info->sample_rate
} * (bits_per_sample >> 3)
* popcount(info->channel_mask))/1000;
fragment_size = ALIGN( fragment_size, 1024); fragment_size = ALIGN (fragment_size, 1024);
if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE) if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE) else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE; fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
ALOGV("%s: fragment_size %d", __func__, fragment_size); ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
return fragment_size; return fragment_size;
} }