mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
347cdcdfeb
Original commit message from CVS: * ext/alsa/gstalsaclock.c: (gst_alsa_clock_wait): Sanity check, don't wait endlessly since the clock might not actually run at this point (which is a deadlock). Fixes #164069.
214 lines
6.2 KiB
C
214 lines
6.2 KiB
C
/*
|
|
* Copyright (C) 2001 CodeFactory AB
|
|
* Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
|
|
* Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
|
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstalsaclock.h"
|
|
|
|
/* clock functions */
|
|
static void gst_alsa_clock_class_init (gpointer g_class, gpointer class_data);
|
|
static void gst_alsa_clock_init (GstAlsaClock * clock);
|
|
|
|
static GstClockTime gst_alsa_clock_get_internal_time (GstClock * clock);
|
|
static guint64 gst_alsa_clock_get_resolution (GstClock * clock);
|
|
static GstClockEntryStatus gst_alsa_clock_wait (GstClock * clock,
|
|
GstClockEntry * entry);
|
|
static void gst_alsa_clock_unlock (GstClock * clock, GstClockEntry * entry);
|
|
|
|
static GstClockClass *clock_parent_class = NULL;
|
|
|
|
/* static guint gst_alsa_clock_signals[LAST_SIGNAL] = { 0 }; */
|
|
|
|
GType
|
|
gst_alsa_clock_get_type (void)
|
|
{
|
|
static GType clock_type = 0;
|
|
|
|
if (!clock_type) {
|
|
static const GTypeInfo clock_info = {
|
|
sizeof (GstAlsaClockClass),
|
|
NULL,
|
|
NULL,
|
|
gst_alsa_clock_class_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof (GstAlsaClock),
|
|
4,
|
|
(GInstanceInitFunc) gst_alsa_clock_init,
|
|
NULL
|
|
};
|
|
|
|
clock_type = g_type_register_static (GST_TYPE_CLOCK, "GstAlsaClock",
|
|
&clock_info, 0);
|
|
}
|
|
return clock_type;
|
|
}
|
|
static void
|
|
gst_alsa_clock_class_init (gpointer g_class, gpointer class_data)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GstObjectClass *gstobject_class;
|
|
GstClockClass *gstclock_class;
|
|
GstAlsaClockClass *klass;
|
|
|
|
klass = (GstAlsaClockClass *) g_class;
|
|
gobject_class = (GObjectClass *) klass;
|
|
gstobject_class = (GstObjectClass *) klass;
|
|
gstclock_class = (GstClockClass *) klass;
|
|
|
|
clock_parent_class = g_type_class_ref (GST_TYPE_CLOCK);
|
|
|
|
gstclock_class->get_internal_time = gst_alsa_clock_get_internal_time;
|
|
gstclock_class->get_resolution = gst_alsa_clock_get_resolution;
|
|
gstclock_class->wait = gst_alsa_clock_wait;
|
|
gstclock_class->unlock = gst_alsa_clock_unlock;
|
|
}
|
|
static void
|
|
gst_alsa_clock_init (GstAlsaClock * clock)
|
|
{
|
|
gst_object_set_name (GST_OBJECT (clock), "GstAlsaClock");
|
|
|
|
clock->start_time = GST_CLOCK_TIME_NONE;
|
|
}
|
|
|
|
GstAlsaClock *
|
|
gst_alsa_clock_new (gchar * name, GstAlsaClockGetTimeFunc get_time,
|
|
GstAlsa * owner)
|
|
{
|
|
GstAlsaClock *alsa_clock =
|
|
GST_ALSA_CLOCK (g_object_new (GST_TYPE_ALSA_CLOCK, NULL));
|
|
|
|
g_assert (alsa_clock);
|
|
|
|
alsa_clock->get_time = get_time;
|
|
alsa_clock->owner = owner;
|
|
alsa_clock->adjust = 0;
|
|
|
|
gst_object_set_name (GST_OBJECT (alsa_clock), name);
|
|
gst_object_set_parent (GST_OBJECT (alsa_clock), GST_OBJECT (owner));
|
|
|
|
return alsa_clock;
|
|
}
|
|
|
|
void
|
|
gst_alsa_clock_start (GstAlsaClock * clock)
|
|
{
|
|
g_assert (!GST_CLOCK_TIME_IS_VALID (clock->start_time));
|
|
|
|
if (clock->owner->format) {
|
|
clock->start_time = gst_clock_get_event_time (GST_CLOCK (clock))
|
|
- clock->get_time (clock->owner);
|
|
} else {
|
|
clock->start_time = gst_clock_get_event_time (GST_CLOCK (clock));
|
|
}
|
|
}
|
|
void
|
|
gst_alsa_clock_stop (GstAlsaClock * clock)
|
|
{
|
|
GTimeVal timeval;
|
|
|
|
g_get_current_time (&timeval);
|
|
|
|
g_assert (GST_CLOCK_TIME_IS_VALID (clock->start_time));
|
|
|
|
clock->adjust +=
|
|
GST_TIMEVAL_TO_TIME (timeval) -
|
|
gst_clock_get_event_time (GST_CLOCK (clock));
|
|
clock->start_time = GST_CLOCK_TIME_NONE;
|
|
}
|
|
|
|
static GstClockTime
|
|
gst_alsa_clock_get_internal_time (GstClock * clock)
|
|
{
|
|
GstAlsaClock *alsa_clock = GST_ALSA_CLOCK (clock);
|
|
|
|
if (GST_CLOCK_TIME_IS_VALID (alsa_clock->start_time)) {
|
|
return alsa_clock->get_time (alsa_clock->owner) + alsa_clock->start_time;
|
|
} else {
|
|
GTimeVal timeval;
|
|
|
|
g_get_current_time (&timeval);
|
|
return GST_TIMEVAL_TO_TIME (timeval) + alsa_clock->adjust;
|
|
}
|
|
}
|
|
static guint64
|
|
gst_alsa_clock_get_resolution (GstClock * clock)
|
|
{
|
|
GstAlsaClock *this = GST_ALSA_CLOCK (clock);
|
|
|
|
if (this->owner->format) {
|
|
return GST_SECOND / this->owner->format->rate;
|
|
} else {
|
|
/* FIXME: is there an "unknown" value? We just return the sysclock's time by default */
|
|
return 1 * GST_USECOND;
|
|
}
|
|
}
|
|
static GstClockEntryStatus
|
|
gst_alsa_clock_wait (GstClock * clock, GstClockEntry * entry)
|
|
{
|
|
GstClockTime target, entry_time, glib_start, glib_cur;
|
|
GstClockTimeDiff diff;
|
|
GstAlsaClock *this = GST_ALSA_CLOCK (clock);
|
|
GTimeVal t;
|
|
|
|
entry_time = gst_alsa_clock_get_internal_time (clock);
|
|
diff = GST_CLOCK_ENTRY_TIME (entry) - gst_clock_get_time (clock);
|
|
|
|
if (diff < 0)
|
|
return GST_CLOCK_ENTRY_EARLY;
|
|
|
|
if (diff > clock->max_diff) {
|
|
GST_INFO_OBJECT (this,
|
|
"GstAlsaClock: abnormal clock request diff: %" GST_TIME_FORMAT ") >"
|
|
" %" GST_TIME_FORMAT, GST_TIME_ARGS (diff),
|
|
GST_TIME_ARGS (clock->max_diff));
|
|
return GST_CLOCK_ENTRY_EARLY;
|
|
}
|
|
|
|
target = entry_time + diff;
|
|
|
|
GST_DEBUG_OBJECT (this, "real_target %" GST_TIME_FORMAT
|
|
" target %" GST_TIME_FORMAT
|
|
" now %" GST_TIME_FORMAT,
|
|
GST_TIME_ARGS (target), GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)),
|
|
GST_TIME_ARGS (entry_time));
|
|
|
|
g_get_current_time (&t);
|
|
glib_cur = glib_start = GST_TIMEVAL_TO_TIME (t);
|
|
while (gst_alsa_clock_get_internal_time (clock) < target &&
|
|
this->last_unlock < entry_time && glib_start + diff * 1.5 > glib_cur) {
|
|
g_usleep (gst_alsa_clock_get_resolution (clock) * G_USEC_PER_SEC /
|
|
GST_SECOND);
|
|
g_get_current_time (&t);
|
|
glib_cur = GST_TIMEVAL_TO_TIME (t);
|
|
}
|
|
|
|
return entry->status;
|
|
}
|
|
static void
|
|
gst_alsa_clock_unlock (GstClock * clock, GstClockEntry * entry)
|
|
{
|
|
GstAlsaClock *this = GST_ALSA_CLOCK (clock);
|
|
|
|
this->last_unlock = this->get_time (this->owner);
|
|
}
|