aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuodong Hu <quic_guodhu@quicinc.com>2023-08-15 13:37:26 +0800
committerGuodong Hu <quic_guodhu@quicinc.com>2023-09-04 13:15:03 +0800
commitbc3af517534346742a2e753f753a0ad21f51513b (patch)
treed8f0fabf18bb5338c21819d8b1669c1031eccb2e
parent7c467a1179cca66bb65a4a04f889319e4bfb9b3e (diff)
Support pcm drain ops
Signed-off-by: Guodong Hu <quic_guodhu@quicinc.com>
-rw-r--r--include/tinyalsa/pcm.h2
-rw-r--r--include/tinyalsa/plugin.h5
-rw-r--r--src/pcm.c16
-rw-r--r--src/pcm_plugin.c13
4 files changed, 35 insertions, 1 deletions
diff --git a/include/tinyalsa/pcm.h b/include/tinyalsa/pcm.h
index 9fca92d..35318a5 100644
--- a/include/tinyalsa/pcm.h
+++ b/include/tinyalsa/pcm.h
@@ -361,6 +361,8 @@ int pcm_prepare(struct pcm *pcm);
int pcm_start(struct pcm *pcm);
+int pcm_drain(struct pcm *pcm);
+
int pcm_stop(struct pcm *pcm);
int pcm_wait(struct pcm *pcm, int timeout);
diff --git a/include/tinyalsa/plugin.h b/include/tinyalsa/plugin.h
index b2f97b9..055734c 100644
--- a/include/tinyalsa/plugin.h
+++ b/include/tinyalsa/plugin.h
@@ -124,7 +124,10 @@ struct pcm_plugin_ops {
int (*prepare) (struct pcm_plugin *plugin);
/** Start data transfer from/to the plugin */
int (*start) (struct pcm_plugin *plugin);
- /** Drop pcm frames */
+ /** Signal the plugin to drain PCM */
+ int (*drain) (struct pcm_plugin *plugin);
+ /** Stop a PCM dropping pending frames if drain() is NOT called.
+ * Stop a PCM preserving pending frames if drain() is called. */
int (*drop) (struct pcm_plugin *plugin);
/** Any custom or alsa specific ioctl implementation */
int (*ioctl) (struct pcm_plugin *plugin,
diff --git a/src/pcm.c b/src/pcm.c
index d681563..1b2103a 100644
--- a/src/pcm.c
+++ b/src/pcm.c
@@ -1218,6 +1218,22 @@ int pcm_start(struct pcm *pcm)
return 0;
}
+/** Drains a PCM.
+ * @param pcm A PCM handle.
+ * @return On success, zero; on failure, a negative number.
+ * @ingroup libtinyalsa-pcm
+ */
+int pcm_drain(struct pcm *pcm)
+{
+ if (!pcm_is_ready(pcm))
+ return -1;
+
+ if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_DRAIN) < 0)
+ return oops(pcm, errno, "cannot drain channel");
+
+ return 0;
+}
+
/** Stops a PCM.
* @param pcm A PCM handle.
* @return On success, zero; on failure, a negative number.
diff --git a/src/pcm_plugin.c b/src/pcm_plugin.c
index b6b69aa..4d2651c 100644
--- a/src/pcm_plugin.c
+++ b/src/pcm_plugin.c
@@ -622,6 +622,16 @@ static int pcm_plug_drop(struct pcm_plug_data *plug_data)
return rc;
}
+static int pcm_plug_drain(struct pcm_plug_data *plug_data)
+{
+ struct pcm_plugin *plugin = plug_data->plugin;
+
+ if (plugin->state != PCM_PLUG_STATE_RUNNING)
+ return -EBADFD;
+
+ return plug_data->ops->drain(plugin);
+}
+
static int pcm_plug_ioctl(void *data, unsigned int cmd, ...)
{
struct pcm_plug_data *plug_data = data;
@@ -659,6 +669,9 @@ static int pcm_plug_ioctl(void *data, unsigned int cmd, ...)
case SNDRV_PCM_IOCTL_START:
ret = pcm_plug_start(plug_data);
break;
+ case SNDRV_PCM_IOCTL_DRAIN:
+ ret = pcm_plug_drain(plug_data);
+ break;
case SNDRV_PCM_IOCTL_DROP:
ret = pcm_plug_drop(plug_data);
break;