Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/ietf_dev.h>
27 :
28 : #ifndef GPAC_DISABLE_STREAMING
29 :
30 : #define MAX_RTP_SN 0x10000
31 :
32 :
33 : GF_EXPORT
34 58 : GF_RTPChannel *gf_rtp_new()
35 : {
36 : GF_RTPChannel *tmp;
37 58 : GF_SAFEALLOC(tmp, GF_RTPChannel);
38 58 : if (!tmp)
39 : return NULL;
40 58 : tmp->first_SR = 1;
41 58 : tmp->SSRC = gf_rand();
42 58 : tmp->bs_r = gf_bs_new("d", 1, GF_BITSTREAM_READ);
43 58 : tmp->bs_w = gf_bs_new("d", 1, GF_BITSTREAM_WRITE);
44 58 : return tmp;
45 : }
46 :
47 : GF_EXPORT
48 58 : void gf_rtp_del(GF_RTPChannel *ch)
49 : {
50 58 : if (!ch) return;
51 58 : if (ch->rtp) gf_sk_del(ch->rtp);
52 58 : if (ch->rtcp) gf_sk_del(ch->rtcp);
53 58 : if (ch->net_info.source) gf_free(ch->net_info.source);
54 58 : if (ch->net_info.destination) gf_free(ch->net_info.destination);
55 58 : if (ch->net_info.Profile) gf_free(ch->net_info.Profile);
56 58 : if (ch->po) gf_rtp_reorderer_del(ch->po);
57 58 : if (ch->send_buffer) gf_free(ch->send_buffer);
58 :
59 58 : if (ch->CName) gf_free(ch->CName);
60 58 : if (ch->s_name) gf_free(ch->s_name);
61 58 : if (ch->s_email) gf_free(ch->s_email);
62 58 : if (ch->s_location) gf_free(ch->s_location);
63 58 : if (ch->s_phone) gf_free(ch->s_phone);
64 58 : if (ch->s_tool) gf_free(ch->s_tool);
65 58 : if (ch->s_note) gf_free(ch->s_note);
66 58 : if (ch->s_priv) gf_free(ch->s_priv);
67 58 : if (ch->bs_r) gf_bs_del(ch->bs_r);
68 58 : if (ch->bs_w) gf_bs_del(ch->bs_w);
69 : memset(ch, 0, sizeof(GF_RTPChannel));
70 58 : gf_free(ch);
71 : }
72 :
73 :
74 : GF_EXPORT
75 66 : GF_Err gf_rtp_setup_transport(GF_RTPChannel *ch, GF_RTSPTransport *trans_info, const char *remote_address)
76 : {
77 66 : if (!ch || !trans_info) return GF_BAD_PARAM;
78 : //assert we have at least ONE source ID
79 66 : if (!trans_info->source && !remote_address) return GF_BAD_PARAM;
80 :
81 66 : if (ch->net_info.destination) gf_free(ch->net_info.destination);
82 66 : ch->net_info.destination = NULL;
83 66 : if (ch->net_info.Profile) gf_free(ch->net_info.Profile);
84 66 : ch->net_info.Profile = NULL;
85 66 : if (ch->net_info.source) gf_free(ch->net_info.source);
86 66 : ch->net_info.source = NULL;
87 66 : memcpy(&ch->net_info, trans_info, sizeof(GF_RTSPTransport));
88 :
89 66 : if (trans_info->destination)
90 39 : ch->net_info.destination = gf_strdup(trans_info->destination);
91 :
92 66 : if (trans_info->Profile)
93 66 : ch->net_info.Profile = gf_strdup(trans_info->Profile);
94 :
95 66 : if (!ch->net_info.IsUnicast && trans_info->destination) {
96 : assert( trans_info->destination );
97 4 : ch->net_info.source = gf_strdup(trans_info->destination);
98 4 : if (ch->net_info.client_port_first) {
99 1 : ch->net_info.port_first = ch->net_info.client_port_first;
100 1 : ch->net_info.port_last = ch->net_info.client_port_last;
101 : }
102 62 : } else if (trans_info->source) {
103 57 : ch->net_info.source = gf_strdup(trans_info->source);
104 : } else {
105 5 : ch->net_info.source = gf_strdup(remote_address);
106 : }
107 66 : if (trans_info->SSRC) {
108 43 : if (trans_info->is_sender) {
109 6 : ch->SSRC = trans_info->SSRC;
110 : } else {
111 37 : ch->SenderSSRC = trans_info->SSRC;
112 : }
113 : }
114 : //check we REALLY have unicast or multicast
115 66 : if (gf_sk_is_multicast_address(ch->net_info.source) && ch->net_info.IsUnicast) return GF_SERVICE_ERROR;
116 66 : return GF_OK;
117 : }
118 :
119 :
120 : GF_EXPORT
121 32 : void gf_rtp_reset_buffers(GF_RTPChannel *ch)
122 : {
123 32 : if (ch->rtp) gf_sk_reset(ch->rtp);
124 32 : if (ch->rtcp) gf_sk_reset(ch->rtcp);
125 32 : if (ch->po) gf_rtp_reorderer_reset(ch->po);
126 32 : ch->first_SR = 1;
127 32 : }
128 :
129 : GF_EXPORT
130 1 : void gf_rtp_reset_ssrc(GF_RTPChannel *ch)
131 : {
132 1 : if (ch) ch->SenderSSRC = 0;
133 1 : }
134 :
135 : GF_EXPORT
136 3 : void gf_rtp_enable_nat_keepalive(GF_RTPChannel *ch, u32 nat_timeout)
137 : {
138 3 : if (ch) {
139 2 : ch->nat_keepalive_time_period = nat_timeout;
140 2 : ch->last_nat_keepalive_time = 0;
141 : }
142 3 : }
143 :
144 :
145 :
146 : GF_EXPORT
147 13 : GF_Err gf_rtp_set_info_rtp(GF_RTPChannel *ch, u32 seq_num, u32 rtp_time, u32 ssrc)
148 : {
149 13 : if (!ch) return GF_BAD_PARAM;
150 13 : ch->CurrentTime = ch->rtp_time = seq_num ? (1 + rtp_time) : 0;
151 13 : ch->last_pck_sn = 0;
152 13 : ch->rtp_first_SN = seq_num;
153 13 : ch->num_sn_loops = 0;
154 : //reset RTCP
155 13 : ch->ntp_init = 0;
156 13 : ch->first_SR = 1;
157 13 : if (ssrc) ch->SenderSSRC = ssrc;
158 13 : ch->total_pck = ch->total_bytes = ch->last_num_pck_rcv = ch->last_num_pck_expected = ch->last_num_pck_loss = ch->tot_num_pck_rcv = ch->tot_num_pck_expected = ch->rtcp_bytes_sent = 0;
159 13 : return GF_OK;
160 : }
161 :
162 : GF_EXPORT
163 1 : GF_Err gf_rtp_stop(GF_RTPChannel *ch)
164 : {
165 1 : if (!ch) return GF_BAD_PARAM;
166 0 : if (ch->rtp) gf_sk_del(ch->rtp);
167 0 : ch->rtp = NULL;
168 0 : if (ch->rtcp) gf_sk_del(ch->rtcp);
169 0 : ch->rtcp = NULL;
170 0 : if (ch->po) gf_rtp_reorderer_del(ch->po);
171 0 : ch->po = NULL;
172 0 : return GF_OK;
173 : }
174 :
175 : GF_EXPORT
176 57 : GF_Err gf_rtp_initialize(GF_RTPChannel *ch, u32 UDPBufferSize, Bool IsSource, u32 PathMTU, u32 ReorederingSize, u32 MaxReorderDelay, char *local_ip)
177 : {
178 : u16 port;
179 : GF_Err e;
180 :
181 57 : if (!ch || (IsSource && !PathMTU)) return GF_BAD_PARAM;
182 :
183 57 : if (ch->rtp) gf_sk_del(ch->rtp);
184 57 : ch->rtp = NULL;
185 57 : if (ch->rtcp) gf_sk_del(ch->rtcp);
186 57 : ch->rtcp = NULL;
187 57 : if (ch->po) gf_rtp_reorderer_del(ch->po);
188 57 : ch->po = NULL;
189 :
190 57 : ch->CurrentTime = 0;
191 57 : ch->rtp_time = 0;
192 :
193 : //create sockets for RTP/AVP profile only
194 114 : if (ch->net_info.Profile &&
195 57 : ( !stricmp(ch->net_info.Profile, GF_RTSP_PROFILE_RTP_AVP)
196 2 : || !stricmp(ch->net_info.Profile, "RTP/AVP/UDP")
197 2 : || !stricmp(ch->net_info.Profile, "RTP/SAVP")
198 : )
199 : ) {
200 : //destination MUST be specified for unicast
201 55 : if (IsSource && ch->net_info.IsUnicast && !ch->net_info.destination) return GF_BAD_PARAM;
202 :
203 : /* forcing unicast when the address is not a multicast */
204 55 : if (!ch->net_info.IsUnicast) {
205 4 : if (IsSource) {
206 2 : if (ch->net_info.destination && !gf_sk_is_multicast_address(ch->net_info.destination)) {
207 0 : ch->net_info.IsUnicast = GF_TRUE;
208 : }
209 : } else {
210 2 : if (ch->net_info.source && !gf_sk_is_multicast_address(ch->net_info.source)) {
211 1 : ch->net_info.IsUnicast = GF_TRUE;
212 : }
213 : }
214 : }
215 : //
216 : // RTP
217 : //
218 55 : ch->rtp = gf_sk_new(GF_SOCK_TYPE_UDP);
219 55 : if (!ch->rtp) return GF_IP_NETWORK_FAILURE;
220 55 : if (ch->net_info.IsUnicast) {
221 : //if client, bind and connect the socket
222 52 : if (!IsSource) {
223 18 : port = ch->net_info.port_first;
224 18 : if (!port) port = ch->net_info.client_port_first;
225 : /*if a destination address was given (rtsd) use it*/
226 18 : if (!local_ip && ch->net_info.destination) local_ip = ch->net_info.destination;
227 :
228 18 : e = gf_sk_bind(ch->rtp, local_ip, ch->net_info.client_port_first, ch->net_info.source, port, GF_SOCK_REUSE_PORT);
229 18 : if (e) return e;
230 : }
231 : //else bind and set remote destination
232 : else {
233 34 : if (!ch->net_info.port_first) ch->net_info.port_first = ch->net_info.client_port_first;
234 34 : e = gf_sk_bind(ch->rtp, local_ip,ch->net_info.port_first, ch->net_info.destination, ch->net_info.client_port_first, GF_SOCK_REUSE_PORT | GF_SOCK_FAKE_BIND);
235 34 : if (e) return e;
236 : }
237 : } else {
238 : //Bind to multicast (auto-join the group).
239 : //we do not bind the socket if this is a source-only channel because some servers
240 : //don't like that on local loop ...
241 3 : e = gf_sk_setup_multicast(ch->rtp, ch->net_info.source, ch->net_info.port_first, ch->net_info.TTL, GF_FALSE, local_ip);
242 3 : if (e) return e;
243 : }
244 55 : if (UDPBufferSize) gf_sk_set_buffer_size(ch->rtp, IsSource, UDPBufferSize);
245 :
246 : //create re-ordering queue for UDP only, and receive
247 55 : if (ReorederingSize && !IsSource) {
248 19 : if (!MaxReorderDelay) MaxReorderDelay = 200;
249 19 : ch->po = gf_rtp_reorderer_new(ReorederingSize, MaxReorderDelay);
250 : }
251 :
252 : //
253 : // RTCP
254 : //
255 55 : ch->rtcp = gf_sk_new(GF_SOCK_TYPE_UDP);
256 55 : if (!ch->rtcp) return GF_IP_NETWORK_FAILURE;
257 55 : if (ch->net_info.IsUnicast) {
258 52 : if (!IsSource) {
259 18 : port = ch->net_info.port_last;
260 18 : if (!port) port = ch->net_info.client_port_last;
261 : /*if a destination address was given (rtsd) use it*/
262 18 : if (!local_ip && ch->net_info.destination) local_ip = ch->net_info.destination;
263 :
264 18 : e = gf_sk_bind(ch->rtcp, local_ip, ch->net_info.client_port_last, ch->net_info.source, port, GF_SOCK_REUSE_PORT);
265 18 : if (e) return e;
266 : } else {
267 34 : e = gf_sk_bind(ch->rtcp, local_ip, ch->net_info.port_last, ch->net_info.destination, ch->net_info.client_port_last, GF_SOCK_REUSE_PORT | GF_SOCK_FAKE_BIND);
268 34 : if (e) return e;
269 : }
270 : } else {
271 3 : if (!ch->net_info.port_last) ch->net_info.port_last = ch->net_info.client_port_last;
272 : //Bind to multicast (auto-join the group)
273 3 : e = gf_sk_setup_multicast(ch->rtcp, ch->net_info.source, ch->net_info.port_last, ch->net_info.TTL, GF_FALSE, local_ip);
274 3 : if (e) return e;
275 : }
276 : }
277 :
278 57 : if (IsSource) {
279 37 : if (ch->send_buffer) gf_free(ch->send_buffer);
280 37 : ch->send_buffer_size = PathMTU + 12;
281 37 : ch->send_buffer = (char *) gf_malloc(sizeof(char) * ch->send_buffer_size);
282 : }
283 :
284 : //format CNAME if not done yet
285 57 : if (!ch->CName) {
286 : //this is the real CName setup
287 57 : if (!ch->rtp) {
288 2 : ch->CName = gf_strdup("mpeg4rtp");
289 : } else {
290 : char name[GF_MAX_IP_NAME_LEN];
291 :
292 : size_t start;
293 55 : gf_get_user_name(name);
294 55 : if (strlen(name)) strcat(name, "@");
295 55 : start = strlen(name);
296 : //get host IP or loopback if error
297 55 : if (gf_sk_get_local_ip(ch->rtp, name+start) != GF_OK) strcpy(name+start, "127.0.0.1");
298 55 : ch->CName = gf_strdup(name);
299 : }
300 : }
301 :
302 : #ifndef GPAC_DISABLE_LOG
303 57 : if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_DEBUG)) {
304 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Packet Log Format: SSRC SequenceNumber TimeStamp NTP@recvTime deviance, Jiter, PckLost PckTotal BytesTotal\n"));
305 : }
306 : #endif
307 :
308 : return GF_OK;
309 : }
310 :
311 : /*get the UTC time expressed in RTP timescale*/
312 755 : u32 gf_rtp_channel_time(GF_RTPChannel *ch)
313 : {
314 : u32 sec, frac, res;
315 755 : gf_net_get_ntp(&sec, &frac);
316 755 : res = ( (u32) ( (frac>>26)*ch->TimeScale) ) >> 6;
317 755 : res += ch->TimeScale*(sec - ch->ntp_init);
318 755 : return (u32) res;
319 : }
320 :
321 1653 : u32 gf_rtp_get_report_time()
322 : {
323 : u32 sec, frac;
324 1715 : gf_net_get_ntp(&sec, &frac);
325 : /*in units of 1/65536 seconds*/
326 1715 : return (u32) ( (frac>>16) + 0x10000L*sec );
327 : }
328 :
329 :
330 62 : void gf_rtp_get_next_report_time(GF_RTPChannel *ch)
331 : {
332 : Double d;
333 :
334 : /*offset between .5 and 1.5 sec*/
335 62 : d = 0.5 + ((Double) gf_rand()) / ((Double) RAND_MAX);
336 : /*of a minimal 5sec interval expressed in 1/65536 of a sec*/
337 62 : d = 5.0 * d * 65536;
338 : /*we should estimate bandwidth sharing too*/
339 62 : ch->next_report_time = gf_rtp_get_report_time() + (u32) d;
340 62 : }
341 :
342 : GF_EXPORT
343 39 : u32 gf_rtp_read_flush(GF_RTPChannel *ch, u8 *buffer, u32 buffer_size)
344 : {
345 : char *pck;
346 39 : u32 res = 0;
347 39 : if (!ch->po) return 0;
348 :
349 : //pck queue may need to be flushed
350 38 : pck = (char *) gf_rtp_reorderer_get(ch->po, &res, GF_TRUE);
351 38 : if (pck) {
352 19 : memcpy(buffer, pck, res);
353 19 : gf_free(pck);
354 : }
355 38 : return res;
356 : }
357 :
358 : GF_EXPORT
359 7 : u32 gf_rtp_flush_rtp(GF_RTPChannel *ch, u8 *buffer, u32 buffer_size)
360 : {
361 : u32 res;
362 : char *pck;
363 :
364 : //only if the socket exist (otherwise RTSP interleaved channel)
365 7 : if (!ch || !ch->rtp || !ch->po) return 0;
366 :
367 : //pck queue may need to be flushed
368 6 : pck = (char *) gf_rtp_reorderer_get(ch->po, &res, GF_FALSE);
369 6 : if (pck) {
370 0 : memcpy(buffer, pck, res);
371 0 : gf_free(pck);
372 0 : return res;
373 : }
374 : return 0;
375 : }
376 :
377 : GF_EXPORT
378 742 : u32 gf_rtp_read_rtp(GF_RTPChannel *ch, u8 *buffer, u32 buffer_size)
379 : {
380 : GF_Err e;
381 : u32 seq_num, res;
382 :
383 : //only if the socket exist (otherwise RTSP interleaved channel)
384 742 : if (!ch || !ch->rtp) return 0;
385 :
386 742 : if (ch->no_select) {
387 0 : e = gf_sk_receive_no_select(ch->rtp, buffer, buffer_size, &res);
388 : } else {
389 742 : e = gf_sk_receive(ch->rtp, buffer, buffer_size, &res);
390 : }
391 742 : if (!res || e || (res < 12)) {
392 : assert(res==0);
393 0 : res = 0;
394 : }
395 742 : if (res) {
396 742 : ch->total_bytes+=res;
397 742 : ch->total_pck++;
398 : }
399 : //add the packet to our Queue if any
400 742 : if (ch->po) {
401 : char *pck;
402 742 : if (res) {
403 742 : seq_num = ((((u32)buffer[2]) << 8) & 0xFF00) | (buffer[3] & 0xFF);
404 742 : gf_rtp_reorderer_add(ch->po, (void *) buffer, res, seq_num);
405 : }
406 :
407 : //pck queue may need to be flushed
408 742 : pck = (char *) gf_rtp_reorderer_get(ch->po, &res, GF_FALSE);
409 742 : if (pck) {
410 723 : memcpy(buffer, pck, res);
411 723 : gf_free(pck);
412 : }
413 : }
414 : /*monitor keep-alive period*/
415 742 : if (ch->nat_keepalive_time_period && !ch->send_interleave) {
416 32 : u32 now = gf_sys_clock();
417 32 : if (res) {
418 30 : ch->last_nat_keepalive_time = now;
419 : } else {
420 2 : if (now - ch->last_nat_keepalive_time >= ch->nat_keepalive_time_period) {
421 : char rtp_nat[12];
422 0 : rtp_nat[0] = (u8) 0xC0;
423 0 : rtp_nat[1] = ch->PayloadType;
424 0 : rtp_nat[2] = (ch->last_pck_sn>>8)&0xFF;
425 0 : rtp_nat[3] = (ch->last_pck_sn)&0xFF;
426 0 : rtp_nat[4] = (ch->last_pck_ts>>24)&0xFF;
427 0 : rtp_nat[5] = (ch->last_pck_ts>>16)&0xFF;
428 0 : rtp_nat[6] = (ch->last_pck_ts>>8)&0xFF;
429 0 : rtp_nat[7] = (ch->last_pck_ts)&0xFF;
430 0 : rtp_nat[8] = (ch->SenderSSRC>>24)&0xFF;
431 0 : rtp_nat[9] = (ch->SenderSSRC>>16)&0xFF;
432 0 : rtp_nat[10] = (ch->SenderSSRC>>8)&0xFF;
433 0 : rtp_nat[11] = (ch->SenderSSRC)&0xFF;
434 0 : e = gf_sk_send(ch->rtp, rtp_nat, 12);
435 0 : if (e) {
436 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Error sending NAT keep-alive packet: %s - disabling NAT\n", gf_error_to_string(e) ));
437 0 : ch->nat_keepalive_time_period = 0;
438 : } else {
439 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Sending NAT keep-alive packet - response %s\n", gf_error_to_string(e) ));
440 : }
441 0 : ch->last_nat_keepalive_time = now;
442 : }
443 : }
444 : }
445 742 : return res;
446 : }
447 :
448 :
449 : GF_EXPORT
450 755 : GF_Err gf_rtp_decode_rtp(GF_RTPChannel *ch, u8 *pck, u32 pck_size, GF_RTPHeader *rtp_hdr, u32 *PayloadStart)
451 : {
452 : GF_Err e;
453 : s32 deviance, delta;
454 : u32 CurrSeq, LastSeq;
455 : u32 ntp, lost, low16;
456 :
457 755 : if (!rtp_hdr) return GF_BAD_PARAM;
458 : e = GF_OK;
459 :
460 755 : gf_bs_reassign_buffer(ch->bs_r, pck, pck_size);
461 : //we need to uncompress the RTP header
462 755 : rtp_hdr->Version = gf_bs_read_int(ch->bs_r, 2);
463 755 : if (rtp_hdr->Version != 2) return GF_NOT_SUPPORTED;
464 :
465 755 : rtp_hdr->Padding = gf_bs_read_int(ch->bs_r, 1);
466 755 : rtp_hdr->Extension = gf_bs_read_int(ch->bs_r, 1);
467 755 : rtp_hdr->CSRCCount = gf_bs_read_int(ch->bs_r, 4);
468 755 : rtp_hdr->Marker = gf_bs_read_int(ch->bs_r, 1);
469 755 : rtp_hdr->PayloadType = gf_bs_read_int(ch->bs_r, 7);
470 :
471 : /*we don't support multiple CSRC now. Only one source (the server) is allowed*/
472 755 : if (rtp_hdr->CSRCCount) return GF_NOT_SUPPORTED;
473 : /*SeqNum*/
474 755 : rtp_hdr->SequenceNumber = gf_bs_read_u16(ch->bs_r);
475 : /*TS*/
476 755 : rtp_hdr->TimeStamp = gf_bs_read_u32(ch->bs_r);
477 : /*SSRC*/
478 755 : rtp_hdr->SSRC = gf_bs_read_u32(ch->bs_r);
479 :
480 : /*update RTP time if we didn't get the info*/
481 755 : if (!ch->rtp_time) {
482 20 : ch->rtp_time = 1 + rtp_hdr->TimeStamp;
483 20 : ch->rtp_first_SN = rtp_hdr->SequenceNumber;
484 20 : ch->num_sn_loops = 0;
485 : }
486 755 : if (ch->first_SR && !ch->SenderSSRC && rtp_hdr->SSRC) {
487 1 : ch->SenderSSRC = rtp_hdr->SSRC;
488 1 : GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTP] Assigning SSRC to %d because none was specified through SDP/RTSP\n", ch->SenderSSRC));
489 : }
490 :
491 755 : if (!ch->ntp_init && ch->SenderSSRC && (ch->SenderSSRC != rtp_hdr->SSRC) ) {
492 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTP] SSRC mismatch: %d vs %d\n", rtp_hdr->SSRC, ch->SenderSSRC));
493 : return GF_IP_NETWORK_EMPTY;
494 : }
495 :
496 :
497 : /*RTP specs annexe A.8*/
498 755 : if (!ch->ntp_init) {
499 20 : gf_net_get_ntp(&ch->ntp_init, &lost);
500 20 : ch->last_pck_sn = (u32) rtp_hdr->SequenceNumber-1;
501 : }
502 : /*this is a loop in SN - add it*/
503 755 : if ( (ch->last_pck_sn + 1 > rtp_hdr->SequenceNumber)
504 0 : && (rtp_hdr->SequenceNumber >= ch->last_pck_sn + MAX_RTP_SN/2)) {
505 0 : ch->num_sn_loops += 1;
506 : }
507 :
508 755 : if (ch->last_SR_rtp_time) {
509 : s64 diff_sec;
510 705 : u32 sec = ch->last_SR_NTP_sec;
511 : s64 frac;
512 :
513 705 : frac = (s64) rtp_hdr->TimeStamp;
514 705 : frac -= (s64) ch->last_SR_rtp_time;
515 705 : if (frac<0) frac += 0xFFFFFFFF;
516 705 : diff_sec = frac / ch->TimeScale;
517 :
518 705 : frac -= diff_sec*ch->TimeScale;
519 705 : frac *= 0xFFFFFFFF;
520 705 : frac /= ch->TimeScale;
521 705 : frac += ch->last_SR_NTP_frac;
522 705 : if (frac>0xFFFFFFFF) {
523 313 : sec += 1;
524 313 : frac -= 0xFFFFFFFF;
525 : }
526 705 : rtp_hdr->recomputed_ntp_ts = sec + (s32) diff_sec;
527 705 : rtp_hdr->recomputed_ntp_ts <<= 32;
528 705 : rtp_hdr->recomputed_ntp_ts |= frac;
529 : }
530 :
531 755 : ntp = gf_rtp_channel_time(ch);
532 755 : deviance = ntp - rtp_hdr->TimeStamp;
533 755 : delta = deviance - ch->last_deviance;
534 755 : ch->last_deviance = deviance;
535 :
536 755 : if (delta < 0) delta = -delta;
537 755 : ch->Jitter += delta - ( (ch->Jitter + 8) >> 4);
538 :
539 755 : lost = 0;
540 755 : LastSeq = ch->last_pck_sn;
541 755 : CurrSeq = (u32) rtp_hdr->SequenceNumber;
542 755 : ch->packet_loss = GF_FALSE;
543 : /*next sequential pck*/
544 755 : if ( ( (LastSeq + 1) & 0xffff ) == CurrSeq ) {
545 755 : ch->last_num_pck_rcv += 1;
546 755 : ch->last_num_pck_expected += 1;
547 : }
548 : /*repeated pck*/
549 0 : else if ( (LastSeq & 0xffff ) == CurrSeq ) {
550 0 : ch->last_num_pck_rcv += 1;
551 : }
552 : /*drop pck*/
553 : else {
554 : low16 = LastSeq & 0xffff;
555 0 : if ( CurrSeq > low16 )
556 0 : lost = CurrSeq - low16;
557 : else
558 0 : lost = 0xffff - low16 + CurrSeq + 1;
559 :
560 0 : ch->last_num_pck_expected += lost;
561 0 : ch->last_num_pck_rcv += 1;
562 0 : ch->last_num_pck_loss += lost;
563 0 : ch->packet_loss = GF_TRUE;
564 : }
565 755 : ch->last_pck_sn = CurrSeq;
566 :
567 : #ifndef GPAC_DISABLE_LOG
568 755 : if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_DEBUG)) {
569 0 : ch->total_bytes += pck_size-12;
570 :
571 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP]\t%d\t%d\t%u\t%d\t%d\t%d\t%d\t%d\t%d\n",
572 : ch->SenderSSRC,
573 : rtp_hdr->SequenceNumber,
574 : rtp_hdr->TimeStamp,
575 : ntp,
576 : delta,
577 : ch->Jitter >> 4,
578 : lost,
579 : ch->total_pck,
580 : ch->total_bytes
581 : ));
582 : }
583 : #endif
584 :
585 : //we work with no CSRC so payload offset is always 12
586 755 : *PayloadStart = 12;
587 :
588 755 : if (rtp_hdr->Extension) {
589 : u16 ext_size;
590 0 : char *payl = pck + *PayloadStart;
591 0 : ext_size = payl[2];
592 0 : ext_size <<= 8;
593 0 : ext_size |= payl[3];
594 0 : *PayloadStart += 4 + (ext_size * 4);
595 : }
596 :
597 : //store the time
598 755 : ch->CurrentTime = rtp_hdr->TimeStamp;
599 755 : return e;
600 : }
601 :
602 :
603 : GF_EXPORT
604 168 : Double gf_rtp_get_current_time(GF_RTPChannel *ch)
605 : {
606 : Double ret;
607 168 : if (!ch || !ch->rtp_time) return 0.0;
608 168 : ret = (Double) ch->CurrentTime;
609 168 : ret -= (Double) (ch->rtp_time-1);
610 168 : ret /= ch->TimeScale;
611 168 : return ret;
612 : }
613 :
614 :
615 :
616 :
617 :
618 :
619 : GF_EXPORT
620 892 : GF_Err gf_rtp_send_packet(GF_RTPChannel *ch, GF_RTPHeader *rtp_hdr, u8 *pck, u32 pck_size, Bool fast_send)
621 : {
622 : GF_Err e;
623 : u32 i, Start;
624 : char *hdr = NULL;
625 :
626 892 : if (!ch || !rtp_hdr
627 892 : || !ch->send_buffer
628 892 : || !pck
629 892 : || (rtp_hdr->CSRCCount > 15)) return GF_BAD_PARAM;
630 :
631 892 : if (rtp_hdr->CSRCCount) fast_send = GF_FALSE;
632 :
633 892 : if (12 + pck_size + 4*rtp_hdr->CSRCCount > ch->send_buffer_size)
634 : return GF_IO_ERR;
635 :
636 892 : if (fast_send) {
637 892 : hdr = pck - 12;
638 892 : gf_bs_reassign_buffer(ch->bs_w, hdr, 12);
639 : } else {
640 0 : gf_bs_reassign_buffer(ch->bs_w, ch->send_buffer, ch->send_buffer_size);
641 : }
642 : //write header
643 892 : gf_bs_write_int(ch->bs_w, rtp_hdr->Version, 2);
644 892 : gf_bs_write_int(ch->bs_w, rtp_hdr->Padding, 1);
645 892 : gf_bs_write_int(ch->bs_w, rtp_hdr->Extension, 1);
646 892 : gf_bs_write_int(ch->bs_w, rtp_hdr->CSRCCount, 4);
647 892 : gf_bs_write_int(ch->bs_w, rtp_hdr->Marker, 1);
648 892 : gf_bs_write_int(ch->bs_w, rtp_hdr->PayloadType, 7);
649 892 : gf_bs_write_u16(ch->bs_w, rtp_hdr->SequenceNumber);
650 892 : gf_bs_write_u32(ch->bs_w, rtp_hdr->TimeStamp);
651 892 : gf_bs_write_u32(ch->bs_w, ch->SSRC);
652 :
653 892 : for (i=0; i<rtp_hdr->CSRCCount; i++) {
654 0 : gf_bs_write_u32(ch->bs_w, rtp_hdr->CSRC[i]);
655 : }
656 : //nb: RTP header is always aligned
657 892 : Start = (u32) gf_bs_get_position(ch->bs_w);
658 :
659 892 : if (ch->send_interleave) {
660 13 : if (fast_send) {
661 13 : e = ch->send_interleave(ch->interleave_cbk1, ch->interleave_cbk2, GF_FALSE, hdr, pck_size+12);
662 : } else {
663 0 : memcpy(ch->send_buffer + Start, pck, pck_size);
664 0 : e = ch->send_interleave(ch->interleave_cbk1, ch->interleave_cbk2, GF_FALSE, ch->send_buffer, Start + pck_size);
665 : }
666 : }
667 : //copy payload
668 879 : else if (fast_send) {
669 879 : e = gf_sk_send(ch->rtp, hdr, pck_size+12);
670 : } else {
671 0 : memcpy(ch->send_buffer + Start, pck, pck_size);
672 0 : e = gf_sk_send(ch->rtp, ch->send_buffer, Start + pck_size);
673 : }
674 892 : if (e) return e;
675 :
676 : //Update RTCP for sender reports
677 892 : ch->pck_sent_since_last_sr += 1;
678 892 : if (ch->first_SR) {
679 : //get a new report time
680 23 : gf_rtp_get_next_report_time(ch);
681 23 : ch->num_payload_bytes = 0;
682 23 : ch->num_pck_sent = 0;
683 23 : ch->first_SR = 0;
684 : }
685 :
686 892 : ch->num_payload_bytes += pck_size;
687 892 : ch->num_pck_sent += 1;
688 : //store timing
689 892 : ch->last_pck_ts = rtp_hdr->TimeStamp;
690 892 : gf_net_get_ntp(&ch->last_pck_ntp_sec, &ch->last_pck_ntp_frac);
691 :
692 892 : if (!ch->no_auto_rtcp) gf_rtp_send_rtcp_report(ch);
693 : return GF_OK;
694 : }
695 :
696 : GF_EXPORT
697 6 : u32 gf_rtp_is_unicast(GF_RTPChannel *ch)
698 : {
699 6 : if (!ch) return 0;
700 6 : return ch->net_info.IsUnicast;
701 : }
702 :
703 : GF_EXPORT
704 23 : u32 gf_rtp_is_interleaved(GF_RTPChannel *ch)
705 : {
706 23 : if (!ch || !ch->net_info.Profile) return 0;
707 23 : return ch->net_info.IsInterleaved;
708 : }
709 :
710 : GF_EXPORT
711 101 : u32 gf_rtp_get_clockrate(GF_RTPChannel *ch)
712 : {
713 101 : if (!ch || !ch->TimeScale) return 0;
714 101 : return ch->TimeScale;
715 : }
716 :
717 : #if 0 //unused
718 : u32 gf_rtp_is_active(GF_RTPChannel *ch)
719 : {
720 : if (!ch) return 0;
721 : if (!ch->rtp_first_SN && !ch->rtp_time) return 0;
722 : return 1;
723 : }
724 : #endif
725 :
726 : GF_EXPORT
727 4 : u8 gf_rtp_get_low_interleave_id(GF_RTPChannel *ch)
728 : {
729 4 : if (!ch || !ch->net_info.IsInterleaved) return 0;
730 4 : return ch->net_info.rtpID;
731 : }
732 :
733 : GF_EXPORT
734 4 : u8 gf_rtp_get_hight_interleave_id(GF_RTPChannel *ch)
735 : {
736 4 : if (!ch || !ch->net_info.IsInterleaved) return 0;
737 4 : return ch->net_info.rtcpID;
738 : }
739 :
740 :
741 : #define RTP_DEFAULT_FIRSTPORT 7040
742 :
743 : static u16 NextAvailablePort = 0;
744 :
745 : GF_EXPORT
746 36 : GF_Err gf_rtp_set_ports(GF_RTPChannel *ch, u16 first_port)
747 : {
748 : u16 p;
749 : GF_Socket *sock;
750 36 : if (!ch) return GF_BAD_PARAM;
751 :
752 36 : if (!NextAvailablePort) {
753 35 : NextAvailablePort = first_port ? first_port : RTP_DEFAULT_FIRSTPORT;
754 : }
755 36 : p = NextAvailablePort;
756 36 : if (ch->net_info.client_port_first) return GF_OK;
757 :
758 36 : sock = gf_sk_new(GF_SOCK_TYPE_UDP);
759 36 : if (!sock) return GF_IO_ERR;
760 :
761 : /*should be way enough (more than 100 rtp streams open on the machine)*/
762 0 : while (1) {
763 : /*try to bind without reuse. If fails this means the port is used on the machine, don't reuse it*/
764 36 : GF_Err e = gf_sk_bind(sock, NULL, p, NULL, 0, 0);
765 36 : if (e==GF_OK) break;
766 0 : if (e!=GF_IP_CONNECTION_FAILURE) {
767 0 : gf_sk_del(sock);
768 0 : return GF_IP_NETWORK_FAILURE;
769 : }
770 0 : p+=2;
771 : }
772 36 : gf_sk_del(sock);
773 36 : ch->net_info.client_port_first = p;
774 36 : ch->net_info.client_port_last = p + 1;
775 36 : NextAvailablePort = p + 2;
776 36 : return GF_OK;
777 : }
778 :
779 :
780 : GF_EXPORT
781 19 : GF_Err gf_rtp_setup_payload(GF_RTPChannel *ch, u32 PayloadType, u32 ClockRate)
782 : {
783 19 : if (!ch || !PayloadType || !ClockRate) return GF_BAD_PARAM;
784 19 : ch->PayloadType = PayloadType;
785 19 : ch->TimeScale = ClockRate;
786 19 : return GF_OK;
787 : }
788 :
789 : GF_EXPORT
790 6 : const GF_RTSPTransport *gf_rtp_get_transport(GF_RTPChannel *ch)
791 : {
792 6 : if (!ch) return NULL;
793 6 : return &ch->net_info;
794 : }
795 :
796 : #if 0 //unused
797 : u32 gf_rtp_get_local_ssrc(GF_RTPChannel *ch)
798 : {
799 : if (!ch) return 0;
800 : return ch->SSRC;
801 : }
802 : #endif
803 :
804 : #if 0
805 : "#RTP log format:\n"
806 : "#RTP SenderSSRC RTP_TimeStamp RTP_SeqNum NTP@Recv Deviance Jitter NbLost NbTotPck NbTotBytes\n"
807 : "#RTCP Sender reports log format:\n"
808 : "#RTCP-SR SenderSSRC RTP_TimeStamp@NTP NbTotPck NbTotBytes NTP\n"
809 : "#RTCP Receiver reports log format:\n"
810 : "#RTCP-RR StreamSSRC Jitter ExtendedSeqNum ExpectDiff LossDiff NTP\n"
811 : #endif
812 :
813 : GF_EXPORT
814 52 : Float gf_rtp_get_loss(GF_RTPChannel *ch)
815 : {
816 52 : if (!ch->tot_num_pck_expected) return 0.0f;
817 0 : return 100.0f - (100.0f * ch->tot_num_pck_rcv) / ch->tot_num_pck_expected;
818 : }
819 :
820 : GF_EXPORT
821 52 : u32 gf_rtp_get_tcp_bytes_sent(GF_RTPChannel *ch)
822 : {
823 52 : return ch->rtcp_bytes_sent;
824 : }
825 :
826 : GF_EXPORT
827 30 : void gf_rtp_get_ports(GF_RTPChannel *ch, u16 *rtp_port, u16 *rtcp_port)
828 : {
829 30 : if (ch->net_info.client_port_first) {
830 29 : if (rtp_port) *rtp_port = ch->net_info.client_port_first;
831 29 : if (rtcp_port) *rtcp_port = ch->net_info.client_port_last;
832 : } else {
833 1 : if (rtp_port) *rtp_port = ch->net_info.port_first;
834 1 : if (rtcp_port) *rtcp_port = ch->net_info.port_last;
835 : }
836 30 : }
837 :
838 :
839 : /*
840 : RTP packet reorderer
841 : */
842 :
843 : #define SN_CHECK_OFFSET 0x0A
844 :
845 : GF_EXPORT
846 19 : GF_RTPReorder *gf_rtp_reorderer_new(u32 MaxCount, u32 MaxDelay)
847 : {
848 : GF_RTPReorder *tmp;
849 :
850 19 : if (MaxCount <= 1 || !MaxDelay) return NULL;
851 :
852 19 : GF_SAFEALLOC(tmp , GF_RTPReorder);
853 19 : if (!tmp) return NULL;
854 19 : tmp->MaxCount = MaxCount;
855 19 : tmp->MaxDelay = MaxDelay;
856 19 : return tmp;
857 : }
858 :
859 : GF_EXPORT
860 19 : void gf_rtp_reorderer_del(GF_RTPReorder *po)
861 : {
862 19 : gf_rtp_reorderer_reset(po);
863 19 : gf_free(po);
864 19 : }
865 :
866 : GF_EXPORT
867 48 : void gf_rtp_reorderer_reset(GF_RTPReorder *po)
868 : {
869 : GF_POItem *item;
870 48 : if (!po) return;
871 :
872 48 : item = po->in;
873 96 : while (item) {
874 0 : GF_POItem *next = item->next;
875 0 : gf_free(item->pck);
876 0 : gf_free(item);
877 : item = next;
878 : }
879 :
880 48 : po->head_seqnum = 0;
881 48 : po->Count = 0;
882 48 : po->IsInit = 0;
883 48 : po->in = NULL;
884 : }
885 :
886 : GF_EXPORT
887 742 : GF_Err gf_rtp_reorderer_add(GF_RTPReorder *po, const void * pck, u32 pck_size, u32 pck_seqnum)
888 : {
889 : GF_POItem *it, *cur;
890 : u32 bounds;
891 :
892 742 : if (!po) return GF_BAD_PARAM;
893 :
894 742 : it = (GF_POItem *) gf_malloc(sizeof(GF_POItem));
895 742 : it->pck_seq_num = pck_seqnum;
896 742 : it->next = NULL;
897 742 : it->size = pck_size;
898 742 : it->pck = gf_malloc(pck_size);
899 : memcpy(it->pck, pck, pck_size);
900 : /*reset timeout*/
901 742 : po->LastTime = 0;
902 :
903 : //no input, this packet will be the input
904 742 : if (!po->in) {
905 : //the seq num was not initialized
906 19 : if (!po->head_seqnum) {
907 19 : po->head_seqnum = pck_seqnum;
908 0 : } else if (!po->IsInit) {
909 : //this is not in our current range for init
910 0 : if (ABSDIFF(po->head_seqnum, pck_seqnum) > SN_CHECK_OFFSET) goto discard;
911 0 : po->IsInit = 1;
912 : }
913 :
914 19 : po->in = it;
915 19 : po->Count += 1;
916 19 : return GF_OK;
917 : }
918 :
919 : //this is 16 bitr seq num, as we work with RTP only for now
920 : bounds = 0;
921 723 : if ( (po->head_seqnum >= 0xf000 ) || (po->head_seqnum <= 0x1000) ) bounds = 0x2000;
922 :
923 : //first check the head of the list
924 : //same seq num, we drop
925 723 : if (po->in->pck_seq_num == pck_seqnum) goto discard;
926 :
927 723 : if ( ( (u16) (pck_seqnum + bounds) <= (u16) (po->in->pck_seq_num + bounds) ) ) {
928 :
929 0 : it->next = po->in;
930 0 : po->in = it;
931 0 : po->Count += 1;
932 :
933 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: inserting packet %d at head\n", pck_seqnum));
934 : return GF_OK;
935 : }
936 :
937 : //no, insert at the right place
938 : cur = po->in;
939 :
940 : while (1) {
941 : //same seq num, we drop
942 723 : if (cur->pck_seq_num == pck_seqnum) goto discard;
943 :
944 : //end of list
945 723 : if (!cur->next) {
946 723 : cur->next = it;
947 723 : po->Count += 1;
948 723 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Appending packet %d (last %d)\n", pck_seqnum, cur->pck_seq_num));
949 : return GF_OK;
950 : }
951 :
952 : //are we in the bounds ??
953 0 : if ( ( (u16) (cur->pck_seq_num + bounds) < (u16) (pck_seqnum + bounds) )
954 0 : && ( (u16) (pck_seqnum + bounds) < (u16) (cur->next->pck_seq_num + bounds)) ) {
955 :
956 : //insert
957 0 : it->next = cur->next;
958 0 : cur->next = it;
959 0 : po->Count += 1;
960 :
961 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Inserting packet %d\n", pck_seqnum));
962 : //done
963 : return GF_OK;
964 : }
965 : cur = cur->next;
966 : }
967 :
968 :
969 0 : discard:
970 0 : gf_free(it->pck);
971 0 : gf_free(it);
972 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp] Packet Reorderer: Dropping packet %d\n", pck_seqnum));
973 : return GF_OK;
974 : }
975 :
976 : //retrieve the first available packet. Note that the behavior will be undefined if the first
977 : //ever received packet if its SeqNum was unknown
978 : //the BUFFER is yours, you must delete it
979 : GF_EXPORT
980 786 : void *gf_rtp_reorderer_get(GF_RTPReorder *po, u32 *pck_size, Bool force_flush)
981 : {
982 : GF_POItem *t;
983 : u32 bounds;
984 : void *ret;
985 :
986 786 : if (!po || !pck_size) return NULL;
987 :
988 786 : *pck_size = 0;
989 :
990 : //empty queue
991 786 : if (!po->in) return NULL;
992 :
993 : //check we have received the first packet
994 761 : if ( po->head_seqnum && po->MaxCount
995 761 : && (po->MaxCount > po->Count)
996 761 : && (po->in->pck_seq_num != po->head_seqnum))
997 : return NULL;
998 :
999 : //no entry
1000 761 : if (!po->in->next) goto check_timeout;
1001 :
1002 : bounds = 0;
1003 723 : if ( (po->head_seqnum >= 0xf000 ) || (po->head_seqnum <= 0x1000) ) bounds = 0x2000;
1004 :
1005 : //release the output if SN in order or maxCount reached
1006 723 : if (( (u16) (po->in->pck_seq_num + bounds + 1) == (u16) (po->in->next->pck_seq_num + bounds))
1007 0 : || (po->MaxCount && (po->Count >= po->MaxCount)) ) {
1008 :
1009 : #ifndef GPAC_DISABLE_LOG
1010 723 : if (po->in->pck_seq_num + 1 != po->in->next->pck_seq_num)
1011 0 : GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[rtp] WARNING Packet Loss: Sending %d out of the queue but next is %d\n", po->in->pck_seq_num, po->in->next->pck_seq_num ));
1012 : #endif
1013 : goto send_it;
1014 : }
1015 : //update timing
1016 : else {
1017 38 : check_timeout:
1018 :
1019 38 : if (force_flush) goto send_it;
1020 :
1021 19 : if (!po->LastTime) {
1022 19 : po->LastTime = gf_sys_clock();
1023 19 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: starting timeout at %d\n", po->LastTime));
1024 : return NULL;
1025 : }
1026 : //if exceeding the delay send the head
1027 0 : if (gf_sys_clock() - po->LastTime >= po->MaxDelay) {
1028 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Forcing output after %d ms wait (max allowed %d)\n", gf_sys_clock() - po->LastTime, po->MaxDelay));
1029 : goto send_it;
1030 : }
1031 : }
1032 : return NULL;
1033 :
1034 :
1035 761 : send_it:
1036 742 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Fetching %d\n", po->in->pck_seq_num));
1037 742 : *pck_size = po->in->size;
1038 742 : t = po->in;
1039 742 : po->in = po->in->next;
1040 : //no other output. reset the head seqnum
1041 742 : po->head_seqnum = po->in ? po->in->pck_seq_num : 0;
1042 742 : po->Count -= 1;
1043 : //release the item
1044 742 : ret = t->pck;
1045 742 : gf_free(t);
1046 742 : return ret;
1047 : }
1048 :
1049 2 : GF_Err gf_rtp_set_interleave_callbacks(GF_RTPChannel *ch, gf_rtp_tcp_callback RTP_TCPCallback, void *cbk1, void *cbk2)
1050 : {
1051 2 : if (!ch) return GF_BAD_PARAM;
1052 2 : ch->send_interleave = RTP_TCPCallback;
1053 2 : ch->interleave_cbk1 = cbk1;
1054 2 : ch->interleave_cbk2 = cbk2;
1055 2 : return GF_OK;
1056 : }
1057 :
1058 :
1059 : #endif /*GPAC_DISABLE_STREAMING*/
1060 :
|