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 :
27 : #include <gpac/internal/ietf_dev.h>
28 :
29 : #ifndef GPAC_DISABLE_STREAMING
30 :
31 : #include <gpac/bitstream.h>
32 :
33 : GF_EXPORT
34 31 : u32 gf_rtp_read_rtcp(GF_RTPChannel *ch, u8 *buffer, u32 buffer_size)
35 : {
36 : GF_Err e;
37 : u32 res;
38 :
39 : //only if the socket exist (otherwise RTSP interleaved channel)
40 31 : if (!ch || !ch->rtcp) return 0;
41 31 : if (ch->no_select) {
42 0 : e = gf_sk_receive_no_select(ch->rtcp, buffer, buffer_size, &res);
43 : } else {
44 31 : e = gf_sk_receive(ch->rtcp, buffer, buffer_size, &res);
45 : }
46 31 : if (e) return 0;
47 31 : return res;
48 : }
49 :
50 : GF_EXPORT
51 31 : GF_Err gf_rtp_decode_rtcp(GF_RTPChannel *ch, u8 *pck, u32 pck_size, Bool *has_sr)
52 : {
53 : GF_RTCPHeader rtcp_hdr;
54 : char sdes_buffer[300];
55 : u32 i, sender_ssrc, cur_ssrc, val, sdes_type, sdes_len, res, first;
56 : GF_Err e = GF_OK;
57 :
58 31 : if (has_sr) *has_sr = GF_FALSE;
59 :
60 : //bad RTCP packet
61 31 : if (pck_size < 4 ) return GF_NON_COMPLIANT_BITSTREAM;
62 31 : gf_bs_reassign_buffer(ch->bs_r, pck, pck_size);
63 :
64 : first = 1;
65 137 : while (pck_size) {
66 : //global header
67 75 : rtcp_hdr.Version = gf_bs_read_int(ch->bs_r, 2);
68 75 : if (rtcp_hdr.Version != 2 ) {
69 : return GF_NOT_SUPPORTED;
70 : }
71 75 : rtcp_hdr.Padding = gf_bs_read_int(ch->bs_r, 1);
72 75 : rtcp_hdr.Count = gf_bs_read_int(ch->bs_r, 5);
73 75 : rtcp_hdr.PayloadType = gf_bs_read_u8(ch->bs_r);
74 75 : rtcp_hdr.Length = 1 + gf_bs_read_u16(ch->bs_r);
75 :
76 : //check pck size
77 75 : if (pck_size < (u32) rtcp_hdr.Length * 4) {
78 : //we return OK
79 : return GF_CORRUPTED_DATA;
80 : }
81 : //subtract this RTCP pck size
82 75 : pck_size -= rtcp_hdr.Length * 4;
83 :
84 : /*we read the RTCP header*/
85 : rtcp_hdr.Length -= 1;
86 :
87 : //in all RTCP Compounds (>1 pck), the first RTCP report SHALL be SR or RR without padding
88 75 : if (first) {
89 31 : if ( ( (rtcp_hdr.PayloadType!=200) && (rtcp_hdr.PayloadType!=201) )
90 31 : || rtcp_hdr.Padding
91 : ) {
92 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTCP] Corrupted RTCP packet: payload type %d (200 or 201 expected) - Padding %d (0 expected)\n", rtcp_hdr.PayloadType, rtcp_hdr.Padding));
93 : return GF_CORRUPTED_DATA;
94 : }
95 : first = 0;
96 : }
97 :
98 : //specific extensions
99 75 : switch (rtcp_hdr.PayloadType) {
100 : //Sender report - we assume there's only one sender
101 31 : case 200:
102 : /*sender ssrc*/
103 31 : sender_ssrc = gf_bs_read_u32(ch->bs_r);
104 31 : rtcp_hdr.Length -= 1;
105 : /*not for us...*/
106 31 : if (ch->SenderSSRC && (ch->SenderSSRC != sender_ssrc)) break;
107 :
108 31 : if (ch->first_SR) {
109 18 : gf_rtp_get_next_report_time(ch);
110 18 : ch->SenderSSRC = sender_ssrc;
111 : }
112 31 : ch->last_report_time = gf_rtp_get_report_time();
113 :
114 31 : ch->last_SR_NTP_sec = gf_bs_read_u32(ch->bs_r);
115 31 : ch->last_SR_NTP_frac = gf_bs_read_u32(ch->bs_r);
116 31 : ch->last_SR_rtp_time = gf_bs_read_u32(ch->bs_r);
117 31 : /*nb_pck = */gf_bs_read_u32(ch->bs_r);
118 31 : /*nb_bytes =*/gf_bs_read_u32(ch->bs_r);
119 :
120 31 : rtcp_hdr.Length -= 5;
121 31 : if (has_sr) *has_sr = GF_TRUE;
122 :
123 : #ifndef GPAC_DISABLE_LOG
124 31 : if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_INFO)) {
125 : #ifndef _WIN32_WCE
126 0 : time_t gtime = ch->last_SR_NTP_sec - GF_NTP_SEC_1900_TO_1970;
127 0 : const char *ascTime = asctime(gf_gmtime(>ime));
128 : #else
129 : const char *ascTime = "Not Available";
130 : #endif
131 0 : GF_LOG(ch->first_SR ? GF_LOG_INFO : GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] RTCP %sSR: SSRC %d - RTP Time %u - Nb Pck %d - Nb Bytes %d - Time %s\n",
132 : ch->first_SR ? "Initial " : "",
133 : ch->SenderSSRC,
134 : ch->last_SR_rtp_time,
135 : ch->total_pck,
136 : ch->total_bytes,
137 : ascTime
138 : ));
139 : }
140 : #endif
141 :
142 31 : ch->first_SR = 0;
143 :
144 : //common encoding for SR and RR
145 31 : goto process_reports;
146 :
147 :
148 0 : case 201:
149 : //sender ssrc
150 0 : /*sender_ssrc = */gf_bs_read_u32(ch->bs_r);
151 0 : rtcp_hdr.Length -= 1;
152 :
153 75 : process_reports:
154 :
155 : #if 0
156 : //process all reports - we actually don't since we do not handle sources
157 : //to add
158 : for (i=0; i<rtcp_hdr.Count; i++) {
159 : //ssrc slot
160 : cur_ssrc = gf_bs_read_u32(ch->bs_r);
161 : //frac lost
162 : gf_bs_read_u8(ch->bs_r);
163 : //cumulative lost
164 : gf_bs_read_u24(ch->bs_r);
165 : //extended seq num
166 : gf_bs_read_u32(ch->bs_r);
167 : //jitter
168 : gf_bs_read_u32(ch->bs_r);
169 : //LSR
170 : gf_bs_read_u32(ch->bs_r);
171 : //DLSR
172 : gf_bs_read_u32(ch->bs_r);
173 :
174 : rtcp_hdr.Length -= 6;
175 : }
176 : //remaining bytes? we skip (this includes padding and crypto - not supported)
177 : #endif
178 : break;
179 :
180 : //SDES
181 : case 202:
182 31 : for (i=0; i<rtcp_hdr.Count; i++) {
183 31 : /*cur_ssrc = */gf_bs_read_u32(ch->bs_r);
184 31 : rtcp_hdr.Length -= 1;
185 :
186 : val = 0;
187 : while (1) {
188 93 : sdes_type = gf_bs_read_u8(ch->bs_r);
189 62 : val += 1;
190 62 : if (!sdes_type) break;
191 31 : sdes_len = gf_bs_read_u8(ch->bs_r);
192 31 : val += 1;
193 31 : gf_bs_read_data(ch->bs_r, sdes_buffer, sdes_len);
194 31 : sdes_buffer[sdes_len] = 0;
195 31 : val += sdes_len;
196 : }
197 :
198 : //re-align on 32bit
199 31 : res = val%4;
200 31 : if (res) {
201 31 : gf_bs_skip_bytes(ch->bs_r, (4-res));
202 31 : val = val/4 + 1;
203 : } else {
204 0 : val = val/4;
205 : }
206 31 : rtcp_hdr.Length -= val;
207 : }
208 : break;
209 :
210 : //BYE packet - close the channel - we work with 1 SSRC only */
211 : case 203:
212 0 : for (i=0; i<rtcp_hdr.Count; i++) {
213 13 : cur_ssrc = gf_bs_read_u32(ch->bs_r);
214 13 : rtcp_hdr.Length -= 1;
215 13 : if (ch->SenderSSRC == cur_ssrc) {
216 : e = GF_EOS;
217 : break;
218 : }
219 : }
220 : //extra info - skip it
221 13 : while (rtcp_hdr.Length) {
222 0 : gf_bs_read_u32(ch->bs_r);
223 0 : rtcp_hdr.Length -= 1;
224 : }
225 : break;
226 : /*
227 : //APP packet
228 : case 204:
229 :
230 :
231 : //sender ssrc
232 : sender_ssrc = gf_bs_read_u32(bs);
233 : //ASCI 4 char type
234 : gf_bs_read_u8(bs);
235 : gf_bs_read_u8(bs);
236 : gf_bs_read_u8(bs);
237 : gf_bs_read_u8(bs);
238 :
239 : rtcp_hdr.Length -= 2;
240 :
241 : //till endd of pck
242 : gf_bs_read_data(bs, sdes_buffer, rtcp_hdr.Length*4);
243 : rtcp_hdr.Length = 0;
244 : break;
245 : */
246 0 : default:
247 : //read all till end
248 0 : gf_bs_read_data(ch->bs_r, sdes_buffer, rtcp_hdr.Length*4);
249 : rtcp_hdr.Length = 0;
250 0 : break;
251 : }
252 : //WE SHALL CONSUME EVERYTHING otherwise the packet is bad
253 75 : if (rtcp_hdr.Length) {
254 : return GF_CORRUPTED_DATA;
255 : }
256 : }
257 : return e;
258 : }
259 :
260 37 : static u32 RTCP_FormatReport(GF_RTPChannel *ch, GF_BitStream *bs, u32 NTP_Time)
261 : {
262 : u32 length, is_sr, sec, frac, expected, val, size;
263 : s32 extended, expect_diff, loss_diff;
264 : Double f;
265 :
266 37 : is_sr = ch->pck_sent_since_last_sr ? 1 : 0;
267 :
268 37 : if (ch->forced_ntp_sec) {
269 37 : sec = ch->forced_ntp_sec;
270 37 : frac = ch->forced_ntp_frac;
271 : is_sr = 1;
272 : } else {
273 0 : gf_net_get_ntp(&sec, &frac);
274 : }
275 :
276 : //common header
277 : //version
278 37 : gf_bs_write_int(bs, 2, 2);
279 : //padding - reports are aligned
280 37 : gf_bs_write_int(bs, 0, 1);
281 : //count - only one for now in RR, 0 in sender mode
282 37 : gf_bs_write_int(bs, !is_sr, 5);
283 : //if we have sent stuff send an SR, otherwise an RR. We need to determine whether
284 : //we are active or not
285 : //type
286 37 : gf_bs_write_u8(bs, is_sr ? 200 : 201);
287 : //length = (num of 32bit words in full pck) - 1
288 : //we're updating only one ssrc for now in RR and none in SR
289 37 : length = is_sr ? 6 : (1 + 6 * 1);
290 37 : gf_bs_write_u16(bs, length);
291 :
292 : //sender SSRC
293 37 : gf_bs_write_u32(bs, ch->SSRC);
294 :
295 : size = 8;
296 :
297 :
298 : //SenderReport part
299 37 : if (is_sr) {
300 : //sender time
301 37 : gf_bs_write_u32(bs, sec);
302 37 : gf_bs_write_u32(bs, frac);
303 : //RTP time at this time
304 37 : f = 1000 * (sec - ch->last_pck_ntp_sec);
305 37 : f += ((frac - ch->last_pck_ntp_frac) >> 4) / 0x10000;
306 37 : f /= 1000;
307 37 : f *= ch->TimeScale;
308 37 : val = (u32) f + ch->last_pck_ts;
309 37 : gf_bs_write_u32(bs, val);
310 : //num pck sent
311 37 : gf_bs_write_u32(bs, ch->num_pck_sent);
312 : //num payload bytes sent
313 37 : gf_bs_write_u32(bs, ch->num_payload_bytes);
314 :
315 :
316 : size += 20;
317 : //nota: as we only support single-way channels we are done for SR...
318 37 : return size;
319 : }
320 : //loop through all our sources (1) and send information...
321 0 : gf_bs_write_u32(bs, ch->SenderSSRC);
322 :
323 : //Fraction lost and cumulative lost
324 0 : extended = ( (ch->num_sn_loops << 16) | ch->last_pck_sn);
325 0 : expected = extended - ch->rtp_first_SN;
326 0 : expect_diff = expected - ch->tot_num_pck_expected;
327 0 : loss_diff = expect_diff - ch->last_num_pck_rcv;
328 :
329 0 : if (!expect_diff || (loss_diff <= 0)) loss_diff = 0;
330 0 : else loss_diff = (loss_diff<<8) / expect_diff;
331 :
332 0 : gf_bs_write_u8(bs, loss_diff);
333 :
334 : //update and write cumulative loss
335 0 : ch->tot_num_pck_rcv += ch->last_num_pck_rcv;
336 0 : ch->tot_num_pck_expected = expected;
337 0 : gf_bs_write_u24(bs, (expected - ch->tot_num_pck_rcv));
338 :
339 : //Extend sequence number
340 0 : gf_bs_write_u32(bs, extended);
341 :
342 :
343 : //Jitter
344 : //RTP specs annexe A.8
345 0 : gf_bs_write_u32(bs, ( ch->Jitter >> 4));
346 : //LSR
347 0 : if (ch->last_SR_NTP_sec) {
348 0 : val = ( ((ch->last_SR_NTP_sec & 0x0000ffff) << 16) | ((ch->last_SR_NTP_frac & 0xffff0000) >> 16));
349 : } else {
350 : val = 0;
351 : }
352 0 : gf_bs_write_u32(bs, val);
353 :
354 : // DLSR
355 0 : gf_bs_write_u32(bs, (NTP_Time - ch->last_report_time));
356 :
357 :
358 : #ifndef GPAC_DISABLE_LOG
359 0 : if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_DEBUG)) {
360 : #ifndef _WIN32_WCE
361 0 : time_t gtime = ch->last_SR_NTP_sec - GF_NTP_SEC_1900_TO_1970;
362 0 : const char *ascTime = asctime(gf_gmtime(>ime));
363 : #else
364 : const char *ascTime = "Not Available";
365 : #endif
366 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] RTCP-RR: SSRC %d Jitter %d extended %d expect_diff %d loss_diff %d time %s\n",
367 : ch->SSRC,
368 : ch->Jitter >> 4,
369 : extended,
370 : expect_diff,
371 : loss_diff,
372 : ascTime
373 : ));
374 : }
375 : #endif
376 :
377 : size += 24;
378 : return size;
379 : }
380 :
381 :
382 51 : static u32 RTCP_FormatSDES(GF_RTPChannel *ch, GF_BitStream *bs)
383 : {
384 : u32 length, padd;
385 :
386 : //we start with header and SSRC: 2x32 bits word
387 : length = 8;
388 : //ten only send one CName item is type (1byte) , len (1byte), data (len byte) + NULL marker (0 on 1 byte) at the end of the item list
389 51 : length += 2 + (u32) strlen(ch->CName) + 1;
390 : //we padd the end of the content to 32-bit boundary, and set length to the number of 32 bit words
391 51 : padd = length % 4;
392 51 : if (padd*4 != 0) {
393 : //padding octets
394 51 : padd = 4 - padd;
395 51 : length = length/4 + 1;
396 : } else {
397 : padd = 0;
398 0 : length = length/4;
399 : }
400 :
401 : //common part as usual
402 51 : gf_bs_write_int(bs, 2, 2);
403 : //notify padding? according to RFC1889 "In a compound RTCP packet, padding should
404 : //only be required on the last individual packet because the compound packet is
405 : //encrypted as a whole" -> we write it without notifying it (this is a bit messy in
406 : //the spec IMO)
407 51 : gf_bs_write_int(bs, 0, 1);
408 : //report count is one
409 51 : gf_bs_write_int(bs, 1, 5);
410 : //SDES pck type
411 51 : gf_bs_write_u8(bs, 202);
412 : //write length minus one
413 51 : gf_bs_write_u16(bs, length - 1);
414 :
415 : //SSRC
416 51 : gf_bs_write_u32(bs, ch->SSRC);
417 :
418 : //CNAME type
419 51 : gf_bs_write_u8(bs, 1);
420 : //length and cname
421 51 : gf_bs_write_u8(bs, (u32) strlen(ch->CName));
422 51 : gf_bs_write_data(bs, ch->CName, (u32) strlen(ch->CName));
423 :
424 51 : gf_bs_write_u8(bs, 0);
425 :
426 : //32-align field with 0
427 51 : gf_bs_write_int(bs, 0, 8*padd);
428 51 : return (length + 1)*4;
429 : }
430 :
431 :
432 30 : static u32 RTCP_FormatBYE(GF_RTPChannel *ch, GF_BitStream *bs)
433 : {
434 : //version
435 30 : gf_bs_write_int(bs, 2, 2);
436 : //no padding
437 30 : gf_bs_write_int(bs, 0, 1);
438 : //count - only one for now
439 30 : gf_bs_write_int(bs, 1, 5);
440 : //type=BYE
441 30 : gf_bs_write_u8(bs, 203);
442 : //length = (num of 32bit words in full pck) - 1
443 30 : gf_bs_write_u16(bs, 1);
444 :
445 : //sender SSRC
446 30 : gf_bs_write_u32(bs, ch->SSRC);
447 30 : return 8;
448 : }
449 :
450 : GF_EXPORT
451 30 : GF_Err gf_rtp_send_bye(GF_RTPChannel *ch)
452 : {
453 : GF_BitStream *bs;
454 : u32 report_size;
455 : u8 *report_buf;
456 : GF_Err e = GF_OK;
457 :
458 30 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
459 :
460 : /*k were received/sent send the RR/SR - note we don't wait for next Repor and force its emission now*/
461 30 : if (ch->last_num_pck_rcv || ch->pck_sent_since_last_sr) {
462 16 : RTCP_FormatReport(ch, bs, gf_rtp_get_report_time());
463 : }
464 :
465 : //always send SDES (CNAME shall be sent at each RTCP)
466 30 : RTCP_FormatSDES(ch, bs);
467 :
468 : //send BYE
469 30 : RTCP_FormatBYE(ch, bs);
470 :
471 :
472 30 : report_buf = NULL;
473 30 : report_size = 0;
474 30 : gf_bs_get_content(bs, &report_buf, &report_size);
475 30 : gf_bs_del(bs);
476 :
477 30 : if (ch->rtcp) {
478 30 : e = gf_sk_send(ch->rtcp, report_buf, report_size);
479 : } else {
480 0 : if (ch->send_interleave)
481 0 : e = ch->send_interleave(ch->interleave_cbk1, ch->interleave_cbk2, GF_TRUE, report_buf, report_size);
482 : else
483 : e = GF_BAD_PARAM;
484 : }
485 30 : gf_free(report_buf);
486 30 : return e;
487 : }
488 :
489 : GF_EXPORT
490 1632 : GF_Err gf_rtp_send_rtcp_report(GF_RTPChannel *ch)
491 : {
492 : u32 Time, report_size;
493 : GF_BitStream *bs;
494 : u8 *report_buf;
495 : GF_Err e = GF_OK;
496 :
497 :
498 : /*skip first SR when acting as a receiver*/
499 1632 : if (!ch->forced_ntp_sec && ch->first_SR) return GF_OK;
500 1606 : Time = gf_rtp_get_report_time();
501 1606 : if ( Time < ch->next_report_time) return GF_OK;
502 :
503 21 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
504 :
505 : //pck were received/sent send the RR/SR
506 21 : if (ch->last_num_pck_rcv || ch->pck_sent_since_last_sr || ch->forced_ntp_sec) {
507 21 : RTCP_FormatReport(ch, bs, Time);
508 : }
509 :
510 : //always send SDES (CNAME shall be sent at each RTCP)
511 21 : RTCP_FormatSDES(ch, bs);
512 :
513 :
514 : //get content
515 21 : report_buf = NULL;
516 21 : report_size = 0;
517 21 : gf_bs_get_content(bs, &report_buf, &report_size);
518 21 : gf_bs_del(bs);
519 :
520 21 : if (ch->rtcp) {
521 20 : e = gf_sk_send(ch->rtcp, report_buf, report_size);
522 : } else {
523 1 : if (ch->send_interleave)
524 1 : e = ch->send_interleave(ch->interleave_cbk1, ch->interleave_cbk2, GF_TRUE, report_buf, report_size);
525 : else
526 : e = GF_BAD_PARAM;
527 : }
528 :
529 21 : ch->rtcp_bytes_sent += report_size;
530 :
531 21 : gf_free(report_buf);
532 :
533 21 : if (!e) {
534 : //Update the channel record if no error - otherwise next RTCP will triger an RR
535 21 : ch->last_num_pck_rcv = ch->last_num_pck_expected = ch->last_num_pck_loss = 0;
536 21 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTCP] SSRC %d: sending RTCP report\n", ch->SSRC));
537 : }
538 : else {
539 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTCP] SSRC %d: error when sending RTCP report\n", ch->SSRC));
540 : }
541 21 : gf_rtp_get_next_report_time(ch);
542 21 : return e;
543 : }
544 :
545 : #if 0 //unused
546 :
547 : enum
548 : {
549 : GF_RTCP_INFO_NAME = 0,
550 : GF_RTCP_INFO_EMAIL,
551 : GF_RTCP_INFO_PHONE,
552 : GF_RTCP_INFO_LOCATION,
553 : GF_RTCP_INFO_TOOL,
554 : GF_RTCP_INFO_NOTE,
555 : GF_RTCP_INFO_PRIV
556 : };
557 :
558 :
559 : #define RTCP_SAFE_FREE(p) if (p) gf_free(p); \
560 : p = NULL;
561 :
562 : GF_Err gf_rtp_set_info_rtcp(GF_RTPChannel *ch, u32 InfoCode, char *info_string)
563 : {
564 : if (!ch) return GF_BAD_PARAM;
565 :
566 : switch (InfoCode) {
567 : case GF_RTCP_INFO_NAME:
568 : RTCP_SAFE_FREE(ch->s_name);
569 : if (info_string) ch->s_name = gf_strdup(info_string);
570 : break;
571 : case GF_RTCP_INFO_EMAIL:
572 : RTCP_SAFE_FREE(ch->s_email);
573 : if (info_string) ch->s_email = gf_strdup(info_string);
574 : break;
575 : case GF_RTCP_INFO_PHONE:
576 : RTCP_SAFE_FREE(ch->s_phone);
577 : if (info_string) ch->s_phone = gf_strdup(info_string);
578 : break;
579 : case GF_RTCP_INFO_LOCATION:
580 : RTCP_SAFE_FREE(ch->s_location);
581 : if (info_string) ch->s_location = gf_strdup(info_string);
582 : break;
583 : case GF_RTCP_INFO_TOOL:
584 : RTCP_SAFE_FREE(ch->s_tool);
585 : if (info_string) ch->s_tool = gf_strdup(info_string);
586 : break;
587 : case GF_RTCP_INFO_NOTE:
588 : RTCP_SAFE_FREE(ch->s_note);
589 : if (info_string) ch->s_note = gf_strdup(info_string);
590 : break;
591 : case GF_RTCP_INFO_PRIV:
592 : RTCP_SAFE_FREE(ch->s_priv);
593 : if (info_string) ch->s_name = gf_strdup(info_string);
594 : break;
595 : default:
596 : return GF_BAD_PARAM;
597 : }
598 : return GF_OK;
599 : }
600 :
601 : #endif
602 :
603 :
604 : #endif /*GPAC_DISABLE_STREAMING*/
|