rtpmux: no need to ref pad in _chain()
[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 gboolean gst_rtp_dtmf_mux_accept_buffer_locked (GstRTPMux * rtp_mux,
70     GstRTPMuxPadPrivate * padpriv, GstBuffer * buffer);
71
72 GST_BOILERPLATE (GstRTPDTMFMux, gst_rtp_dtmf_mux, GstRTPMux, GST_TYPE_RTP_MUX);
73
74 static void
75 gst_rtp_dtmf_mux_init (GstRTPDTMFMux * object, GstRTPDTMFMuxClass * g_class)
76 {
77 }
78
79 static void
80 gst_rtp_dtmf_mux_base_init (gpointer g_class)
81 {
82   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
83
84   gst_element_class_add_pad_template (element_class,
85       gst_static_pad_template_get (&priority_sink_factory));
86
87   gst_element_class_set_details_simple (element_class, "RTP muxer",
88       "Codec/Muxer",
89       "mixes RTP DTMF streams into other RTP streams",
90       "Zeeshan Ali <first.last@nokia.com>");
91 }
92
93 static void
94 gst_rtp_dtmf_mux_class_init (GstRTPDTMFMuxClass * klass)
95 {
96   GObjectClass *gobject_class;
97   GstElementClass *gstelement_class;
98   GstRTPMuxClass *gstrtpmux_class;
99
100   gobject_class = (GObjectClass *) klass;
101   gstelement_class = (GstElementClass *) klass;
102   gstrtpmux_class = (GstRTPMuxClass *) klass;
103
104   gstelement_class->request_new_pad =
105       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_request_new_pad);
106   gstelement_class->change_state =
107       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_change_state);
108   gstrtpmux_class->accept_buffer_locked = gst_rtp_dtmf_mux_accept_buffer_locked;
109 }
110
111 static gboolean
112 gst_rtp_dtmf_mux_accept_buffer_locked (GstRTPMux * rtp_mux,
113     GstRTPMuxPadPrivate * padpriv, GstBuffer * buffer)
114 {
115   GstRTPDTMFMux *mux = GST_RTP_DTMF_MUX (rtp_mux);
116   GstClockTime running_ts;
117
118   running_ts = GST_BUFFER_TIMESTAMP (buffer);
119
120   if (GST_CLOCK_TIME_IS_VALID (running_ts)) {
121     if (padpriv && padpriv->segment.format == GST_FORMAT_TIME)
122       running_ts = gst_segment_to_running_time (&padpriv->segment,
123           GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer));
124
125     if (padpriv && padpriv->priority) {
126       if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
127         if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end))
128           mux->last_priority_end =
129               MAX (running_ts + GST_BUFFER_DURATION (buffer),
130               mux->last_priority_end);
131         else
132           mux->last_priority_end = running_ts + GST_BUFFER_DURATION (buffer);
133         GST_LOG_OBJECT (mux, "Got buffer %p on priority pad, "
134             " blocking regular pads until %" GST_TIME_FORMAT, buffer,
135             GST_TIME_ARGS (mux->last_priority_end));
136       } else {
137         GST_WARNING_OBJECT (mux, "Buffer %p has an invalid duration,"
138             " not blocking other pad", buffer);
139       }
140     } else {
141       if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end) &&
142           running_ts < mux->last_priority_end) {
143         GST_LOG_OBJECT (mux, "Dropping buffer %p because running time"
144             " %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT, buffer,
145             GST_TIME_ARGS (running_ts), GST_TIME_ARGS (mux->last_priority_end));
146         return FALSE;
147       }
148     }
149   } else {
150     GST_LOG_OBJECT (mux, "Buffer %p has an invalid timestamp,"
151         " letting through", buffer);
152   }
153
154   return TRUE;
155 }
156
157
158 static GstPad *
159 gst_rtp_dtmf_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
160     const gchar * name)
161 {
162   GstPad *pad;
163
164   pad = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, request_new_pad,
165       (element, templ, name), NULL);
166
167   if (pad) {
168     GstRTPMuxPadPrivate *padpriv;
169
170     GST_OBJECT_LOCK (element);
171     padpriv = gst_pad_get_element_private (pad);
172
173     if (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element),
174             "priority_sink_%d") == gst_pad_get_pad_template (pad))
175       padpriv->priority = TRUE;
176     GST_OBJECT_UNLOCK (element);
177   }
178
179   return pad;
180 }
181
182
183 static GstStateChangeReturn
184 gst_rtp_dtmf_mux_change_state (GstElement * element, GstStateChange transition)
185 {
186   GstStateChangeReturn ret;
187   GstRTPDTMFMux *mux = GST_RTP_DTMF_MUX (element);
188
189   switch (transition) {
190     case GST_STATE_CHANGE_READY_TO_PAUSED:
191     {
192       GST_OBJECT_LOCK (mux);
193       mux->last_priority_end = GST_CLOCK_TIME_NONE;
194       GST_OBJECT_UNLOCK (mux);
195       break;
196     }
197     default:
198       break;
199   }
200
201   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
202
203   return ret;
204 }
205
206 gboolean
207 gst_rtp_dtmf_mux_plugin_init (GstPlugin * plugin)
208 {
209   GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_mux_debug, "rtpdtmfmux", 0,
210       "rtp dtmf muxer");
211
212   return gst_element_register (plugin, "rtpdtmfmux", GST_RANK_NONE,
213       GST_TYPE_RTP_DTMF_MUX);
214 }