mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-09-03 18:53:58 +00:00
alsasink: pause/resume
alsasink can now detect a resume, stop and pause. The sink is now properly paused using snd_pcm_pause(), and without losing any data
This commit is contained in:
parent
feb1e24347
commit
5d3c948572
2 changed files with 95 additions and 9 deletions
|
@ -94,7 +94,9 @@ static gboolean gst_alsasink_close (GstAudioSink * asink);
|
||||||
static gint gst_alsasink_write (GstAudioSink * asink, gpointer data,
|
static gint gst_alsasink_write (GstAudioSink * asink, gpointer data,
|
||||||
guint length);
|
guint length);
|
||||||
static guint gst_alsasink_delay (GstAudioSink * asink);
|
static guint gst_alsasink_delay (GstAudioSink * asink);
|
||||||
static void gst_alsasink_reset (GstAudioSink * asink);
|
static void gst_alsasink_pause (GstAudioSink * asink);
|
||||||
|
static void gst_alsasink_resume (GstAudioSink * asink);
|
||||||
|
static void gst_alsasink_stop (GstAudioSink * asink);
|
||||||
static gboolean gst_alsasink_acceptcaps (GstAlsaSink * alsa, GstCaps * caps);
|
static gboolean gst_alsasink_acceptcaps (GstAlsaSink * alsa, GstCaps * caps);
|
||||||
static GstBuffer *gst_alsasink_payload (GstAudioBaseSink * sink,
|
static GstBuffer *gst_alsasink_payload (GstAudioBaseSink * sink,
|
||||||
GstBuffer * buf);
|
GstBuffer * buf);
|
||||||
|
@ -181,7 +183,9 @@ gst_alsasink_class_init (GstAlsaSinkClass * klass)
|
||||||
gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_alsasink_close);
|
gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_alsasink_close);
|
||||||
gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_alsasink_write);
|
gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_alsasink_write);
|
||||||
gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_alsasink_delay);
|
gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_alsasink_delay);
|
||||||
gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_alsasink_reset);
|
gstaudiosink_class->stop = GST_DEBUG_FUNCPTR (gst_alsasink_stop);
|
||||||
|
gstaudiosink_class->pause = GST_DEBUG_FUNCPTR (gst_alsasink_pause);
|
||||||
|
gstaudiosink_class->resume = GST_DEBUG_FUNCPTR (gst_alsasink_resume);
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_DEVICE,
|
g_object_class_install_property (gobject_class, PROP_DEVICE,
|
||||||
g_param_spec_string ("device", "Device",
|
g_param_spec_string ("device", "Device",
|
||||||
|
@ -259,6 +263,9 @@ gst_alsasink_init (GstAlsaSink * alsasink)
|
||||||
alsasink->device = g_strdup (DEFAULT_DEVICE);
|
alsasink->device = g_strdup (DEFAULT_DEVICE);
|
||||||
alsasink->handle = NULL;
|
alsasink->handle = NULL;
|
||||||
alsasink->cached_caps = NULL;
|
alsasink->cached_caps = NULL;
|
||||||
|
alsasink->is_paused = FALSE;
|
||||||
|
alsasink->after_paused = FALSE;
|
||||||
|
alsasink->hw_support_pause = FALSE;
|
||||||
g_mutex_init (&alsasink->alsa_lock);
|
g_mutex_init (&alsasink->alsa_lock);
|
||||||
g_mutex_init (&alsasink->delay_lock);
|
g_mutex_init (&alsasink->delay_lock);
|
||||||
|
|
||||||
|
@ -545,6 +552,11 @@ retry:
|
||||||
GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size,
|
GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size,
|
||||||
alsa->period_size);
|
alsa->period_size);
|
||||||
|
|
||||||
|
/* Check if hardware supports pause */
|
||||||
|
alsa->hw_support_pause = snd_pcm_hw_params_can_pause (params);
|
||||||
|
GST_DEBUG_OBJECT (alsa, "Hw support pause: %s",
|
||||||
|
alsa->hw_support_pause ? "yes" : "no");
|
||||||
|
|
||||||
snd_pcm_hw_params_free (params);
|
snd_pcm_hw_params_free (params);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1084,12 +1096,23 @@ gst_alsasink_delay (GstAudioSink * asink)
|
||||||
{
|
{
|
||||||
GstAlsaSink *alsa;
|
GstAlsaSink *alsa;
|
||||||
snd_pcm_sframes_t delay;
|
snd_pcm_sframes_t delay;
|
||||||
int res;
|
int res = 0;
|
||||||
|
|
||||||
alsa = GST_ALSA_SINK (asink);
|
alsa = GST_ALSA_SINK (asink);
|
||||||
|
|
||||||
GST_DELAY_SINK_LOCK (asink);
|
GST_DELAY_SINK_LOCK (asink);
|
||||||
res = snd_pcm_delay (alsa->handle, &delay);
|
if (alsa->is_paused == TRUE) {
|
||||||
|
delay = alsa->pos_in_buffer;
|
||||||
|
alsa->is_paused = FALSE;
|
||||||
|
alsa->after_paused = TRUE;
|
||||||
|
} else {
|
||||||
|
if (alsa->after_paused == TRUE) {
|
||||||
|
delay = alsa->pos_in_buffer;
|
||||||
|
alsa->after_paused = FALSE;
|
||||||
|
} else {
|
||||||
|
res = snd_pcm_delay (alsa->handle, &delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
GST_DELAY_SINK_UNLOCK (asink);
|
GST_DELAY_SINK_UNLOCK (asink);
|
||||||
if (G_UNLIKELY (res < 0)) {
|
if (G_UNLIKELY (res < 0)) {
|
||||||
/* on errors, report 0 delay */
|
/* on errors, report 0 delay */
|
||||||
|
@ -1106,7 +1129,65 @@ gst_alsasink_delay (GstAudioSink * asink)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_alsasink_reset (GstAudioSink * asink)
|
gst_alsasink_pause (GstAudioSink * asink)
|
||||||
|
{
|
||||||
|
GstAlsaSink *alsa;
|
||||||
|
gint err;
|
||||||
|
snd_pcm_sframes_t delay;
|
||||||
|
|
||||||
|
alsa = GST_ALSA_SINK (asink);
|
||||||
|
|
||||||
|
if (alsa->hw_support_pause == TRUE) {
|
||||||
|
GST_ALSA_SINK_LOCK (asink);
|
||||||
|
snd_pcm_delay (alsa->handle, &delay);
|
||||||
|
alsa->pos_in_buffer = delay;
|
||||||
|
CHECK (snd_pcm_pause (alsa->handle, 1), pause_error);
|
||||||
|
GST_DEBUG_OBJECT (alsa, "pause done");
|
||||||
|
alsa->is_paused = TRUE;
|
||||||
|
GST_ALSA_SINK_UNLOCK (asink);
|
||||||
|
} else {
|
||||||
|
gst_alsasink_stop (asink);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
pause_error:
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (alsa, "alsa-pause: pcm pause error: %s",
|
||||||
|
snd_strerror (err));
|
||||||
|
GST_ALSA_SINK_UNLOCK (asink);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_alsasink_resume (GstAudioSink * asink)
|
||||||
|
{
|
||||||
|
GstAlsaSink *alsa;
|
||||||
|
gint err;
|
||||||
|
|
||||||
|
alsa = GST_ALSA_SINK (asink);
|
||||||
|
|
||||||
|
if (alsa->hw_support_pause == TRUE) {
|
||||||
|
GST_ALSA_SINK_LOCK (asink);
|
||||||
|
CHECK (snd_pcm_pause (alsa->handle, 0), resume_error);
|
||||||
|
GST_DEBUG_OBJECT (alsa, "resume done");
|
||||||
|
GST_ALSA_SINK_UNLOCK (asink);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
resume_error:
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (alsa, "alsa-resume: pcm resume error: %s",
|
||||||
|
snd_strerror (err));
|
||||||
|
GST_ALSA_SINK_UNLOCK (asink);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_alsasink_stop (GstAudioSink * asink)
|
||||||
{
|
{
|
||||||
GstAlsaSink *alsa;
|
GstAlsaSink *alsa;
|
||||||
gint err;
|
gint err;
|
||||||
|
@ -1118,7 +1199,7 @@ gst_alsasink_reset (GstAudioSink * asink)
|
||||||
CHECK (snd_pcm_drop (alsa->handle), drop_error);
|
CHECK (snd_pcm_drop (alsa->handle), drop_error);
|
||||||
GST_DEBUG_OBJECT (alsa, "prepare");
|
GST_DEBUG_OBJECT (alsa, "prepare");
|
||||||
CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
|
CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
|
||||||
GST_DEBUG_OBJECT (alsa, "reset done");
|
GST_DEBUG_OBJECT (alsa, "stop done");
|
||||||
GST_ALSA_SINK_UNLOCK (asink);
|
GST_ALSA_SINK_UNLOCK (asink);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -1126,14 +1207,14 @@ gst_alsasink_reset (GstAudioSink * asink)
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
drop_error:
|
drop_error:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (alsa, "alsa-reset: pcm drop error: %s",
|
GST_ERROR_OBJECT (alsa, "alsa-stop: pcm drop error: %s",
|
||||||
snd_strerror (err));
|
snd_strerror (err));
|
||||||
GST_ALSA_SINK_UNLOCK (asink);
|
GST_ALSA_SINK_UNLOCK (asink);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
prepare_error:
|
prepare_error:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (alsa, "alsa-reset: pcm prepare error: %s",
|
GST_ERROR_OBJECT (alsa, "alsa-stop: pcm prepare error: %s",
|
||||||
snd_strerror (err));
|
snd_strerror (err));
|
||||||
GST_ALSA_SINK_UNLOCK (asink);
|
GST_ALSA_SINK_UNLOCK (asink);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
|
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstalsasink.h:
|
* gstalsasink.h:
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -74,6 +74,11 @@ struct _GstAlsaSink {
|
||||||
|
|
||||||
GstCaps *cached_caps;
|
GstCaps *cached_caps;
|
||||||
|
|
||||||
|
gboolean is_paused;
|
||||||
|
gboolean after_paused;
|
||||||
|
gboolean hw_support_pause;
|
||||||
|
snd_pcm_sframes_t pos_in_buffer;
|
||||||
|
|
||||||
GMutex alsa_lock;
|
GMutex alsa_lock;
|
||||||
GMutex delay_lock;
|
GMutex delay_lock;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue