gst-indent
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpgsmdepay.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 #ifdef HAVE_CONFIG_H
16 #  include "config.h"
17 #endif
18
19 #include <string.h>
20 #include "gstrtpgsmparse.h"
21 #include "gstrtp-common.h"
22
23 /* elementfactory information */
24 static GstElementDetails gst_rtp_gsmparse_details = {
25   "RTP packet parser",
26   "Codec/Parser/Network",
27   "Extracts GSM audio from RTP packets",
28   "Zeeshan Ali <zak147@yahoo.com>"
29 };
30
31 /* RtpGSMParse signals and args */
32 enum
33 {
34   /* FILL ME */
35   LAST_SIGNAL
36 };
37
38 enum
39 {
40   ARG_0,
41   ARG_FREQUENCY
42 };
43
44 static GstStaticPadTemplate gst_rtpgsmparse_src_template =
45 GST_STATIC_PAD_TEMPLATE ("src",
46     GST_PAD_SRC,
47     GST_PAD_ALWAYS,
48     GST_STATIC_CAPS ("audio/x-gsm, " "rate = (int) [ 1000, 48000 ]")
49     );
50
51 static GstStaticPadTemplate gst_rtpgsmparse_sink_template =
52 GST_STATIC_PAD_TEMPLATE ("sink",
53     GST_PAD_SINK,
54     GST_PAD_ALWAYS,
55     GST_STATIC_CAPS ("application/x-rtp")
56     );
57
58
59 static void gst_rtpgsmparse_class_init (GstRtpGSMParseClass * klass);
60 static void gst_rtpgsmparse_base_init (GstRtpGSMParseClass * klass);
61 static void gst_rtpgsmparse_init (GstRtpGSMParse * rtpgsmparse);
62
63 static void gst_rtpgsmparse_chain (GstPad * pad, GstData * _data);
64
65 static void gst_rtpgsmparse_set_property (GObject * object, guint prop_id,
66     const GValue * value, GParamSpec * pspec);
67 static void gst_rtpgsmparse_get_property (GObject * object, guint prop_id,
68     GValue * value, GParamSpec * pspec);
69 static GstElementStateReturn gst_rtpgsmparse_change_state (GstElement *
70     element);
71
72 static GstElementClass *parent_class = NULL;
73
74 static GType
75 gst_rtpgsmparse_get_type (void)
76 {
77   static GType rtpgsmparse_type = 0;
78
79   if (!rtpgsmparse_type) {
80     static const GTypeInfo rtpgsmparse_info = {
81       sizeof (GstRtpGSMParseClass),
82       (GBaseInitFunc) gst_rtpgsmparse_base_init,
83       NULL,
84       (GClassInitFunc) gst_rtpgsmparse_class_init,
85       NULL,
86       NULL,
87       sizeof (GstRtpGSMParse),
88       0,
89       (GInstanceInitFunc) gst_rtpgsmparse_init,
90     };
91
92     rtpgsmparse_type =
93         g_type_register_static (GST_TYPE_ELEMENT, "GstRtpGSMParse",
94         &rtpgsmparse_info, 0);
95   }
96   return rtpgsmparse_type;
97 }
98
99 static void
100 gst_rtpgsmparse_base_init (GstRtpGSMParseClass * klass)
101 {
102   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
103
104   gst_element_class_add_pad_template (element_class,
105       gst_static_pad_template_get (&gst_rtpgsmparse_src_template));
106   gst_element_class_add_pad_template (element_class,
107       gst_static_pad_template_get (&gst_rtpgsmparse_sink_template));
108   gst_element_class_set_details (element_class, &gst_rtp_gsmparse_details);
109 }
110
111 static void
112 gst_rtpgsmparse_class_init (GstRtpGSMParseClass * klass)
113 {
114   GObjectClass *gobject_class;
115   GstElementClass *gstelement_class;
116
117   gobject_class = (GObjectClass *) klass;
118   gstelement_class = (GstElementClass *) klass;
119
120   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
121
122   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FREQUENCY,
123       g_param_spec_int ("frequency", "frequency", "frequency",
124           G_MININT, G_MAXINT, 8000, G_PARAM_READWRITE));
125
126   gobject_class->set_property = gst_rtpgsmparse_set_property;
127   gobject_class->get_property = gst_rtpgsmparse_get_property;
128
129   gstelement_class->change_state = gst_rtpgsmparse_change_state;
130 }
131
132 static void
133 gst_rtpgsmparse_init (GstRtpGSMParse * rtpgsmparse)
134 {
135   rtpgsmparse->srcpad =
136       gst_pad_new_from_template (gst_static_pad_template_get
137       (&gst_rtpgsmparse_src_template), "src");
138   rtpgsmparse->sinkpad =
139       gst_pad_new_from_template (gst_static_pad_template_get
140       (&gst_rtpgsmparse_sink_template), "sink");
141   gst_element_add_pad (GST_ELEMENT (rtpgsmparse), rtpgsmparse->srcpad);
142   gst_element_add_pad (GST_ELEMENT (rtpgsmparse), rtpgsmparse->sinkpad);
143   gst_pad_set_chain_function (rtpgsmparse->sinkpad, gst_rtpgsmparse_chain);
144
145   rtpgsmparse->frequency = 8000;
146 }
147
148 void
149 gst_rtpgsmparse_ntohs (GstBuffer * buf)
150 {
151   gint16 *i, *len;
152
153   /* FIXME: is this code correct or even sane at all? */
154   i = (gint16 *) GST_BUFFER_DATA (buf);
155   len = i + GST_BUFFER_SIZE (buf) / sizeof (gint16 *);
156
157   for (; i < len; i++) {
158     *i = g_ntohs (*i);
159   }
160 }
161
162 void
163 gst_rtpgsm_caps_nego (GstRtpGSMParse * rtpgsmparse)
164 {
165   GstCaps *caps;
166
167   caps = gst_caps_new_simple ("audio/x-gsm",
168       "rate", G_TYPE_INT, rtpgsmparse->frequency);
169
170   gst_pad_try_set_caps (rtpgsmparse->srcpad, caps);
171 }
172
173 static void
174 gst_rtpgsmparse_chain (GstPad * pad, GstData * _data)
175 {
176   GstBuffer *buf = GST_BUFFER (_data);
177   GstRtpGSMParse *rtpgsmparse;
178   GstBuffer *outbuf;
179   Rtp_Packet packet;
180   rtp_payload_t pt;
181
182   g_return_if_fail (pad != NULL);
183   g_return_if_fail (GST_IS_PAD (pad));
184   g_return_if_fail (buf != NULL);
185
186   rtpgsmparse = GST_RTP_GSM_PARSE (GST_OBJECT_PARENT (pad));
187
188   g_return_if_fail (rtpgsmparse != NULL);
189   g_return_if_fail (GST_IS_RTP_GSM_PARSE (rtpgsmparse));
190
191   if (GST_IS_EVENT (buf)) {
192     GstEvent *event = GST_EVENT (buf);
193
194     gst_pad_event_default (pad, event);
195
196     return;
197   }
198
199   if (GST_PAD_CAPS (rtpgsmparse->srcpad) == NULL) {
200     gst_rtpgsm_caps_nego (rtpgsmparse);
201   }
202
203   packet =
204       rtp_packet_new_copy_data (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
205
206   pt = rtp_packet_get_payload_type (packet);
207
208   if (pt != PAYLOAD_GSM) {
209     g_warning ("Unexpected paload type %u\n", pt);
210     rtp_packet_free (packet);
211     gst_buffer_unref (buf);
212     return;
213   }
214
215   outbuf = gst_buffer_new ();
216   GST_BUFFER_SIZE (outbuf) = rtp_packet_get_payload_len (packet);
217   GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
218   GST_BUFFER_TIMESTAMP (outbuf) =
219       g_ntohl (rtp_packet_get_timestamp (packet)) * GST_SECOND;
220
221   memcpy (GST_BUFFER_DATA (outbuf), rtp_packet_get_payload (packet),
222       GST_BUFFER_SIZE (outbuf));
223
224   GST_DEBUG ("gst_rtpgsmparse_chain: pushing buffer of size %d",
225       GST_BUFFER_SIZE (outbuf));
226
227 /* FIXME: According to RFC 1890, this is required, right? */
228 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
229   gst_rtpgsmparse_ntohs (outbuf);
230 #endif
231
232   gst_pad_push (rtpgsmparse->srcpad, GST_DATA (outbuf));
233
234   rtp_packet_free (packet);
235   gst_buffer_unref (buf);
236 }
237
238 static void
239 gst_rtpgsmparse_set_property (GObject * object, guint prop_id,
240     const GValue * value, GParamSpec * pspec)
241 {
242   GstRtpGSMParse *rtpgsmparse;
243
244   /* it's not null if we got it, but it might not be ours */
245   g_return_if_fail (GST_IS_RTP_GSM_PARSE (object));
246   rtpgsmparse = GST_RTP_GSM_PARSE (object);
247
248   switch (prop_id) {
249     case ARG_FREQUENCY:
250       rtpgsmparse->frequency = g_value_get_int (value);
251       break;
252     default:
253       break;
254   }
255 }
256
257 static void
258 gst_rtpgsmparse_get_property (GObject * object, guint prop_id, GValue * value,
259     GParamSpec * pspec)
260 {
261   GstRtpGSMParse *rtpgsmparse;
262
263   /* it's not null if we got it, but it might not be ours */
264   g_return_if_fail (GST_IS_RTP_GSM_PARSE (object));
265   rtpgsmparse = GST_RTP_GSM_PARSE (object);
266
267   switch (prop_id) {
268     case ARG_FREQUENCY:
269       g_value_set_int (value, rtpgsmparse->frequency);
270       break;
271     default:
272       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
273       break;
274   }
275 }
276
277 static GstElementStateReturn
278 gst_rtpgsmparse_change_state (GstElement * element)
279 {
280   GstRtpGSMParse *rtpgsmparse;
281
282   g_return_val_if_fail (GST_IS_RTP_GSM_PARSE (element), GST_STATE_FAILURE);
283
284   rtpgsmparse = GST_RTP_GSM_PARSE (element);
285
286   GST_DEBUG ("state pending %d\n", GST_STATE_PENDING (element));
287
288   switch (GST_STATE_TRANSITION (element)) {
289     case GST_STATE_NULL_TO_READY:
290       break;
291     case GST_STATE_READY_TO_NULL:
292       break;
293     default:
294       break;
295   }
296
297   /* if we haven't failed already, give the parent class a chance to ;-) */
298   if (GST_ELEMENT_CLASS (parent_class)->change_state)
299     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
300
301   return GST_STATE_SUCCESS;
302 }
303
304 gboolean
305 gst_rtpgsmparse_plugin_init (GstPlugin * plugin)
306 {
307   return gst_element_register (plugin, "rtpgsmparse",
308       GST_RANK_NONE, GST_TYPE_RTP_GSM_PARSE);
309 }