aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--include/sound/compress_driver.h16
-rw-r--r--sound/core/compress_offload.c39
2 files changed, 47 insertions, 8 deletions
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index 70cbc5095e72..277087f635f3 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -67,6 +67,7 @@ struct snd_compr_runtime {
* @metadata_set: metadata set flag, true when set
* @next_track: has userspace signal next track transition, true when set
* @partial_drain: undergoing partial_drain for stream, true when set
+ * @pause_in_draining: paused during draining state, true when set
* @private_data: pointer to DSP private data
* @dma_buffer: allocated buffer if any
*/
@@ -80,6 +81,7 @@ struct snd_compr_stream {
bool metadata_set;
bool next_track;
bool partial_drain;
+ bool pause_in_draining;
void *private_data;
struct snd_dma_buffer dma_buffer;
};
@@ -142,6 +144,7 @@ struct snd_compr_ops {
* @direction: Playback or capture direction
* @lock: device lock
* @device: device id
+ * @use_pause_in_draining: allow pause in draining, true when set
*/
struct snd_compr {
const char *name;
@@ -152,6 +155,7 @@ struct snd_compr {
unsigned int direction;
struct mutex lock;
int device;
+ bool use_pause_in_draining;
#ifdef CONFIG_SND_VERBOSE_PROCFS
/* private: */
char id[64];
@@ -166,6 +170,18 @@ int snd_compress_deregister(struct snd_compr *device);
int snd_compress_new(struct snd_card *card, int device,
int type, const char *id, struct snd_compr *compr);
+/**
+ * snd_compr_use_pause_in_draining - Allow pause and resume in draining state
+ * @substream: compress substream to set
+ *
+ * Allow pause and resume in draining state.
+ * Only HW driver supports this transition can call this API.
+ */
+static inline void snd_compr_use_pause_in_draining(struct snd_compr_stream *substream)
+{
+ substream->device->use_pause_in_draining = true;
+}
+
/* dsp driver callback apis
* For playback: driver should call snd_compress_fragment_elapsed() to let the
* framework know that a fragment has been consumed from the ring buffer
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index c1fec932c49d..debc30fcf5b3 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -709,11 +709,22 @@ static int snd_compr_pause(struct snd_compr_stream *stream)
{
int retval;
- if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_RUNNING:
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
+ break;
+ case SNDRV_PCM_STATE_DRAINING:
+ if (!stream->device->use_pause_in_draining)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
+ if (!retval)
+ stream->pause_in_draining = true;
+ break;
+ default:
return -EPERM;
- retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
- if (!retval)
- stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
+ }
return retval;
}
@@ -721,11 +732,22 @@ static int snd_compr_resume(struct snd_compr_stream *stream)
{
int retval;
- if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_PAUSED:
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+ break;
+ case SNDRV_PCM_STATE_DRAINING:
+ if (!stream->pause_in_draining)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
+ if (!retval)
+ stream->pause_in_draining = false;
+ break;
+ default:
return -EPERM;
- retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
- if (!retval)
- stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+ }
return retval;
}
@@ -768,6 +790,7 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
/* clear flags and stop any drain wait */
stream->partial_drain = false;
stream->metadata_set = false;
+ stream->pause_in_draining = false;
snd_compr_drain_notify(stream);
stream->runtime->total_bytes_available = 0;
stream->runtime->total_bytes_transferred = 0;