~ubuntu-branches/ubuntu/vivid/linphone/vivid

« back to all changes in this revision

Viewing changes to oRTP/src/rtcp.c

  • Committer: Bazaar Package Importer
  • Author(s): Samuel Mimram
  • Date: 2006-11-15 10:34:50 UTC
  • mfrom: (1.2.1 upstream) (2.1.8 feisty)
  • Revision ID: james.westby@ubuntu.com-20061115103450-qgafwcks2lkhctlj
* New upstream release.
* Enable video support.
* Fix mismatched #endif in mscommon.h, closes: #398307.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
 
3
  Copyright (C) 2001  Simon MORLAT simon.morlat@linphone.org
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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
 
18
*/
 
19
 
 
20
/***************************************************************************
 
21
 *            rtcp.c
 
22
 *
 
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"
 
30
#include "utils.h"
 
31
#include "rtpsession_priv.h"
 
32
 
 
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])
 
35
 
 
36
 
 
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);
 
43
}
 
44
 
 
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;
 
48
        sc->csrc=htonl(ssrc);
 
49
        m->b_wptr+=sizeof(sc->csrc);
 
50
        return m;
 
51
}
 
52
 
 
53
 
 
54
static mblk_t * sdes_chunk_append_item(mblk_t *m, rtcp_sdes_type_t sdes_type, const char *content)
 
55
{       
 
56
        if ( content )
 
57
        {
 
58
                sdes_item_t si;
 
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);
 
63
        }
 
64
        return m;
 
65
}
 
66
 
 
67
static void sdes_chunk_set_ssrc(mblk_t *m, uint32_t ssrc){
 
68
        sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
 
69
        sc->csrc=htonl(ssrc);
 
70
}
 
71
 
 
72
#define sdes_chunk_get_ssrc(m) ntohl(((sdes_chunk_t*)((m)->b_rptr))->csrc)
 
73
 
 
74
static mblk_t * sdes_chunk_pad(mblk_t *m){
 
75
        return appendb(m,"",1,TRUE);
 
76
}
 
77
 
 
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);
 
82
        mblk_t *m=chunk;
 
83
        const char *_cname=cname;
 
84
        if (_cname==NULL)
 
85
        {
 
86
                _cname="Unknown";
 
87
        }
 
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);
 
97
        session->sd=m;
 
98
}
 
99
 
 
100
void
 
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)
 
104
{
 
105
        mblk_t *chunk = sdes_chunk_new(csrc);
 
106
        mblk_t *m=chunk;
 
107
        char *_cname=(char*)cname;
 
108
        if (_cname==NULL)
 
109
        {
 
110
                _cname="toto";
 
111
        }
 
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);
 
121
}
 
122
 
 
123
 
 
124
 
 
125
mblk_t* rtp_session_create_rtcp_sdes_packet(RtpSession *session)
 
126
{
 
127
    mblk_t *mp=allocb(sizeof(rtcp_common_header_t),0);
 
128
        rtcp_common_header_t *rtcp;
 
129
    mblk_t *tmp,*m=mp;
 
130
        queue_t *q;
 
131
        int rc=0;
 
132
    rtcp = (rtcp_common_header_t*)mp->b_wptr;
 
133
        mp->b_wptr+=sizeof(rtcp_common_header_t);
 
134
        
 
135
        /* concatenate all sdes chunks */
 
136
        sdes_chunk_set_ssrc(session->sd,session->send_ssrc);
 
137
        m=concatb(m,dupmsg(session->sd));
 
138
        rc++;
 
139
        
 
140
        q=&session->contributing_sources;
 
141
    for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,mp)){
 
142
                m=concatb(m,dupmsg(tmp));
 
143
                rc++;
 
144
        }
 
145
        rtcp_common_header_init(rtcp,session,RTCP_SDES,rc,msgdsize(mp));
 
146
    return mp;
 
147
}
 
148
 
 
149
 
 
150
mblk_t *rtcp_create_simple_bye_packet(uint32_t ssrc, const char *reason)
 
151
{       
 
152
        int packet_size;
 
153
        int strsize = 0;
 
154
        int strpadding = 0;
 
155
        mblk_t *mp;
 
156
        rtcp_bye_t *rtcp;
 
157
 
 
158
        packet_size     = RTCP_BYE_HEADER_SIZE;
 
159
        if (reason!=NULL) {
 
160
                strsize=(int)MIN(strlen(reason),RTCP_BYE_REASON_MAX_STRING_SIZE);
 
161
                if (strsize > 0) {
 
162
                        strpadding = 3 - (strsize % 4);
 
163
                        packet_size += 1 + strsize + strpadding;
 
164
                }
 
165
        }
 
166
        mp      = allocb(packet_size, 0);
 
167
 
 
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*/
 
173
        if (reason!=NULL) {
 
174
                const char pad[] = {0, 0, 0};
 
175
                unsigned char strsize_octet = (unsigned char)strsize;
 
176
                
 
177
                appendb(mp, (const char*)&strsize_octet, 1, FALSE);
 
178
                appendb(mp, reason,strsize, FALSE);
 
179
                appendb(mp, pad,strpadding, FALSE);
 
180
        }
 
181
        return mp;
 
182
}
 
183
 
 
184
void rtp_session_remove_contributing_sources(RtpSession *session, uint32_t ssrc)
 
185
{
 
186
        queue_t *q=&session->contributing_sources;
 
187
        mblk_t *tmp;
 
188
        for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,tmp)){
 
189
                uint32_t csrc=sdes_chunk_get_ssrc(tmp);
 
190
                if (csrc==ssrc) {
 
191
                        remq(q,tmp);
 
192
                        break;
 
193
                }
 
194
        }
 
195
        tmp=rtcp_create_simple_bye_packet(ssrc, NULL);
 
196
        rtp_session_rtcp_send(session,tmp);
 
197
}
 
198
 
 
199
static void sender_info_init(sender_info_t *info, RtpSession *session){
 
200
        struct timeval tv;
 
201
        uint32_t tmp;
 
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);
 
206
#else
 
207
        tmp=(uint32_t)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6);
 
208
#endif
 
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;
 
214
}
 
215
 
 
216
 
 
217
 
 
218
static void report_block_init(report_block_t *b, RtpSession *session){
 
219
        int packet_loss=0;
 
220
        uint8_t loss_fraction=0;
 
221
        RtpStream *stream=&session->rtp;
 
222
        uint32_t delay_snc_last_sr=0;
 
223
        uint32_t fl_cnpl;
 
224
        
 
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
 
230
                );*/
 
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;
 
233
                if (packet_loss<0)
 
234
                        packet_loss=0;
 
235
                stream->stats.cum_packet_loss+=packet_loss;
 
236
                loss_fraction=(int)(256.0*(float)packet_loss/(float)stream->hwrcv_since_last_SR);
 
237
        }
 
238
        /* reset them */
 
239
        stream->hwrcv_since_last_SR=0;
 
240
        stream->hwrcv_seq_at_last_SR=stream->hwrcv_extseq;
 
241
        
 
242
        if (stream->last_rcv_SR_time.tv_sec!=0){
 
243
                struct timeval now;
 
244
                float delay;
 
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;
 
249
        }
 
250
        
 
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);
 
258
}
 
259
 
 
260
 
 
261
 
 
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);
 
270
}
 
271
 
 
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);
 
279
}
 
280
 
 
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);
 
289
}
 
290
 
 
291
static mblk_t * make_rr(RtpSession *session){
 
292
        mblk_t *cm=NULL;
 
293
        mblk_t *sdes=NULL;
 
294
        
 
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);
 
300
        /* link them */
 
301
        cm->b_cont=sdes;
 
302
        return cm;
 
303
}
 
304
 
 
305
 
 
306
static mblk_t * make_sr(RtpSession *session){
 
307
        mblk_t *cm=NULL;
 
308
        mblk_t *sdes=NULL;
 
309
        
 
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);
 
314
        /* link them */
 
315
        cm->b_cont=sdes;
 
316
        return cm;
 
317
}
 
318
 
 
319
void rtp_session_rtcp_process_send(RtpSession *session){
 
320
        RtpStream *st=&session->rtp;
 
321
        mblk_t *m;
 
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;
 
326
                m=make_sr(session);
 
327
                /* send the compound packet */
 
328
                rtp_session_rtcp_send(session,m);
 
329
                ortp_debug("Rtcp compound message sent.");
 
330
        }
 
331
}
 
332
 
 
333
void rtp_session_rtcp_process_recv(RtpSession *session){
 
334
        RtpStream *st=&session->rtp;
 
335
        mblk_t *m;
 
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;
 
340
 
 
341
                if (session->rtp.last_rtcp_packet_count<session->rtp.stats.packet_sent){
 
342
                        m=make_sr(session);
 
343
                        session->rtp.last_rtcp_packet_count=session->rtp.stats.packet_sent;
 
344
                }else{
 
345
                        m=make_rr(session);
 
346
                }
 
347
                /* send the compound packet */
 
348
                rtp_session_rtcp_send(session,m);
 
349
                ortp_debug("Rtcp compound message sent.");
 
350
        }
 
351
}
 
352
 
 
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);
 
355
        mblk_t *d;
 
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);
 
358
        h->b_cont=d;
 
359
        rtp_session_rtcp_send(session,h);
 
360
}
 
361
 
 
362
/**
 
363
 *rtp_session_bye:
 
364
 *@session: #RtpSession to send RTCP BYE packet on.
 
365
 *@mode: One of the #RtpSessionMode flags.
 
366
 *
 
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.
 
370
 *
 
371
 *Returns: the newly created rtp session.
 
372
**/
 
373
int
 
374
rtp_session_bye(RtpSession *session, const char *reason)
 
375
{
 
376
    mblk_t *cm;
 
377
    mblk_t *sdes = NULL;
 
378
    mblk_t *bye = NULL;
 
379
    int ret;
 
380
 
 
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);
 
383
 
 
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)
 
388
    {
 
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);
 
393
        /* link them */
 
394
        concatb(concatb(cm, sdes), bye);
 
395
    } else {
 
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));
 
399
        /* link them */
 
400
        cm->b_cont = bye;
 
401
    }
 
402
 
 
403
    /* Send compound packet. */
 
404
    ret = rtp_session_rtcp_send(session, cm);
 
405
 
 
406
    return ret;
 
407
}
 
408