2
The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
3
Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
15
You should have received a copy of the GNU Lesser General Public
16
License along with this library; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
/***************************************************************************
23
* Wed Dec 1 11:45:30 2004
24
* Copyright 2004 Simon Morlat
25
* Email simon dot morlat at linphone dot org
26
****************************************************************************/
27
#include "ortp/ortp.h"
28
#include "ortp/rtpsession.h"
29
#include "ortp/rtcp.h"
31
#include "rtpsession_priv.h"
33
#define rtcp_bye_set_ssrc(b,pos,ssrc) (b)->ssrc[pos]=htonl(ssrc)
34
#define rtcp_bye_get_ssrc(b,pos) ntohl((b)->ssrc[pos])
37
void rtcp_common_header_init(rtcp_common_header_t *ch, RtpSession *s,int type, int rc, int bytes_len){
38
rtcp_common_header_set_version(ch,2);
39
rtcp_common_header_set_padbit(ch,0);
40
rtcp_common_header_set_packet_type(ch,type);
41
rtcp_common_header_set_rc(ch,rc); /* as we don't yet support multi source receiving */
42
rtcp_common_header_set_length(ch,(bytes_len/4)-1);
45
static mblk_t *sdes_chunk_new(uint32_t ssrc){
46
mblk_t *m=allocb(RTCP_SDES_CHUNK_DEFAULT_SIZE,0);
47
sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
49
m->b_wptr+=sizeof(sc->csrc);
54
static mblk_t * sdes_chunk_append_item(mblk_t *m, rtcp_sdes_type_t sdes_type, const char *content)
59
si.item_type=sdes_type;
60
si.len=(uint8_t) MIN(strlen(content),RTCP_SDES_MAX_STRING_SIZE);
61
m=appendb(m,(char*)&si,RTCP_SDES_ITEM_HEADER_SIZE,FALSE);
62
m=appendb(m,content,si.len,FALSE);
67
static void sdes_chunk_set_ssrc(mblk_t *m, uint32_t ssrc){
68
sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
72
#define sdes_chunk_get_ssrc(m) ntohl(((sdes_chunk_t*)((m)->b_rptr))->csrc)
74
static mblk_t * sdes_chunk_pad(mblk_t *m){
75
return appendb(m,"",1,TRUE);
78
void rtp_session_set_source_description(RtpSession *session,
79
const char *cname, const char *name, const char *email, const char *phone,
80
const char *loc, const char *tool, const char *note){
81
mblk_t *chunk = sdes_chunk_new(session->send_ssrc);
83
const char *_cname=cname;
88
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_CNAME, _cname);
89
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NAME, name);
90
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_EMAIL, email);
91
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_PHONE, phone);
92
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_LOC, loc);
93
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_TOOL, tool);
94
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NOTE, note);
95
chunk=sdes_chunk_pad(chunk);
96
if (session->sd!=NULL) freemsg(session->sd);
101
rtp_session_add_contributing_source(RtpSession *session, uint32_t csrc,
102
const char *cname, const char *name, const char *email, const char *phone,
103
const char *loc, const char *tool, const char *note)
105
mblk_t *chunk = sdes_chunk_new(csrc);
107
char *_cname=(char*)cname;
112
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_CNAME, cname);
113
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NAME, name);
114
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_EMAIL, email);
115
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_PHONE, phone);
116
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_LOC, loc);
117
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_TOOL, tool);
118
chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NOTE, note);
119
chunk=sdes_chunk_pad(chunk);
120
putq(&session->contributing_sources,m);
125
mblk_t* rtp_session_create_rtcp_sdes_packet(RtpSession *session)
127
mblk_t *mp=allocb(sizeof(rtcp_common_header_t),0);
128
rtcp_common_header_t *rtcp;
132
rtcp = (rtcp_common_header_t*)mp->b_wptr;
133
mp->b_wptr+=sizeof(rtcp_common_header_t);
135
/* concatenate all sdes chunks */
136
sdes_chunk_set_ssrc(session->sd,session->send_ssrc);
137
m=concatb(m,dupmsg(session->sd));
140
q=&session->contributing_sources;
141
for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,mp)){
142
m=concatb(m,dupmsg(tmp));
145
rtcp_common_header_init(rtcp,session,RTCP_SDES,rc,msgdsize(mp));
150
mblk_t *rtcp_create_simple_bye_packet(uint32_t ssrc, const char *reason)
158
packet_size = RTCP_BYE_HEADER_SIZE;
160
strsize=(int)MIN(strlen(reason),RTCP_BYE_REASON_MAX_STRING_SIZE);
162
strpadding = 3 - (strsize % 4);
163
packet_size += 1 + strsize + strpadding;
166
mp = allocb(packet_size, 0);
168
rtcp = (rtcp_bye_t*)mp->b_rptr;
169
rtcp_common_header_init(&rtcp->ch,NULL,RTCP_BYE,1,packet_size);
170
rtcp->ssrc[0] = htonl(ssrc);
171
mp->b_wptr += RTCP_BYE_HEADER_SIZE;
172
/* append the reason if any*/
174
const char pad[] = {0, 0, 0};
175
unsigned char strsize_octet = (unsigned char)strsize;
177
appendb(mp, (const char*)&strsize_octet, 1, FALSE);
178
appendb(mp, reason,strsize, FALSE);
179
appendb(mp, pad,strpadding, FALSE);
184
void rtp_session_remove_contributing_sources(RtpSession *session, uint32_t ssrc)
186
queue_t *q=&session->contributing_sources;
188
for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,tmp)){
189
uint32_t csrc=sdes_chunk_get_ssrc(tmp);
195
tmp=rtcp_create_simple_bye_packet(ssrc, NULL);
196
rtp_session_rtcp_send(session,tmp);
199
static void sender_info_init(sender_info_t *info, RtpSession *session){
202
gettimeofday(&tv,NULL);
203
info->ntp_timestamp_msw=htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
204
#if defined(_WIN32_WCE)
205
tmp=(uint32_t)((double)tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6);
207
tmp=(uint32_t)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6);
209
info->ntp_timestamp_lsw=htonl(tmp);
210
info->rtp_timestamp=htonl(session->rtp.snd_last_ts);
211
info->senders_packet_count=(uint32_t) htonl((u_long) session->rtp.stats.packet_sent);
212
info->senders_octet_count=(uint32_t) htonl((u_long) session->rtp.stats.sent);
213
session->rtp.last_rtcp_packet_count=session->rtp.stats.packet_sent;
218
static void report_block_init(report_block_t *b, RtpSession *session){
220
uint8_t loss_fraction=0;
221
RtpStream *stream=&session->rtp;
222
uint32_t delay_snc_last_sr=0;
225
/* compute the statistics */
226
/*printf("hwrcv_extseq.one=%u, hwrcv_seq_at_last_SR=%u hwrcv_since_last_SR=%u\n",
227
stream->hwrcv_extseq.one,
228
stream->hwrcv_seq_at_last_SR,
229
stream->hwrcv_since_last_SR
231
if (stream->hwrcv_seq_at_last_SR!=0){
232
packet_loss=(stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR) - stream->hwrcv_since_last_SR;
235
stream->stats.cum_packet_loss+=packet_loss;
236
loss_fraction=(int)(256.0*(float)packet_loss/(float)stream->hwrcv_since_last_SR);
239
stream->hwrcv_since_last_SR=0;
240
stream->hwrcv_seq_at_last_SR=stream->hwrcv_extseq;
242
if (stream->last_rcv_SR_time.tv_sec!=0){
245
gettimeofday(&now,NULL);
246
delay=(float) ((now.tv_sec-stream->last_rcv_SR_time.tv_sec)*1e6 ) + (now.tv_usec-stream->last_rcv_SR_time.tv_usec);
247
delay=(float) (delay*65536*1e-6);
248
delay_snc_last_sr=(uint32_t) delay;
251
b->ssrc=htonl(session->recv_ssrc);
252
fl_cnpl=((loss_fraction&0xFF)<<24) | (stream->stats.cum_packet_loss & 0xFFFFFF);
253
b->fl_cnpl=htonl(fl_cnpl);
254
b->interarrival_jitter=htonl((uint32_t) stream->jittctl.inter_jitter);
255
b->ext_high_seq_num_rec=htonl(stream->hwrcv_extseq);
256
b->lsr=htonl(stream->last_rcv_SR_ts);
257
b->delay_snc_last_sr=htonl(delay_snc_last_sr);
262
static int rtcp_sr_init(RtpSession *session, uint8_t *buf, int size){
263
rtcp_sr_t *sr=(rtcp_sr_t*)buf;
264
if (size<sizeof(rtcp_sr_t)) return 0;
265
rtcp_common_header_init(&sr->ch,session,RTCP_SR,1,sizeof(rtcp_sr_t));
266
sr->ssrc=htonl(session->send_ssrc);
267
sender_info_init(&sr->si,session);
268
report_block_init(&sr->rb[0],session);
269
return sizeof(rtcp_sr_t);
272
static int rtcp_rr_init(RtpSession *session, uint8_t *buf, int size){
273
rtcp_rr_t *rr=(rtcp_rr_t*)buf;
274
if (size<sizeof(rtcp_rr_t)) return 0;
275
rtcp_common_header_init(&rr->ch,session,RTCP_RR,1,sizeof(rtcp_rr_t));
276
rr->ssrc=htonl(session->send_ssrc);
277
report_block_init(&rr->rb[0],session);
278
return sizeof(rtcp_rr_t);
281
static int rtcp_app_init(RtpSession *session, uint8_t *buf, uint8_t subtype, const char *name, int size){
282
rtcp_app_t *app=(rtcp_app_t*)buf;
283
if (size<sizeof(rtcp_app_t)) return 0;
284
rtcp_common_header_init(&app->ch,session,RTCP_APP,subtype,size);
285
app->ssrc=htonl(session->send_ssrc);
286
memset(app->name,0,4);
287
strncpy(app->name,name,4);
288
return sizeof(rtcp_app_t);
291
static mblk_t * make_rr(RtpSession *session){
295
cm=allocb(sizeof(rtcp_sr_t),0);
296
cm->b_wptr+=rtcp_rr_init(session,cm->b_wptr,sizeof(rtcp_rr_t));
297
/* make a SDES packet */
298
if (session->sd!=NULL)
299
sdes=rtp_session_create_rtcp_sdes_packet(session);
306
static mblk_t * make_sr(RtpSession *session){
310
cm=allocb(sizeof(rtcp_sr_t),0);
311
cm->b_wptr+=rtcp_sr_init(session,cm->b_wptr,sizeof(rtcp_sr_t));
312
/* make a SDES packet */
313
sdes=rtp_session_create_rtcp_sdes_packet(session);
319
void rtp_session_rtcp_process_send(RtpSession *session){
320
RtpStream *st=&session->rtp;
322
if (st->rcv_last_app_ts - st->last_rtcp_report_snt_r > st->rtcp_report_snt_interval
323
|| st->snd_last_ts - st->last_rtcp_report_snt_s > st->rtcp_report_snt_interval){
324
st->last_rtcp_report_snt_r=st->rcv_last_app_ts;
325
st->last_rtcp_report_snt_s=st->snd_last_ts;
327
/* send the compound packet */
328
rtp_session_rtcp_send(session,m);
329
ortp_debug("Rtcp compound message sent.");
333
void rtp_session_rtcp_process_recv(RtpSession *session){
334
RtpStream *st=&session->rtp;
336
if (st->rcv_last_app_ts - st->last_rtcp_report_snt_r > st->rtcp_report_snt_interval
337
|| st->snd_last_ts - st->last_rtcp_report_snt_s > st->rtcp_report_snt_interval){
338
st->last_rtcp_report_snt_r=st->rcv_last_app_ts;
339
st->last_rtcp_report_snt_s=st->snd_last_ts;
341
if (session->rtp.last_rtcp_packet_count<session->rtp.stats.packet_sent){
343
session->rtp.last_rtcp_packet_count=session->rtp.stats.packet_sent;
347
/* send the compound packet */
348
rtp_session_rtcp_send(session,m);
349
ortp_debug("Rtcp compound message sent.");
353
void rtp_session_send_rtcp_APP(RtpSession *session, uint8_t subtype, const char *name, const uint8_t *data, int datalen){
354
mblk_t *h=allocb(sizeof(rtcp_app_t),0);
356
h->b_wptr+=rtcp_app_init(session,h->b_wptr,subtype,name,datalen+sizeof(rtcp_app_t));
357
d=esballoc((uint8_t*)data,datalen,0,NULL);
359
rtp_session_rtcp_send(session,h);
364
*@session: #RtpSession to send RTCP BYE packet on.
365
*@mode: One of the #RtpSessionMode flags.
367
* Creates a new rtp session.
368
* If the session is able to send data (RTP_SESSION_SENDONLY or RTP_SESSION_SENDRECV), then a
369
* random SSRC number is choosed for the outgoing stream.
371
*Returns: the newly created rtp session.
374
rtp_session_bye(RtpSession *session, const char *reason)
381
/* Make a BYE packet (will be on the end of the compund packet). */
382
bye = rtcp_create_simple_bye_packet(session->send_ssrc, reason);
384
/* SR or RR should be determined by the fact whether st was sent,
385
not on the mode. But we follow the current ortplib logic. */
386
if (session->mode==RTP_SESSION_SENDONLY
387
|| session->mode==RTP_SESSION_SENDRECV)
389
cm = allocb(sizeof(rtcp_sr_t), 0);
390
cm->b_wptr += rtcp_sr_init(session,cm->b_wptr, sizeof(rtcp_sr_t));
391
/* make a SDES packet */
392
sdes = rtp_session_create_rtcp_sdes_packet(session);
394
concatb(concatb(cm, sdes), bye);
396
/* make a RR packet */
397
cm = allocb(sizeof(rtcp_rr_t), 0);
398
cm->b_wptr += rtcp_rr_init(session, cm->b_wptr, sizeof(rtcp_rr_t));
403
/* Send compound packet. */
404
ret = rtp_session_rtcp_send(session, cm);