[MOVED FROM GST-P-FARSIGHT] Do wierd casting of the volume to make MSVC happy
[platform/upstream/gstreamer.git] / gst / dtmf / gstdtmfsrc.c
index 71e5dbb..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 named events.
+ * 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>
 #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,11 +227,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
     GST_STATIC_CAPS ("audio/x-raw-int, "
         "width = (int) 16, "
         "depth = (int) 16, "
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-        "endianness = (int) 1234, "
-#else
-        "endianness = (int) 4321, "
-#endif
+        "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
         "signed = (bool) true, "
         "rate = (int) 8000, "
         "channels = (int) 1")
@@ -246,8 +244,6 @@ static void gst_dtmf_src_get_property (GObject * object, guint prop_id,
 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 GstFlowReturn gst_dtmf_src_create (GstBaseSrc * basesrc,
     guint64 offset, guint length, GstBuffer ** buffer);
 static void gst_dtmf_src_add_start_event (GstDTMFSrc *dtmfsrc,
@@ -257,6 +253,7 @@ 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)
@@ -306,7 +303,8 @@ gst_dtmf_src_class_init (GstDTMFSrcClass * klass)
       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);
 }
 
 
@@ -322,6 +320,8 @@ gst_dtmf_src_init (GstDTMFSrc * dtmfsrc, GstDTMFSrcClass *g_class)
   dtmfsrc->event_queue = g_async_queue_new ();
   dtmfsrc->last_event = NULL;
 
+  dtmfsrc->sample_rate = DEFAULT_SAMPLE_RATE;
+
   GST_DEBUG_OBJECT (dtmfsrc, "init done");
 }
 
@@ -526,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);
@@ -540,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;
@@ -549,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);
@@ -566,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;
 
@@ -606,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++;
 
@@ -810,6 +812,78 @@ gst_dtmf_src_unlock_stop (GstBaseSrc *src) {
   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;
+    }
+
+    if (gst_caps_is_empty (temp)) {
+      GST_DEBUG_OBJECT (dtmfsrc, "Intersection with peer caps is empty");
+      gst_caps_unref (temp);
+      return FALSE;
+    }
+
+    /* 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
 gst_dtmf_src_change_state (GstElement * element, GstStateChange transition)
 {