3 * Copyright 2007 Nokia Corporation
4 * Copyright 2007 Collabora Ltd,
5 * @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>
7 * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
32 #include <gst/rtp/gstrtpbuffer.h>
33 #include "gstrtpdtmfdepay.h"
36 # define M_PI 3.14159265358979323846 /* pi */
40 #define GST_TONE_DTMF_TYPE_EVENT 0
41 #define DEFAULT_PACKET_INTERVAL 50 /* ms */
42 #define MIN_PACKET_INTERVAL 10 /* ms */
43 #define MAX_PACKET_INTERVAL 50 /* ms */
44 #define SAMPLE_RATE 8000
45 #define SAMPLE_SIZE 16
51 #define MIN_INTER_DIGIT_INTERVAL 100
52 #define MIN_PULSE_DURATION 250
53 #define MIN_DUTY_CYCLE (MIN_INTER_DIGIT_INTERVAL + MIN_PULSE_DURATION)
56 typedef struct st_dtmf_key {
63 static const DTMF_KEY DTMF_KEYS[] = {
64 {"DTMF_KEY_EVENT_0", 0, 941, 1336},
65 {"DTMF_KEY_EVENT_1", 1, 697, 1209},
66 {"DTMF_KEY_EVENT_2", 2, 697, 1336},
67 {"DTMF_KEY_EVENT_3", 3, 697, 1477},
68 {"DTMF_KEY_EVENT_4", 4, 770, 1209},
69 {"DTMF_KEY_EVENT_5", 5, 770, 1336},
70 {"DTMF_KEY_EVENT_6", 6, 770, 1477},
71 {"DTMF_KEY_EVENT_7", 7, 852, 1209},
72 {"DTMF_KEY_EVENT_8", 8, 852, 1336},
73 {"DTMF_KEY_EVENT_9", 9, 852, 1477},
74 {"DTMF_KEY_EVENT_S", 10, 941, 1209},
75 {"DTMF_KEY_EVENT_P", 11, 941, 1477},
76 {"DTMF_KEY_EVENT_A", 12, 697, 1633},
77 {"DTMF_KEY_EVENT_B", 13, 770, 1633},
78 {"DTMF_KEY_EVENT_C", 14, 852, 1633},
79 {"DTMF_KEY_EVENT_D", 15, 941, 1633},
82 #define MAX_DTMF_EVENTS 16
95 DTMF_KEY_EVENT_STAR = 10,
96 DTMF_KEY_EVENT_POUND = 11,
97 DTMF_KEY_EVENT_A = 12,
98 DTMF_KEY_EVENT_B = 13,
99 DTMF_KEY_EVENT_C = 14,
100 DTMF_KEY_EVENT_D = 15,
103 /* elementfactory information */
104 static const GstElementDetails gst_rtp_dtmfdepay_details =
105 GST_ELEMENT_DETAILS ("RTP DTMF packet depayloader",
106 "Codec/Depayloader/Network",
107 "Generates DTMF Sound from telephone-event RTP packets",
108 "Youness Alaoui <youness.alaoui@collabora.co.uk>");
110 GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_depay_debug);
111 #define GST_CAT_DEFAULT gst_rtp_dtmf_depay_debug
124 static GstStaticPadTemplate gst_rtp_dtmf_depay_src_template =
125 GST_STATIC_PAD_TEMPLATE ("src",
128 GST_STATIC_CAPS ("audio/x-raw-int, "
131 "endianness = (int) 1234, "
132 "signed = (boolean) true, "
133 "rate = (int) [0, MAX], "
134 "channels = (int) 1")
137 static GstStaticPadTemplate gst_rtp_dtmf_depay_sink_template =
138 GST_STATIC_PAD_TEMPLATE ("sink",
141 GST_STATIC_CAPS ("application/x-rtp, "
142 "media = (string) \"audio\", "
143 "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
144 "clock-rate = (int) [ 0, MAX ], "
145 "encoding-name = (string) \"TELEPHONE-EVENT\"")
148 GST_BOILERPLATE (GstRtpDTMFDepay, gst_rtp_dtmf_depay, GstBaseRTPDepayload,
149 GST_TYPE_BASE_RTP_DEPAYLOAD);
152 static GstBuffer *gst_rtp_dtmf_depay_process (GstBaseRTPDepayload * depayload,
154 gboolean gst_rtp_dtmf_depay_setcaps (GstBaseRTPDepayload * filter,
158 gst_rtp_dtmf_depay_set_gst_timestamp (GstBaseRTPDepayload * filter,
159 guint32 rtptime, GstBuffer * buf);
163 gst_rtp_dtmf_depay_base_init (gpointer klass)
165 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
167 gst_element_class_add_pad_template (element_class,
168 gst_static_pad_template_get (&gst_rtp_dtmf_depay_src_template));
169 gst_element_class_add_pad_template (element_class,
170 gst_static_pad_template_get (&gst_rtp_dtmf_depay_sink_template));
173 GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_depay_debug,
174 "rtpdtmfdepay", 0, "rtpdtmfdepay element");
175 gst_element_class_set_details (element_class, &gst_rtp_dtmfdepay_details);
179 gst_rtp_dtmf_depay_class_init (GstRtpDTMFDepayClass * klass)
181 GObjectClass *gobject_class;
182 GstElementClass *gstelement_class;
183 GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
185 gobject_class = (GObjectClass *) klass;
186 gstelement_class = (GstElementClass *) klass;
187 gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
189 parent_class = g_type_class_peek_parent (klass);
191 gstbasertpdepayload_class->process = gst_rtp_dtmf_depay_process;
192 gstbasertpdepayload_class->set_caps = gst_rtp_dtmf_depay_setcaps;
193 // gstbasertpdepayload_class->set_gst_timestamp = gst_rtp_dtmf_depay_set_gst_timestamp;
198 gst_rtp_dtmf_depay_init (GstRtpDTMFDepay * rtpdtmfdepay,
199 GstRtpDTMFDepayClass * klass)
206 gst_rtp_dtmf_depay_setcaps (GstBaseRTPDepayload * filter, GstCaps * caps)
209 GstStructure *structure = gst_caps_get_structure (caps, 0);
210 gint clock_rate = 8000; /* default */
212 gst_structure_get_int (structure, "clock-rate", &clock_rate);
213 filter->clock_rate = clock_rate;
215 srccaps = gst_caps_new_simple ("audio/x-raw-int",
216 "width", G_TYPE_INT, 16,
217 "depth", G_TYPE_INT, 16,
218 "endianness", G_TYPE_INT, 1234,
219 "signed", G_TYPE_BOOLEAN, TRUE,
220 "channels", G_TYPE_INT, 1,
221 "rate", G_TYPE_INT, clock_rate, NULL);
222 gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (filter), srccaps);
223 gst_caps_unref (srccaps);
229 gst_rtp_dtmf_depay_set_gst_timestamp (GstBaseRTPDepayload * filter,
230 guint32 rtptime, GstBuffer * buf)
232 GstClockTime timestamp, duration;
235 timestamp = GST_BUFFER_TIMESTAMP (buf);
236 duration = GST_BUFFER_DURATION (buf);
238 /* if this is the first buffer send a NEWSEGMENT */
239 if (filter->need_newsegment) {
241 GstClockTime stop, position;
248 gst_event_new_new_segment_full (FALSE, 1.0,
249 1.0, GST_FORMAT_TIME, 0, stop, position);
251 gst_pad_push_event (filter->srcpad, event);
253 filter->need_newsegment = FALSE;
254 GST_DEBUG_OBJECT (filter, "Pushed newsegment event on this first buffer");
260 gst_dtmf_src_generate_silence(GstBuffer * buffer, float duration)
264 /* Create a buffer with data set to 0 */
265 buf_size = ((duration/1000)*SAMPLE_RATE*SAMPLE_SIZE*CHANNELS)/8;
266 GST_BUFFER_SIZE (buffer) = buf_size;
267 GST_BUFFER_MALLOCDATA (buffer) = g_malloc0(buf_size);
268 GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
274 gst_dtmf_src_generate_tone(GstRtpDTMFDepay *rtpdtmfdepay,
275 GstRTPDTMFPayload payload, GstBuffer * buffer)
280 double amplitude, f1, f2;
281 double volume_factor;
282 DTMF_KEY key = DTMF_KEYS[payload.event];
283 guint32 clock_rate = 8000 /* default */;
284 GstBaseRTPDepayload * depayload = GST_BASE_RTP_DEPAYLOAD (rtpdtmfdepay);
286 clock_rate = depayload->clock_rate;
288 /* Create a buffer for the tone */
289 tone_size = (payload.duration*SAMPLE_SIZE*CHANNELS)/8;
290 GST_BUFFER_SIZE (buffer) = tone_size;
291 GST_BUFFER_MALLOCDATA (buffer) = g_malloc(tone_size);
292 GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
293 GST_BUFFER_DURATION (buffer) = payload.duration * GST_SECOND / clock_rate;
295 p = (gint16 *) GST_BUFFER_MALLOCDATA (buffer);
297 volume_factor = pow (10, (-payload.volume) / 20);
300 * For each sample point we calculate 'x' as the
301 * the amplitude value.
303 for (i = 0; i < (tone_size / (SAMPLE_SIZE/8)); i++) {
305 * We add the fundamental frequencies together.
307 f1 = sin(2 * M_PI * key.low_frequency * (rtpdtmfdepay->sample / clock_rate));
308 f2 = sin(2 * M_PI * key.high_frequency * (rtpdtmfdepay->sample / clock_rate));
310 amplitude = (f1 + f2) / 2;
312 /* Adjust the volume */
313 amplitude *= volume_factor;
315 /* Make the [-1:1] interval into a [-32767:32767] interval */
318 /* Store it in the data buffer */
319 *(p++) = (gint16) amplitude;
321 (rtpdtmfdepay->sample)++;
327 gst_rtp_dtmf_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
330 GstRtpDTMFDepay *rtpdtmfdepay = NULL;
331 GstBuffer *outbuf = NULL;
333 guint8 *payload = NULL;
335 GstRTPDTMFPayload dtmf_payload;
337 GstStructure *structure = NULL;
338 GstMessage *dtmf_message = NULL;
340 rtpdtmfdepay = GST_RTP_DTMF_DEPAY (depayload);
342 if (!gst_rtp_buffer_validate (buf))
345 payload_len = gst_rtp_buffer_get_payload_len (buf);
346 payload = gst_rtp_buffer_get_payload (buf);
348 if (payload_len != sizeof(GstRTPDTMFPayload) )
351 memcpy (&dtmf_payload, payload, sizeof (GstRTPDTMFPayload));
353 if (dtmf_payload.event > MAX_EVENT)
357 marker = gst_rtp_buffer_get_marker (buf);
359 timestamp = gst_rtp_buffer_get_timestamp (buf);
361 dtmf_payload.duration = g_ntohs (dtmf_payload.duration);
363 GST_DEBUG_OBJECT (depayload, "Received new RTP DTMF packet : "
364 "marker=%d - timestamp=%u - event=%d - duration=%d",
365 marker, timestamp, dtmf_payload.event, dtmf_payload.duration);
367 GST_DEBUG_OBJECT (depayload, "Previous information : timestamp=%u - duration=%d",
368 rtpdtmfdepay->previous_ts, rtpdtmfdepay->previous_duration);
371 if (marker || rtpdtmfdepay->previous_ts != timestamp) {
372 rtpdtmfdepay->sample = 0;
373 rtpdtmfdepay->previous_ts = timestamp;
374 rtpdtmfdepay->previous_duration = dtmf_payload.duration;
375 rtpdtmfdepay->first_gst_ts = GST_BUFFER_TIMESTAMP (buf);
377 structure = gst_structure_new ("dtmf-event",
378 "number", G_TYPE_INT, dtmf_payload.event,
379 "volume", G_TYPE_INT, dtmf_payload.volume,
380 "type", G_TYPE_INT, 1,
381 "method", G_TYPE_INT, 1,
384 dtmf_message = gst_message_new_element (GST_OBJECT (depayload), structure);
386 if (!gst_element_post_message (GST_ELEMENT (depayload), dtmf_message)) {
387 GST_DEBUG_OBJECT (depayload, "Unable to send dtmf-event message to bus");
390 GST_DEBUG_OBJECT (depayload, "Unable to create dtmf-event message");
393 GST_DEBUG_OBJECT (depayload, "Unable to create dtmf-event structure");
396 guint16 duration = dtmf_payload.duration;
397 dtmf_payload.duration -= rtpdtmfdepay->previous_duration;
398 /* If late buffer, ignore */
399 if (duration > rtpdtmfdepay->previous_duration)
400 rtpdtmfdepay->previous_duration = duration;
403 GST_DEBUG_OBJECT (depayload, "new previous duration : %d - new duration : %d"
404 " - diff : %d - clock rate : %d - timestamp : %llu",
405 rtpdtmfdepay->previous_duration, dtmf_payload.duration,
406 (rtpdtmfdepay->previous_duration - dtmf_payload.duration),
407 depayload->clock_rate, GST_BUFFER_TIMESTAMP (buf));
409 /* If late or duplicate packet (like the redundant end packet). Ignore */
410 if (dtmf_payload.duration > 0) {
411 outbuf = gst_buffer_new ();
412 gst_dtmf_src_generate_tone(rtpdtmfdepay, dtmf_payload, outbuf);
415 GST_BUFFER_TIMESTAMP (outbuf) = rtpdtmfdepay->first_gst_ts +
416 (rtpdtmfdepay->previous_duration - dtmf_payload.duration) *
417 GST_SECOND / depayload->clock_rate;
418 GST_BUFFER_OFFSET (outbuf) =
419 (rtpdtmfdepay->previous_duration - dtmf_payload.duration) *
420 GST_SECOND / depayload->clock_rate;
421 GST_BUFFER_OFFSET_END (outbuf) = rtpdtmfdepay->previous_duration *
422 GST_SECOND / depayload->clock_rate;
424 GST_DEBUG_OBJECT (depayload, "timestamp : %llu - time %" GST_TIME_FORMAT,
425 GST_BUFFER_TIMESTAMP (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
433 GST_ELEMENT_WARNING (rtpdtmfdepay, STREAM, DECODE,
434 ("Packet did not validate"), (NULL));
439 gst_rtp_dtmf_depay_plugin_init (GstPlugin * plugin)
441 return gst_element_register (plugin, "rtpdtmfdepay",
442 GST_RANK_MARGINAL, GST_TYPE_RTP_DTMF_DEPAY);