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:
parent
6008e9cf77
commit
1f64cd2458
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue