linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support
@ 2020-07-07 16:36 Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 01/11] ASoC: q6asm: add command opcode to timeout error report Srinivas Kandagatla
                   ` (12 more replies)
  0 siblings, 13 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

This patchset adds gapless compressed audio support on q6asm.
Gapless on q6asm is implemented using 2 streams in a single asm session.

First few patches are enhacements done to q6asm interface to allow
stream id per each command, gapless flags and silence meta data.
Along with this there are few trivial changes which I thought are necessary!
Last patch implements copy callback to allow finer control over buffer offsets,
specially in partial drain cases.

This patchset is tested on RB3 aka DB845c platform.

Thanks,
srini


Srinivas Kandagatla (11):
  ASoC: q6asm: add command opcode to timeout error report
  ASoC: q6asm: rename misleading session id variable
  ASoC: q6asm: make commands specific to streams
  ASoC: q6asm: use flags directly from asm-dai
  ASoC: q6asm: add length to write command token
  ASoC: q6asm: add support to remove intial and trailing silence
  ASoC: q6asm: add support to gapless flag in asm open
  ASoC: q6asm-dai: add next track metadata support
  ASoC: qdsp6: use dev_err instead of pr_err
  ASoC: qdsp6-dai: add gapless support
  ASoC: q6asm-dai: add support to copy callback

 sound/soc/qcom/qdsp6/q6asm-dai.c | 397 +++++++++++++++++++++++--------
 sound/soc/qcom/qdsp6/q6asm.c     | 173 +++++++++-----
 sound/soc/qcom/qdsp6/q6asm.h     |  48 ++--
 3 files changed, 458 insertions(+), 160 deletions(-)

-- 
2.21.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 01/11] ASoC: q6asm: add command opcode to timeout error report
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 02/11] ASoC: q6asm: rename misleading session id variable Srinivas Kandagatla
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

Make the error reporting more useful by adding opcode to it.
Without this its almost impossible to say which command actually
timed out.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index ae4b2cabdf2d..e0983970cba9 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -311,7 +311,7 @@ static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac,
 					5 * HZ);
 
 	if (!rc) {
-		dev_err(a->dev, "CMD timeout\n");
+		dev_err(a->dev, "CMD %x timeout\n", hdr->opcode);
 		rc = -ETIMEDOUT;
 	} else if (ac->result.status > 0) {
 		dev_err(a->dev, "DSP returned error[%x]\n",
@@ -891,7 +891,7 @@ static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
 	rc = wait_event_timeout(ac->cmd_wait,
 				(ac->result.opcode == hdr->opcode), 5 * HZ);
 	if (!rc) {
-		dev_err(ac->dev, "CMD timeout\n");
+		dev_err(ac->dev, "CMD %x timeout\n", hdr->opcode);
 		rc =  -ETIMEDOUT;
 		goto err;
 	}
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 02/11] ASoC: q6asm: rename misleading session id variable
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 01/11] ASoC: q6asm: add command opcode to timeout error report Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 03/11] ASoC: q6asm: make commands specific to streams Srinivas Kandagatla
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

Each q6asm session can have multiple streams, mixing usage of these
names in variable are bit misleading to reader, so rename them accordingly.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index e0983970cba9..51da3717a6a6 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -828,21 +828,21 @@ EXPORT_SYMBOL_GPL(q6asm_get_session_id);
  * @dev: Pointer to asm child device.
  * @cb: event callback.
  * @priv: private data associated with this client.
- * @stream_id: stream id
+ * @session_id: session id
  * @perf_mode: performace mode for this client
  *
  * Return: Will be an error pointer on error or a valid audio client
  * on success.
  */
 struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
-					      void *priv, int stream_id,
+					      void *priv, int session_id,
 					      int perf_mode)
 {
 	struct q6asm *a = dev_get_drvdata(dev->parent);
 	struct audio_client *ac;
 	unsigned long flags;
 
-	ac = q6asm_get_audio_client(a, stream_id + 1);
+	ac = q6asm_get_audio_client(a, session_id + 1);
 	if (ac) {
 		dev_err(dev, "Audio Client already active\n");
 		return ac;
@@ -853,9 +853,9 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
 		return ERR_PTR(-ENOMEM);
 
 	spin_lock_irqsave(&a->slock, flags);
-	a->session[stream_id + 1] = ac;
+	a->session[session_id + 1] = ac;
 	spin_unlock_irqrestore(&a->slock, flags);
-	ac->session = stream_id + 1;
+	ac->session = session_id + 1;
 	ac->cb = cb;
 	ac->dev = dev;
 	ac->q6asm = a;
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 03/11] ASoC: q6asm: make commands specific to streams
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 01/11] ASoC: q6asm: add command opcode to timeout error report Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 02/11] ASoC: q6asm: rename misleading session id variable Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:52   ` Pierre-Louis Bossart
  2020-07-07 16:36 ` [PATCH 04/11] ASoC: q6asm: use flags directly from asm-dai Srinivas Kandagatla
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

Each ASM session can have multiple streams attached to it,
current design was to allow only one static stream id 1 per each session.
However for use-case like gapless, we would need 2 streams to open per session.

This patch converts all the asm apis to take stream id as argument
to allow multiple streams to open on a single session, This is useful
for gapless playback cases.

Now the dai driver can specify which stream id for each command.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm-dai.c | 86 ++++++++++++++++++-----------
 sound/soc/qcom/qdsp6/q6asm.c     | 92 ++++++++++++++++++--------------
 sound/soc/qcom/qdsp6/q6asm.h     | 38 ++++++++-----
 3 files changed, 133 insertions(+), 83 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index aff57052a735..bcedcc3f8a5c 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -67,6 +67,8 @@ struct q6asm_dai_rtd {
 	uint16_t bits_per_sample;
 	uint16_t source; /* Encoding source bit mask */
 	struct audio_client *audio_client;
+	/* Active */
+	uint32_t stream_id;
 	uint16_t session_id;
 	enum stream_state state;
 };
@@ -184,8 +186,8 @@ static void event_handler(uint32_t opcode, uint32_t token,
 	switch (opcode) {
 	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			q6asm_write_async(prtd->audio_client,
-				   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+			q6asm_write_async(prtd->audio_client, prtd->stream_id,
+				   prtd->pcm_count, 0, 0, 0);
 		break;
 	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
 		prtd->state = Q6ASM_STREAM_STOPPED;
@@ -194,8 +196,8 @@ static void event_handler(uint32_t opcode, uint32_t token,
 		prtd->pcm_irq_pos += prtd->pcm_count;
 		snd_pcm_period_elapsed(substream);
 		if (prtd->state == Q6ASM_STREAM_RUNNING)
-			q6asm_write_async(prtd->audio_client,
-					   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+			q6asm_write_async(prtd->audio_client, prtd->stream_id,
+					   prtd->pcm_count, 0, 0, 0);
 
 		break;
 		}
@@ -203,7 +205,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
 		prtd->pcm_irq_pos += prtd->pcm_count;
 		snd_pcm_period_elapsed(substream);
 		if (prtd->state == Q6ASM_STREAM_RUNNING)
-			q6asm_read(prtd->audio_client);
+			q6asm_read(prtd->audio_client, prtd->stream_id);
 
 		break;
 	default:
@@ -235,7 +237,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 	/* rate and channels are sent to audio driver */
 	if (prtd->state) {
 		/* clear the previous setup if any  */
-		q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+		q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
 		q6asm_unmap_memory_regions(substream->stream,
 					   prtd->audio_client);
 		q6routing_stream_close(soc_prtd->dai_link->id,
@@ -254,11 +256,13 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM,
+		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
+				       FORMAT_LINEAR_PCM,
 				       0, prtd->bits_per_sample);
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM,
-				       prtd->bits_per_sample);
+		ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
+				      FORMAT_LINEAR_PCM,
+				      prtd->bits_per_sample);
 	}
 
 	if (ret < 0) {
@@ -278,17 +282,19 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		ret = q6asm_media_format_block_multi_ch_pcm(
-				prtd->audio_client, runtime->rate,
-				runtime->channels, NULL,
+				prtd->audio_client, prtd->stream_id,
+				runtime->rate, runtime->channels, NULL,
 				prtd->bits_per_sample);
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
-					runtime->rate, runtime->channels,
-					prtd->bits_per_sample);
+							   prtd->stream_id,
+							   runtime->rate,
+							   runtime->channels,
+							   prtd->bits_per_sample);
 
 		/* Queue the buffers */
 		for (i = 0; i < runtime->periods; i++)
-			q6asm_read(prtd->audio_client);
+			q6asm_read(prtd->audio_client, prtd->stream_id);
 
 	}
 	if (ret < 0)
@@ -310,15 +316,18 @@ static int q6asm_dai_trigger(struct snd_soc_component *component,
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
+				       0, 0, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		prtd->state = Q6ASM_STREAM_STOPPED;
-		ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
+				       CMD_EOS);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
+				       CMD_PAUSE);
 		break;
 	default:
 		ret = -EINVAL;
@@ -363,6 +372,9 @@ static int q6asm_dai_open(struct snd_soc_component *component,
 		return ret;
 	}
 
+	/* DSP expects stream id from 1 */
+	prtd->stream_id = 1;
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		runtime->hw = q6asm_dai_hardware_playback;
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -429,7 +441,8 @@ static int q6asm_dai_close(struct snd_soc_component *component,
 
 	if (prtd->audio_client) {
 		if (prtd->state)
-			q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+			q6asm_cmd(prtd->audio_client, prtd->stream_id,
+				  CMD_CLOSE);
 
 		q6asm_unmap_memory_regions(substream->stream,
 					   prtd->audio_client);
@@ -501,8 +514,8 @@ 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_write_async(prtd->audio_client, prtd->pcm_count,
-					  0, 0, NO_TIMESTAMP);
+			q6asm_write_async(prtd->audio_client, prtd->stream_id,
+					  prtd->pcm_count, 0, 0, 0);
 			prtd->bytes_sent += prtd->pcm_count;
 		}
 
@@ -527,8 +540,8 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
 		avail = prtd->bytes_received - prtd->bytes_sent;
 
 		if (avail >= prtd->pcm_count) {
-			q6asm_write_async(prtd->audio_client,
-					   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+			q6asm_write_async(prtd->audio_client, prtd->stream_id,
+					   prtd->pcm_count, 0, 0, 0);
 			prtd->bytes_sent += prtd->pcm_count;
 		}
 
@@ -562,6 +575,9 @@ static int q6asm_dai_compr_open(struct snd_soc_component *component,
 	if (!prtd)
 		return -ENOMEM;
 
+	/* DSP expects stream id from 1 */
+	prtd->stream_id = 1;
+
 	prtd->cstream = stream;
 	prtd->audio_client = q6asm_audio_client_alloc(dev,
 					(q6asm_cb)compress_event_handler,
@@ -609,7 +625,8 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component,
 
 	if (prtd->audio_client) {
 		if (prtd->state)
-			q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+			q6asm_cmd(prtd->audio_client, prtd->stream_id,
+				  CMD_CLOSE);
 
 		snd_dma_free_pages(&prtd->dma_buffer);
 		q6asm_unmap_memory_regions(stream->direction,
@@ -664,8 +681,9 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 	prtd->pcm_size = runtime->fragments * runtime->fragment_size;
 	prtd->bits_per_sample = 16;
 	if (dir == SND_COMPRESS_PLAYBACK) {
-		ret = q6asm_open_write(prtd->audio_client, params->codec.id,
-				params->codec.profile, prtd->bits_per_sample);
+		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
+				       params->codec.id, params->codec.profile,
+				       prtd->bits_per_sample);
 
 		if (ret < 0) {
 			dev_err(dev, "q6asm_open_write failed\n");
@@ -699,6 +717,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 		flac_cfg.min_frame_size = flac->min_frame_size;
 
 		ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
+							   prtd->stream_id,
 							   &flac_cfg);
 		if (ret < 0) {
 			dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
@@ -758,10 +777,12 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 
 		if (wma_v9)
 			ret = q6asm_stream_media_format_block_wma_v9(
-					prtd->audio_client, &wma_cfg);
+					prtd->audio_client, prtd->stream_id,
+					&wma_cfg);
 		else
 			ret = q6asm_stream_media_format_block_wma_v10(
-					prtd->audio_client, &wma_cfg);
+					prtd->audio_client, prtd->stream_id,
+					&wma_cfg);
 		if (ret < 0) {
 			dev_err(dev, "WMA9 CMD failed:%d\n", ret);
 			return -EIO;
@@ -794,6 +815,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 			break;
 		}
 		ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
+							   prtd->stream_id,
 							   &alac_cfg);
 		if (ret < 0) {
 			dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
@@ -818,6 +840,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 		ape_cfg.seek_table_present = ape->seek_table_present;
 
 		ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
+							  prtd->stream_id,
 							  &ape_cfg);
 		if (ret < 0) {
 			dev_err(dev, "APE CMD Format block failed:%d\n", ret);
@@ -854,15 +877,18 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
+				       0, 0, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		prtd->state = Q6ASM_STREAM_STOPPED;
-		ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
+				       CMD_EOS);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
+				       CMD_PAUSE);
 		break;
 	default:
 		ret = -EINVAL;
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 51da3717a6a6..f5d1f3c2c1ec 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -270,7 +270,6 @@ struct audio_client {
 	wait_queue_head_t cmd_wait;
 	struct aprv2_ibasic_rsp_result_t result;
 	int perf_mode;
-	int stream_id;
 	struct q6asm *q6asm;
 	struct device *dev;
 };
@@ -862,8 +861,6 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
 	ac->priv = priv;
 	ac->io_mode = ASM_SYNC_IO_MODE;
 	ac->perf_mode = perf_mode;
-	/* DSP expects stream id from 1 */
-	ac->stream_id = 1;
 	ac->adev = a->adev;
 	kref_init(&ac->refcount);
 
@@ -919,8 +916,9 @@ static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
  *
  * Return: Will be an negative value on error or zero on success
  */
-int q6asm_open_write(struct audio_client *ac, uint32_t format,
-		     u32 codec_profile, uint16_t bits_per_sample)
+int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
+		     uint32_t format, u32 codec_profile,
+		     uint16_t bits_per_sample)
 {
 	struct asm_stream_cmd_open_write_v3 *open;
 	struct apr_pkt *pkt;
@@ -935,7 +933,7 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format,
 
 	pkt = p;
 	open = p + APR_HDR_SIZE;
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open->mode_flags = 0x00;
@@ -998,8 +996,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format,
 }
 EXPORT_SYMBOL_GPL(q6asm_open_write);
 
-static int __q6asm_run(struct audio_client *ac, uint32_t flags,
-	      uint32_t msw_ts, uint32_t lsw_ts, bool wait)
+static int __q6asm_run(struct audio_client *ac, uint32_t stream_id,
+		       uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts,
+		       bool wait)
 {
 	struct asm_session_cmd_run_v2 *run;
 	struct apr_pkt *pkt;
@@ -1014,7 +1013,7 @@ static int __q6asm_run(struct audio_client *ac, uint32_t flags,
 	pkt = p;
 	run = p + APR_HDR_SIZE;
 
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
 	run->flags = flags;
@@ -1042,10 +1041,10 @@ static int __q6asm_run(struct audio_client *ac, uint32_t flags,
  *
  * Return: Will be an negative value on error or zero on success
  */
-int q6asm_run(struct audio_client *ac, uint32_t flags,
+int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
 	      uint32_t msw_ts, uint32_t lsw_ts)
 {
-	return __q6asm_run(ac, flags, msw_ts, lsw_ts, true);
+	return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true);
 }
 EXPORT_SYMBOL_GPL(q6asm_run);
 
@@ -1053,16 +1052,17 @@ EXPORT_SYMBOL_GPL(q6asm_run);
  * q6asm_run_nowait() - start the audio client withou blocking
  *
  * @ac: audio client pointer
+ * @stream_id: stream id
  * @flags: flags associated with write
  * @msw_ts: timestamp msw
  * @lsw_ts: timestamp lsw
  *
  * Return: Will be an negative value on error or zero on success
  */
-int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
-	      uint32_t msw_ts, uint32_t lsw_ts)
+int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
+		     uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts)
 {
-	return __q6asm_run(ac, flags, msw_ts, lsw_ts, false);
+	return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false);
 }
 EXPORT_SYMBOL_GPL(q6asm_run_nowait);
 
@@ -1070,6 +1070,7 @@ EXPORT_SYMBOL_GPL(q6asm_run_nowait);
  * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
  *
  * @ac: audio client pointer
+ * @stream_id: stream id
  * @rate: audio sample rate
  * @channels: number of audio channels.
  * @channel_map: channel map pointer
@@ -1078,6 +1079,7 @@ EXPORT_SYMBOL_GPL(q6asm_run_nowait);
  * Return: Will be an negative value on error or zero on success
  */
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+					  uint32_t stream_id,
 					  uint32_t rate, uint32_t channels,
 					  u8 channel_map[PCM_MAX_NUM_CHANNEL],
 					  uint16_t bits_per_sample)
@@ -1096,7 +1098,7 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
 	pkt = p;
 	fmt = p + APR_HDR_SIZE;
 
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1125,8 +1127,8 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
 }
 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
 
-
 int q6asm_stream_media_format_block_flac(struct audio_client *ac,
+					 uint32_t stream_id,
 					 struct q6asm_flac_cfg *cfg)
 {
 	struct asm_flac_fmt_blk_v2 *fmt;
@@ -1142,7 +1144,7 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac,
 	pkt = p;
 	fmt = p + APR_HDR_SIZE;
 
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1163,6 +1165,7 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac,
 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
 
 int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
+					   uint32_t stream_id,
 					   struct q6asm_wma_cfg *cfg)
 {
 	struct asm_wmastdv9_fmt_blk_v2 *fmt;
@@ -1178,7 +1181,7 @@ int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
 	pkt = p;
 	fmt = p + APR_HDR_SIZE;
 
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1200,6 +1203,7 @@ int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9);
 
 int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
+					    uint32_t stream_id,
 					    struct q6asm_wma_cfg *cfg)
 {
 	struct asm_wmaprov10_fmt_blk_v2 *fmt;
@@ -1215,7 +1219,7 @@ int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
 	pkt = p;
 	fmt = p + APR_HDR_SIZE;
 
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1238,6 +1242,7 @@ int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10);
 
 int q6asm_stream_media_format_block_alac(struct audio_client *ac,
+					 uint32_t stream_id,
 					 struct q6asm_alac_cfg *cfg)
 {
 	struct asm_alac_fmt_blk_v2 *fmt;
@@ -1253,7 +1258,7 @@ int q6asm_stream_media_format_block_alac(struct audio_client *ac,
 	pkt = p;
 	fmt = p + APR_HDR_SIZE;
 
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1279,6 +1284,7 @@ int q6asm_stream_media_format_block_alac(struct audio_client *ac,
 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac);
 
 int q6asm_stream_media_format_block_ape(struct audio_client *ac,
+					uint32_t stream_id,
 					struct q6asm_ape_cfg *cfg)
 {
 	struct asm_ape_fmt_blk_v2 *fmt;
@@ -1294,7 +1300,7 @@ int q6asm_stream_media_format_block_ape(struct audio_client *ac,
 	pkt = p;
 	fmt = p + APR_HDR_SIZE;
 
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1321,6 +1327,7 @@ EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
  * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
  *
  * @ac: audio client pointer
+ * @stream_id: stream id
  * @rate: audio sample rate
  * @channels: number of audio channels.
  * @bits_per_sample: bits per sample
@@ -1328,7 +1335,9 @@ EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
  * Return: Will be an negative value on error or zero on success
  */
 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
-		uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
+					 uint32_t stream_id, uint32_t rate,
+					 uint32_t channels,
+					 uint16_t bits_per_sample)
 {
 	struct asm_multi_channel_pcm_enc_cfg_v2  *enc_cfg;
 	struct apr_pkt *pkt;
@@ -1344,7 +1353,7 @@ int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
 
 	pkt = p;
 	enc_cfg = p + APR_HDR_SIZE;
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
 
 	pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
@@ -1376,10 +1385,11 @@ EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
  * q6asm_read() - read data of period size from audio client
  *
  * @ac: audio client pointer
+ * @stream_id: stream id
  *
  * Return: Will be an negative value on error or zero on success
  */
-int q6asm_read(struct audio_client *ac)
+int q6asm_read(struct audio_client *ac, uint32_t stream_id)
 {
 	struct asm_data_cmd_read_v2 *read;
 	struct audio_port_data *port;
@@ -1400,7 +1410,7 @@ int q6asm_read(struct audio_client *ac)
 
 	spin_lock_irqsave(&ac->lock, flags);
 	port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
 	ab = &port->buf[port->dsp_buf];
 	pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
 	read->buf_addr_lsw = lower_32_bits(ab->phys);
@@ -1428,7 +1438,7 @@ int q6asm_read(struct audio_client *ac)
 }
 EXPORT_SYMBOL_GPL(q6asm_read);
 
-static int __q6asm_open_read(struct audio_client *ac,
+static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
 		uint32_t format, uint16_t bits_per_sample)
 {
 	struct asm_stream_cmd_open_read_v3 *open;
@@ -1444,7 +1454,7 @@ static int __q6asm_open_read(struct audio_client *ac,
 	pkt = p;
 	open = p + APR_HDR_SIZE;
 
-	q6asm_add_hdr(ac, &pkt->hdr,  pkt_size, true, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr,  pkt_size, true, stream_id);
 	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
 	/* Stream prio : High, provide meta info with encoded frames */
 	open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1475,15 +1485,16 @@ static int __q6asm_open_read(struct audio_client *ac,
  * q6asm_open_read() - Open audio client for reading
  *
  * @ac: audio client pointer
+ * @stream_id: stream id
  * @format: audio sample format
  * @bits_per_sample: bits per sample
  *
  * Return: Will be an negative value on error or zero on success
  */
-int q6asm_open_read(struct audio_client *ac, uint32_t format,
-			uint16_t bits_per_sample)
+int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
+		    uint32_t format, uint16_t bits_per_sample)
 {
-	return __q6asm_open_read(ac, format, bits_per_sample);
+	return __q6asm_open_read(ac, stream_id, format, bits_per_sample);
 }
 EXPORT_SYMBOL_GPL(q6asm_open_read);
 
@@ -1491,6 +1502,7 @@ EXPORT_SYMBOL_GPL(q6asm_open_read);
  * q6asm_write_async() - non blocking write
  *
  * @ac: audio client pointer
+ * @stream_id: stream id
  * @len: length in bytes
  * @msw_ts: timestamp msw
  * @lsw_ts: timestamp lsw
@@ -1498,8 +1510,8 @@ EXPORT_SYMBOL_GPL(q6asm_open_read);
  *
  * Return: Will be an negative value on error or zero on success
  */
-int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
-		       uint32_t lsw_ts, uint32_t wflags)
+int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
+		      uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags)
 {
 	struct asm_data_cmd_write_v2 *write;
 	struct audio_port_data *port;
@@ -1520,7 +1532,7 @@ int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
 
 	spin_lock_irqsave(&ac->lock, flags);
 	port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
-	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
 
 	ab = &port->buf[port->dsp_buf];
 	pkt->hdr.token = port->dsp_buf;
@@ -1567,9 +1579,9 @@ static void q6asm_reset_buf_state(struct audio_client *ac)
 	spin_unlock_irqrestore(&ac->lock, flags);
 }
 
-static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
+static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd,
+		       bool wait)
 {
-	int stream_id = ac->stream_id;
 	struct apr_pkt pkt;
 	int rc;
 
@@ -1616,13 +1628,14 @@ static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
  * q6asm_cmd() - run cmd on audio client
  *
  * @ac: audio client pointer
+ * @stream_id: stream id
  * @cmd: command to run on audio client.
  *
  * Return: Will be an negative value on error or zero on success
  */
-int q6asm_cmd(struct audio_client *ac, int cmd)
+int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd)
 {
-	return __q6asm_cmd(ac, cmd, true);
+	return __q6asm_cmd(ac, stream_id, cmd, true);
 }
 EXPORT_SYMBOL_GPL(q6asm_cmd);
 
@@ -1630,13 +1643,14 @@ EXPORT_SYMBOL_GPL(q6asm_cmd);
  * q6asm_cmd_nowait() - non blocking, run cmd on audio client
  *
  * @ac: audio client pointer
+ * @stream_id: stream id
  * @cmd: command to run on audio client.
  *
  * Return: Will be an negative value on error or zero on success
  */
-int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd)
 {
-	return __q6asm_cmd(ac, cmd, false);
+	return __q6asm_cmd(ac, stream_id, cmd, false);
 }
 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
 
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index 38a207d6cd95..ceece124dd3d 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -93,37 +93,47 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev,
 					      q6asm_cb cb, void *priv,
 					      int session_id, int perf_mode);
 void q6asm_audio_client_free(struct audio_client *ac);
-int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
-		       uint32_t lsw_ts, uint32_t flags);
-int q6asm_open_write(struct audio_client *ac, uint32_t format,
-		     u32 codec_profile, uint16_t bits_per_sample);
-
-int q6asm_open_read(struct audio_client *ac, uint32_t format,
+int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
+		      uint32_t msw_ts, uint32_t lsw_ts, uint32_t flags);
+int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
+		     uint32_t format, u32 codec_profile,
 		     uint16_t bits_per_sample);
+
+int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
+		    uint32_t format, uint16_t bits_per_sample);
 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
-		uint32_t rate, uint32_t channels, uint16_t bits_per_sample);
-int q6asm_read(struct audio_client *ac);
+					 uint32_t stream_id, uint32_t rate,
+					 uint32_t channels,
+					 uint16_t bits_per_sample);
+
+int q6asm_read(struct audio_client *ac, uint32_t stream_id);
 
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+					  uint32_t stream_id,
 					  uint32_t rate, uint32_t channels,
 					  u8 channel_map[PCM_MAX_NUM_CHANNEL],
 					  uint16_t bits_per_sample);
 int q6asm_stream_media_format_block_flac(struct audio_client *ac,
+					 uint32_t stream_id,
 					 struct q6asm_flac_cfg *cfg);
 int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
+					   uint32_t stream_id,
 					   struct q6asm_wma_cfg *cfg);
 int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
+					    uint32_t stream_id,
 					    struct q6asm_wma_cfg *cfg);
 int q6asm_stream_media_format_block_alac(struct audio_client *ac,
+					 uint32_t stream_id,
 					 struct q6asm_alac_cfg *cfg);
 int q6asm_stream_media_format_block_ape(struct audio_client *ac,
+					uint32_t stream_id,
 					struct q6asm_ape_cfg *cfg);
-int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts,
-	      uint32_t lsw_ts);
-int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts,
-		     uint32_t lsw_ts);
-int q6asm_cmd(struct audio_client *ac, int cmd);
-int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
+	      uint32_t msw_ts, uint32_t lsw_ts);
+int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
+		     uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts);
+int q6asm_cmd(struct audio_client *ac, uint32_t stream_id,  int cmd);
+int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id,  int cmd);
 int q6asm_get_session_id(struct audio_client *ac);
 int q6asm_map_memory_regions(unsigned int dir,
 			     struct audio_client *ac,
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 04/11] ASoC: q6asm: use flags directly from asm-dai
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (2 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 03/11] ASoC: q6asm: make commands specific to streams Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 05/11] ASoC: q6asm: add length to write command token Srinivas Kandagatla
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

use flags set by asm-dais directly!

This will be useful gapless case where write needs a special flag to indicate
that last buffer.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index f5d1f3c2c1ec..d6728304ce6a 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -1546,10 +1546,7 @@ int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
 	write->mem_map_handle =
 	    ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
 
-	if (wflags == NO_TIMESTAMP)
-		write->flags = (wflags & 0x800000FF);
-	else
-		write->flags = (0x80000000 | wflags);
+	write->flags = wflags;
 
 	port->dsp_buf++;
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 05/11] ASoC: q6asm: add length to write command token
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (3 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 04/11] ASoC: q6asm: use flags directly from asm-dai Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 06/11] ASoC: q6asm: add support to remove intial and trailing silence Srinivas Kandagatla
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

Add length to write command packet token so that we can track exactly
how many bytes are consumed by DSP in the command reply.

This is useful in some use-cases where the end of the file/stream
is not aligned with period size.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm-dai.c | 4 +++-
 sound/soc/qcom/qdsp6/q6asm.c     | 7 ++++---
 sound/soc/qcom/qdsp6/q6asm.h     | 3 +++
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index bcedcc3f8a5c..c3558288242a 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -509,6 +509,7 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
 	struct snd_compr_stream *substream = prtd->cstream;
 	unsigned long flags;
 	uint64_t avail;
+	uint32_t bytes_written;
 
 	switch (opcode) {
 	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
@@ -529,7 +530,8 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
 	case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
 		spin_lock_irqsave(&prtd->lock, flags);
 
-		prtd->copied_total += prtd->pcm_count;
+		bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
+		prtd->copied_total += bytes_written;
 		snd_compr_fragment_elapsed(substream);
 
 		if (prtd->state != Q6ASM_STREAM_RUNNING) {
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index d6728304ce6a..205453d1c1fc 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -670,6 +670,7 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
 		if (ac->io_mode & ASM_SYNC_IO_MODE) {
 			phys_addr_t phys;
 			unsigned long flags;
+			int token = hdr->token & ASM_WRITE_TOKEN_MASK;
 
 			spin_lock_irqsave(&ac->lock, flags);
 
@@ -681,12 +682,12 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
 				goto done;
 			}
 
-			phys = port->buf[hdr->token].phys;
+			phys = port->buf[token].phys;
 
 			if (lower_32_bits(phys) != result->opcode ||
 			    upper_32_bits(phys) != result->status) {
 				dev_err(ac->dev, "Expected addr %pa\n",
-					&port->buf[hdr->token].phys);
+					&port->buf[token].phys);
 				spin_unlock_irqrestore(&ac->lock, flags);
 				ret = -EINVAL;
 				goto done;
@@ -1535,7 +1536,7 @@ int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
 
 	ab = &port->buf[port->dsp_buf];
-	pkt->hdr.token = port->dsp_buf;
+	pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT);
 	pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
 	write->buf_addr_lsw = lower_32_bits(ab->phys);
 	write->buf_addr_msw = upper_32_bits(ab->phys);
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index ceece124dd3d..0379580f0742 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -20,6 +20,9 @@
 #define ASM_CLIENT_EVENT_CMD_RUN_DONE		0x1008
 #define ASM_CLIENT_EVENT_DATA_WRITE_DONE	0x1009
 #define ASM_CLIENT_EVENT_DATA_READ_DONE		0x100a
+#define ASM_WRITE_TOKEN_MASK			GENMASK(15, 0)
+#define ASM_WRITE_TOKEN_LEN_MASK		GENMASK(31, 16)
+#define ASM_WRITE_TOKEN_LEN_SHIFT		16
 
 enum {
 	LEGACY_PCM_MODE = 0,
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 06/11] ASoC: q6asm: add support to remove intial and trailing silence
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (4 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 05/11] ASoC: q6asm: add length to write command token Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:55   ` Pierre-Louis Bossart
  2020-07-07 16:36 ` [PATCH 07/11] ASoC: q6asm: add support to gapless flag in asm open Srinivas Kandagatla
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

This patch adds support to ASM_DATA_CMD_REMOVE_INITIAL_SILENCE
and ASM_DATA_CMD_REMOVE_TRAILING_SILENCE asm command to support
compressed metadata for gapless playback.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm.c | 53 ++++++++++++++++++++++++++++++++++++
 sound/soc/qcom/qdsp6/q6asm.h |  6 ++++
 2 files changed, 59 insertions(+)

diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 205453d1c1fc..14ec7dad5b65 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -51,6 +51,8 @@
 #define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
 #define ASM_MEDIA_FMT_ALAC			0x00012f31
 #define ASM_MEDIA_FMT_APE			0x00012f32
+#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE	0x00010D67
+#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE	0x00010D68
 
 
 #define ASM_LEGACY_STREAM_SESSION	0
@@ -639,6 +641,8 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
 		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+		case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
 			if (result->status != 0) {
 				dev_err(ac->dev,
 					"cmd = 0x%x returned error = 0x%x\n",
@@ -1324,6 +1328,55 @@ int q6asm_stream_media_format_block_ape(struct audio_client *ac,
 }
 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
 
+static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id,
+				       uint32_t cmd,
+				       uint32_t num_samples)
+{
+	uint32_t *samples;
+	struct apr_pkt *pkt;
+	void *p;
+	int rc, pkt_size;
+
+	pkt_size = APR_HDR_SIZE + sizeof(uint32_t);
+	p = kzalloc(pkt_size, GFP_ATOMIC);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	samples = p + APR_HDR_SIZE;
+
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
+
+	pkt->hdr.opcode = cmd;
+	*samples = num_samples;
+	rc = apr_send_pkt(ac->adev, pkt);
+	if (rc == pkt_size)
+		rc = 0;
+
+	kfree(pkt);
+
+	return rc;
+}
+
+int q6asm_stream_remove_initial_silence(struct audio_client *ac,
+					uint32_t stream_id,
+					uint32_t initial_samples)
+{
+	return q6asm_stream_remove_silence(ac, stream_id,
+					   ASM_DATA_CMD_REMOVE_INITIAL_SILENCE,
+					   initial_samples);
+}
+EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence);
+
+int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id,
+					 uint32_t trailing_samples)
+{
+	return q6asm_stream_remove_silence(ac, stream_id,
+				   ASM_DATA_CMD_REMOVE_TRAILING_SILENCE,
+				   trailing_samples);
+}
+EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence);
+
 /**
  * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
  *
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index 0379580f0742..e315f7ff5e54 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -135,6 +135,12 @@ int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
 	      uint32_t msw_ts, uint32_t lsw_ts);
 int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
 		     uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts);
+int q6asm_stream_remove_initial_silence(struct audio_client *ac,
+					uint32_t stream_id,
+					uint32_t initial_samples);
+int q6asm_stream_remove_trailing_silence(struct audio_client *ac,
+					 uint32_t stream_id,
+					 uint32_t trailing_samples);
 int q6asm_cmd(struct audio_client *ac, uint32_t stream_id,  int cmd);
 int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id,  int cmd);
 int q6asm_get_session_id(struct audio_client *ac);
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 07/11] ASoC: q6asm: add support to gapless flag in asm open
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (5 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 06/11] ASoC: q6asm: add support to remove intial and trailing silence Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:57   ` Pierre-Louis Bossart
  2020-07-07 16:36 ` [PATCH 08/11] ASoC: q6asm-dai: add next track metadata support Srinivas Kandagatla
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

This patch adds support to gapless flag to q6asm_open_write().

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm-dai.c | 4 ++--
 sound/soc/qcom/qdsp6/q6asm.c     | 4 +++-
 sound/soc/qcom/qdsp6/q6asm.h     | 2 +-
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index c3558288242a..8c214436a2c2 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -258,7 +258,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
 				       FORMAT_LINEAR_PCM,
-				       0, prtd->bits_per_sample);
+				       0, prtd->bits_per_sample, false);
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
 				      FORMAT_LINEAR_PCM,
@@ -685,7 +685,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 	if (dir == SND_COMPRESS_PLAYBACK) {
 		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
 				       params->codec.id, params->codec.profile,
-				       prtd->bits_per_sample);
+				       prtd->bits_per_sample, true);
 
 		if (ret < 0) {
 			dev_err(dev, "q6asm_open_write failed\n");
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 14ec7dad5b65..22ac99029e56 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -923,7 +923,7 @@ static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
  */
 int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
 		     uint32_t format, u32 codec_profile,
-		     uint16_t bits_per_sample)
+		     uint16_t bits_per_sample, bool is_gapless)
 {
 	struct asm_stream_cmd_open_write_v3 *open;
 	struct apr_pkt *pkt;
@@ -943,6 +943,8 @@ int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
 	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open->mode_flags = 0x00;
 	open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
+	if (is_gapless)
+		open->mode_flags |= BIT(ASM_SHIFT_GAPLESS_MODE_FLAG);
 
 	/* source endpoint : matrix */
 	open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index e315f7ff5e54..69513ac1fa55 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -100,7 +100,7 @@ int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
 		      uint32_t msw_ts, uint32_t lsw_ts, uint32_t flags);
 int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
 		     uint32_t format, u32 codec_profile,
-		     uint16_t bits_per_sample);
+		     uint16_t bits_per_sample, bool is_gapless);
 
 int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
 		    uint32_t format, uint16_t bits_per_sample);
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 08/11] ASoC: q6asm-dai: add next track metadata support
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (6 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 07/11] ASoC: q6asm: add support to gapless flag in asm open Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 09/11] ASoC: qdsp6: use dev_err instead of pr_err Srinivas Kandagatla
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

This patch adds support to metadata required to do a gapless playback.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm-dai.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 8c214436a2c2..c0e1e84267bf 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -71,6 +71,8 @@ struct q6asm_dai_rtd {
 	uint32_t stream_id;
 	uint16_t session_id;
 	enum stream_state state;
+	uint32_t initial_samples_drop;
+	uint32_t trailing_samples_drop;
 };
 
 struct q6asm_dai_data {
@@ -868,6 +870,28 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 	return 0;
 }
 
+static int q6asm_dai_compr_set_metadata(struct snd_compr_stream *stream,
+					struct snd_compr_metadata *metadata)
+{
+	struct snd_compr_runtime *runtime = stream->runtime;
+	struct q6asm_dai_rtd *prtd = runtime->private_data;
+	int ret = 0;
+
+	switch (metadata->key) {
+	case SNDRV_COMPRESS_ENCODER_PADDING:
+		prtd->trailing_samples_drop = metadata->value[0];
+		break;
+	case SNDRV_COMPRESS_ENCODER_DELAY:
+		prtd->initial_samples_drop = metadata->value[0];
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
 				   struct snd_compr_stream *stream, int cmd)
 {
@@ -984,6 +1008,7 @@ static struct snd_compress_ops q6asm_dai_compress_ops = {
 	.open		= q6asm_dai_compr_open,
 	.free		= q6asm_dai_compr_free,
 	.set_params	= q6asm_dai_compr_set_params,
+	.set_metadata	= q6asm_dai_compr_set_metadata,
 	.pointer	= q6asm_dai_compr_pointer,
 	.trigger	= q6asm_dai_compr_trigger,
 	.get_caps	= q6asm_dai_compr_get_caps,
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 09/11] ASoC: qdsp6: use dev_err instead of pr_err
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (7 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 08/11] ASoC: q6asm-dai: add next track metadata support Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 16:36 ` [PATCH 10/11] ASoC: qdsp6-dai: add gapless support Srinivas Kandagatla
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm-dai.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index c0e1e84267bf..c4b4684b7824 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -222,6 +222,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct q6asm_dai_rtd *prtd = runtime->private_data;
 	struct q6asm_dai_data *pdata;
+	struct device *dev = component->dev;
 	int ret, i;
 
 	pdata = snd_soc_component_get_drvdata(component);
@@ -229,7 +230,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 		return -EINVAL;
 
 	if (!prtd || !prtd->audio_client) {
-		pr_err("%s: private data null or audio client freed\n",
+		dev_err(dev, "%s: private data null or audio client freed\n",
 			__func__);
 		return -EINVAL;
 	}
@@ -252,7 +253,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 				       prtd->periods);
 
 	if (ret < 0) {
-		pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
+		dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n",
 							ret);
 		return -ENOMEM;
 	}
@@ -268,7 +269,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 	}
 
 	if (ret < 0) {
-		pr_err("%s: q6asm_open_write failed\n", __func__);
+		dev_err(dev, "%s: q6asm_open_write failed\n", __func__);
 		q6asm_audio_client_free(prtd->audio_client);
 		prtd->audio_client = NULL;
 		return -ENOMEM;
@@ -278,7 +279,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 	ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
 			      prtd->session_id, substream->stream);
 	if (ret) {
-		pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
+		dev_err(dev, "%s: stream reg failed ret:%d\n", __func__, ret);
 		return ret;
 	}
 
@@ -300,7 +301,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 
 	}
 	if (ret < 0)
-		pr_info("%s: CMD Format block failed\n", __func__);
+		dev_info(dev, "%s: CMD Format block failed\n", __func__);
 
 	prtd->state = Q6ASM_STREAM_RUNNING;
 
@@ -355,7 +356,7 @@ static int q6asm_dai_open(struct snd_soc_component *component,
 
 	pdata = snd_soc_component_get_drvdata(component);
 	if (!pdata) {
-		pr_err("Drv data not found ..\n");
+		dev_err(dev, "Drv data not found ..\n");
 		return -EINVAL;
 	}
 
@@ -368,7 +369,7 @@ static int q6asm_dai_open(struct snd_soc_component *component,
 				(q6asm_cb)event_handler, prtd, stream_id,
 				LEGACY_PCM_MODE);
 	if (IS_ERR(prtd->audio_client)) {
-		pr_info("%s: Could not allocate memory\n", __func__);
+		dev_info(dev, "%s: Could not allocate memory\n", __func__);
 		ret = PTR_ERR(prtd->audio_client);
 		kfree(prtd);
 		return ret;
@@ -386,12 +387,12 @@ static int q6asm_dai_open(struct snd_soc_component *component,
 				SNDRV_PCM_HW_PARAM_RATE,
 				&constraints_sample_rates);
 	if (ret < 0)
-		pr_info("snd_pcm_hw_constraint_list failed\n");
+		dev_info(dev, "snd_pcm_hw_constraint_list failed\n");
 	/* Ensure that buffer size is a multiple of period size */
 	ret = snd_pcm_hw_constraint_integer(runtime,
 					    SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0)
-		pr_info("snd_pcm_hw_constraint_integer failed\n");
+		dev_info(dev, "snd_pcm_hw_constraint_integer failed\n");
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		ret = snd_pcm_hw_constraint_minmax(runtime,
@@ -399,21 +400,21 @@ static int q6asm_dai_open(struct snd_soc_component *component,
 			PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
 			PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
 		if (ret < 0) {
-			pr_err("constraint for buffer bytes min max ret = %d\n",
-									ret);
+			dev_err(dev, "constraint for buffer bytes min max ret = %d\n",
+				ret);
 		}
 	}
 
 	ret = snd_pcm_hw_constraint_step(runtime, 0,
 		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
 	if (ret < 0) {
-		pr_err("constraint for period bytes step ret = %d\n",
+		dev_err(dev, "constraint for period bytes step ret = %d\n",
 								ret);
 	}
 	ret = snd_pcm_hw_constraint_step(runtime, 0,
 		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
 	if (ret < 0) {
-		pr_err("constraint for buffer bytes step ret = %d\n",
+		dev_err(dev, "constraint for buffer bytes step ret = %d\n",
 								ret);
 	}
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 10/11] ASoC: qdsp6-dai: add gapless support
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (8 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 09/11] ASoC: qdsp6: use dev_err instead of pr_err Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-07 17:07   ` Pierre-Louis Bossart
  2020-07-07 16:36 ` [PATCH 11/11] ASoC: q6asm-dai: add support to copy callback Srinivas Kandagatla
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

Add support to gapless playback by implementing metadata,
next_track, drain and partial drain support.

Gapless on Q6ASM is implemented by opening 2 streams in a single asm stream
and toggling them on next track.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm-dai.c | 212 +++++++++++++++++++++++--------
 sound/soc/qcom/qdsp6/q6asm.h     |   1 +
 2 files changed, 158 insertions(+), 55 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index c4b4684b7824..f48eca227fb5 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -67,12 +67,15 @@ struct q6asm_dai_rtd {
 	uint16_t bits_per_sample;
 	uint16_t source; /* Encoding source bit mask */
 	struct audio_client *audio_client;
+	uint32_t next_track_stream_id;
+	bool next_track;
 	/* Active */
 	uint32_t stream_id;
 	uint16_t session_id;
 	enum stream_state state;
 	uint32_t initial_samples_drop;
 	uint32_t trailing_samples_drop;
+	bool notify_on_drain;
 };
 
 struct q6asm_dai_data {
@@ -510,9 +513,11 @@ 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;
+	u32 wflags = 0;
 	uint64_t avail;
-	uint32_t bytes_written;
+	uint32_t bytes_written, bytes_to_write;
+	bool is_last_buffer = false;
 
 	switch (opcode) {
 	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
@@ -527,7 +532,25 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
 		break;
 
 	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
-		prtd->state = Q6ASM_STREAM_STOPPED;
+		if (prtd->notify_on_drain) {
+			if (substream->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;
+			}
+
+			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:
@@ -543,13 +566,32 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
 		}
 
 		avail = prtd->bytes_received - prtd->bytes_sent;
+		if (avail > prtd->pcm_count) {
+			bytes_to_write = prtd->pcm_count;
+		} else {
+			if (substream->partial_drain || prtd->notify_on_drain)
+				is_last_buffer = true;
+			bytes_to_write = avail;
+		}
+
+		if (bytes_to_write) {
+			if (substream->partial_drain && is_last_buffer) {
+				wflags |= ASM_LAST_BUFFER_FLAG;
+				q6asm_stream_remove_trailing_silence(prtd->audio_client,
+						     prtd->stream_id,
+						     prtd->trailing_samples_drop);
+			}
 
-		if (avail >= prtd->pcm_count) {
 			q6asm_write_async(prtd->audio_client, prtd->stream_id,
-					   prtd->pcm_count, 0, 0, 0);
-			prtd->bytes_sent += prtd->pcm_count;
+					  bytes_to_write, 0, 0, wflags);
+
+			prtd->bytes_sent += bytes_to_write;
 		}
 
+		if (prtd->notify_on_drain && is_last_buffer)
+			q6asm_cmd_nowait(prtd->audio_client,
+					 prtd->stream_id, CMD_EOS);
+
 		spin_unlock_irqrestore(&prtd->lock, flags);
 		break;
 
@@ -629,9 +671,15 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component,
 	struct snd_soc_pcm_runtime *rtd = stream->private_data;
 
 	if (prtd->audio_client) {
-		if (prtd->state)
+		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,
@@ -645,15 +693,13 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component,
 	return 0;
 }
 
-static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
-				      struct snd_compr_stream *stream,
-				      struct snd_compr_params *params)
+static int __q6asm_dai_compr_set_codec_params(struct snd_soc_component *component,
+					      struct snd_compr_stream *stream,
+					      struct snd_compr_params *params,
+					      int stream_id)
 {
 	struct snd_compr_runtime *runtime = stream->runtime;
 	struct q6asm_dai_rtd *prtd = runtime->private_data;
-	struct snd_soc_pcm_runtime *rtd = stream->private_data;
-	int dir = stream->direction;
-	struct q6asm_dai_data *pdata;
 	struct q6asm_flac_cfg flac_cfg;
 	struct q6asm_wma_cfg wma_cfg;
 	struct q6asm_alac_cfg alac_cfg;
@@ -669,43 +715,8 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 
 	codec_options = &(prtd->codec_param.codec.options);
 
-
 	memcpy(&prtd->codec_param, params, sizeof(*params));
 
-	pdata = snd_soc_component_get_drvdata(component);
-	if (!pdata)
-		return -EINVAL;
-
-	if (!prtd || !prtd->audio_client) {
-		dev_err(dev, "private data null or audio client freed\n");
-		return -EINVAL;
-	}
-
-	prtd->periods = runtime->fragments;
-	prtd->pcm_count = runtime->fragment_size;
-	prtd->pcm_size = runtime->fragments * runtime->fragment_size;
-	prtd->bits_per_sample = 16;
-	if (dir == SND_COMPRESS_PLAYBACK) {
-		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
-				       params->codec.id, params->codec.profile,
-				       prtd->bits_per_sample, true);
-
-		if (ret < 0) {
-			dev_err(dev, "q6asm_open_write failed\n");
-			q6asm_audio_client_free(prtd->audio_client);
-			prtd->audio_client = NULL;
-			return ret;
-		}
-	}
-
-	prtd->session_id = q6asm_get_session_id(prtd->audio_client);
-	ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
-			      prtd->session_id, dir);
-	if (ret) {
-		dev_err(dev, "Stream reg failed ret:%d\n", ret);
-		return ret;
-	}
-
 	switch (params->codec.id) {
 	case SND_AUDIOCODEC_FLAC:
 
@@ -722,7 +733,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 		flac_cfg.min_frame_size = flac->min_frame_size;
 
 		ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
-							   prtd->stream_id,
+							   stream_id,
 							   &flac_cfg);
 		if (ret < 0) {
 			dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
@@ -782,11 +793,11 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 
 		if (wma_v9)
 			ret = q6asm_stream_media_format_block_wma_v9(
-					prtd->audio_client, prtd->stream_id,
+					prtd->audio_client, stream_id,
 					&wma_cfg);
 		else
 			ret = q6asm_stream_media_format_block_wma_v10(
-					prtd->audio_client, prtd->stream_id,
+					prtd->audio_client, stream_id,
 					&wma_cfg);
 		if (ret < 0) {
 			dev_err(dev, "WMA9 CMD failed:%d\n", ret);
@@ -820,7 +831,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 			break;
 		}
 		ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
-							   prtd->stream_id,
+							   stream_id,
 							   &alac_cfg);
 		if (ret < 0) {
 			dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
@@ -845,7 +856,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 		ape_cfg.seek_table_present = ape->seek_table_present;
 
 		ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
-							  prtd->stream_id,
+							  stream_id,
 							  &ape_cfg);
 		if (ret < 0) {
 			dev_err(dev, "APE CMD Format block failed:%d\n", ret);
@@ -857,6 +868,63 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 		break;
 	}
 
+	return 0;
+}
+
+static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
+				      struct snd_compr_stream *stream,
+				      struct snd_compr_params *params)
+{
+	struct snd_compr_runtime *runtime = stream->runtime;
+	struct q6asm_dai_rtd *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = stream->private_data;
+	int dir = stream->direction;
+	struct q6asm_dai_data *pdata;
+	struct device *dev = component->dev;
+	int ret;
+
+	pdata = snd_soc_component_get_drvdata(component);
+	if (!pdata)
+		return -EINVAL;
+
+	if (!prtd || !prtd->audio_client) {
+		dev_err(dev, "private data null or audio client freed\n");
+		return -EINVAL;
+	}
+
+	prtd->periods = runtime->fragments;
+	prtd->pcm_count = runtime->fragment_size;
+	prtd->pcm_size = runtime->fragments * runtime->fragment_size;
+	prtd->bits_per_sample = 16;
+
+	if (dir == SND_COMPRESS_PLAYBACK) {
+		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id,
+				params->codec.profile, prtd->bits_per_sample,
+				true);
+
+		if (ret < 0) {
+			dev_err(dev, "q6asm_open_write failed\n");
+			q6asm_audio_client_free(prtd->audio_client);
+			prtd->audio_client = NULL;
+			return ret;
+		}
+	}
+
+	prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+	ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
+			      prtd->session_id, dir);
+	if (ret) {
+		dev_err(dev, "Stream reg failed ret:%d\n", ret);
+		return ret;
+	}
+
+	ret = __q6asm_dai_compr_set_codec_params(component, stream, params,
+						 prtd->stream_id);
+	if (ret) {
+		dev_err(dev, "codec param setup failed ret:%d\n", ret);
+		return ret;
+	}
+
 	ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
 				       (prtd->pcm_size / prtd->periods),
 				       prtd->periods);
@@ -871,12 +939,13 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
 	return 0;
 }
 
-static int q6asm_dai_compr_set_metadata(struct snd_compr_stream *stream,
+static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
+					struct snd_compr_stream *stream,
 					struct snd_compr_metadata *metadata)
 {
 	struct snd_compr_runtime *runtime = stream->runtime;
 	struct q6asm_dai_rtd *prtd = runtime->private_data;
-	int ret = 0;
+	int stream_id = prtd->stream_id, ret = 0;
 
 	switch (metadata->key) {
 	case SNDRV_COMPRESS_ENCODER_PADDING:
@@ -884,6 +953,31 @@ static int q6asm_dai_compr_set_metadata(struct snd_compr_stream *stream,
 		break;
 	case SNDRV_COMPRESS_ENCODER_DELAY:
 		prtd->initial_samples_drop = metadata->value[0];
+		if (prtd->next_track_stream_id) {
+			stream_id = prtd->next_track_stream_id;
+			ret = q6asm_open_write(prtd->audio_client,
+					       prtd->next_track_stream_id,
+					       prtd->codec_param.codec.id,
+					       prtd->codec_param.codec.profile,
+					       prtd->bits_per_sample,
+				       true);
+			if (ret < 0) {
+				dev_err(component->dev, "q6asm_open_write failed\n");
+				return ret;
+			}
+			ret = __q6asm_dai_compr_set_codec_params(component, stream,
+								 &prtd->codec_param,
+								 prtd->next_track_stream_id);
+			if (ret < 0) {
+				dev_err(component->dev, "q6asm_open_write failed\n");
+				return ret;
+			}
+
+		}
+
+		q6asm_stream_remove_initial_silence(prtd->audio_client,
+						    stream_id,
+						    prtd->initial_samples_drop);
 		break;
 	default:
 		ret = -EINVAL;
@@ -917,6 +1011,14 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
 		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
 				       CMD_PAUSE);
 		break;
+	case SND_COMPR_TRIGGER_NEXT_TRACK:
+		prtd->next_track = true;
+		prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1);
+		break;
+	case SND_COMPR_TRIGGER_DRAIN:
+	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
+		prtd->notify_on_drain = true;
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index 69513ac1fa55..a8dddfeb28da 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -34,6 +34,7 @@ enum {
 #define MAX_SESSIONS	8
 #define NO_TIMESTAMP    0xFF00
 #define FORMAT_LINEAR_PCM   0x0000
+#define ASM_LAST_BUFFER_FLAG           BIT(30)
 
 struct q6asm_flac_cfg {
         u32 sample_rate;
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 11/11] ASoC: q6asm-dai: add support to copy callback
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (9 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 10/11] ASoC: qdsp6-dai: add gapless support Srinivas Kandagatla
@ 2020-07-07 16:36 ` Srinivas Kandagatla
  2020-07-08 13:32 ` [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Mark Brown
  2020-07-08 16:59 ` Mark Brown
  12 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-07 16:36 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel,
	ckeepax, Srinivas Kandagatla

During gapless playback, its possible for previous track to
end at unaligned boundary, starting next track on the same
boundary can lead to unaligned address exception in dsp.

So implement copy callback for finer control on the buffer offsets.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/q6asm-dai.c | 65 +++++++++++++++++++++++++++++---
 1 file changed, 60 insertions(+), 5 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index f48eca227fb5..0b285b759409 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -1045,16 +1045,71 @@ static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
 	return 0;
 }
 
-static int q6asm_dai_compr_ack(struct snd_soc_component *component,
-			       struct snd_compr_stream *stream,
-			       size_t count)
+static int q6asm_compr_copy(struct snd_soc_component *component,
+			    struct snd_compr_stream *stream, char __user *buf,
+			    size_t count)
 {
 	struct snd_compr_runtime *runtime = stream->runtime;
 	struct q6asm_dai_rtd *prtd = runtime->private_data;
 	unsigned long flags;
+	u32 wflags = 0;
+	int avail, bytes_in_flight = 0;
+	void *dstn;
+	size_t copy;
+	u32 app_pointer;
+	u32 bytes_received;
+
+	bytes_received = prtd->bytes_received;
+
+	/**
+	 * Make sure that next track data pointer is aligned at 32 bit boundary
+	 * This is a Mandatory requirement from DSP data buffers alignment
+	 */
+	if (prtd->next_track)
+		bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
+
+	app_pointer = bytes_received/prtd->pcm_size;
+	app_pointer = bytes_received -  (app_pointer * prtd->pcm_size);
+	dstn = prtd->dma_buffer.area + app_pointer;
+
+	if (count < prtd->pcm_size - app_pointer) {
+		if (copy_from_user(dstn, buf, count))
+			return -EFAULT;
+	} else {
+		copy = prtd->pcm_size - app_pointer;
+		if (copy_from_user(dstn, buf, copy))
+			return -EFAULT;
+		if (copy_from_user(prtd->dma_buffer.area, buf + copy,
+				   count - copy))
+			return -EFAULT;
+	}
 
 	spin_lock_irqsave(&prtd->lock, flags);
-	prtd->bytes_received += count;
+
+	bytes_in_flight = prtd->bytes_received - prtd->copied_total;
+
+	if (prtd->next_track) {
+		prtd->next_track = false;
+		prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
+		prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
+	}
+
+	prtd->bytes_received = bytes_received + count;
+
+	/* Kick off the data to dsp if its starving!! */
+	if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
+		uint32_t bytes_to_write = prtd->pcm_count;
+
+		avail = prtd->bytes_received - prtd->bytes_sent;
+
+		if (avail < prtd->pcm_count)
+			bytes_to_write = avail;
+
+		q6asm_write_async(prtd->audio_client, prtd->stream_id,
+				  bytes_to_write, 0, 0, wflags);
+		prtd->bytes_sent += bytes_to_write;
+	}
+
 	spin_unlock_irqrestore(&prtd->lock, flags);
 
 	return count;
@@ -1117,7 +1172,7 @@ static struct snd_compress_ops q6asm_dai_compress_ops = {
 	.get_caps	= q6asm_dai_compr_get_caps,
 	.get_codec_caps	= q6asm_dai_compr_get_codec_caps,
 	.mmap		= q6asm_dai_compr_mmap,
-	.ack		= q6asm_dai_compr_ack,
+	.copy		= q6asm_compr_copy,
 };
 
 static int q6asm_dai_pcm_new(struct snd_soc_component *component,
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH 03/11] ASoC: q6asm: make commands specific to streams
  2020-07-07 16:36 ` [PATCH 03/11] ASoC: q6asm: make commands specific to streams Srinivas Kandagatla
@ 2020-07-07 16:52   ` Pierre-Louis Bossart
  2020-07-08  9:44     ` Srinivas Kandagatla
  0 siblings, 1 reply; 29+ messages in thread
From: Pierre-Louis Bossart @ 2020-07-07 16:52 UTC (permalink / raw)
  To: Srinivas Kandagatla, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul




> @@ -184,8 +186,8 @@ static void event_handler(uint32_t opcode, uint32_t token,
>   	switch (opcode) {
>   	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
>   		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> -			q6asm_write_async(prtd->audio_client,
> -				   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
> +			q6asm_write_async(prtd->audio_client, prtd->stream_id,
> +				   prtd->pcm_count, 0, 0, 0);

sound/soc/qcom/qdsp6/q6asm.h:#define NO_TIMESTAMP    0xFF00

is the change on the previous line intentional?

>   		break;
>   	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
>   		prtd->state = Q6ASM_STREAM_STOPPED;
> @@ -194,8 +196,8 @@ static void event_handler(uint32_t opcode, uint32_t token,
>   		prtd->pcm_irq_pos += prtd->pcm_count;
>   		snd_pcm_period_elapsed(substream);
>   		if (prtd->state == Q6ASM_STREAM_RUNNING)
> -			q6asm_write_async(prtd->audio_client,
> -					   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
> +			q6asm_write_async(prtd->audio_client, prtd->stream_id,
> +					   prtd->pcm_count, 0, 0, 0);

ditto for the timestamp change?


> @@ -501,8 +514,8 @@ 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_write_async(prtd->audio_client, prtd->pcm_count,
> -					  0, 0, NO_TIMESTAMP);
> +			q6asm_write_async(prtd->audio_client, prtd->stream_id,
> +					  prtd->pcm_count, 0, 0, 0);

and here as well.

>   			prtd->bytes_sent += prtd->pcm_count;
>   		}
>   
> @@ -527,8 +540,8 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
>   		avail = prtd->bytes_received - prtd->bytes_sent;
>   
>   		if (avail >= prtd->pcm_count) {
> -			q6asm_write_async(prtd->audio_client,
> -					   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
> +			q6asm_write_async(prtd->audio_client, prtd->stream_id,
> +					   prtd->pcm_count, 0, 0, 0);

and here.


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 06/11] ASoC: q6asm: add support to remove intial and trailing silence
  2020-07-07 16:36 ` [PATCH 06/11] ASoC: q6asm: add support to remove intial and trailing silence Srinivas Kandagatla
@ 2020-07-07 16:55   ` Pierre-Louis Bossart
  2020-07-08  9:44     ` Srinivas Kandagatla
  0 siblings, 1 reply; 29+ messages in thread
From: Pierre-Louis Bossart @ 2020-07-07 16:55 UTC (permalink / raw)
  To: Srinivas Kandagatla, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul




> +int q6asm_stream_remove_initial_silence(struct audio_client *ac,
> +					uint32_t stream_id,
> +					uint32_t initial_samples)
> +{
> +	return q6asm_stream_remove_silence(ac, stream_id,
> +					   ASM_DATA_CMD_REMOVE_INITIAL_SILENCE,
> +					   initial_samples);
> +}
> +EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence);
> +
> +int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id,
> +					 uint32_t trailing_samples)
> +{
> +	return q6asm_stream_remove_silence(ac, stream_id,
> +				   ASM_DATA_CMD_REMOVE_TRAILING_SILENCE,
> +				   trailing_samples);
> +}
> +EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence);

do you need those wrappers? Might as well call the _remove_silence() 
function with the right parameters, no?

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 07/11] ASoC: q6asm: add support to gapless flag in asm open
  2020-07-07 16:36 ` [PATCH 07/11] ASoC: q6asm: add support to gapless flag in asm open Srinivas Kandagatla
@ 2020-07-07 16:57   ` Pierre-Louis Bossart
  2020-07-08  9:44     ` Srinivas Kandagatla
  0 siblings, 1 reply; 29+ messages in thread
From: Pierre-Louis Bossart @ 2020-07-07 16:57 UTC (permalink / raw)
  To: Srinivas Kandagatla, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul


> diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
> index c3558288242a..8c214436a2c2 100644
> --- a/sound/soc/qcom/qdsp6/q6asm-dai.c
> +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
> @@ -258,7 +258,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
>   	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>   		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
>   				       FORMAT_LINEAR_PCM,
> -				       0, prtd->bits_per_sample);
> +				       0, prtd->bits_per_sample, false);

nit-pick: it's a bit ironic that is_gapless is false for PCM, when there 
is no gap in the first place..

>   	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
>   		ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
>   				      FORMAT_LINEAR_PCM,
> @@ -685,7 +685,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
>   	if (dir == SND_COMPRESS_PLAYBACK) {
>   		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
>   				       params->codec.id, params->codec.profile,
> -				       prtd->bits_per_sample);
> +				       prtd->bits_per_sample, true);

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 10/11] ASoC: qdsp6-dai: add gapless support
  2020-07-07 16:36 ` [PATCH 10/11] ASoC: qdsp6-dai: add gapless support Srinivas Kandagatla
@ 2020-07-07 17:07   ` Pierre-Louis Bossart
  2020-07-08  9:44     ` Srinivas Kandagatla
  0 siblings, 1 reply; 29+ messages in thread
From: Pierre-Louis Bossart @ 2020-07-07 17:07 UTC (permalink / raw)
  To: Srinivas Kandagatla, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul



On 7/7/20 11:36 AM, Srinivas Kandagatla wrote:
> Add support to gapless playback by implementing metadata,
> next_track, drain and partial drain support.
> 
> Gapless on Q6ASM is implemented by opening 2 streams in a single asm stream

What does 'in a single asm stream' means?

> and toggling them on next track.

It really seems to me that you have two streams at the lowest level, 
along with the knowledge of how many samples to remove/insert and hence 
could do a much better job - including gapless support between unrelated 
profiles and cross-fading - without the partial drain and next_track 
mechanism that was defined assuming a single stream/profile.


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 03/11] ASoC: q6asm: make commands specific to streams
  2020-07-07 16:52   ` Pierre-Louis Bossart
@ 2020-07-08  9:44     ` Srinivas Kandagatla
  2020-07-08 13:13       ` Mark Brown
  0 siblings, 1 reply; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-08  9:44 UTC (permalink / raw)
  To: Pierre-Louis Bossart, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul

Thanks Pierre for quick review,

On 07/07/2020 17:52, Pierre-Louis Bossart wrote:
> 
> 
> 
>> @@ -184,8 +186,8 @@ static void event_handler(uint32_t opcode, 
>> uint32_t token,
>>       switch (opcode) {
>>       case ASM_CLIENT_EVENT_CMD_RUN_DONE:
>>           if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
>> -            q6asm_write_async(prtd->audio_client,
>> -                   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
>> +            q6asm_write_async(prtd->audio_client, prtd->stream_id,
>> +                   prtd->pcm_count, 0, 0, 0);
> 
> sound/soc/qcom/qdsp6/q6asm.h:#define NO_TIMESTAMP    0xFF00
> 
> is the change on the previous line intentional?

May be not!

Plan is that the users of these apis will send flags directly instead of 
boiler plating this!

This change should go as part of next patch("[PATCH 04/11] ASoC: q6asm: 
use flags directly from asm-dai") which would make it much clear!

thanks,
srini

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 06/11] ASoC: q6asm: add support to remove intial and trailing silence
  2020-07-07 16:55   ` Pierre-Louis Bossart
@ 2020-07-08  9:44     ` Srinivas Kandagatla
  0 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-08  9:44 UTC (permalink / raw)
  To: Pierre-Louis Bossart, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul

Thanks Pierre for review,

On 07/07/2020 17:55, Pierre-Louis Bossart wrote:
> 
> 
> 
>> +int q6asm_stream_remove_initial_silence(struct audio_client *ac,
>> +                    uint32_t stream_id,
>> +                    uint32_t initial_samples)
>> +{
>> +    return q6asm_stream_remove_silence(ac, stream_id,
>> +                       ASM_DATA_CMD_REMOVE_INITIAL_SILENCE,
>> +                       initial_samples);
>> +}
>> +EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence);
>> +
>> +int q6asm_stream_remove_trailing_silence(struct audio_client *ac, 
>> uint32_t stream_id,
>> +                     uint32_t trailing_samples)
>> +{
>> +    return q6asm_stream_remove_silence(ac, stream_id,
>> +                   ASM_DATA_CMD_REMOVE_TRAILING_SILENCE,
>> +                   trailing_samples);
>> +}
>> +EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence);
> 
> do you need those wrappers? Might as well call the _remove_silence() 
> function with the right parameters, no?

Intention is to abstract out the CMDs within dsp specific wrappers.
This is how rest of the apis are also done! Also its possible that in 
future these IDs could potentially upgraded on different versions of DSP fw.
Making a single call would mean that either CMD IDs or some kinda of 
other intermediate flags.

So I would like to keep it as it is for now!

Thanks,
srini


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 07/11] ASoC: q6asm: add support to gapless flag in asm open
  2020-07-07 16:57   ` Pierre-Louis Bossart
@ 2020-07-08  9:44     ` Srinivas Kandagatla
  0 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-08  9:44 UTC (permalink / raw)
  To: Pierre-Louis Bossart, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul


Thanks Pierre for review,

On 07/07/2020 17:57, Pierre-Louis Bossart wrote:
> 
>> diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c 
>> b/sound/soc/qcom/qdsp6/q6asm-dai.c
>> index c3558288242a..8c214436a2c2 100644
>> --- a/sound/soc/qcom/qdsp6/q6asm-dai.c
>> +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
>> @@ -258,7 +258,7 @@ static int q6asm_dai_prepare(struct 
>> snd_soc_component *component,
>>       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>>           ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
>>                          FORMAT_LINEAR_PCM,
>> -                       0, prtd->bits_per_sample);
>> +                       0, prtd->bits_per_sample, false);
> 
> nit-pick: it's a bit ironic that is_gapless is false for PCM, when there 
> is no gap in the first place..

I think this is to do with same apis reused for both compressed and pcm.

Probably we can live with it for now!

--srini
> 
>>       } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
>>           ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
>>                         FORMAT_LINEAR_PCM,
>> @@ -685,7 +685,7 @@ static int q6asm_dai_compr_set_params(struct 
>> snd_soc_component *component,
>>       if (dir == SND_COMPRESS_PLAYBACK) {
>>           ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
>>                          params->codec.id, params->codec.profile,
>> -                       prtd->bits_per_sample);
>> +                       prtd->bits_per_sample, true);

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 10/11] ASoC: qdsp6-dai: add gapless support
  2020-07-07 17:07   ` Pierre-Louis Bossart
@ 2020-07-08  9:44     ` Srinivas Kandagatla
  2020-07-08 13:32       ` Pierre-Louis Bossart
  0 siblings, 1 reply; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-08  9:44 UTC (permalink / raw)
  To: Pierre-Louis Bossart, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul

Thanks Pierre for review,

On 07/07/2020 18:07, Pierre-Louis Bossart wrote:
> 
> 
> On 7/7/20 11:36 AM, Srinivas Kandagatla wrote:
>> Add support to gapless playback by implementing metadata,
>> next_track, drain and partial drain support.
>>
>> Gapless on Q6ASM is implemented by opening 2 streams in a single asm 
>> stream
> 
> What does 'in a single asm stream' means?


So in QDSP6 ASM (Audio Stream Manager) terminology we have something 
called "asm session" for each ASoC FE DAI, Each asm session can be 
connected with multiple streams (upto 8 I think). However there will be 
only one active stream at anytime. Also there only single data buffer 
associated with each asm session.

For Gapless usecase, we can keep two streams open for one asm-session, 
allowing us to fill in data on second stream while first stream is playing.

> 
>> and toggling them on next track.
> 
> It really seems to me that you have two streams at the lowest level, 
> along with the knowledge of how many samples to remove/insert and hence 
> could do a much better job - including gapless support between unrelated 
> profiles and cross-fading - without the partial drain and next_track 
> mechanism that was defined assuming a single stream/profile.
At the end of the day its a single session with one data buffer but with 
multiple streams.

Achieving cross fade should be easy with this design.

We need those hooks for partial drain and next track to allow us to 
switch between streams and pass silence information to respective stream 
ids.

--srini
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 03/11] ASoC: q6asm: make commands specific to streams
  2020-07-08  9:44     ` Srinivas Kandagatla
@ 2020-07-08 13:13       ` Mark Brown
  2020-07-08 15:26         ` Srinivas Kandagatla
  0 siblings, 1 reply; 29+ messages in thread
From: Mark Brown @ 2020-07-08 13:13 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Pierre-Louis Bossart, alsa-devel, ckeepax, tiwai, lgirdwood,
	linux-kernel, vkoul

[-- Attachment #1: Type: text/plain, Size: 970 bytes --]

On Wed, Jul 08, 2020 at 10:44:19AM +0100, Srinivas Kandagatla wrote:
> On 07/07/2020 17:52, Pierre-Louis Bossart wrote:

> > >           if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> > > -            q6asm_write_async(prtd->audio_client,
> > > -                   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
> > > +            q6asm_write_async(prtd->audio_client, prtd->stream_id,
> > > +                   prtd->pcm_count, 0, 0, 0);

> > sound/soc/qcom/qdsp6/q6asm.h:#define NO_TIMESTAMP    0xFF00

> > is the change on the previous line intentional?

> May be not!

> Plan is that the users of these apis will send flags directly instead of
> boiler plating this!

> This change should go as part of next patch("[PATCH 04/11] ASoC: q6asm: use
> flags directly from asm-dai") which would make it much clear!

It should be in here.

Please be also consistent in your use of ASM, especially given that asm
is a widely used name in the kernel.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 10/11] ASoC: qdsp6-dai: add gapless support
  2020-07-08  9:44     ` Srinivas Kandagatla
@ 2020-07-08 13:32       ` Pierre-Louis Bossart
  2020-07-08 13:42         ` Mark Brown
  2020-07-08 15:23         ` Srinivas Kandagatla
  0 siblings, 2 replies; 29+ messages in thread
From: Pierre-Louis Bossart @ 2020-07-08 13:32 UTC (permalink / raw)
  To: Srinivas Kandagatla, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul


>>> Add support to gapless playback by implementing metadata,
>>> next_track, drain and partial drain support.
>>>
>>> Gapless on Q6ASM is implemented by opening 2 streams in a single asm 
>>> stream
>>
>> What does 'in a single asm stream' means?
> 
> 
> So in QDSP6 ASM (Audio Stream Manager) terminology we have something 
> called "asm session" for each ASoC FE DAI, Each asm session can be 
> connected with multiple streams (upto 8 I think). However there will be 
> only one active stream at anytime. Also there only single data buffer 
> associated with each asm session.
> 
> For Gapless usecase, we can keep two streams open for one asm-session, 
> allowing us to fill in data on second stream while first stream is playing.

Ah, that's interesting, thanks for the details. So you have one DMA 
transfer and the data from the previous and next track are provided in 
consecutive bytes in a ring buffer, but at the DSP level you have a 
switch that will feed data for the previous and next tracks into 
different decoders, yes?

If that is the case, indeed the extension you suggested earlier to 
change the profile is valid. You could even change the format I guess.

To avoid confusion I believe the capabilities would need to be extended 
so that applications know that gapless playback is supported across 
unrelated profiles/formats. The point is that you don't want a 
traditional implementation to use a capability that isn't supported in 
hardware or will lead to audio issues.

>>> and toggling them on next track.
>>
>> It really seems to me that you have two streams at the lowest level, 
>> along with the knowledge of how many samples to remove/insert and 
>> hence could do a much better job - including gapless support between 
>> unrelated profiles and cross-fading - without the partial drain and 
>> next_track mechanism that was defined assuming a single stream/profile.
> At the end of the day its a single session with one data buffer but with 
> multiple streams.
> 
> Achieving cross fade should be easy with this design.

looks like it indeed.

> We need those hooks for partial drain and next track to allow us to 
> switch between streams and pass silence information to respective stream 
> ids.

right, but the key point is 'switch between streams'. That means a more 
complex/capable implementation that should be advertised as such to 
applications. This is not the default behavior assumed initially: to 
allow for minimal implementations in memory-constrained devices, we 
assumed gapless was supported with a single decoder.

Maybe the right way to do this is extend the snd_compr_caps structure:

/**
  * struct snd_compr_caps - caps descriptor
  * @codecs: pointer to array of codecs
  * @direction: direction supported. Of type snd_compr_direction
  * @min_fragment_size: minimum fragment supported by DSP
  * @max_fragment_size: maximum fragment supported by DSP
  * @min_fragments: min fragments supported by DSP
  * @max_fragments: max fragments supported by DSP
  * @num_codecs: number of codecs supported
  * @reserved: reserved field
  */
struct snd_compr_caps {
	__u32 num_codecs;
	__u32 direction;
	__u32 min_fragment_size;
	__u32 max_fragment_size;
	__u32 min_fragments;
	__u32 max_fragments;
	__u32 codecs[MAX_NUM_CODECS];
	__u32 reserved[11];
} __attribute__((packed, aligned(4)));


and use a reserved field to provide info on capabilities, and filter the 
set_codec_params() addition based this capability - i.e. return -ENOTSUP 
in 'traditional' implementations based on a single 'stream'/decoder 
instance.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (10 preceding siblings ...)
  2020-07-07 16:36 ` [PATCH 11/11] ASoC: q6asm-dai: add support to copy callback Srinivas Kandagatla
@ 2020-07-08 13:32 ` Mark Brown
  2020-07-08 15:24   ` Srinivas Kandagatla
  2020-07-08 16:59 ` Mark Brown
  12 siblings, 1 reply; 29+ messages in thread
From: Mark Brown @ 2020-07-08 13:32 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel, ckeepax

[-- Attachment #1: Type: text/plain, Size: 403 bytes --]

On Tue, Jul 07, 2020 at 05:36:30PM +0100, Srinivas Kandagatla wrote:

> Along with this there are few trivial changes which I thought are necessary!

It's better to split stuff like this out of the series, or put it near
the start after any fixes if other things depend on it.  That way it can
progress without getting caught up with the rest of the series and the
series gets smaller and more focused.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 10/11] ASoC: qdsp6-dai: add gapless support
  2020-07-08 13:32       ` Pierre-Louis Bossart
@ 2020-07-08 13:42         ` Mark Brown
  2020-07-08 15:23         ` Srinivas Kandagatla
  1 sibling, 0 replies; 29+ messages in thread
From: Mark Brown @ 2020-07-08 13:42 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: Srinivas Kandagatla, alsa-devel, ckeepax, tiwai, lgirdwood,
	linux-kernel, vkoul

[-- Attachment #1: Type: text/plain, Size: 472 bytes --]

On Wed, Jul 08, 2020 at 08:32:02AM -0500, Pierre-Louis Bossart wrote:

> To avoid confusion I believe the capabilities would need to be extended so
> that applications know that gapless playback is supported across unrelated
> profiles/formats. The point is that you don't want a traditional
> implementation to use a capability that isn't supported in hardware or will
> lead to audio issues.

We'd also need error handling in case someone ignores the capability
checks.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 10/11] ASoC: qdsp6-dai: add gapless support
  2020-07-08 13:32       ` Pierre-Louis Bossart
  2020-07-08 13:42         ` Mark Brown
@ 2020-07-08 15:23         ` Srinivas Kandagatla
  2020-07-08 16:58           ` Pierre-Louis Bossart
  1 sibling, 1 reply; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-08 15:23 UTC (permalink / raw)
  To: Pierre-Louis Bossart, broonie
  Cc: alsa-devel, ckeepax, tiwai, lgirdwood, linux-kernel, vkoul



On 08/07/2020 14:32, Pierre-Louis Bossart wrote:
> 
>>>> Add support to gapless playback by implementing metadata,
>>>> next_track, drain and partial drain support.
>>>>
>>>> Gapless on Q6ASM is implemented by opening 2 streams in a single asm 
>>>> stream
>>>
>>> What does 'in a single asm stream' means?
>>
>>
>> So in QDSP6 ASM (Audio Stream Manager) terminology we have something 
>> called "asm session" for each ASoC FE DAI, Each asm session can be 
>> connected with multiple streams (upto 8 I think). However there will 
>> be only one active stream at anytime. Also there only single data 
>> buffer associated with each asm session.
>>
>> For Gapless usecase, we can keep two streams open for one asm-session, 
>> allowing us to fill in data on second stream while first stream is 
>> playing.
> 
> Ah, that's interesting, thanks for the details. So you have one DMA 
> transfer and the data from the previous and next track are provided in 
> consecutive bytes in a ring buffer, but at the DSP level you have a 
> switch that will feed data for the previous and next tracks into 
> different decoders, yes?

Yes, that's true, we can drain and stop first stream and start next 
stream which will do the switch!

> 
> If that is the case, indeed the extension you suggested earlier to 
> change the profile is valid. You could even change the format I guess.
> 

Exactly, we did test this patchset along with the extension suggested!


> To avoid confusion I believe the capabilities would need to be extended 
> so that applications know that gapless playback is supported across 
> unrelated profiles/formats. The point is that you don't want a 
> traditional implementation to use a capability that isn't supported in 
> hardware or will lead to audio issues.
>  >>>> and toggling them on next track.
>>>
>>> It really seems to me that you have two streams at the lowest level, 
>>> along with the knowledge of how many samples to remove/insert and 
>>> hence could do a much better job - including gapless support between 
>>> unrelated profiles and cross-fading - without the partial drain and 
>>> next_track mechanism that was defined assuming a single stream/profile.
>> At the end of the day its a single session with one data buffer but 
>> with multiple streams.
>>
>> Achieving cross fade should be easy with this design.
> 
> looks like it indeed.
> 
>> We need those hooks for partial drain and next track to allow us to 
>> switch between streams and pass silence information to respective 
>> stream ids.
> 
> right, but the key point is 'switch between streams'. That means a more 
> complex/capable implementation that should be advertised as such to 
> applications. This is not the default behavior assumed initially: to 
> allow for minimal implementations in memory-constrained devices, we 
> assumed gapless was supported with a single decoder.
> 
> Maybe the right way to do this is extend the snd_compr_caps structure:
> 
> /**
>   * struct snd_compr_caps - caps descriptor
>   * @codecs: pointer to array of codecs
>   * @direction: direction supported. Of type snd_compr_direction
>   * @min_fragment_size: minimum fragment supported by DSP
>   * @max_fragment_size: maximum fragment supported by DSP
>   * @min_fragments: min fragments supported by DSP
>   * @max_fragments: max fragments supported by DSP
>   * @num_codecs: number of codecs supported
>   * @reserved: reserved field
>   */
> struct snd_compr_caps {
>      __u32 num_codecs;
>      __u32 direction;
>      __u32 min_fragment_size;
>      __u32 max_fragment_size;
>      __u32 min_fragments;
>      __u32 max_fragments;
>      __u32 codecs[MAX_NUM_CODECS];
>      __u32 reserved[11];
> } __attribute__((packed, aligned(4)));
> 
> 
> and use a reserved field to provide info on capabilities, and filter the 
> set_codec_params() addition based this capability - i.e. return -ENOTSUP 
> in 'traditional' implementations based on a single 'stream'/decoder 
> instance.
Sounds good!
I will give it a go and see how it ends up!


--srini


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support
  2020-07-08 13:32 ` [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Mark Brown
@ 2020-07-08 15:24   ` Srinivas Kandagatla
  0 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-08 15:24 UTC (permalink / raw)
  To: Mark Brown
  Cc: vkoul, perex, tiwai, lgirdwood, alsa-devel, linux-kernel, ckeepax



On 08/07/2020 14:32, Mark Brown wrote:
> On Tue, Jul 07, 2020 at 05:36:30PM +0100, Srinivas Kandagatla wrote:
> 
>> Along with this there are few trivial changes which I thought are necessary!
> 
> It's better to split stuff like this out of the series, or put it near
> the start after any fixes if other things depend on it.  That way it can
> progress without getting caught up with the rest of the series and the
> series gets smaller and more focused.
> 
Thanks, I will split the cleanup stuff and send it as separate set!

--srini

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 03/11] ASoC: q6asm: make commands specific to streams
  2020-07-08 13:13       ` Mark Brown
@ 2020-07-08 15:26         ` Srinivas Kandagatla
  0 siblings, 0 replies; 29+ messages in thread
From: Srinivas Kandagatla @ 2020-07-08 15:26 UTC (permalink / raw)
  To: Mark Brown
  Cc: Pierre-Louis Bossart, alsa-devel, ckeepax, tiwai, lgirdwood,
	linux-kernel, vkoul



On 08/07/2020 14:13, Mark Brown wrote:
>> Plan is that the users of these apis will send flags directly instead of
>> boiler plating this!
>> This change should go as part of next patch("[PATCH 04/11] ASoC: q6asm: use
>> flags directly from asm-dai") which would make it much clear!
> It should be in here.
> 
> Please be also consistent in your use of ASM, especially given that asm
> is a widely used name in the kernel.

I agree, I will fix such usage in next patchset!

--srini

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 10/11] ASoC: qdsp6-dai: add gapless support
  2020-07-08 15:23         ` Srinivas Kandagatla
@ 2020-07-08 16:58           ` Pierre-Louis Bossart
  0 siblings, 0 replies; 29+ messages in thread
From: Pierre-Louis Bossart @ 2020-07-08 16:58 UTC (permalink / raw)
  To: Srinivas Kandagatla, broonie
  Cc: alsa-devel, ckeepax, lgirdwood, linux-kernel, tiwai, vkoul


>> right, but the key point is 'switch between streams'. That means a 
>> more complex/capable implementation that should be advertised as such 
>> to applications. This is not the default behavior assumed initially: 
>> to allow for minimal implementations in memory-constrained devices, we 
>> assumed gapless was supported with a single decoder.
>>
>> Maybe the right way to do this is extend the snd_compr_caps structure:
>>
>> /**
>>   * struct snd_compr_caps - caps descriptor
>>   * @codecs: pointer to array of codecs
>>   * @direction: direction supported. Of type snd_compr_direction
>>   * @min_fragment_size: minimum fragment supported by DSP
>>   * @max_fragment_size: maximum fragment supported by DSP
>>   * @min_fragments: min fragments supported by DSP
>>   * @max_fragments: max fragments supported by DSP
>>   * @num_codecs: number of codecs supported
>>   * @reserved: reserved field
>>   */
>> struct snd_compr_caps {
>>      __u32 num_codecs;
>>      __u32 direction;
>>      __u32 min_fragment_size;
>>      __u32 max_fragment_size;
>>      __u32 min_fragments;
>>      __u32 max_fragments;
>>      __u32 codecs[MAX_NUM_CODECS];
>>      __u32 reserved[11];
>> } __attribute__((packed, aligned(4)));
>>
>>
>> and use a reserved field to provide info on capabilities, and filter 
>> the set_codec_params() addition based this capability - i.e. return 
>> -ENOTSUP in 'traditional' implementations based on a single 
>> 'stream'/decoder instance.

I think this is also what Mark was referring to earlier.

> Sounds good!
> I will give it a go and see how it ends up!

Glad to see this discussion progressing.

We may also want to document the 3 possible ways of supporting gapless 
playback while we are at it:
a) with the existing single decoder assumption
b) with your suggested solution with a switch at the DSP level
c) with 2 streams at the userspace level and a switch/x-fade at the DSP 
level - which may simplify userspace quite a bit and was the initial 
design in a non-Linux OS.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support
  2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
                   ` (11 preceding siblings ...)
  2020-07-08 13:32 ` [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Mark Brown
@ 2020-07-08 16:59 ` Mark Brown
  12 siblings, 0 replies; 29+ messages in thread
From: Mark Brown @ 2020-07-08 16:59 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: tiwai, ckeepax, linux-kernel, vkoul, alsa-devel, lgirdwood

On Tue, 7 Jul 2020 17:36:30 +0100, Srinivas Kandagatla wrote:
> This patchset adds gapless compressed audio support on q6asm.
> Gapless on q6asm is implemented using 2 streams in a single asm session.
> 
> First few patches are enhacements done to q6asm interface to allow
> stream id per each command, gapless flags and silence meta data.
> Along with this there are few trivial changes which I thought are necessary!
> Last patch implements copy callback to allow finer control over buffer offsets,
> specially in partial drain cases.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/2] ASoC: q6asm: add command opcode to timeout error report
      commit: b6198097b84abcbf9d098ddf5887fe62f9da2e3c
[2/2] ASoC: qdsp6: use dev_err instead of pr_err
      commit: 0579ece8f4de9956ea7087c63f55663ea79283bc

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2020-07-08 17:00 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-07 16:36 [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 01/11] ASoC: q6asm: add command opcode to timeout error report Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 02/11] ASoC: q6asm: rename misleading session id variable Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 03/11] ASoC: q6asm: make commands specific to streams Srinivas Kandagatla
2020-07-07 16:52   ` Pierre-Louis Bossart
2020-07-08  9:44     ` Srinivas Kandagatla
2020-07-08 13:13       ` Mark Brown
2020-07-08 15:26         ` Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 04/11] ASoC: q6asm: use flags directly from asm-dai Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 05/11] ASoC: q6asm: add length to write command token Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 06/11] ASoC: q6asm: add support to remove intial and trailing silence Srinivas Kandagatla
2020-07-07 16:55   ` Pierre-Louis Bossart
2020-07-08  9:44     ` Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 07/11] ASoC: q6asm: add support to gapless flag in asm open Srinivas Kandagatla
2020-07-07 16:57   ` Pierre-Louis Bossart
2020-07-08  9:44     ` Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 08/11] ASoC: q6asm-dai: add next track metadata support Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 09/11] ASoC: qdsp6: use dev_err instead of pr_err Srinivas Kandagatla
2020-07-07 16:36 ` [PATCH 10/11] ASoC: qdsp6-dai: add gapless support Srinivas Kandagatla
2020-07-07 17:07   ` Pierre-Louis Bossart
2020-07-08  9:44     ` Srinivas Kandagatla
2020-07-08 13:32       ` Pierre-Louis Bossart
2020-07-08 13:42         ` Mark Brown
2020-07-08 15:23         ` Srinivas Kandagatla
2020-07-08 16:58           ` Pierre-Louis Bossart
2020-07-07 16:36 ` [PATCH 11/11] ASoC: q6asm-dai: add support to copy callback Srinivas Kandagatla
2020-07-08 13:32 ` [PATCH 00/11] ASoC: qdsp6: add gapless compressed audio support Mark Brown
2020-07-08 15:24   ` Srinivas Kandagatla
2020-07-08 16:59 ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).