diff options
author | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2020-06-09 14:43:25 +0100 |
---|---|---|
committer | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2020-06-09 15:05:22 +0100 |
commit | c04d64096211748f21c5a3f17c577688e148bb93 (patch) | |
tree | 666139fcdd21b97835e0d844cc0273fbbddd8cb6 | |
parent | b1df5643c0e203672f90167e468de1388b2bb533 (diff) |
ASoC: q6asm-dai: add gapless supportgapless/rfc
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-rw-r--r-- | sound/soc/qcom/qdsp6/q6asm-dai.c | 135 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6asm.h | 2 |
2 files changed, 131 insertions, 6 deletions
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index f2a83f9c9aa8d..1fcd958c86e28 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -74,6 +74,9 @@ struct q6asm_dai_rtd { enum stream_state state; uint32_t initial_samples_drop; uint32_t trailing_samples_drop; + bool notify_on_drain; + bool partial_drain; + int gapless_in_progress; }; struct q6asm_dai_data { @@ -505,7 +508,7 @@ static void compress_event_handler(uint32_t opcode, uint32_t token, { struct q6asm_dai_rtd *prtd = priv; struct snd_compr_stream *substream = prtd->cstream; - unsigned long flags; + unsigned long flags = 0; uint64_t avail; uint32_t bytes_written; @@ -513,16 +516,40 @@ static void compress_event_handler(uint32_t opcode, uint32_t token, case ASM_CLIENT_EVENT_CMD_RUN_DONE: spin_lock_irqsave(&prtd->lock, flags); if (!prtd->bytes_sent) { + q6asm_stream_remove_initial_silence(prtd->audio_client, + prtd->stream_id, + prtd->initial_samples_drop); + avail = prtd->bytes_received - prtd->bytes_sent; + q6asm_write_async(prtd->audio_client, prtd->stream_id, prtd->pcm_count, 0, 0, 0); prtd->bytes_sent += prtd->pcm_count; + q6asm_stream_remove_trailing_silence(prtd->audio_client, + prtd->stream_id, + prtd->trailing_samples_drop); } spin_unlock_irqrestore(&prtd->lock, flags); break; case ASM_CLIENT_EVENT_CMD_EOS_DONE: - prtd->state = Q6ASM_STREAM_STOPPED; + if (prtd->notify_on_drain) { + if (prtd->partial_drain && prtd->next_track_stream_id) { + /* Close old stream and make it stale, switch + * the active stream now! */ + q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id, + CMD_CLOSE); + prtd->stream_id = prtd->next_track_stream_id; + prtd->next_track_stream_id = 0; + } + + pr_err("DEBUG: DRAIN REQUEST - ACKED...>.......\n"); + snd_compr_drain_notify(prtd->cstream); + prtd->notify_on_drain = false; + + } else { + prtd->state = Q6ASM_STREAM_STOPPED; + } break; case ASM_CLIENT_EVENT_DATA_WRITE_DONE: @@ -544,9 +571,34 @@ static void compress_event_handler(uint32_t opcode, uint32_t token, } if (avail >= prtd->pcm_count) { + if (prtd->partial_drain && avail == prtd->pcm_count) + flags |= ASM_LAST_BUFFER_FLAG; + + q6asm_write_async(prtd->audio_client, prtd->stream_id, - prtd->pcm_count, 0, 0, 0); + prtd->pcm_count, 0, 0, flags); + + if (prtd->notify_on_drain && avail == prtd->pcm_count) + q6asm_cmd_nowait(prtd->audio_client, + prtd->stream_id, CMD_EOS); + + prtd->bytes_sent += prtd->pcm_count; + } else if (avail > 0 && (prtd->partial_drain || + prtd->notify_on_drain)) { + uint32_t flags = 0; + /* Check if partial drain is active and mark last buffer*/ + if (prtd->partial_drain && avail <= prtd->pcm_count) + flags |= ASM_LAST_BUFFER_FLAG; + + q6asm_write_async(prtd->audio_client, prtd->stream_id, + avail /*prtd->pcm_count*/, 0, 0, flags); + + if (prtd->notify_on_drain && avail <= prtd->pcm_count) + q6asm_cmd_nowait(prtd->audio_client, + prtd->stream_id, CMD_EOS); + + prtd->bytes_sent += avail; } spin_unlock_irqrestore(&prtd->lock, flags); @@ -627,8 +679,15 @@ static int q6asm_dai_compr_free(struct snd_compr_stream *stream) struct snd_soc_pcm_runtime *rtd = stream->private_data; if (prtd->audio_client) { - if (prtd->state) - q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); + if (prtd->state) { + q6asm_cmd(prtd->audio_client, prtd->stream_id, + CMD_CLOSE); + if (prtd->next_track_stream_id) { + q6asm_cmd(prtd->audio_client, + prtd->next_track_stream_id, + CMD_CLOSE); + } + } snd_dma_free_pages(&prtd->dma_buffer); q6asm_unmap_memory_regions(stream->direction, @@ -821,6 +880,25 @@ static int __q6asm_dai_compr_set_codec_params(struct snd_compr_stream *stream, return 0; } +static int q6asm_dai_compr_set_codec_params(struct snd_compr_stream *stream, + struct snd_codec *codec) +{ + struct snd_compr_runtime *runtime = stream->runtime; + struct q6asm_dai_rtd *prtd = runtime->private_data; + int ret; + + ret = q6asm_open_write(prtd->audio_client, prtd->next_track_stream_id, + codec->id, codec->profile, prtd->bits_per_sample, + true); + if (ret < 0) { + pr_err("q6asm_open_write failed\n"); + return ret; + } + + return __q6asm_dai_compr_set_codec_params(stream, codec, + prtd->next_track_stream_id); +} + static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream, struct snd_compr_params *params) { @@ -937,6 +1015,35 @@ static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id, CMD_PAUSE); break; + case SND_COMPR_TRIGGER_DRAIN: + //Wait till EOS + pr_err("DEBUG: DRAIN REQUESTED>.......\n"); + prtd->notify_on_drain = true; + break; + case SND_COMPR_TRIGGER_NEXT_TRACK: + /* Get Next stream id + open it + */ + prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1); + pr_err("DEBUG: NEXT TRACK REQUESTED>.... new stream id from %d to %d...\n", + prtd->stream_id, prtd->next_track_stream_id); + + + break; + + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + //FIXME TBD + /* + Find Last buffer to mark + Wait for EOS + */ + pr_err("DEBUG: PARTIAL DRAIN REQUESTED>.......\n"); + pr_err("DEBUG: %s BUFFER receviced vs sent %d vs %d.......\n", __func__, prtd->bytes_received, prtd->bytes_sent); + prtd->partial_drain = true; + prtd->notify_on_drain = true; + prtd->gapless_in_progress = true; + break; + default: ret = -EINVAL; break; @@ -968,11 +1075,28 @@ static int q6asm_dai_compr_ack(struct snd_compr_stream *stream, struct snd_compr_runtime *runtime = stream->runtime; struct q6asm_dai_rtd *prtd = runtime->private_data; unsigned long flags; + int avail; + + avail = prtd->bytes_received - prtd->bytes_sent; spin_lock_irqsave(&prtd->lock, flags); prtd->bytes_received += count; spin_unlock_irqrestore(&prtd->lock, flags); + + /* Kick off the data to dsp if dsp was starving */ + if (prtd->gapless_in_progress && !avail) { + q6asm_stream_remove_initial_silence(prtd->audio_client, + prtd->stream_id, + prtd->initial_samples_drop); + + q6asm_write_async(prtd->audio_client, prtd->stream_id, + 0, 0, 0, 0); + q6asm_stream_remove_trailing_silence(prtd->audio_client, + prtd->stream_id, + prtd->trailing_samples_drop); + } + return count; } @@ -1026,6 +1150,7 @@ static struct snd_compr_ops q6asm_dai_compr_ops = { .open = q6asm_dai_compr_open, .free = q6asm_dai_compr_free, .set_params = q6asm_dai_compr_set_params, + .set_codec_params = q6asm_dai_compr_set_codec_params, .set_metadata = q6asm_dai_compr_set_metadata, .pointer = q6asm_dai_compr_pointer, .trigger = q6asm_dai_compr_trigger, diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index 2df1038e5d5ad..c586b3c980b98 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -29,7 +29,7 @@ enum { }; #define MAX_SESSIONS 8 -#define NO_TIMESTAMP 0xFF00 +#define ASM_LAST_BUFFER_FLAG BIT(30) #define FORMAT_LINEAR_PCM 0x0000 struct q6asm_flac_cfg { |