diff --git a/Documentation/sound/designs/compress-offload.rst b/Documentation/sound/designs/compress-offload.rst index ad4bfbdacc83..a29e4e632bf6 100644 --- a/Documentation/sound/designs/compress-offload.rst +++ b/Documentation/sound/designs/compress-offload.rst @@ -183,6 +183,11 @@ partial drain EOF is reached and now DSP can start skipping padding delay. Also next write data would belong to next track +- set_next_track_param +This routine is called to send to DSP codec specific data of subsequent track +in gapless before first write. + + Sequence flow for gapless would be: - Open - Get caps / codec caps @@ -194,6 +199,7 @@ Sequence flow for gapless would be: - Indicate next track data by sending set_next_track - Set metadata of the next track - then call partial_drain to flush most of buffer in DSP +- set codec specific data of subsequent track - Fill data of the next track - DSP switches to second track diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index f29c60bc1401..325c72ad8fda 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -84,6 +84,8 @@ struct snd_compr_stream { * @get_params: retrieve the codec parameters, mandatory * @set_metadata: Set the metadata values for a stream * @get_metadata: retrieves the requested metadata values from stream + * @set_next_track_param: send codec specific data of subsequent track + * in gapless * @trigger: Trigger operations like start, pause, resume, drain, stop. * This callback is mandatory * @pointer: Retrieve current h/w pointer information. Mandatory @@ -106,6 +108,8 @@ struct snd_compr_ops { struct snd_compr_metadata *metadata); int (*get_metadata)(struct snd_compr_stream *stream, struct snd_compr_metadata *metadata); + int (*set_next_track_param)(struct snd_compr_stream *stream, + union snd_codec_options *codec_options); int (*trigger)(struct snd_compr_stream *stream, int cmd); int (*pointer)(struct snd_compr_stream *stream, struct snd_compr_tstamp *tstamp); diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 38cc30a37fcc..eac1e0166d26 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -172,6 +172,8 @@ struct snd_compr_metadata { * SNDRV_COMPRESS_STOP: stop a running stream, discarding ring buffer content * and the buffers currently with DSP * SNDRV_COMPRESS_DRAIN: Play till end of buffers and stop after that + * SNDRV_COMPRESS_SET_NEXT_TRACK_PARAM: send codec specific data for the next + * track in gapless * SNDRV_COMPRESS_IOCTL_VERSION: Query the API version */ #define SNDRV_COMPRESS_IOCTL_VERSION _IOR('C', 0x00, int) @@ -193,6 +195,8 @@ struct snd_compr_metadata { #define SNDRV_COMPRESS_DRAIN _IO('C', 0x34) #define SNDRV_COMPRESS_NEXT_TRACK _IO('C', 0x35) #define SNDRV_COMPRESS_PARTIAL_DRAIN _IO('C', 0x36) +#define SNDRV_COMPRESS_SET_NEXT_TRACK_PARAM\ + _IOW('C', 0x80, union snd_codec_options) /* * TODO * 1. add mmap support diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 0716e88eef4d..1bf0397175c3 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -891,6 +891,25 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream) return snd_compress_wait_for_drain(stream); } +static int snd_compr_set_next_track_param(struct snd_compr_stream *stream, + unsigned long arg) +{ + union snd_codec_options codec_options; + int retval; + + /* set next track params when stream is running or has been setup */ + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP && + stream->runtime->state != SNDRV_PCM_STATE_RUNNING) + return -EPERM; + + if (copy_from_user(&codec_options, (void __user *)arg, + sizeof(codec_options))) + return -EFAULT; + + retval = stream->ops->set_next_track_param(stream, &codec_options); + return retval; +} + static int snd_compress_simple_ioctls(struct file *file, struct snd_compr_stream *stream, unsigned int cmd, unsigned long arg) @@ -982,6 +1001,10 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) retval = snd_compr_next_track(stream); break; + case _IOC_NR(SNDRV_COMPRESS_SET_NEXT_TRACK_PARAM): + retval = snd_compr_set_next_track_param(stream, arg); + break; + default: mutex_unlock(&stream->device->lock); return snd_compress_simple_ioctls(f, stream, cmd, arg); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 409d082e80d1..4e6e9b6463b0 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -774,6 +774,28 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, return ret; } +static int sst_compr_set_next_track_param(struct snd_compr_stream *cstream, + union snd_codec_options *codec_options) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; + int ret = 0; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->driver->compr_ops && + component->driver->compr_ops->set_next_track_param) + ret = + component->driver->compr_ops->set_next_track_param( + cstream, codec_options); + } + + return ret; +} + + static int soc_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata) { @@ -840,6 +862,7 @@ static struct snd_compr_ops soc_compr_ops = { .free = soc_compr_free, .set_params = soc_compr_set_params, .set_metadata = soc_compr_set_metadata, + .set_next_track_param = sst_compr_set_next_track_param, .get_metadata = soc_compr_get_metadata, .get_params = soc_compr_get_params, .trigger = soc_compr_trigger, @@ -856,6 +879,7 @@ static struct snd_compr_ops soc_compr_dyn_ops = { .set_params = soc_compr_set_params_fe, .get_params = soc_compr_get_params, .set_metadata = soc_compr_set_metadata, + .set_next_track_param = sst_compr_set_next_track_param, .get_metadata = soc_compr_get_metadata, .trigger = soc_compr_trigger_fe, .pointer = soc_compr_pointer,