Complete the move of the RTP plugin
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpL16parse.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more 
13  */
14
15 #include <string.h>
16 #include "gstrtpL16parse.h"
17 #include "gstrtp-common.h"
18
19 /* elementfactory information */
20 static GstElementDetails gst_rtp_L16parse_details = {
21   "RTP packet parser",
22   "RtpL16Parse",
23   "GPL",
24   "Extracts raw audio from RTP packets",
25   VERSION,
26   "Zeeshan Ali <zak147@yahoo.com>",
27   "(C) 2003",
28 };
29
30 /* RtpL16Parse signals and args */
31 enum
32 {
33   /* FILL ME */
34   LAST_SIGNAL
35 };
36
37 enum
38 {
39   ARG_0,
40   ARG_FREQUENCY,
41   ARG_PAYLOAD_TYPE,
42 };
43
44 GST_PAD_TEMPLATE_FACTORY (src_factory,
45         "src",
46         GST_PAD_SRC,
47         GST_PAD_ALWAYS,
48         GST_CAPS_NEW (
49                  "audio_raw",
50                  "audio/raw",
51                  "format",      GST_PROPS_STRING ("int"),
52                  "law",         GST_PROPS_INT (0),
53                  "endianness",  GST_PROPS_INT (G_BYTE_ORDER), 
54                  "signed",      GST_PROPS_BOOLEAN (TRUE), 
55                  "width",       GST_PROPS_INT (16), 
56                  "depth",       GST_PROPS_INT (16), 
57                  "rate",        GST_PROPS_INT_RANGE (1000, 48000),
58                  "channels",    GST_PROPS_INT_RANGE (1, 2))
59 )
60  
61 GST_PAD_TEMPLATE_FACTORY (sink_factory,
62         "sink",
63         GST_PAD_SINK,
64         GST_PAD_ALWAYS,
65         GST_CAPS_NEW (
66                 "rtp",
67                 "application/x-rtp",
68                 NULL)
69 );
70
71 static void gst_rtpL16parse_class_init (GstRtpL16ParseClass * klass);
72 static void gst_rtpL16parse_init (GstRtpL16Parse * rtpL16parse);
73
74 static void gst_rtpL16parse_chain (GstPad * pad, GstBuffer * buf);
75
76 static void gst_rtpL16parse_set_property (GObject * object, guint prop_id,
77                                    const GValue * value, GParamSpec * pspec);
78 static void gst_rtpL16parse_get_property (GObject * object, guint prop_id,
79                                    GValue * value, GParamSpec * pspec);
80 static GstElementStateReturn gst_rtpL16parse_change_state (GstElement * element);
81
82 static GstElementClass *parent_class = NULL;
83
84 static GType gst_rtpL16parse_get_type (void)
85 {
86   static GType rtpL16parse_type = 0;
87
88   if (!rtpL16parse_type) {
89     static const GTypeInfo rtpL16parse_info = {
90       sizeof (GstRtpL16ParseClass),
91       NULL,
92       NULL,
93       (GClassInitFunc) gst_rtpL16parse_class_init,
94       NULL,
95       NULL,
96       sizeof (GstRtpL16Parse),
97       0,
98       (GInstanceInitFunc) gst_rtpL16parse_init,
99     };
100
101     rtpL16parse_type = g_type_register_static (GST_TYPE_ELEMENT, "GstRtpL16Parse", &rtpL16parse_info, 0);
102   }
103   return rtpL16parse_type;
104 }
105
106 static void
107 gst_rtpL16parse_class_init (GstRtpL16ParseClass * klass)
108 {
109   GObjectClass *gobject_class;
110   GstElementClass *gstelement_class;
111
112   gobject_class = (GObjectClass *) klass;
113   gstelement_class = (GstElementClass *) klass;
114
115   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
116
117   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PAYLOAD_TYPE, 
118                 g_param_spec_int ("payload_type", "payload_type", "payload type", 
119                         G_MININT, G_MAXINT, PAYLOAD_L16_STEREO, G_PARAM_READABLE));
120   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FREQUENCY, 
121                 g_param_spec_int ("frequency", "frequency", "frequency", 
122                         G_MININT, G_MAXINT, 44100, G_PARAM_READWRITE));
123
124   gobject_class->set_property = gst_rtpL16parse_set_property;
125   gobject_class->get_property = gst_rtpL16parse_get_property;
126
127   gstelement_class->change_state = gst_rtpL16parse_change_state;
128 }
129
130 static void
131 gst_rtpL16parse_init (GstRtpL16Parse * rtpL16parse)
132 {
133   rtpL16parse->srcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (src_factory), "src");
134   rtpL16parse->sinkpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (sink_factory), "sink");
135   gst_element_add_pad (GST_ELEMENT (rtpL16parse), rtpL16parse->srcpad);
136   gst_element_add_pad (GST_ELEMENT (rtpL16parse), rtpL16parse->sinkpad);
137   gst_pad_set_chain_function (rtpL16parse->sinkpad, gst_rtpL16parse_chain);
138
139   rtpL16parse->frequency = 44100;
140   rtpL16parse->channels = 2;
141
142   rtpL16parse->payload_type = PAYLOAD_L16_STEREO;
143 }
144
145 void
146 gst_rtpL16parse_ntohs (GstBuffer *buf)
147 {
148   guint16 *i, *len;
149
150   /* FIXME: is this code correct or even sane at all? */
151   i = (guint16 *) GST_BUFFER_DATA(buf); 
152   len = i + GST_BUFFER_SIZE (buf) / sizeof (guint16 *);
153
154   for (; i<len; i++) {
155       *i = g_ntohs (*i);
156   }
157 }
158
159 void
160 gst_rtpL16_caps_nego (GstRtpL16Parse *rtpL16parse)
161 {
162   GstCaps *caps;
163
164   caps = GST_CAPS_NEW (
165                  "audio_raw",
166                  "audio/raw",
167                  "format",      GST_PROPS_STRING ("int"),
168                  "law",         GST_PROPS_INT (0),
169                  "endianness",  GST_PROPS_INT (G_BYTE_ORDER), 
170                  "signed",      GST_PROPS_BOOLEAN (TRUE), 
171                  "width",       GST_PROPS_INT (16), 
172                  "depth",       GST_PROPS_INT (16), 
173                  "rate",        GST_PROPS_INT (rtpL16parse->frequency),
174                  "channels",    GST_PROPS_INT (rtpL16parse->channels));
175
176   gst_pad_try_set_caps (rtpL16parse->srcpad, caps);
177 }
178
179 void
180 gst_rtpL16parse_payloadtype_change (GstRtpL16Parse *rtpL16parse, rtp_payload_t pt)
181 {
182   rtpL16parse->payload_type = pt;
183   
184   switch (pt) {
185         case PAYLOAD_L16_MONO:
186                 rtpL16parse->channels = 1;
187                 break;
188         case PAYLOAD_L16_STEREO:
189                 rtpL16parse->channels = 2;
190                 break;
191         default:
192                 g_warning ("unkown payload_t %d\n", pt);
193   }
194
195   gst_rtpL16_caps_nego (rtpL16parse);
196 }
197
198 static void
199 gst_rtpL16parse_chain (GstPad * pad, GstBuffer * buf)
200 {
201   GstRtpL16Parse *rtpL16parse;
202   GstBuffer *outbuf;
203   Rtp_Packet packet;
204   rtp_payload_t pt;
205
206   g_return_if_fail (pad != NULL);
207   g_return_if_fail (GST_IS_PAD (pad));
208   g_return_if_fail (buf != NULL);
209
210   rtpL16parse = GST_RTP_L16_PARSE (GST_OBJECT_PARENT (pad));
211
212   g_return_if_fail (rtpL16parse != NULL);
213   g_return_if_fail (GST_IS_RTP_L16_PARSE (rtpL16parse));
214
215   if (GST_IS_EVENT (buf)) {
216     GstEvent *event = GST_EVENT (buf);
217     gst_pad_event_default (pad, event);
218   
219     return;
220   }
221
222   if (GST_PAD_CAPS (rtpL16parse->srcpad) == NULL) {
223     gst_rtpL16_caps_nego (rtpL16parse);
224   }
225
226   packet = rtp_packet_new_copy_data (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
227
228   pt = rtp_packet_get_payload_type (packet);
229
230   if (pt != rtpL16parse->payload_type) {
231         gst_rtpL16parse_payloadtype_change (rtpL16parse, pt);
232   }
233
234   outbuf = gst_buffer_new ();
235   GST_BUFFER_SIZE (outbuf) = rtp_packet_get_payload_len (packet);
236   GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
237   GST_BUFFER_TIMESTAMP (outbuf) = g_ntohl (rtp_packet_get_timestamp (packet)) * GST_SECOND;
238
239   memcpy (GST_BUFFER_DATA (outbuf), rtp_packet_get_payload (packet), GST_BUFFER_SIZE (outbuf));
240         
241   GST_DEBUG (0,"gst_rtpL16parse_chain: pushing buffer of size %d", GST_BUFFER_SIZE(outbuf));
242
243   /* FIXME: According to RFC 1890, this is required, right? */
244 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
245      gst_rtpL16parse_ntohs (outbuf);
246 #endif
247
248   gst_pad_push (rtpL16parse->srcpad, outbuf);
249
250   rtp_packet_free (packet);
251   gst_buffer_unref (buf);
252 }
253
254 static void
255 gst_rtpL16parse_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
256 {
257   GstRtpL16Parse *rtpL16parse;
258
259   /* it's not null if we got it, but it might not be ours */
260   g_return_if_fail (GST_IS_RTP_L16_PARSE (object));
261   rtpL16parse = GST_RTP_L16_PARSE (object);
262
263   switch (prop_id) {
264     case ARG_PAYLOAD_TYPE:
265       gst_rtpL16parse_payloadtype_change (rtpL16parse, g_value_get_int (value));
266       break;
267     case ARG_FREQUENCY:
268       rtpL16parse->frequency = g_value_get_int (value);
269       break;
270     default:
271       break;
272   }
273 }
274
275 static void
276 gst_rtpL16parse_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
277 {
278   GstRtpL16Parse *rtpL16parse;
279
280   /* it's not null if we got it, but it might not be ours */
281   g_return_if_fail (GST_IS_RTP_L16_PARSE (object));
282   rtpL16parse = GST_RTP_L16_PARSE (object);
283
284   switch (prop_id) {
285     case ARG_PAYLOAD_TYPE:
286       g_value_set_int (value, rtpL16parse->payload_type);
287       break;
288     case ARG_FREQUENCY:
289       g_value_set_int (value, rtpL16parse->frequency);
290       break;
291     default:
292       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
293       break;
294   }
295 }
296
297 static GstElementStateReturn
298 gst_rtpL16parse_change_state (GstElement * element)
299 {
300   GstRtpL16Parse *rtpL16parse;
301
302   g_return_val_if_fail (GST_IS_RTP_L16_PARSE (element), GST_STATE_FAILURE);
303
304   rtpL16parse = GST_RTP_L16_PARSE (element);
305
306   GST_DEBUG (0, "state pending %d\n", GST_STATE_PENDING (element));
307
308   switch (GST_STATE_TRANSITION (element)) {
309     case GST_STATE_NULL_TO_READY:
310       break;
311     case GST_STATE_READY_TO_NULL:
312       break;
313     default:
314       break;
315   }
316
317   /* if we haven't failed already, give the parent class a chance to ;-) */
318   if (GST_ELEMENT_CLASS (parent_class)->change_state)
319     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
320
321   return GST_STATE_SUCCESS;
322 }
323
324 gboolean
325 gst_rtpL16parse_plugin_init (GModule * module, GstPlugin * plugin)
326 {
327   GstElementFactory *rtpL16parse;
328
329   rtpL16parse = gst_element_factory_new ("rtpL16parse", GST_TYPE_RTP_L16_PARSE, &gst_rtp_L16parse_details);
330   g_return_val_if_fail (rtpL16parse != NULL, FALSE);
331
332   gst_element_factory_add_pad_template (rtpL16parse, GST_PAD_TEMPLATE_GET (src_factory));
333   gst_element_factory_add_pad_template (rtpL16parse, GST_PAD_TEMPLATE_GET (sink_factory));
334
335   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (rtpL16parse));
336
337   return TRUE;
338 }