ASoC: msm: qdsp6v2: Fix offload gapless transition

Use smaller fragment sizes at DSP interface than at
user space interface.
This allows to write earlier to the DSP without waiting for
a full user space fragement in case of underrun or gapless
transition.

Bug: 28545177

Signed-off-by: Eric Laurent <elaurent@google.com>
This commit is contained in:
Eric Laurent 2016-05-10 18:21:41 -07:00 committed by syphyr
parent 6008e9cf77
commit 1f64cd2458
1 changed files with 53 additions and 14 deletions

View File

@ -63,6 +63,7 @@
#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
#define COMPR_PLAYBACK_DSP_FRAGMEMT_SIZE (32 * 1024)
#define COMPRESSED_LR_VOL_MAX_STEPS 0x2000
const DECLARE_TLV_DB_LINEAR(msm_compr_vol_gain, 0,
@ -160,6 +161,11 @@ struct msm_compr_audio {
wait_queue_head_t close_wait;
wait_queue_head_t wait_for_stream_avail;
uint32_t dsp_fragment_size;
uint32_t dsp_fragments;
uint32_t dsp_fragment_ratio;
uint32_t dsp_fragments_sent;
spinlock_t lock;
};
@ -350,10 +356,16 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd)
prtd->gapless_state.initial_samples_drop,
prtd->gapless_state.trailing_samples_drop);
buffer_length = prtd->codec_param.buffer.fragment_size;
bytes_available = prtd->bytes_received - prtd->copied_total;
if (bytes_available < prtd->codec_param.buffer.fragment_size)
if (bytes_available < prtd->dsp_fragment_size)
buffer_length = bytes_available;
else if (bytes_available > prtd->cstream->runtime->fragment_size)
buffer_length = prtd->cstream->runtime->fragment_size;
else
buffer_length =
(bytes_available / prtd->dsp_fragment_size) * prtd->dsp_fragment_size;
if (prtd->byte_offset + buffer_length > prtd->buffer_size) {
buffer_length = (prtd->buffer_size - prtd->byte_offset);
@ -441,7 +453,11 @@ static void compr_event_handler(uint32_t opcode,
if (prtd->byte_offset >= prtd->buffer_size)
prtd->byte_offset -= prtd->buffer_size;
snd_compr_fragment_elapsed(cstream);
prtd->dsp_fragments_sent += token / prtd->dsp_fragment_size;
if (prtd->dsp_fragments_sent >= prtd->dsp_fragment_ratio) {
snd_compr_fragment_elapsed(cstream);
prtd->dsp_fragments_sent = 0;
}
if (!atomic_read(&prtd->start)) {
/* Writes must be restarted from _copy() */
@ -452,7 +468,7 @@ static void compr_event_handler(uint32_t opcode,
}
bytes_available = prtd->bytes_received - prtd->copied_total;
if (bytes_available < cstream->runtime->fragment_size) {
if (bytes_available < prtd->dsp_fragment_size) {
pr_debug("WRITE_DONE Insufficient data to send. break out\n");
atomic_set(&prtd->xrun, 1);
@ -464,8 +480,8 @@ static void compr_event_handler(uint32_t opcode,
wake_up(&prtd->drain_wait);
atomic_set(&prtd->drain, 0);
}
} else if ((bytes_available == cstream->runtime->fragment_size)
&& atomic_read(&prtd->drain)) {
} else if ((bytes_available == prtd->dsp_fragment_size)
&& atomic_read(&prtd->drain)) {
prtd->last_buffer = 1;
msm_compr_send_buffer(prtd);
prtd->last_buffer = 0;
@ -529,7 +545,7 @@ static void compr_event_handler(uint32_t opcode,
spin_lock_irqsave(&prtd->lock, flags);
if (!prtd->bytes_sent) {
bytes_available = prtd->bytes_received - prtd->copied_total;
if (bytes_available < cstream->runtime->fragment_size) {
if (bytes_available < prtd->dsp_fragment_size) {
pr_debug("CMD_RUN_V2 Insufficient data to send. break out\n");
atomic_set(&prtd->xrun, 1);
} else
@ -1022,12 +1038,32 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
prtd->gapless_state.stream_opened[stream_index] = 1;
runtime->fragments = prtd->codec_param.buffer.fragments;
runtime->fragment_size = prtd->codec_param.buffer.fragment_size;
/* use smaller DSP fragments to ease gapless transition by reducing the
* minimum amount of data necessary to start DSP decoding
*/
if (runtime->fragment_size < COMPR_PLAYBACK_DSP_FRAGMEMT_SIZE) {
prtd->dsp_fragment_size = runtime->fragment_size;
} else if ((runtime->fragment_size % COMPR_PLAYBACK_DSP_FRAGMEMT_SIZE) != 0) {
pr_err("%s: Invalid fragment size: %d", __func__, runtime->fragment_size);
return -EINVAL;
} else {
prtd->dsp_fragment_size = COMPR_PLAYBACK_DSP_FRAGMEMT_SIZE;
}
prtd->dsp_fragment_ratio = runtime->fragment_size / prtd->dsp_fragment_size;
prtd->dsp_fragments = runtime->fragments * prtd->dsp_fragment_ratio;
if (prtd->dsp_fragments > COMPR_PLAYBACK_MAX_NUM_FRAGMENTS) {
pr_err("%s: Invalid fragment count: %d", __func__, prtd->dsp_fragments);
return -EINVAL;
}
pr_debug("allocate %d buffers each of size %d\n",
runtime->fragments,
runtime->fragment_size);
ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac,
runtime->fragment_size,
runtime->fragments);
prtd->dsp_fragment_size,
prtd->dsp_fragments);
if (ret < 0) {
pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
return -ENOMEM;
@ -1038,6 +1074,7 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
prtd->app_pointer = 0;
prtd->bytes_received = 0;
prtd->bytes_sent = 0;
prtd->dsp_fragments_sent = 0;
prtd->buffer = ac->port[dir].buf[0].data;
prtd->buffer_paddr = ac->port[dir].buf[0].phys;
prtd->buffer_size = runtime->fragments * runtime->fragment_size;
@ -1591,6 +1628,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
prtd->bytes_received = 0;
prtd->bytes_sent = 0;
prtd->marker_timestamp = 0;
prtd->dsp_fragments_sent = 0;
atomic_set(&prtd->xrun, 0);
spin_unlock_irqrestore(&prtd->lock, flags);
@ -1651,8 +1689,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
*/
bytes_to_write = prtd->bytes_received
- prtd->copied_total;
WARN(bytes_to_write > runtime->fragment_size,
"last write %d cannot be > than fragment_size",
WARN(bytes_to_write > prtd->dsp_fragment_size,
"last write %d cannot be > than dsp_fragment_size",
bytes_to_write);
if (bytes_to_write > 0) {
@ -1726,7 +1764,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
prtd->last_buffer = 0;
prtd->gapless_state.gapless_transition = 1;
prtd->marker_timestamp = 0;
prtd->dsp_fragments_sent = 0;
/*
Don't reset these as these vars map to
total_bytes_transferred and total_bytes_available
@ -1833,6 +1871,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
prtd->app_pointer = 0;
prtd->first_buffer = 1;
prtd->last_buffer = 0;
prtd->dsp_fragments_sent = 0;
atomic_set(&prtd->drain, 0);
atomic_set(&prtd->xrun, 1);
spin_unlock_irqrestore(&prtd->lock, flags);
@ -2114,7 +2153,7 @@ static int msm_compr_copy(struct snd_compr_stream *cstream,
/*
* If stream is started and there has been an xrun,
* since the available bytes fits fragment_size, copy the data right away
* since the available bytes fits dsp_fragment_size, copy the data right away
*/
spin_lock_irqsave(&prtd->lock, flags);
prtd->bytes_received += count;
@ -2122,7 +2161,7 @@ static int msm_compr_copy(struct snd_compr_stream *cstream,
if (atomic_read(&prtd->xrun)) {
pr_debug("%s: in xrun, count = %zd\n", __func__, count);
bytes_available = prtd->bytes_received - prtd->copied_total;
if (bytes_available >= runtime->fragment_size) {
if (bytes_available >= prtd->dsp_fragment_size) {
pr_debug("%s: handle xrun, bytes_to_write = %llu\n",
__func__,
bytes_available);