Imported Upstream version 0.10.23
[profile/ivi/gst-plugins-bad.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 GST_DEBUG_CATEGORY (dtmf_detect_debug);
68 #define GST_CAT_DEFAULT (dtmf_detect_debug)
69
70 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
71     GST_PAD_SINK,
72     GST_PAD_ALWAYS,
73     GST_STATIC_CAPS ("audio/x-raw-int, "
74         "width = (int) 16, "
75         "depth = (int) 16, "
76         "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
77         "signed = (bool) true, rate = (int) 8000, channels = (int) 1"));
78
79 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
80     GST_PAD_SRC,
81     GST_PAD_ALWAYS,
82     GST_STATIC_CAPS ("audio/x-raw-int, "
83         "width = (int) 16, "
84         "depth = (int) 16, "
85         "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
86         "signed = (bool) true, rate = (int) 8000, channels = (int) 1"));
87
88 /* signals and args */
89 enum
90 {
91   /* FILL ME */
92   LAST_SIGNAL
93 };
94
95 enum
96 {
97   PROP_0,
98 };
99
100 static gboolean gst_dtmf_detect_set_caps (GstBaseTransform * trans,
101     GstCaps * incaps, GstCaps * outcaps);
102 static GstFlowReturn gst_dtmf_detect_transform_ip (GstBaseTransform * trans,
103     GstBuffer * buf);
104 static gboolean gst_dtmf_detect_event (GstBaseTransform * trans,
105     GstEvent * event);
106
107 static void
108 _do_init (GType type)
109 {
110   GST_DEBUG_CATEGORY_INIT (dtmf_detect_debug, "dtmfdetect", 0, "dtmfdetect");
111 }
112
113 GST_BOILERPLATE_FULL (GstDtmfDetect, gst_dtmf_detect, GstBaseTransform,
114     GST_TYPE_BASE_TRANSFORM, _do_init);
115
116 static void
117 gst_dtmf_detect_base_init (gpointer klass)
118 {
119   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
120
121   gst_element_class_add_static_pad_template (element_class, &srctemplate);
122   gst_element_class_add_static_pad_template (element_class, &sinktemplate);
123
124   gst_element_class_set_details_simple (element_class, "DTMF detector element",
125       "Filter/Analyzer/Audio",
126       "This element detects DTMF tones",
127       "Olivier Crete <olivier.crete@collabora.co.uk>");
128 }
129
130 static void
131 gst_dtmf_detect_class_init (GstDtmfDetectClass * klass)
132 {
133   GstBaseTransformClass *gstbasetransform_class;
134
135   gstbasetransform_class = (GstBaseTransformClass *) klass;
136
137   gstbasetransform_class->set_caps =
138       GST_DEBUG_FUNCPTR (gst_dtmf_detect_set_caps);
139   gstbasetransform_class->transform_ip =
140       GST_DEBUG_FUNCPTR (gst_dtmf_detect_transform_ip);
141   gstbasetransform_class->event = GST_DEBUG_FUNCPTR (gst_dtmf_detect_event);
142 }
143
144 static void
145 gst_dtmf_detect_init (GstDtmfDetect * dtmfdetect, GstDtmfDetectClass * klass)
146 {
147   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (dtmfdetect), TRUE);
148   gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (dtmfdetect), TRUE);
149 }
150
151 static gboolean
152 gst_dtmf_detect_set_caps (GstBaseTransform * trans, GstCaps * incaps,
153     GstCaps * outcaps)
154 {
155   GstDtmfDetect *self = GST_DTMF_DETECT (trans);
156
157   zap_dtmf_detect_init (&self->dtmf_state);
158
159   return TRUE;
160 }
161
162
163 static GstFlowReturn
164 gst_dtmf_detect_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
165 {
166   GstDtmfDetect *self = GST_DTMF_DETECT (trans);
167   gint dtmf_count;
168   gchar dtmfbuf[MAX_DTMF_DIGITS] = "";
169   gint i;
170
171   if (GST_BUFFER_IS_DISCONT (buf))
172     zap_dtmf_detect_init (&self->dtmf_state);
173   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))
174     return GST_FLOW_OK;
175
176   zap_dtmf_detect (&self->dtmf_state, (gint16 *) GST_BUFFER_DATA (buf),
177       GST_BUFFER_SIZE (buf) / 2, FALSE);
178
179   dtmf_count = zap_dtmf_get (&self->dtmf_state, dtmfbuf, MAX_DTMF_DIGITS);
180
181   if (dtmf_count)
182     GST_DEBUG_OBJECT (self, "Got %d DTMF events: %s", dtmf_count, dtmfbuf);
183   else
184     GST_LOG_OBJECT (self, "Got no DTMF events");
185
186   for (i = 0; i < dtmf_count; i++) {
187     GstMessage *dtmf_message = NULL;
188     GstStructure *structure;
189     gint dtmf_payload_event;
190
191     GST_DEBUG_OBJECT (self, "Got DTMF event %c", dtmfbuf[i]);
192
193     switch (dtmfbuf[i]) {
194       case '0':
195         dtmf_payload_event = 0;
196         break;
197       case '1':
198         dtmf_payload_event = 1;
199         break;
200       case '2':
201         dtmf_payload_event = 2;
202         break;
203       case '3':
204         dtmf_payload_event = 3;
205         break;
206       case '4':
207         dtmf_payload_event = 4;
208         break;
209       case '5':
210         dtmf_payload_event = 5;
211         break;
212       case '6':
213         dtmf_payload_event = 6;
214         break;
215       case '7':
216         dtmf_payload_event = 7;
217         break;
218       case '8':
219         dtmf_payload_event = 8;
220         break;
221       case '9':
222         dtmf_payload_event = 9;
223         break;
224       case '*':
225         dtmf_payload_event = 10;
226         break;
227       case '#':
228         dtmf_payload_event = 11;
229         break;
230       case 'A':
231         dtmf_payload_event = 12;
232         break;
233       case 'B':
234         dtmf_payload_event = 13;
235         break;
236       case 'C':
237         dtmf_payload_event = 14;
238         break;
239       case 'D':
240         dtmf_payload_event = 15;
241         break;
242       default:
243         continue;
244     }
245
246     structure = gst_structure_new ("dtmf-event",
247         "type", G_TYPE_INT, 1,
248         "number", G_TYPE_INT, dtmf_payload_event,
249         "method", G_TYPE_INT, 2, NULL);
250     dtmf_message = gst_message_new_element (GST_OBJECT (self), structure);
251     gst_element_post_message (GST_ELEMENT (self), dtmf_message);
252   }
253
254   return GST_FLOW_OK;
255 }
256
257
258 static gboolean
259 gst_dtmf_detect_event (GstBaseTransform * trans, GstEvent * event)
260 {
261   GstDtmfDetect *self = GST_DTMF_DETECT (trans);
262
263   switch (GST_EVENT_TYPE (event)) {
264     case GST_EVENT_FLUSH_STOP:
265       zap_dtmf_detect_init (&self->dtmf_state);
266       break;
267     default:
268       break;
269   }
270
271   return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_TRANSFORM_CLASS, event,
272       (trans, event), TRUE);
273 }
274
275
276 gboolean
277 gst_dtmf_detect_plugin_init (GstPlugin * plugin)
278 {
279   return gst_element_register (plugin, "dtmfdetect",
280       GST_RANK_MARGINAL, GST_TYPE_DTMF_DETECT);
281 }