57aa64c65096786a808c232ac5d1738f6860534f
[platform/upstream/gstreamer.git] / gst / rtpmanager / gstrtpdtmfmux.c
1 /* RTP DTMF muxer element for GStreamer
2  *
3  * gstrtpdtmfmux.c:
4  *
5  * Copyright (C) <2007-2010> Nokia Corporation.
6  *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
7  * Copyright (C) <2007-2010> Collabora Ltd
8  *   Contact: Olivier Crete <olivier.crete@collabora.co.uk>
9  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
10  *               2000,2005 Wim Taymans <wim@fluendo.com>
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with this library; if not, write to the
24  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25  * Boston, MA 02111-1307, USA.
26  */
27
28 /**
29  * SECTION:element-rtpdtmfmux
30  * @see_also: rtpdtmfsrc, dtmfsrc, rtpmux
31  *
32  * The RTP "DTMF" Muxer muxes multiple RTP streams into a valid RTP
33  * stream. It does exactly what it's parent (#rtpmux) does, except
34  * that it prevent buffers coming over a regular sink_%%d pad from going through
35  * for the duration of buffers that came in a priority_sink_%%d pad.
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <gst/gst.h>
43 #include <string.h>
44
45 #include "gstrtpdtmfmux.h"
46
47 GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_mux_debug);
48 #define GST_CAT_DEFAULT gst_rtp_dtmf_mux_debug
49
50 enum
51 {
52   LAST_SIGNAL
53 };
54
55
56 static GstStaticPadTemplate priority_sink_factory =
57 GST_STATIC_PAD_TEMPLATE ("priority_sink_%d",
58     GST_PAD_SINK,
59     GST_PAD_REQUEST,
60     GST_STATIC_CAPS ("application/x-rtp"));
61
62 // static guint gst_rtpdtmfmux_signals[LAST_SIGNAL] = { 0 };
63
64 static GstPad *gst_rtp_dtmf_mux_request_new_pad (GstElement * element,
65     GstPadTemplate * templ, const gchar * name);
66 static GstStateChangeReturn gst_rtp_dtmf_mux_change_state (GstElement * element,
67     GstStateChange transition);
68
69 static GstFlowReturn gst_rtp_dtmf_mux_chain (GstPad * pad, GstBuffer * buffer);
70
71 GST_BOILERPLATE (GstRTPDTMFMux, gst_rtp_dtmf_mux, GstRTPMux, GST_TYPE_RTP_MUX);
72
73 static void
74 gst_rtp_dtmf_mux_init (GstRTPDTMFMux * object, GstRTPDTMFMuxClass * g_class)
75 {
76 }
77
78 static void
79 gst_rtp_dtmf_mux_base_init (gpointer g_class)
80 {
81   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
82
83   gst_element_class_add_pad_template (element_class,
84       gst_static_pad_template_get (&priority_sink_factory));
85
86   gst_element_class_set_details_simple (element_class, "RTP muxer",
87       "Codec/Muxer",
88       "mixes RTP DTMF streams into other RTP streams",
89       "Zeeshan Ali <first.last@nokia.com>");
90 }
91
92 static void
93 gst_rtp_dtmf_mux_class_init (GstRTPDTMFMuxClass * klass)
94 {
95   GObjectClass *gobject_class;
96   GstElementClass *gstelement_class;
97   GstRTPMuxClass *gstrtpmux_class;
98
99   gobject_class = (GObjectClass *) klass;
100   gstelement_class = (GstElementClass *) klass;
101   gstrtpmux_class = (GstRTPMuxClass *) klass;
102
103   gstelement_class->request_new_pad =
104       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_request_new_pad);
105   gstelement_class->change_state =
106       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_change_state);
107   gstrtpmux_class->chain_func = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_chain);
108 }
109
110 static GstFlowReturn
111 gst_rtp_dtmf_mux_chain (GstPad * pad, GstBuffer * buffer)
112 {
113   GstRTPDTMFMux *mux;
114   GstFlowReturn ret = GST_FLOW_ERROR;
115   GstRTPMuxPadPrivate *padpriv = NULL;
116   GstClockTime running_ts;
117
118   mux = GST_RTP_DTMF_MUX (gst_pad_get_parent (pad));
119
120   running_ts = GST_BUFFER_TIMESTAMP (buffer);
121
122   GST_OBJECT_LOCK (mux);
123   if (GST_CLOCK_TIME_IS_VALID (running_ts)) {
124     padpriv = gst_pad_get_element_private (pad);
125     if (padpriv && padpriv->segment.format == GST_FORMAT_TIME)
126       running_ts = gst_segment_to_running_time (&padpriv->segment,
127           GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer));
128
129     if (padpriv && padpriv->priority) {
130       if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
131         if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end))
132           mux->last_priority_end =
133               MAX (running_ts + GST_BUFFER_DURATION (buffer),
134               mux->last_priority_end);
135         else
136           mux->last_priority_end = running_ts + GST_BUFFER_DURATION (buffer);
137       }
138     } else {
139       if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end) &&
140           running_ts < mux->last_priority_end)
141         goto drop_buffer;
142     }
143   }
144   GST_OBJECT_UNLOCK (mux);
145
146   if (parent_class->chain_func)
147     ret = parent_class->chain_func (pad, buffer);
148   else
149     gst_buffer_unref (buffer);
150
151 out:
152
153   gst_object_unref (mux);
154   return ret;
155
156 drop_buffer:
157   gst_buffer_unref (buffer);
158   ret = GST_FLOW_OK;
159   GST_OBJECT_UNLOCK (mux);
160   goto out;
161 }
162
163
164 static GstPad *
165 gst_rtp_dtmf_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
166     const gchar * name)
167 {
168   GstPad *pad;
169
170   pad = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, request_new_pad,
171       (element, templ, name), NULL);
172
173   if (pad) {
174     GstRTPMuxPadPrivate *padpriv;
175
176     GST_OBJECT_LOCK (element);
177     padpriv = gst_pad_get_element_private (pad);
178
179     if (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element),
180             "priority_sink_%d") == gst_pad_get_pad_template (pad))
181       padpriv->priority = TRUE;
182     GST_OBJECT_UNLOCK (element);
183   }
184
185   return pad;
186 }
187
188
189 static GstStateChangeReturn
190 gst_rtp_dtmf_mux_change_state (GstElement * element, GstStateChange transition)
191 {
192   GstStateChangeReturn ret;
193   GstRTPDTMFMux *mux = GST_RTP_DTMF_MUX (element);
194
195   switch (transition) {
196     case GST_STATE_CHANGE_READY_TO_PAUSED:
197     {
198       GST_OBJECT_LOCK (mux);
199       mux->last_priority_end = GST_CLOCK_TIME_NONE;
200       GST_OBJECT_UNLOCK (mux);
201       break;
202     }
203     default:
204       break;
205   }
206
207   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
208
209   return ret;
210 }
211
212 gboolean
213 gst_rtp_dtmf_mux_plugin_init (GstPlugin * plugin)
214 {
215   GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_mux_debug, "rtpdtmfmux", 0,
216       "rtp dtmf muxer");
217
218   return gst_element_register (plugin, "rtpdtmfmux", GST_RANK_NONE,
219       GST_TYPE_RTP_DTMF_MUX);
220 }