--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstclock.c: Clock subsystem for maintaining time sync
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstossclock.h"
+
+static GMemChunk *_gst_clock_entries_chunk;
+static GMutex *_gst_clock_entries_chunk_lock;
+static GList *_gst_clock_entries_pool;
+
+typedef struct _GstClockEntry GstClockEntry;
+
+typedef enum {
+ GST_ENTRY_OK,
+ GST_ENTRY_RESTART,
+} GstEntryStatus;
+
+struct _GstClockEntry {
+ GstClockTime time;
+ GstEntryStatus status;
+ GMutex *lock;
+ GCond *cond;
+};
+
+static void gst_oss_clock_class_init (GstOssClockClass *klass);
+static void gst_oss_clock_init (GstOssClock *clock);
+
+static void gst_oss_clock_reset (GstClock *clock);
+static void gst_oss_clock_activate (GstClock *clock, gboolean activate);
+static void gst_oss_clock_set_time (GstClock *clock, GstClockTime time);
+static GstClockReturn gst_oss_clock_wait (GstClock *clock, GstClockTime time);
+
+static GstSystemClockClass *parent_class = NULL;
+/* static guint gst_oss_clock_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_oss_clock_get_type (void)
+{
+ static GType clock_type = 0;
+
+ if (!clock_type) {
+ static const GTypeInfo clock_info = {
+ sizeof (GstOssClockClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_oss_clock_class_init,
+ NULL,
+ NULL,
+ sizeof (GstOssClock),
+ 4,
+ (GInstanceInitFunc) gst_oss_clock_init,
+ NULL
+ };
+ clock_type = g_type_register_static (GST_TYPE_SYSTEM_CLOCK, "GstOssClock",
+ &clock_info, 0);
+ }
+ return clock_type;
+}
+
+
+static void
+gst_oss_clock_class_init (GstOssClockClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstObjectClass *gstobject_class;
+ GstClockClass *gstclock_class;
+
+ gobject_class = (GObjectClass*) klass;
+ gstobject_class = (GstObjectClass*) klass;
+ gstclock_class = (GstClockClass*) klass;
+
+ parent_class = g_type_class_ref (GST_TYPE_SYSTEM_CLOCK);
+
+ gstclock_class->reset = gst_oss_clock_reset;
+ gstclock_class->activate = gst_oss_clock_activate;
+ gstclock_class->set_time = gst_oss_clock_set_time;
+ gstclock_class->wait = gst_oss_clock_wait;
+}
+
+static void
+gst_oss_clock_init (GstOssClock *clock)
+{
+ gst_object_set_name (GST_OBJECT (clock), "GstOssClock");
+ clock->is_updated = FALSE;
+}
+
+#define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry))
+#define GST_CLOCK_ENTRY_TIME(entry) (((GstClockEntry *)(entry))->time)
+#define GST_CLOCK_ENTRY_LOCK(entry) (g_mutex_lock ((entry)->lock))
+#define GST_CLOCK_ENTRY_UNLOCK(entry) (g_mutex_unlock ((entry)->lock))
+#define GST_CLOCK_ENTRY_SIGNAL(entry) (g_cond_signal ((entry)->cond))
+#define GST_CLOCK_ENTRY_WAIT(entry) (g_cond_wait (entry->cond, entry->lock))
+#define GST_CLOCK_ENTRY_TIMED_WAIT(entry, time) (g_cond_timed_wait (entry->cond, entry->lock, (time)))
+
+static GstClockEntry*
+gst_clock_entry_new (GstClockTime time)
+{
+ GstClockEntry *entry;
+
+ g_mutex_lock (_gst_clock_entries_chunk_lock);
+ if (_gst_clock_entries_pool) {
+ entry = GST_CLOCK_ENTRY (_gst_clock_entries_pool->data);
+
+ _gst_clock_entries_pool = g_list_remove (_gst_clock_entries_pool, entry);
+ g_mutex_unlock (_gst_clock_entries_chunk_lock);
+ }
+ else {
+ entry = g_mem_chunk_alloc (_gst_clock_entries_chunk);
+ g_mutex_unlock (_gst_clock_entries_chunk_lock);
+
+ entry->lock = g_mutex_new ();
+ entry->cond = g_cond_new ();
+ }
+
+ entry->time = time;
+
+ return entry;
+}
+
+static void
+gst_clock_entry_free (GstClockEntry *entry)
+{
+ g_mutex_lock (_gst_clock_entries_chunk_lock);
+ _gst_clock_entries_pool = g_list_prepend (_gst_clock_entries_pool, entry);
+ g_mutex_unlock (_gst_clock_entries_chunk_lock);
+}
+
+GstOssClock*
+gst_oss_clock_new (gchar *name, GstElement *owner)
+{
+ GstOssClock *oss_clock = GST_OSS_CLOCK (g_object_new (GST_TYPE_OSS_CLOCK, NULL));
+
+ oss_clock->entries = NULL;
+ oss_clock->current_time = 0;
+ oss_clock->next_time = 0;
+
+ _gst_clock_entries_chunk = g_mem_chunk_new ("GstClockEntries",
+ sizeof (GstClockEntry), sizeof (GstClockEntry) * 32,
+ G_ALLOC_AND_FREE);
+ _gst_clock_entries_chunk_lock = g_mutex_new ();
+ _gst_clock_entries_pool = NULL;
+
+ return oss_clock;
+}
+
+void
+gst_oss_clock_set_update (GstOssClock *clock, gboolean update)
+{
+ GST_LOCK (clock);
+
+ if (!update) {
+
+ GST_UNLOCK (clock);
+ GST_CLOCK_CLASS (parent_class)->set_time (GST_CLOCK (clock), clock->current_time);
+ GST_LOCK (clock);
+ clock->is_updated = FALSE;
+
+ /* FIXME, convert the entries to ones that wait for the system clock */
+ if (clock->entries) {
+ GList *entries = g_list_copy (clock->entries);
+ while (entries) {
+ GstClockEntry *entry = (GstClockEntry *)entries->data;
+
+ GST_CLOCK_ENTRY_LOCK (entry);
+ GST_CLOCK_ENTRY_SIGNAL (entry);
+ entry->status = GST_ENTRY_RESTART;
+ GST_CLOCK_ENTRY_UNLOCK (entry);
+
+ clock->entries = g_list_remove (clock->entries, entry);
+ entries = g_list_next (entries);
+ }
+ }
+ }
+ else {
+ clock->is_updated = TRUE;
+ }
+
+ GST_UNLOCK (clock);
+}
+
+void
+gst_oss_clock_set_base (GstOssClock *clock, guint64 base)
+{
+ GstOssClock *oss_clock = GST_OSS_CLOCK (clock);
+
+ oss_clock->base_time = base;
+
+ GST_CLOCK_CLASS (parent_class)->set_time (clock, base);
+}
+
+static void
+gst_oss_clock_reset (GstClock *clock)
+{
+ GstOssClock *oss_clock = GST_OSS_CLOCK (clock);
+
+ oss_clock->next_time = 0;
+ oss_clock->current_time = 0;
+ oss_clock->base_time = 0;
+
+ GST_CLOCK_CLASS (parent_class)->reset (clock);
+}
+
+static void
+gst_oss_clock_activate (GstClock *clock, gboolean activate)
+{
+ GstOssClock *oss_clock = GST_OSS_CLOCK (clock);
+
+ if (!activate) {
+ oss_clock->base_time = oss_clock->current_time;
+ }
+
+ GST_CLOCK_CLASS (parent_class)->activate (clock, activate);
+}
+
+static void
+gst_oss_clock_set_time (GstClock *clock, GstClockTime time)
+{
+ GList *entries;
+ GstOssClock *oss_clock = GST_OSS_CLOCK (clock);
+
+ GST_LOCK (clock);
+
+ time += oss_clock->base_time;
+
+ //g_print ("set time %llu\n", time);
+
+ oss_clock->current_time = time;
+
+ if (oss_clock->next_time > time) {
+ GST_UNLOCK (clock);
+ return;
+ }
+
+ entries = g_list_copy (oss_clock->entries);
+
+ while (entries) {
+ GstClockEntry *entry = (GstClockEntry *)entries->data;
+
+ if (GST_CLOCK_ENTRY_TIME (entry) <= oss_clock->current_time) {
+
+ GST_CLOCK_ENTRY_LOCK (entry);
+ GST_CLOCK_ENTRY_SIGNAL (entry);
+ entry->status = GST_ENTRY_OK;
+ GST_CLOCK_ENTRY_UNLOCK (entry);
+
+ oss_clock->entries = g_list_remove (oss_clock->entries, entry);
+ }
+ else {
+ break;
+ }
+ entries = g_list_next (entries);
+ }
+
+ if (oss_clock->entries) {
+ oss_clock->next_time = GST_CLOCK_ENTRY_TIME (oss_clock->entries->data);
+ }
+ else {
+ oss_clock->next_time = 0;
+ }
+
+ GST_UNLOCK (oss_clock);
+}
+
+static gint
+clock_compare_func (gconstpointer a,
+ gconstpointer b)
+{
+ GstClockEntry *entry1 = (GstClockEntry *)a;
+ GstClockEntry *entry2 = (GstClockEntry *)b;
+
+ return (entry1->time - entry2->time);
+}
+
+static GstClockReturn
+gst_oss_clock_wait (GstClock *clock, GstClockTime time)
+{
+ GstClockReturn ret;
+ GstOssClock *oss_clock = GST_OSS_CLOCK (clock);
+
+ GST_LOCK (clock);
+restart:
+ if (!oss_clock->is_updated) {
+ GST_UNLOCK (clock);
+ ret = GST_CLOCK_CLASS (parent_class)->wait (clock, time);
+ }
+ else if (time > oss_clock->current_time) {
+ GstClockEntry *entry = gst_clock_entry_new (time);
+
+ oss_clock->entries = g_list_insert_sorted (oss_clock->entries, entry, clock_compare_func);
+
+ oss_clock->next_time = GST_CLOCK_ENTRY_TIME (oss_clock->entries->data);
+
+ GST_CLOCK_ENTRY_LOCK (entry);
+ GST_UNLOCK (clock);
+ GST_CLOCK_ENTRY_WAIT (entry);
+ if (entry->status == GST_ENTRY_RESTART)
+ goto restart;
+ GST_CLOCK_ENTRY_UNLOCK (entry);
+
+ gst_clock_entry_free (entry);
+
+ ret = GST_CLOCK_TIMEOUT;
+ }
+ else {
+ GST_UNLOCK (clock);
+
+ ret = GST_CLOCK_EARLY;
+ }
+
+ return ret;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstclock.h: Header for clock subsystem
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_OSS_CLOCK_H__
+#define __GST_OSS_CLOCK_H__
+
+#include <gst/gstsystemclock.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_OSS_CLOCK \
+ (gst_oss_clock_get_type())
+#define GST_OSS_CLOCK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS_CLOCK,GstOssClock))
+#define GST_OSS_CLOCK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS_CLOCK,GstOssClockClass))
+#define GST_IS_OSS_CLOCK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS_CLOCK))
+#define GST_IS_OSS_CLOCK_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS_CLOCK))
+
+typedef struct _GstOssClock GstOssClock;
+typedef struct _GstOssClockClass GstOssClockClass;
+
+struct _GstOssClock {
+ GstSystemClock clock;
+
+ GList *entries;
+ GstClockTime current_time;
+ GstClockTime next_time;
+ GstClockTime base_time;
+ gboolean is_updated;
+ GstClockTime start_time;
+ GstClockTime origin;
+
+ GstElement *owner;
+};
+
+struct _GstOssClockClass {
+ GstSystemClockClass parent_class;
+};
+
+GType gst_oss_clock_get_type (void);
+GstOssClock* gst_oss_clock_new (gchar *name, GstElement *owner);
+
+void gst_oss_clock_set_update (GstOssClock *clock, gboolean update);
+void gst_oss_clock_set_base (GstOssClock *clock, guint64 base);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_OSS_CLOCK_H__ */