Pay attention to cache behavior, resulting in fast_scale_y being about
[xiph/unicode.git] / xiph-rtp / xiph_rtp.c
blob5413fda8a04b78564be00719ba58563b865ab62d
1 /*
2 Copyright (c) 2006, Fluendo / Xiph.Org
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice,
8 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
14 * Neither the name of the Xiph.Org nor the names of its contributors may
15 be used to endorse or promote products derived from this software without
16 specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 THE POSSIBILITY OF SUCH DAMAGE.
30 Author: Luca Barbato <lu_zero@gentoo.org>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <time.h>
40 #include <vorbis/codec.h>
41 #include <theora/theora.h>
43 #include <arpa/inet.h>
44 #include <netinet/in.h>
45 #include <netdb.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
49 #include "xiph_rtp.h"
52 void progressmarker (int type)
54 static int outmarkpos=0;
55 FILE *out=stderr;
57 switch (type) {
58 case 0:
59 fprintf (out, "."); /* normal */
60 break;
61 case 1:
62 fprintf (out, "<"); /* start fragment */
63 break;
65 case 2:
66 fprintf (out, "+"); /* middle fragment */
67 break;
69 case 3:
70 fprintf (out, ">"); /* end fragment */
71 break;
72 #if 0
73 case 4:
74 fprintf (stdout, "b"); /* setup header */
75 break;
77 case 5:
78 fprintf (stdout, "p"); /* packed */
79 break;
81 case 6:
82 fprintf (stdout, "c"); /* info header */
83 break;
85 #endif
86 default:
87 break;
90 fflush (NULL);
92 if (outmarkpos == 70) {
93 fprintf (out, "\n");
94 outmarkpos = 0;
95 } else
96 outmarkpos++;
101 int createsocket (xiph_rtp_t *xr, char *addr, unsigned int port,
102 unsigned char TTL)
104 int ret;
105 int optval = 0;
106 struct sockaddr_in sin;
107 rtp_headers_t *headers= &xr->headers;
109 /* Init RTP headers */
111 /* Sets v=2, p=0, x=0, cc=0 */
112 headers -> flags1 = 0x80;
114 /* Sets m=0, pt=96 */
115 headers -> flags2 = 0x60;
117 headers -> sequence = htonl (rand () & 65535);
118 headers -> timestamp = htonl (rand ());
119 headers -> ssrc = htonl (rand ());
121 /* Create socket */
123 xr->socket = socket(AF_INET, SOCK_DGRAM, 0);
125 if (xr->socket < 0) {
126 fprintf (stderr, "Socket creation failed.\n");
127 return -1;
130 xr->rtpsock.sin_family = sin.sin_family = AF_INET;
131 xr->rtpsock.sin_port = sin.sin_port = htons (port);
132 xr->rtpsock.sin_addr.s_addr = inet_addr (addr);
134 ret = setsockopt (xr->socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (int));
136 if (ret < 0) {
137 fprintf (stderr, "setsockopt SO_REUSEADDR error\n");
138 return -1;
141 /* Set multicast parameters */
143 if (IN_MULTICAST (ntohl (xr->rtpsock.sin_addr.s_addr))) {
145 ret = setsockopt (xr->socket, IPPROTO_IP, IP_MULTICAST_TTL, &TTL, sizeof (char));
147 if (ret < 0) {
148 fprintf (stderr, "Multicast setsockopt TTL failed.\n");
149 return -1;
152 optval = 1;
154 ret = setsockopt (xr->socket, IPPROTO_IP, IP_MULTICAST_LOOP, &optval, sizeof (char));
156 if (ret < 0) {
157 fprintf (stderr, "Multicast setsockopt LOOP failed.\n");
158 return -1;
162 return 0;
165 int sendrtp (xiph_rtp_t *xr, const void *data, int len)
167 int ret;
168 char *outbuffer;
170 #if 0
171 fprintf(stderr,"sent %d bytes\n",len);
172 #endif
173 outbuffer = malloc (sizeof (rtp_headers_t) + len);
175 memcpy (outbuffer, &xr->headers, sizeof (rtp_headers_t));
176 memcpy (outbuffer + sizeof (rtp_headers_t), data, len);
178 ret = sendto (xr->socket, outbuffer, sizeof (rtp_headers_t) + len,
179 0, (struct sockaddr *) &xr->rtpsock,
180 sizeof (struct sockaddr_in));
182 free (outbuffer);
183 return (ret);
187 static void flush_stack (xiph_rtp_t *xr, long timestamp, long sleeptime)
189 framestack_t *fs = &xr->fs;
190 unsigned char *packet;
192 if ( fs->stackcount )
194 /* Set Vorbis header flags */
195 xr->bitfield.frag_type = 0;
196 xr->bitfield.data_type = 0;
197 xr->bitfield.pkts = fs->stackcount;
199 packet = malloc (fs->stacksize + 4);
201 makeheader (xr, packet, fs->stacksize + 4);
202 memcpy (packet + 4, fs->framestack, fs->stacksize);
204 /* Swap RTP headers from host to network order */
205 xr->headers.sequence = htons (xr->headers.sequence);
206 xr->headers.timestamp = htonl (xr->headers.timestamp);
208 sendrtp (xr, packet, fs->stacksize + 4);
210 /* Swap headers back to host order */
211 xr->headers.sequence = ntohs (xr->headers.sequence);
212 xr->headers.timestamp = ntohl (xr->headers.timestamp);
214 if (fs->stackcount == 1)
215 progressmarker (0);
216 else
217 progressmarker (5);
219 usleep (sleeptime);
221 xr->headers.sequence++;
222 xr->headers.timestamp += timestamp;
224 fs->stacksize = 0;
225 fs->stackcount = 0;
227 free (packet);
231 static void stack_packet(xiph_rtp_t *xr, unsigned char* vorbdata, int length,
232 long timestamp)
234 framestack_t *fs = &xr->fs;
236 fs->framestack =
237 realloc (fs->framestack, (fs->stacksize + (length + 2)));
238 fs->framestack[fs->stacksize++]= (length&0xff00)>>8;
239 fs->framestack[fs->stacksize++]= length&0xff;
241 memcpy (fs->framestack + (fs->stacksize), vorbdata, length);
243 fs->stackcount++;
244 fs->stacksize += length;
245 xr->headers.timestamp += timestamp;
249 //FIXME max_payload should stay somewhere else
250 void creatertp (xiph_rtp_t *xr, unsigned char* vorbdata, int length,
251 long timestamp, long sleeptime, int type, int last)
253 int frag, position = 0;
254 unsigned short framesize;
255 unsigned char *packet;
256 framestack_t *fs = &xr->fs;
257 const unsigned int max_payload = 1000;
259 if (type)
261 // flush any other packet in queue (chained ogg!)
262 flush_stack(xr, timestamp, sleeptime);
263 sleeptime = 300; // ((1 / (float) bitrate) * 1000000);
266 /* Frame packing. Used only for type 0 packets (raw Vorbis data) */
268 if ((length <= max_payload && type == 0 ) || fs->stacksize ) {
270 if (length + fs->stacksize <= max_payload
271 && fs->stackcount < 15)
273 stack_packet(xr, vorbdata, length, timestamp);
276 else if (length + fs->stacksize > max_payload
277 || fs->stackcount >= 15)
279 flush_stack(xr, timestamp, sleeptime);
281 if (length <= max_payload)
282 stack_packet(xr, vorbdata, length, timestamp);
284 if (last)
285 flush_stack(xr, timestamp, sleeptime);
289 /* Send header packets (under max_payload octets) - No Packing */
291 else if (length < max_payload) {
293 /* Set Vorbis header flags */
294 xr->bitfield.frag_type = 0;
295 xr->bitfield.data_type = type;
296 xr->bitfield.pkts = 1;
298 framesize = (unsigned char) length;
300 packet = malloc (length + 4 + 2);
302 makeheader (xr, packet, length + 4 + 2);
304 packet[4]=(length&0xff00)>>8;
305 packet[5]=length&0xff;
307 memcpy (packet + 4 + 2, vorbdata, length);
309 /* Swap RTP headers from host to network order */
310 xr->headers.sequence = htons (xr->headers.sequence);
311 xr->headers.timestamp = htonl (xr->headers.timestamp);
313 sendrtp (xr, packet, length + 4 + 2);
315 /* Swap headers back to host order */
316 xr->headers.sequence = htons (xr->headers.sequence);
317 xr->headers.timestamp = ntohl (xr->headers.timestamp);
319 /* We need to sleep enough time to not overflow
320 * the playout buffer nor starve it */
321 usleep (sleeptime);
323 xr->headers.sequence++;
324 xr->headers.timestamp += timestamp;
326 free (packet);
329 /* Frame fragmentation */
331 if (length > max_payload) {
332 frag = 1;
333 while (length > max_payload) {
334 /* Set Vorbis header flags */
335 xr->bitfield.frag_type = frag;
336 xr->bitfield.data_type = type;
337 xr->bitfield.pkts = 0;
339 framesize = max_payload;
341 packet = malloc (framesize + 4 + 2);
343 makeheader (xr, packet, framesize + 2 + 4);
344 /* write 16-bit network order fragment length */
345 packet[4]=(framesize&0xff00)>>8;
346 packet[5]=framesize&0xff;
347 memcpy (packet + 4 + 2, vorbdata + position, framesize);
349 /* Swap RTP headers from host to network order */
350 xr->headers.sequence = htons (xr->headers.sequence);
352 sendrtp (xr, packet, framesize + 4 + 2);
354 /* Swap headers back to host order */
355 xr->headers.sequence = ntohs (xr->headers.sequence);
357 length -= max_payload;
358 position += max_payload;
359 frag = 2;
361 xr->headers.sequence = xr->headers.sequence + 1;
363 progressmarker (1);
365 free (packet);
368 /* Set Vorbis header flags */
369 xr->bitfield.frag_type = 3;
370 xr->bitfield.data_type = type;
371 xr->bitfield.pkts = 0;
373 framesize = length;
375 packet = malloc (length + 4 + 2);
377 makeheader (xr, packet, length + 4 + 2);
378 packet[4]=(framesize&0xff00)>>8;
379 packet[5]=framesize&0xff;
380 memcpy (packet + 4 + 2, vorbdata + position, length);
382 /* Swap RTP headers from host to network order */
383 xr->headers.sequence = htons (xr->headers.sequence);
384 xr->headers.timestamp = htonl (xr->headers.timestamp);
386 sendrtp (xr, packet, length + 4 + 2);
388 /* Swap headers back to host order */
389 xr->headers.sequence = htons (xr->headers.sequence);
390 xr->headers.timestamp = ntohl (xr->headers.timestamp);
392 /* Increment RTP headers */
393 xr->headers.sequence++;
394 xr->headers.timestamp += timestamp;
396 progressmarker (2);
398 free (packet);
399 return;
403 int makeheader (xiph_rtp_t *xr, unsigned char *packet, int length)
405 if (xr->codec == 3) return 0; //Speex has no header
407 /* Vorbis and Theora header */
408 if (length < sizeof(header_bitfield_t)) return -1;
410 printf( "ident %06x, frag type %d,"
411 " data type %d, pkts %02d, size %d\n", xr->bitfield.cbident,
412 xr->bitfield.frag_type, xr->bitfield.data_type,
413 xr->bitfield.pkts, length);
415 packet[0] = (xr->bitfield.cbident&0xff0000)>>16;
416 packet[1] = (xr->bitfield.cbident&0xff00)>>8;
417 packet[2] = xr->bitfield.cbident&0xff;
419 packet[3] = (xr->bitfield.frag_type) << 6;
420 packet[3] |= (xr->bitfield.data_type) << 4;
421 packet[3] |= (xr->bitfield.pkts) & 0xf;
423 return 0;
427 int ogg_copy_packet(ogg_packet *dst, ogg_packet *src)
430 dst->packet = malloc(src->bytes);
431 memcpy(dst->packet, src->packet, src->bytes);
432 dst->bytes = src->bytes;
433 dst->b_o_s = src->b_o_s;
434 dst->e_o_s = src->e_o_s;
436 dst->granulepos = src->granulepos;
437 dst->packetno = src->packetno;
439 #ifdef DEBUG
440 printf("- bytes %ld bos %ld eos %ld gp %lld pno %lld\n",
441 dst->bytes, dst->b_o_s, dst->e_o_s, dst->granulepos, dst->packetno);
442 #endif
444 return 0;