replace gst_element_class_set_details_simple with gst_element_class_set_metadata
[platform/upstream/gstreamer.git] / gst / dtmf / gstdtmfdetect.c
1 /*
2  * GStreamer - DTMF Detection
3  *
4  *  Copyright 2009 Nokia Corporation
5  *  Copyright 2009 Collabora Ltd,
6  *   @author: Olivier Crete <olivier.crete@collabora.co.uk>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  */
24
25 /**
26  * SECTION:element-dtmfdetect
27  * @short_description: Detects DTMF tones
28  *
29  * This element will detect DTMF tones and emit messages.
30  *
31  * The message is called <classname>&quot;dtmf-event&quot;</classname> and has
32  * the following fields:
33  * <itemizedlist>
34  * <listitem>
35  *   <para>
36  *   gint <classname>type</classname> (0-1):
37  *   The application uses this field to specify which of the two methods
38  *   specified in RFC 2833 to use. The value should be 0 for tones and 1 for
39  *   named events. Tones are specified by their frequencies and events are
40  *   specfied by their number. This element can only take events as input.
41  *   Do not confuse with "method" which specified the output.
42  *   </para>
43  * </listitem>
44  * <listitem>
45  *   <para>
46  *   gint <classname>number</classname> (0-16):
47  *   The event number.
48  *   </para>
49  * </listitem>
50  * <listitem>
51  *   <para>
52  *   gint <classname>method</classname> (2):
53  *   This field will always been 2 (ie sound) from this element.
54  *   </para>
55  * </listitem>
56  * </itemizedlist>
57  */
58
59 #ifdef HAVE_CONFIG_H
60 #include "config.h"
61 #endif
62
63 #include "gstdtmfdetect.h"
64
65 #include <string.h>
66
67 #include <gst/audio/audio.h>
68
69 GST_DEBUG_CATEGORY (dtmf_detect_debug);
70 #define GST_CAT_DEFAULT (dtmf_detect_debug)
71
72 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
73     GST_PAD_SINK,
74     GST_PAD_ALWAYS,
75     GST_STATIC_CAPS ("audio/x-raw, "
76         "format = (string) \"" GST_AUDIO_NE (S16) "\", "
77         "rate = (int) 8000, " "channels = (int) 1")
78     );
79
80
81 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
82     GST_PAD_SRC,
83     GST_PAD_ALWAYS,
84     GST_STATIC_CAPS ("audio/x-raw, "
85         "format = (string) \"" GST_AUDIO_NE (S16) "\", "
86         "rate = (int) 8000, " "channels = (int) 1")
87     );
88
89 /* signals and args */
90 enum
91 {
92   /* FILL ME */
93   LAST_SIGNAL
94 };
95
96 enum
97 {
98   PROP_0,
99 };
100
101 static gboolean gst_dtmf_detect_set_caps (GstBaseTransform * trans,
102     GstCaps * incaps, GstCaps * outcaps);
103 static GstFlowReturn gst_dtmf_detect_transform_ip (GstBaseTransform * trans,
104     GstBuffer * buf);
105 static gboolean gst_dtmf_detect_sink_event (GstBaseTransform * trans,
106     GstEvent * event);
107
108 G_DEFINE_TYPE (GstDtmfDetect, gst_dtmf_detect, GST_TYPE_BASE_TRANSFORM);
109
110 static void
111 gst_dtmf_detect_class_init (GstDtmfDetectClass * klass)
112 {
113   GstElementClass *gstelement_class;
114   GstBaseTransformClass *gstbasetransform_class;
115
116   gstelement_class = GST_ELEMENT_CLASS (klass);
117   gstbasetransform_class = (GstBaseTransformClass *) klass;
118
119   GST_DEBUG_CATEGORY_INIT (dtmf_detect_debug, "dtmfdetect", 0, "dtmfdetect");
120
121   gst_element_class_add_pad_template (gstelement_class,
122       gst_static_pad_template_get (&srctemplate));
123   gst_element_class_add_pad_template (gstelement_class,
124       gst_static_pad_template_get (&sinktemplate));
125
126   gst_element_class_set_metadata (gstelement_class, "DTMF detector element",
127       "Filter/Analyzer/Audio",
128       "This element detects DTMF tones",
129       "Olivier Crete <olivier.crete@collabora.com>");
130
131   gstbasetransform_class->set_caps =
132       GST_DEBUG_FUNCPTR (gst_dtmf_detect_set_caps);
133   gstbasetransform_class->transform_ip =
134       GST_DEBUG_FUNCPTR (gst_dtmf_detect_transform_ip);
135   gstbasetransform_class->sink_event =
136       GST_DEBUG_FUNCPTR (gst_dtmf_detect_sink_event);
137 }
138
139 static void
140 gst_dtmf_detect_init (GstDtmfDetect * dtmfdetect)
141 {
142   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (dtmfdetect), TRUE);
143   gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (dtmfdetect), TRUE);
144 }
145
146 static gboolean
147 gst_dtmf_detect_set_caps (GstBaseTransform * trans, GstCaps * incaps,
148     GstCaps * outcaps)
149 {
150   GstDtmfDetect *self = GST_DTMF_DETECT (trans);
151
152   zap_dtmf_detect_init (&self->dtmf_state);
153
154   return TRUE;
155 }
156
157
158 static GstFlowReturn
159 gst_dtmf_detect_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
160 {
161   GstDtmfDetect *self = GST_DTMF_DETECT (trans);
162   gint dtmf_count;
163   gchar dtmfbuf[MAX_DTMF_DIGITS] = "";
164   gint i;
165   GstMapInfo map;
166
167   if (GST_BUFFER_IS_DISCONT (buf))
168     zap_dtmf_detect_init (&self->dtmf_state);
169   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))
170     return GST_FLOW_OK;
171
172   gst_buffer_map (buf, &map, GST_MAP_READ);
173
174   zap_dtmf_detect (&self->dtmf_state, (gint16 *) map.data, map.size / 2, FALSE);
175
176   dtmf_count = zap_dtmf_get (&self->dtmf_state, dtmfbuf, MAX_DTMF_DIGITS);
177
178   if (dtmf_count)
179     GST_DEBUG_OBJECT (self, "Got %d DTMF events: %s", dtmf_count, dtmfbuf);
180   else
181     GST_LOG_OBJECT (self, "Got no DTMF events");
182
183   gst_buffer_unmap (buf, &map);
184
185   for (i = 0; i < dtmf_count; i++) {
186     GstMessage *dtmf_message = NULL;
187     GstStructure *structure;
188     gint dtmf_payload_event;
189
190     GST_DEBUG_OBJECT (self, "Got DTMF event %c", dtmfbuf[i]);
191
192     switch (dtmfbuf[i]) {
193       case '0':
194         dtmf_payload_event = 0;
195         break;
196       case '1':
197         dtmf_payload_event = 1;
198         break;
199       case '2':
200         dtmf_payload_event = 2;
201         break;
202       case '3':
203         dtmf_payload_event = 3;
204         break;
205       case '4':
206         dtmf_payload_event = 4;
207         break;
208       case '5':
209         dtmf_payload_event = 5;
210         break;
211       case '6':
212         dtmf_payload_event = 6;
213         break;
214       case '7':
215         dtmf_payload_event = 7;
216         break;
217       case '8':
218         dtmf_payload_event = 8;
219         break;
220       case '9':
221         dtmf_payload_event = 9;
222         break;
223       case '*':
224         dtmf_payload_event = 10;
225         break;
226       case '#':
227         dtmf_payload_event = 11;
228         break;
229       case 'A':
230         dtmf_payload_event = 12;
231         break;
232       case 'B':
233         dtmf_payload_event = 13;
234         break;
235       case 'C':
236         dtmf_payload_event = 14;
237         break;
238       case 'D':
239         dtmf_payload_event = 15;
240         break;
241       default:
242         continue;
243     }
244
245     structure = gst_structure_new ("dtmf-event",
246         "type", G_TYPE_INT, 1,
247         "number", G_TYPE_INT, dtmf_payload_event,
248         "method", G_TYPE_INT, 2, NULL);
249     dtmf_message = gst_message_new_element (GST_OBJECT (self), structure);
250     gst_element_post_message (GST_ELEMENT (self), dtmf_message);
251   }
252
253   return GST_FLOW_OK;
254 }
255
256
257 static gboolean
258 gst_dtmf_detect_sink_event (GstBaseTransform * trans, GstEvent * event)
259 {
260   GstDtmfDetect *self = GST_DTMF_DETECT (trans);
261
262   switch (GST_EVENT_TYPE (event)) {
263     case GST_EVENT_FLUSH_STOP:
264       zap_dtmf_detect_init (&self->dtmf_state);
265       break;
266     default:
267       break;
268   }
269
270   return GST_BASE_TRANSFORM_CLASS (gst_dtmf_detect_parent_class)->sink_event
271       (trans, event);
272 }
273
274
275 gboolean
276 gst_dtmf_detect_plugin_init (GstPlugin * plugin)
277 {
278   return gst_element_register (plugin, "dtmfdetect",
279       GST_RANK_MARGINAL, GST_TYPE_DTMF_DETECT);
280 }