gst-indent
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpL16enc.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 details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <string.h>
24 #include "gstrtpL16enc.h"
25
26 /* elementfactory information */
27 static GstElementDetails gst_rtpL16enc_details = {
28   "RTP RAW Audio Encoder",
29   "Codec/Encoder/Network",
30   "Encodes Raw Audio into an RTP packet",
31   "Zeeshan Ali <zak147@yahoo.com>"
32 };
33
34 /* RtpL16Enc signals and args */
35 enum
36 {
37   /* FILL ME */
38   LAST_SIGNAL
39 };
40
41 enum
42 {
43   /* FILL ME */
44   ARG_0,
45 };
46
47 static GstStaticPadTemplate gst_rtpL16enc_sink_template =
48 GST_STATIC_PAD_TEMPLATE ("sink",
49     GST_PAD_SINK,
50     GST_PAD_ALWAYS,
51     GST_STATIC_CAPS ("audio/x-raw-int, "
52         "endianness = (int) BYTE_ORDER, "
53         "signed = (boolean) true, "
54         "width = (int) 16, "
55         "depth = (int) 16, "
56         "rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]")
57     );
58
59 static GstStaticPadTemplate gst_rtpL16enc_src_template =
60 GST_STATIC_PAD_TEMPLATE ("src",
61     GST_PAD_SRC,
62     GST_PAD_ALWAYS,
63     GST_STATIC_CAPS ("application/x-rtp")
64     );
65
66 static void gst_rtpL16enc_class_init (GstRtpL16EncClass * klass);
67 static void gst_rtpL16enc_base_init (GstRtpL16EncClass * klass);
68 static void gst_rtpL16enc_init (GstRtpL16Enc * rtpL16enc);
69 static void gst_rtpL16enc_chain (GstPad * pad, GstData * _data);
70 static void gst_rtpL16enc_set_property (GObject * object, guint prop_id,
71     const GValue * value, GParamSpec * pspec);
72 static void gst_rtpL16enc_get_property (GObject * object, guint prop_id,
73     GValue * value, GParamSpec * pspec);
74 static GstPadLinkReturn gst_rtpL16enc_sinkconnect (GstPad * pad,
75     const GstCaps * caps);
76 static GstElementStateReturn gst_rtpL16enc_change_state (GstElement * element);
77
78 static GstElementClass *parent_class = NULL;
79
80 static GType
81 gst_rtpL16enc_get_type (void)
82 {
83   static GType rtpL16enc_type = 0;
84
85   if (!rtpL16enc_type) {
86     static const GTypeInfo rtpL16enc_info = {
87       sizeof (GstRtpL16EncClass),
88       (GBaseInitFunc) gst_rtpL16enc_base_init,
89       NULL,
90       (GClassInitFunc) gst_rtpL16enc_class_init,
91       NULL,
92       NULL,
93       sizeof (GstRtpL16Enc),
94       0,
95       (GInstanceInitFunc) gst_rtpL16enc_init,
96     };
97
98     rtpL16enc_type =
99         g_type_register_static (GST_TYPE_ELEMENT, "GstRtpL16Enc",
100         &rtpL16enc_info, 0);
101   }
102   return rtpL16enc_type;
103 }
104
105 static void
106 gst_rtpL16enc_base_init (GstRtpL16EncClass * klass)
107 {
108   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
109
110   gst_element_class_add_pad_template (element_class,
111       gst_static_pad_template_get (&gst_rtpL16enc_sink_template));
112   gst_element_class_add_pad_template (element_class,
113       gst_static_pad_template_get (&gst_rtpL16enc_src_template));
114   gst_element_class_set_details (element_class, &gst_rtpL16enc_details);
115 }
116
117 static void
118 gst_rtpL16enc_class_init (GstRtpL16EncClass * klass)
119 {
120   GObjectClass *gobject_class;
121   GstElementClass *gstelement_class;
122
123   gobject_class = (GObjectClass *) klass;
124   gstelement_class = (GstElementClass *) klass;
125
126   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
127
128   gobject_class->set_property = gst_rtpL16enc_set_property;
129   gobject_class->get_property = gst_rtpL16enc_get_property;
130
131   gstelement_class->change_state = gst_rtpL16enc_change_state;
132 }
133
134 static void
135 gst_rtpL16enc_init (GstRtpL16Enc * rtpL16enc)
136 {
137   rtpL16enc->sinkpad =
138       gst_pad_new_from_template (gst_static_pad_template_get
139       (&gst_rtpL16enc_sink_template), "sink");
140   rtpL16enc->srcpad =
141       gst_pad_new_from_template (gst_static_pad_template_get
142       (&gst_rtpL16enc_src_template), "src");
143   gst_element_add_pad (GST_ELEMENT (rtpL16enc), rtpL16enc->sinkpad);
144   gst_element_add_pad (GST_ELEMENT (rtpL16enc), rtpL16enc->srcpad);
145   gst_pad_set_chain_function (rtpL16enc->sinkpad, gst_rtpL16enc_chain);
146   gst_pad_set_link_function (rtpL16enc->sinkpad, gst_rtpL16enc_sinkconnect);
147
148   rtpL16enc->frequency = 44100;
149   rtpL16enc->channels = 2;
150
151   rtpL16enc->next_time = 0;
152   rtpL16enc->time_interval = 0;
153
154   rtpL16enc->seq = 0;
155   rtpL16enc->ssrc = random ();
156 }
157
158 static GstPadLinkReturn
159 gst_rtpL16enc_sinkconnect (GstPad * pad, const GstCaps * caps)
160 {
161   GstRtpL16Enc *rtpL16enc;
162   GstStructure *structure;
163   gboolean ret;
164
165   rtpL16enc = GST_RTP_L16_ENC (gst_pad_get_parent (pad));
166
167   structure = gst_caps_get_structure (caps, 0);
168
169   ret = gst_structure_get_int (structure, "rate", &rtpL16enc->frequency);
170   ret &= gst_structure_get_int (structure, "channels", &rtpL16enc->channels);
171
172   if (!ret)
173     return GST_PAD_LINK_REFUSED;
174
175   /* Pre-calculate what we can */
176   rtpL16enc->time_interval =
177       GST_SECOND / (2 * rtpL16enc->channels * rtpL16enc->frequency);
178
179   return GST_PAD_LINK_OK;
180 }
181
182
183 void
184 gst_rtpL16enc_htons (GstBuffer * buf)
185 {
186   gint16 *i, *len;
187
188   /* FIXME: is this code correct or even sane at all? */
189   i = (gint16 *) GST_BUFFER_DATA (buf);
190   len = i + GST_BUFFER_SIZE (buf) / sizeof (gint16 *);
191
192   for (; i < len; i++) {
193     *i = g_htons (*i);
194   }
195 }
196
197 static void
198 gst_rtpL16enc_chain (GstPad * pad, GstData * _data)
199 {
200   GstBuffer *buf = GST_BUFFER (_data);
201   GstRtpL16Enc *rtpL16enc;
202   GstBuffer *outbuf;
203   Rtp_Packet packet;
204
205   g_return_if_fail (pad != NULL);
206   g_return_if_fail (GST_IS_PAD (pad));
207   g_return_if_fail (buf != NULL);
208
209   rtpL16enc = GST_RTP_L16_ENC (GST_OBJECT_PARENT (pad));
210
211   g_return_if_fail (rtpL16enc != NULL);
212   g_return_if_fail (GST_IS_RTP_L16_ENC (rtpL16enc));
213
214   if (GST_IS_EVENT (buf)) {
215     GstEvent *event = GST_EVENT (buf);
216
217     switch (GST_EVENT_TYPE (event)) {
218       case GST_EVENT_DISCONTINUOUS:
219         GST_DEBUG ("discont");
220         rtpL16enc->next_time = 0;
221         gst_pad_event_default (pad, event);
222         return;
223       default:
224         gst_pad_event_default (pad, event);
225         return;
226     }
227   }
228
229   /* We only need the header */
230   packet = rtp_packet_new_allocate (0, 0, 0);
231
232   rtp_packet_set_csrc_count (packet, 0);
233   rtp_packet_set_extension (packet, 0);
234   rtp_packet_set_padding (packet, 0);
235   rtp_packet_set_version (packet, RTP_VERSION);
236   rtp_packet_set_marker (packet, 0);
237   rtp_packet_set_ssrc (packet, g_htonl (rtpL16enc->ssrc));
238   rtp_packet_set_seq (packet, g_htons (rtpL16enc->seq));
239   rtp_packet_set_timestamp (packet,
240       g_htonl ((guint32) rtpL16enc->next_time / GST_SECOND));
241
242   if (rtpL16enc->channels == 1) {
243     rtp_packet_set_payload_type (packet, (guint8) PAYLOAD_L16_MONO);
244   }
245
246   else {
247     rtp_packet_set_payload_type (packet, (guint8) PAYLOAD_L16_STEREO);
248   }
249
250   /* FIXME: According to RFC 1890, this is required, right? */
251 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
252   gst_rtpL16enc_htons (buf);
253 #endif
254
255   outbuf = gst_buffer_new ();
256   GST_BUFFER_SIZE (outbuf) =
257       rtp_packet_get_packet_len (packet) + GST_BUFFER_SIZE (buf);
258   GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
259   GST_BUFFER_TIMESTAMP (outbuf) = rtpL16enc->next_time;
260
261   memcpy (GST_BUFFER_DATA (outbuf), packet->data,
262       rtp_packet_get_packet_len (packet));
263   memcpy (GST_BUFFER_DATA (outbuf) + rtp_packet_get_packet_len (packet),
264       GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
265
266   GST_DEBUG ("gst_rtpL16enc_chain: pushing buffer of size %d",
267       GST_BUFFER_SIZE (outbuf));
268   gst_pad_push (rtpL16enc->srcpad, GST_DATA (outbuf));
269
270   ++rtpL16enc->seq;
271   rtpL16enc->next_time += rtpL16enc->time_interval * GST_BUFFER_SIZE (buf);
272
273   rtp_packet_free (packet);
274   gst_buffer_unref (buf);
275 }
276
277 static void
278 gst_rtpL16enc_set_property (GObject * object, guint prop_id,
279     const GValue * value, GParamSpec * pspec)
280 {
281   GstRtpL16Enc *rtpL16enc;
282
283   /* it's not null if we got it, but it might not be ours */
284   g_return_if_fail (GST_IS_RTP_L16_ENC (object));
285   rtpL16enc = GST_RTP_L16_ENC (object);
286
287   switch (prop_id) {
288     default:
289       break;
290   }
291 }
292
293 static void
294 gst_rtpL16enc_get_property (GObject * object, guint prop_id, GValue * value,
295     GParamSpec * pspec)
296 {
297   GstRtpL16Enc *rtpL16enc;
298
299   /* it's not null if we got it, but it might not be ours */
300   g_return_if_fail (GST_IS_RTP_L16_ENC (object));
301   rtpL16enc = GST_RTP_L16_ENC (object);
302
303   switch (prop_id) {
304     default:
305       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
306       break;
307   }
308 }
309
310 static GstElementStateReturn
311 gst_rtpL16enc_change_state (GstElement * element)
312 {
313   GstRtpL16Enc *rtpL16enc;
314
315   g_return_val_if_fail (GST_IS_RTP_L16_ENC (element), GST_STATE_FAILURE);
316
317   rtpL16enc = GST_RTP_L16_ENC (element);
318
319   GST_DEBUG ("state pending %d\n", GST_STATE_PENDING (element));
320
321   /* if going down into NULL state, close the file if it's open */
322   switch (GST_STATE_TRANSITION (element)) {
323     case GST_STATE_NULL_TO_READY:
324       break;
325
326     case GST_STATE_READY_TO_NULL:
327       break;
328
329     default:
330       break;
331   }
332
333   /* if we haven't failed already, give the parent class a chance to ;-) */
334   if (GST_ELEMENT_CLASS (parent_class)->change_state)
335     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
336
337   return GST_STATE_SUCCESS;
338 }
339
340 gboolean
341 gst_rtpL16enc_plugin_init (GstPlugin * plugin)
342 {
343   return gst_element_register (plugin, "rtpL16enc",
344       GST_RANK_NONE, GST_TYPE_RTP_L16_ENC);
345 }