[MOVED FROM GST-P-FARSIGHT] Do wierd casting of the volume to make MSVC happy
[platform/upstream/gstreamer.git] / gst / dtmf / gstdtmfsrc.c
index 7befc54..4b2f9a2 100644 (file)
@@ -64,7 +64,9 @@
  * <entry>0-1</entry>
  * <entry>The application uses this field to specify which of the two methods
  * specified in RFC 2833 to use. The value should be 0 for tones and 1 for
- * named events. This element is only capable of generating tones.
+ * named events. Tones are specified by their frequencies and events are specied
+ * by their number. This element can only take events as input. Do not confuse
+ * with "method" which specified the output.
  * </entry>
  * </row>
  * <row>
@@ -91,9 +93,9 @@
  * <row>
  * <entry>method</entry>
  * <entry>G_TYPE_INT</entry>
- * <entry>1</entry>
- * <entry>The method used for sending event, this element will react if this field
- * is absent or 2.
+ * <entry>2</entry>
+ * <entry>The method used for sending event, this element will react if this
+ * field is absent or 2.
  * </entry>
  * </row>
  * </tbody>
  * <para>
  * <programlisting>
  * structure = gst_structure_new ("dtmf-event",
- *                    "type", G_TYPE_INT, 0,
+ *                    "type", G_TYPE_INT, 1,
  *                    "number", G_TYPE_INT, 1,
  *                    "volume", G_TYPE_INT, 25,
  *                    "start", G_TYPE_BOOLEAN, TRUE, NULL);
 
 #include "gstdtmfsrc.h"
 
-#define GST_TONE_DTMF_TYPE_EVENT 0
+#define GST_TONE_DTMF_TYPE_EVENT 1
 #define DEFAULT_PACKET_INTERVAL  50 /* ms */
 #define MIN_PACKET_INTERVAL      10 /* ms */
 #define MAX_PACKET_INTERVAL      50 /* ms */
-#define SAMPLE_RATE              8000
+#define DEFAULT_SAMPLE_RATE      8000
 #define SAMPLE_SIZE              16
 #define CHANNELS                 1
 #define MIN_EVENT                0
@@ -225,59 +227,34 @@ GST_STATIC_PAD_TEMPLATE ("src",
     GST_STATIC_CAPS ("audio/x-raw-int, "
         "width = (int) 16, "
         "depth = (int) 16, "
-        "endianness = (int) 1234, "
+        "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
         "signed = (bool) true, "
         "rate = (int) 8000, "
         "channels = (int) 1")
     );
 
-static GstElementClass *parent_class = NULL;
+GST_BOILERPLATE (GstDTMFSrc, gst_dtmf_src, GstBaseSrc, GST_TYPE_BASE_SRC);
 
-static void gst_dtmf_src_base_init (gpointer g_class);
-static void gst_dtmf_src_class_init (GstDTMFSrcClass * klass);
-static void gst_dtmf_src_init (GstDTMFSrc * dtmfsrc, gpointer g_class);
 static void gst_dtmf_src_finalize (GObject * object);
 
-GType
-gst_dtmf_src_get_type (void)
-{
-  static GType base_src_type = 0;
-
-  if (G_UNLIKELY (base_src_type == 0)) {
-    static const GTypeInfo base_src_info = {
-      sizeof (GstDTMFSrcClass),
-      (GBaseInitFunc) gst_dtmf_src_base_init,
-      NULL,
-      (GClassInitFunc) gst_dtmf_src_class_init,
-      NULL,
-      NULL,
-      sizeof (GstDTMFSrc),
-      0,
-      (GInstanceInitFunc) gst_dtmf_src_init,
-    };
-
-    base_src_type = g_type_register_static (GST_TYPE_ELEMENT,
-        "GstDTMFSrc", &base_src_info, 0);
-  }
-  return base_src_type;
-}
-
 static void gst_dtmf_src_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_dtmf_src_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
-static gboolean gst_dtmf_src_handle_event (GstPad * pad, GstEvent * event);
+static gboolean gst_dtmf_src_handle_event (GstBaseSrc *src, GstEvent * event);
 static GstStateChangeReturn gst_dtmf_src_change_state (GstElement * element,
     GstStateChange transition);
-static void gst_dtmf_src_generate_tone(GstDTMFSrcEvent *event, DTMF_KEY key,
-    float duration, GstBuffer * buffer);
-static void gst_dtmf_src_push_next_tone_packet (GstDTMFSrc *dtmfsrc);
-static void gst_dtmf_src_start (GstDTMFSrc *dtmfsrc);
-static void gst_dtmf_src_stop (GstDTMFSrc *dtmfsrc);
+static GstFlowReturn gst_dtmf_src_create (GstBaseSrc * basesrc,
+    guint64 offset, guint length, GstBuffer ** buffer);
 static void gst_dtmf_src_add_start_event (GstDTMFSrc *dtmfsrc,
     gint event_number, gint event_volume);
 static void gst_dtmf_src_add_stop_event (GstDTMFSrc *dtmfsrc);
 
+static gboolean gst_dtmf_src_unlock (GstBaseSrc *src);
+
+static gboolean gst_dtmf_src_unlock_stop (GstBaseSrc *src);
+static gboolean gst_dtmf_src_negotiate (GstBaseSrc * basesrc);
+
 static void
 gst_dtmf_src_base_init (gpointer g_class)
 {
@@ -296,12 +273,13 @@ static void
 gst_dtmf_src_class_init (GstDTMFSrcClass * klass)
 {
   GObjectClass *gobject_class;
+  GstBaseSrcClass *gstbasesrc_class;
   GstElementClass *gstelement_class;
 
   gobject_class = G_OBJECT_CLASS (klass);
+  gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
   gstelement_class = GST_ELEMENT_CLASS (klass);
 
-  parent_class = g_type_class_peek_parent (klass);
 
   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_dtmf_src_finalize);
   gobject_class->set_property =
@@ -310,29 +288,40 @@ gst_dtmf_src_class_init (GstDTMFSrcClass * klass)
       GST_DEBUG_FUNCPTR (gst_dtmf_src_get_property);
 
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INTERVAL,
-      g_param_spec_int ("interval", "Interval between tone packets",
+      g_param_spec_uint ("interval", "Interval between tone packets",
           "Interval in ms between two tone packets", MIN_PACKET_INTERVAL,
           MAX_PACKET_INTERVAL, DEFAULT_PACKET_INTERVAL, G_PARAM_READWRITE));
 
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_dtmf_src_change_state);
+  gstbasesrc_class->unlock =
+      GST_DEBUG_FUNCPTR (gst_dtmf_src_unlock);
+  gstbasesrc_class->unlock_stop =
+      GST_DEBUG_FUNCPTR (gst_dtmf_src_unlock_stop);
+
+  gstbasesrc_class->event =
+      GST_DEBUG_FUNCPTR (gst_dtmf_src_handle_event);
+  gstbasesrc_class->create =
+      GST_DEBUG_FUNCPTR (gst_dtmf_src_create);
+  gstbasesrc_class->negotiate =
+      GST_DEBUG_FUNCPTR (gst_dtmf_src_negotiate);
 }
 
+
 static void
-gst_dtmf_src_init (GstDTMFSrc * dtmfsrc, gpointer g_class)
+gst_dtmf_src_init (GstDTMFSrc * dtmfsrc, GstDTMFSrcClass *g_class)
 {
-  dtmfsrc->srcpad =
-      gst_pad_new_from_static_template (&gst_dtmf_src_template, "src");
-  GST_DEBUG_OBJECT (dtmfsrc, "adding src pad");
-  gst_element_add_pad (GST_ELEMENT (dtmfsrc), dtmfsrc->srcpad);
-
-  gst_pad_set_event_function (dtmfsrc->srcpad, gst_dtmf_src_handle_event);
+  /* we operate in time */
+  gst_base_src_set_format (GST_BASE_SRC (dtmfsrc), GST_FORMAT_TIME);
+  gst_base_src_set_live (GST_BASE_SRC (dtmfsrc), TRUE);
 
   dtmfsrc->interval = DEFAULT_PACKET_INTERVAL;
 
   dtmfsrc->event_queue = g_async_queue_new ();
   dtmfsrc->last_event = NULL;
 
+  dtmfsrc->sample_rate = DEFAULT_SAMPLE_RATE;
+
   GST_DEBUG_OBJECT (dtmfsrc, "init done");
 }
 
@@ -343,9 +332,6 @@ gst_dtmf_src_finalize (GObject * object)
 
   dtmfsrc = GST_DTMF_SRC (object);
 
-
-  gst_dtmf_src_stop (dtmfsrc);
-
   if (dtmfsrc->event_queue) {
     g_async_queue_unref (dtmfsrc->event_queue);
     dtmfsrc->event_queue = NULL;
@@ -405,7 +391,7 @@ gst_dtmf_src_handle_custom_upstream (GstDTMFSrc *dtmfsrc,
   GstState state;
   GstStateChangeReturn ret;
 
-  ret = gst_element_get_state (dtmfsrc, &state, NULL, 0);
+  ret = gst_element_get_state (GST_ELEMENT (dtmfsrc), &state, NULL, 0);
   if (ret != GST_STATE_CHANGE_SUCCESS || state != GST_STATE_PLAYING) {
     GST_DEBUG_OBJECT (dtmfsrc, "Received event while not in PLAYING state");
     goto ret;
@@ -421,49 +407,18 @@ ret:
 }
 
 static gboolean
-gst_dtmf_src_handle_event (GstPad * pad, GstEvent * event)
+gst_dtmf_src_handle_event (GstBaseSrc * src, GstEvent * event)
 {
   GstDTMFSrc *dtmfsrc;
   gboolean result = FALSE;
-  GstElement *parent = gst_pad_get_parent_element (pad);
-  dtmfsrc = GST_DTMF_SRC (parent);
+
+  dtmfsrc = GST_DTMF_SRC (src);
 
   GST_DEBUG_OBJECT (dtmfsrc, "Received an event on the src pad");
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_CUSTOM_UPSTREAM:
-    {
-      result = gst_dtmf_src_handle_custom_upstream (dtmfsrc, event);
-      break;
-    }
-    /* Ideally this element should not be flushed but let's handle the event
-     * just in case it is */
-    case GST_EVENT_FLUSH_START:
-      gst_dtmf_src_stop (dtmfsrc);
-      result = TRUE;
-      break;
-    case GST_EVENT_FLUSH_STOP:
-      gst_segment_init (&dtmfsrc->segment, GST_FORMAT_TIME);
-      break;
-    case GST_EVENT_NEWSEGMENT:
-      {
-        gboolean update;
-        gdouble rate;
-        GstFormat fmt;
-        gint64 start, stop, position;
-
-        gst_event_parse_new_segment (event, &update, &rate, &fmt, &start,
-            &stop, &position);
-        gst_segment_set_newsegment (&dtmfsrc->segment, update, rate, fmt,
-            start, stop, position);
-      }
-      /* fallthrough */
-    default:
-      result = gst_pad_event_default (pad, event);
-      break;
+  if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) {
+    result = gst_dtmf_src_handle_custom_upstream (dtmfsrc, event);
   }
 
-  gst_object_unref (parent);
-  gst_event_unref (event);
   return result;
 }
 
@@ -477,7 +432,7 @@ gst_dtmf_src_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_INTERVAL:
-      dtmfsrc->interval = g_value_get_int (value);
+      dtmfsrc->interval = g_value_get_uint (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -506,6 +461,7 @@ gst_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
 static void
 gst_dtmf_src_set_stream_lock (GstDTMFSrc *dtmfsrc, gboolean lock)
 {
+   GstPad *srcpad = GST_BASE_SRC_PAD (dtmfsrc);
    GstEvent *event;
    GstStructure *structure;
 
@@ -513,7 +469,7 @@ gst_dtmf_src_set_stream_lock (GstDTMFSrc *dtmfsrc, gboolean lock)
                       "lock", G_TYPE_BOOLEAN, lock, NULL);
 
    event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, structure);
-   if (!gst_pad_push_event (dtmfsrc->srcpad, event)) {
+   if (!gst_pad_push_event (srcpad, event)) {
      GST_WARNING_OBJECT (dtmfsrc, "stream-lock event not handled");
    }
 }
@@ -522,10 +478,17 @@ static void
 gst_dtmf_prepare_timestamps (GstDTMFSrc *dtmfsrc)
 {
   GstClock *clock;
+  GstClockTime base_time;
+
+  base_time = gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
 
-  clock = gst_element_get_clock (dtmfsrc);
+  clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
   if (clock != NULL) {
+#ifdef MAEMO_BROKEN
     dtmfsrc->timestamp = gst_clock_get_time (clock);
+#else
+    dtmfsrc->timestamp = gst_clock_get_time (clock) - base_time;
+#endif
     gst_object_unref (clock);
   } else {
     gchar *dtmf_name = gst_element_get_name (dtmfsrc);
@@ -536,52 +499,6 @@ gst_dtmf_prepare_timestamps (GstDTMFSrc *dtmfsrc)
 }
 
 static void
-gst_dtmf_src_start (GstDTMFSrc *dtmfsrc)
-{
-  GstCaps * caps = gst_pad_get_pad_template_caps (dtmfsrc->srcpad);
-
-  if (!gst_pad_set_caps (dtmfsrc->srcpad, caps))
-    GST_ERROR_OBJECT (dtmfsrc,
-            "Failed to set caps %" GST_PTR_FORMAT " on src pad", caps);
-  else
-    GST_DEBUG_OBJECT (dtmfsrc,
-            "caps %" GST_PTR_FORMAT " set on src pad", caps);
-
-
-  if (!gst_pad_start_task (dtmfsrc->srcpad,
-      (GstTaskFunction) gst_dtmf_src_push_next_tone_packet, dtmfsrc)) {
-    GST_ERROR_OBJECT (dtmfsrc, "Failed to start task on src pad");
-  }
-}
-
-static void
-gst_dtmf_src_stop (GstDTMFSrc *dtmfsrc)
-{
-  /* Don't forget to release the stream lock */
-  gst_dtmf_src_set_stream_lock (dtmfsrc, FALSE);
-
-
-  /* Flushing the event queue */
-  GstDTMFSrcEvent *event = g_async_queue_try_pop (dtmfsrc->event_queue);
-
-  while (event != NULL) {
-    g_free (event);
-    event = g_async_queue_try_pop (dtmfsrc->event_queue);
-  }
-
-  if (dtmfsrc->last_event) {
-    g_free (dtmfsrc->last_event);
-    dtmfsrc->last_event = NULL;
-  }
-
-  if (!gst_pad_pause_task (dtmfsrc->srcpad)) {
-    GST_ERROR_OBJECT (dtmfsrc, "Failed to pause task on src pad");
-    return;
-  }
-
-}
-
-static void
 gst_dtmf_src_add_start_event (GstDTMFSrc *dtmfsrc, gint event_number,
     gint event_volume)
 {
@@ -609,12 +526,13 @@ gst_dtmf_src_add_stop_event (GstDTMFSrc *dtmfsrc)
 }
 
 static void
-gst_dtmf_src_generate_silence(GstBuffer * buffer, float duration)
+gst_dtmf_src_generate_silence(GstBuffer * buffer, float duration,
+    gint sample_rate)
 {
   gint buf_size;
 
   /* Create a buffer with data set to 0 */
-  buf_size = ((duration/1000)*SAMPLE_RATE*SAMPLE_SIZE*CHANNELS)/8;
+  buf_size = ((duration/1000)*sample_rate*SAMPLE_SIZE*CHANNELS)/8;
   GST_BUFFER_SIZE (buffer) = buf_size;
   GST_BUFFER_MALLOCDATA (buffer) = g_malloc0(buf_size);
   GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
@@ -623,7 +541,7 @@ gst_dtmf_src_generate_silence(GstBuffer * buffer, float duration)
 
 static void
 gst_dtmf_src_generate_tone(GstDTMFSrcEvent *event, DTMF_KEY key, float duration,
-    GstBuffer * buffer)
+    GstBuffer * buffer, gint sample_rate)
 {
   gint16 *p;
   gint tone_size;
@@ -632,7 +550,7 @@ gst_dtmf_src_generate_tone(GstDTMFSrcEvent *event, DTMF_KEY key, float duration,
   double volume_factor;
 
   /* Create a buffer for the tone */
-  tone_size = ((duration/1000)*SAMPLE_RATE*SAMPLE_SIZE*CHANNELS)/8;
+  tone_size = ((duration/1000)*sample_rate*SAMPLE_SIZE*CHANNELS)/8;
   GST_BUFFER_SIZE (buffer) = tone_size;
   GST_BUFFER_MALLOCDATA (buffer) = g_malloc(tone_size);
   GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
@@ -649,8 +567,8 @@ gst_dtmf_src_generate_tone(GstDTMFSrcEvent *event, DTMF_KEY key, float duration,
     /*
      * We add the fundamental frequencies together.
      */
-    f1 = sin(2 * M_PI * key.low_frequency * (event->sample / SAMPLE_RATE));
-    f2 = sin(2 * M_PI * key.high_frequency * (event->sample / SAMPLE_RATE));
+    f1 = sin(2 * M_PI * key.low_frequency * (event->sample / sample_rate));
+    f2 = sin(2 * M_PI * key.high_frequency * (event->sample / sample_rate));
 
     amplitude = (f1 + f2) / 2;
 
@@ -667,33 +585,6 @@ gst_dtmf_src_generate_tone(GstDTMFSrcEvent *event, DTMF_KEY key, float duration,
   }
 }
 
-static void
-gst_dtmf_src_wait_for_buffer_ts (GstDTMFSrc *dtmfsrc, GstBuffer * buf)
-{
-  GstClock *clock;
-
-  clock = gst_element_get_clock (dtmfsrc);
-  if (clock != NULL) {
-    GstClockID clock_id;
-    GstClockReturn clock_ret;
-
-    clock_id = gst_clock_new_single_shot_id (clock, GST_BUFFER_TIMESTAMP (buf));
-    clock_ret = gst_clock_id_wait (clock_id, NULL);
-    if (clock_ret != GST_CLOCK_OK && clock_ret != GST_CLOCK_EARLY) {
-      gchar *clock_name = gst_element_get_name (clock);
-      GST_ERROR_OBJECT (dtmfsrc, "Failed to wait on clock %s", clock_name);
-      g_free (clock_name);
-    }
-    gst_clock_id_unref (clock_id);
-    gst_object_unref (clock);
-  }
-
-  else {
-    gchar *dtmf_name = gst_element_get_name (dtmfsrc);
-    GST_ERROR_OBJECT (dtmfsrc, "No clock set for element %s", dtmf_name);
-    g_free (dtmf_name);
-  }
-}
 
 
 static GstBuffer *
@@ -702,6 +593,7 @@ gst_dtmf_src_create_next_tone_packet (GstDTMFSrc *dtmfsrc,
 {
   GstBuffer *buf = NULL;
   gboolean send_silence = FALSE;
+  GstPad *srcpad = GST_BASE_SRC_PAD (dtmfsrc);
 
   GST_DEBUG_OBJECT (dtmfsrc, "Creating buffer for tone %s",
       DTMF_KEYS[event->event_number].event_name);
@@ -715,11 +607,12 @@ gst_dtmf_src_create_next_tone_packet (GstDTMFSrc *dtmfsrc,
 
   if (send_silence) {
     GST_DEBUG_OBJECT (dtmfsrc,  "Generating silence");
-    gst_dtmf_src_generate_silence (buf, dtmfsrc->interval);
+    gst_dtmf_src_generate_silence (buf, dtmfsrc->interval,
+        dtmfsrc->sample_rate);
   } else {
     GST_DEBUG_OBJECT (dtmfsrc,  "Generating tone");
     gst_dtmf_src_generate_tone(event, DTMF_KEYS[event->event_number],
-        dtmfsrc->interval, buf);
+        dtmfsrc->interval, buf, dtmfsrc->sample_rate);
   }
   event->packet_count++;
 
@@ -729,72 +622,266 @@ gst_dtmf_src_create_next_tone_packet (GstDTMFSrc *dtmfsrc,
   GST_BUFFER_TIMESTAMP (buf) = dtmfsrc->timestamp;
   dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
 
-  /* FIXME: Should we sync to clock ourselves or leave it to sink */
-  gst_dtmf_src_wait_for_buffer_ts (dtmfsrc, buf);
-
   /* Set caps on the buffer before pushing it */
-  gst_buffer_set_caps (buf, GST_PAD_CAPS (dtmfsrc->srcpad));
+  gst_buffer_set_caps (buf, GST_PAD_CAPS (srcpad));
 
   return buf;
 }
 
-static void
-gst_dtmf_src_push_next_tone_packet (GstDTMFSrc *dtmfsrc)
+static GstFlowReturn
+gst_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
+    guint length, GstBuffer ** buffer)
 {
   GstBuffer *buf = NULL;
-  GstFlowReturn ret;
   GstDTMFSrcEvent *event;
+  GstDTMFSrc * dtmfsrc;
+  GstClock *clock;
+  GstClockID *clockid;
+  GstClockReturn clockret;
+
+  dtmfsrc = GST_DTMF_SRC (basesrc);
+
+  do {
+
+    if (dtmfsrc->last_event == NULL) {
+      GST_DEBUG_OBJECT (dtmfsrc, "popping");
+      event = g_async_queue_pop (dtmfsrc->event_queue);
+
+      GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);
+
+      switch (event->event_type) {
+        case DTMF_EVENT_TYPE_STOP:
+          GST_WARNING_OBJECT (dtmfsrc,
+              "Received a DTMF stop event when already stopped");
+          break;
+        case DTMF_EVENT_TYPE_START:
+          gst_dtmf_prepare_timestamps (dtmfsrc);
+
+          /* Don't forget to get exclusive access to the stream */
+          gst_dtmf_src_set_stream_lock (dtmfsrc, TRUE);
+
+          event->packet_count = 0;
+          dtmfsrc->last_event = event;
+          event = NULL;
+          break;
+        case DTMF_EVENT_TYPE_PAUSE_TASK:
+          /*
+           * We're pushing it back because it has to stay in there until
+           * the task is really paused (and the queue will then be flushed)
+           */
+          GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
+          GST_OBJECT_LOCK (dtmfsrc);
+          if (dtmfsrc->paused) {
+            g_async_queue_push (dtmfsrc->event_queue, event);
+            goto paused_locked;
+          }
+          GST_OBJECT_UNLOCK (dtmfsrc);
+          break;
+      }
+      if (event)
+        g_free (event);
+    } else if (dtmfsrc->last_event->packet_count  * dtmfsrc->interval >=
+        MIN_DUTY_CYCLE) {
+      event = g_async_queue_try_pop (dtmfsrc->event_queue);
+
+      if (event != NULL) {
+
+        switch (event->event_type) {
+          case DTMF_EVENT_TYPE_START:
+            GST_WARNING_OBJECT (dtmfsrc,
+                "Received two consecutive DTMF start events");
+            break;
+          case DTMF_EVENT_TYPE_STOP:
+            gst_dtmf_src_set_stream_lock (dtmfsrc, FALSE);
+
+            g_free (dtmfsrc->last_event);
+            dtmfsrc->last_event = NULL;
+            break;
+          case DTMF_EVENT_TYPE_PAUSE_TASK:
+            /*
+             * We're pushing it back because it has to stay in there until
+             * the task is really paused (and the queue will then be flushed)
+             */
+            GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
+
+            GST_OBJECT_LOCK (dtmfsrc);
+            if (dtmfsrc->paused) {
+              g_async_queue_push (dtmfsrc->event_queue, event);
+              goto paused_locked;
+            }
+            GST_OBJECT_UNLOCK (dtmfsrc);
+
+            break;
+        }
+        g_free (event);
+      }
+    }
+  } while (dtmfsrc->last_event == NULL);
 
-  g_async_queue_ref (dtmfsrc->event_queue);
+  GST_DEBUG_OBJECT (dtmfsrc, "end event check, now wait for the proper time");
 
-  if (dtmfsrc->last_event == NULL) {
-    event = g_async_queue_pop (dtmfsrc->event_queue);
+  clock = gst_element_get_clock (GST_ELEMENT (basesrc));
 
-    if (event->event_type == DTMF_EVENT_TYPE_STOP) {
-      GST_WARNING_OBJECT (dtmfsrc,
-          "Received a DTMF stop event when already stopped");
-    } else if (event->event_type == DTMF_EVENT_TYPE_START) {
-      gst_dtmf_prepare_timestamps (dtmfsrc);
+#ifdef MAEMO_BROKEN
+  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp);
+#else
+  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
+      gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
+#endif
+  gst_object_unref (clock);
 
-      /* Don't forget to get exclusive access to the stream */
-      gst_dtmf_src_set_stream_lock (dtmfsrc, TRUE);
+  GST_OBJECT_LOCK (dtmfsrc);
+  if (!dtmfsrc->paused) {
+    dtmfsrc->clockid = clockid;
+    GST_OBJECT_UNLOCK (dtmfsrc);
 
-      event->packet_count = 0;
-      dtmfsrc->last_event = event;
-    }
-  } else if (dtmfsrc->last_event->packet_count  * dtmfsrc->interval >=
-      MIN_DUTY_CYCLE) {
-    event = g_async_queue_try_pop (dtmfsrc->event_queue);
-
-    if (event != NULL) {
-      if (event->event_type == DTMF_EVENT_TYPE_START) {
-        GST_WARNING_OBJECT (dtmfsrc,
-            "Received two consecutive DTMF start events");
-      } else if (event->event_type == DTMF_EVENT_TYPE_STOP) {
-        gst_dtmf_src_set_stream_lock (dtmfsrc, FALSE);
-        g_free (dtmfsrc->last_event);
-        dtmfsrc->last_event = NULL;
-      }
-    }
+    clockret = gst_clock_id_wait (clockid, NULL);
+
+    GST_OBJECT_LOCK (dtmfsrc);
+    if (dtmfsrc->paused)
+      clockret = GST_CLOCK_UNSCHEDULED;
+  } else  {
+    clockret = GST_CLOCK_UNSCHEDULED;
   }
-  g_async_queue_unref (dtmfsrc->event_queue);
+  gst_clock_id_unref (clockid);
+  dtmfsrc->clockid = NULL;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  if (clockret == GST_CLOCK_UNSCHEDULED) {
+    goto paused;
+  }
+
+  buf = gst_dtmf_src_create_next_tone_packet (dtmfsrc, dtmfsrc->last_event);
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Created buffer of size %d", GST_BUFFER_SIZE (buf));
+  *buffer = buf;
+
+  GST_DEBUG_OBJECT (dtmfsrc, "returning a buffer");
+  return GST_FLOW_OK;
+
+ paused_locked:
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+ paused:
 
   if (dtmfsrc->last_event) {
-    buf = gst_dtmf_src_create_next_tone_packet (dtmfsrc, dtmfsrc->last_event);
+    GST_DEBUG_OBJECT (dtmfsrc, "Stopping current event");
+    /* Don't forget to release the stream lock */
+    gst_dtmf_src_set_stream_lock (dtmfsrc, FALSE);
+    g_free (dtmfsrc->last_event);
+    dtmfsrc->last_event = NULL;
+  }
+
+  return GST_FLOW_WRONG_STATE;
+
+}
+
+static gboolean
+gst_dtmf_src_unlock (GstBaseSrc *src) {
+  GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (src);
+  GstDTMFSrcEvent *event = NULL;
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Called unlock");
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  dtmfsrc->paused = TRUE;
+  if (dtmfsrc->clockid) {
+    gst_clock_id_unschedule (dtmfsrc->clockid);
+  }
+  GST_OBJECT_UNLOCK (dtmfsrc);
 
-    gst_buffer_ref(buf);
+  GST_DEBUG_OBJECT (dtmfsrc, "Pushing the PAUSE_TASK event on unlock request");
+  event = g_malloc (sizeof(GstDTMFSrcEvent));
+  event->event_type = DTMF_EVENT_TYPE_PAUSE_TASK;
+  g_async_queue_push (dtmfsrc->event_queue, event);
+
+  return TRUE;
+}
+
+
+static gboolean
+gst_dtmf_src_unlock_stop (GstBaseSrc *src) {
+  GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (src);
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Unlock stopped");
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  dtmfsrc->paused = FALSE;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  return TRUE;
+}
+
+
+static gboolean
+gst_dtmf_src_negotiate (GstBaseSrc * basesrc)
+{
+  GstCaps *srccaps, *peercaps;
+  GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (basesrc);
+  gboolean ret = FALSE;
+
+  srccaps = gst_caps_new_simple ("audio/x-raw-int",
+      "width", G_TYPE_INT, 16,
+      "depth", G_TYPE_INT, 16,
+      "endianness", G_TYPE_INT, G_BYTE_ORDER,
+      "signed", G_TYPE_BOOLEAN, TRUE,
+      "channels", G_TYPE_INT, 1,
+      NULL);
+
+  peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
+
+  if (peercaps == NULL) {
+    /* no peer caps, just add the other properties */
+    gst_caps_set_simple (srccaps,
+        "rate", G_TYPE_INT, dtmfsrc->sample_rate,
+        NULL);
+  } else {
+    GstStructure *s;
+    gint sample_rate;
+    GstCaps *temp = NULL;
+
+    /* peer provides caps we can use to fixate, intersect. This always returns a
+     * writable caps. */
+    temp = gst_caps_intersect (srccaps, peercaps);
+    gst_caps_unref (srccaps);
+    gst_caps_unref (peercaps);
+
+    if (!temp) {
+      GST_DEBUG_OBJECT (dtmfsrc, "Could not get intersection with peer caps");
+      return FALSE;
+    }
 
-    GST_DEBUG_OBJECT (dtmfsrc,
-        "pushing buffer on src pad of size %d", GST_BUFFER_SIZE (buf));
-    ret = gst_pad_push (dtmfsrc->srcpad, buf);
-    if (ret != GST_FLOW_OK) {
-      GST_ERROR_OBJECT (dtmfsrc, "Failed to push buffer on src pad");
+    if (gst_caps_is_empty (temp)) {
+      GST_DEBUG_OBJECT (dtmfsrc, "Intersection with peer caps is empty");
+      gst_caps_unref (temp);
+      return FALSE;
     }
 
-    gst_buffer_unref(buf);
-    GST_DEBUG_OBJECT (dtmfsrc, "pushed DTMF tone on src pad");
+    /* now fixate, start by taking the first caps */
+    gst_caps_truncate (temp);
+    srccaps = temp;
+
+    /* get first structure */
+    s = gst_caps_get_structure (srccaps, 0);
+
+    if (gst_structure_get_int (s, "rate", &sample_rate))
+    {
+      dtmfsrc->sample_rate = sample_rate;
+      GST_LOG_OBJECT (dtmfsrc, "using rate from caps %d",
+          dtmfsrc->sample_rate);
+    } else {
+      GST_LOG_OBJECT (dtmfsrc, "using existing rate %d",
+          dtmfsrc->sample_rate);
+    }
+    gst_structure_set (s, "rate", G_TYPE_INT, dtmfsrc->sample_rate,
+        NULL);
   }
 
+  ret = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), srccaps);
+
+  gst_caps_unref (srccaps);
+
+  return ret;
 }
 
 static GstStateChangeReturn
@@ -803,22 +890,21 @@ gst_dtmf_src_change_state (GstElement * element, GstStateChange transition)
   GstDTMFSrc *dtmfsrc;
   GstStateChangeReturn result;
   gboolean no_preroll = FALSE;
+  GstDTMFSrcEvent *event = NULL;
 
   dtmfsrc = GST_DTMF_SRC (element);
 
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      gst_segment_init (&dtmfsrc->segment, GST_FORMAT_TIME);
-      gst_pad_push_event (dtmfsrc->srcpad, gst_event_new_new_segment (FALSE,
-              dtmfsrc->segment.rate, dtmfsrc->segment.format,
-              dtmfsrc->segment.start, dtmfsrc->segment.stop,
-              dtmfsrc->segment.time));
-      /* Indicate that we don't do PRE_ROLL */
+      /* Flushing the event queue */
+      event = g_async_queue_try_pop (dtmfsrc->event_queue);
+
+      while (event != NULL) {
+        g_free (event);
+        event = g_async_queue_try_pop (dtmfsrc->event_queue);
+      }
       no_preroll = TRUE;
       break;
-    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
-      gst_dtmf_src_start (dtmfsrc);
-      break;
     default:
       break;
   }
@@ -830,10 +916,19 @@ gst_dtmf_src_change_state (GstElement * element, GstStateChange transition)
 
   switch (transition) {
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
-      /* Indicate that we don't do PRE_ROLL */
-      gst_dtmf_src_stop (dtmfsrc);
       no_preroll = TRUE;
       break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_DEBUG_OBJECT (dtmfsrc, "Flushing event queue");
+      /* Flushing the event queue */
+      event = g_async_queue_try_pop (dtmfsrc->event_queue);
+
+      while (event != NULL) {
+        g_free (event);
+        event = g_async_queue_try_pop (dtmfsrc->event_queue);
+      }
+
+      break;
     default:
       break;
   }