source: mediastreamer2/linphone/oRTP/src/rtpsession.c @ 180:ecf35790a355

Last change on this file since 180:ecf35790a355 was 180:ecf35790a355, checked in by smorlat <smorlat@…>, 4 years ago
  • allow setting of nowebcam and remote ring path

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@183 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 51.3 KB
Line 
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#if defined(WIN32) || defined(_WIN32_WCE)
22#include "ortp-config-win32.h"
23#else
24#include "ortp-config.h"
25#endif
26
27#include "ortp/ortp.h"
28#include "ortp/telephonyevents.h"
29#include "ortp/rtcp.h"
30#include "jitterctl.h"
31#include "scheduler.h"
32#include "utils.h"
33#include "rtpsession_priv.h"
34
35extern mblk_t *rtcp_create_simple_bye_packet(uint32_t ssrc, const char *reason);
36extern int rtcp_sr_init(RtpSession *session, char *buf, int size);
37extern int rtcp_rr_init(RtpSession *session, char *buf, int size);
38
39
40
41/* this function initialize all session parameter's that depend on the payload type */
42static void payload_type_changed(RtpSession *session, PayloadType *pt){
43        jitter_control_set_payload(&session->rtp.jittctl,pt);
44        session->rtp.rtcp_report_snt_interval=RTCP_DEFAULT_REPORT_INTERVAL*pt->clock_rate;
45        rtp_session_set_time_jump_limit(session,session->rtp.time_jump);
46        if (pt->type==PAYLOAD_VIDEO){
47                session->permissive=TRUE;
48                ortp_message("Using permissive algorithm");
49        }
50        else session->permissive=FALSE;
51}
52
53void wait_point_init(WaitPoint *wp){
54        ortp_mutex_init(&wp->lock,NULL);
55        ortp_cond_init(&wp->cond,NULL);
56        wp->time=0;
57        wp->wakeup=FALSE;
58}
59void wait_point_uninit(WaitPoint *wp){
60        ortp_cond_destroy(&wp->cond);
61        ortp_mutex_destroy(&wp->lock);
62}
63
64#define wait_point_lock(wp) ortp_mutex_lock(&(wp)->lock)
65#define wait_point_unlock(wp) ortp_mutex_unlock(&(wp)->lock)
66
67void wait_point_wakeup_at(WaitPoint *wp, uint32_t t, bool_t dosleep){
68        wp->time=t;
69        wp->wakeup=TRUE;
70        if (dosleep) ortp_cond_wait(&wp->cond,&wp->lock);
71}
72
73
74bool_t wait_point_check(WaitPoint *wp, uint32_t t){
75        bool_t ok=FALSE;
76       
77        if (wp->wakeup){
78                if (TIME_IS_NEWER_THAN(t,wp->time)){
79                        wp->wakeup=FALSE;
80                        ok=TRUE;
81                       
82                }
83        }
84        return ok;
85}
86#define wait_point_wakeup(wp) ortp_cond_signal(&(wp)->cond);
87
88extern void rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts,
89                struct sockaddr *addr, socklen_t addrlen);
90
91
92static uint32_t uint32_t_random(){
93        return random();
94}
95
96
97#define RTP_SEQ_IS_GREATER(seq1,seq2)\
98        ((uint16_t)((uint16_t)(seq1) - (uint16_t)(seq2))< (uint16_t)(1<<15))
99
100/* put an rtp packet in queue. It is called by rtp_parse()*/
101void rtp_putq(queue_t *q, mblk_t *mp)
102{
103        mblk_t *tmp;
104        rtp_header_t *rtp=(rtp_header_t*)mp->b_rptr,*tmprtp;
105        /* insert message block by increasing time stamp order : the last (at the bottom)
106                message of the queue is the newest*/
107        ortp_debug("rtp_putq(): Enqueuing packet with ts=%i and seq=%i",rtp->timestamp,rtp->seq_number);
108       
109        if (qempty(q)) {
110                putq(q,mp);
111                return;
112        }
113        tmp=qlast(q);
114        /* we look at the queue from bottom to top, because enqueued packets have a better chance
115        to be enqueued at the bottom, since there are surely newer */
116        while (!qend(q,tmp))
117        {
118                tmprtp=(rtp_header_t*)tmp->b_rptr;
119                ortp_debug("rtp_putq(): Seeing packet with seq=%i",tmprtp->seq_number);
120               
121                if (rtp->seq_number == tmprtp->seq_number)
122                {
123                        /* this is a duplicated packet. Don't queue it */
124                        ortp_debug("rtp_putq: duplicated message.");
125                        freemsg(mp);
126                        return;
127                }else if (RTP_SEQ_IS_GREATER(rtp->seq_number,tmprtp->seq_number)){
128                       
129                        insq(q,tmp->b_next,mp);
130                        return;
131                }
132                tmp=tmp->b_prev;
133        }
134        /* this packet is the oldest, it has to be
135        placed on top of the queue */
136        insq(q,qfirst(q),mp);
137       
138}
139
140
141
142mblk_t *rtp_getq(queue_t *q,uint32_t timestamp, int *rejected)
143{
144        mblk_t *tmp,*ret=NULL,*old=NULL;
145        rtp_header_t *tmprtp;
146        uint32_t ts_found=0;
147       
148        *rejected=0;
149        ortp_debug("rtp_getq(): Timestamp %i wanted.",timestamp);
150
151        if (qempty(q))
152        {
153                /*ortp_debug("rtp_getq: q is empty.");*/
154                return NULL;
155        }
156        /* return the packet with ts just equal or older than the asked timestamp */
157        /* packets with older timestamps are discarded */
158        while ((tmp=qfirst(q))!=NULL)
159        {
160                tmprtp=(rtp_header_t*)tmp->b_rptr;
161                ortp_debug("rtp_getq: Seeing packet with ts=%i",tmprtp->timestamp);
162                if ( RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,tmprtp->timestamp) )
163                {
164                        if (ret!=NULL && tmprtp->timestamp==ts_found) {
165                                /* we've found two packets with same timestamp. return the first one */
166                                break;
167                        }
168                        if (old!=NULL) {
169                                ortp_debug("rtp_getq: discarding too old packet with ts=%i",ts_found);
170                                (*rejected)++;
171                                freemsg(old);
172                        }
173                        ret=getq(q); /* dequeue the packet, since it has an interesting timestamp*/
174                        ts_found=tmprtp->timestamp;
175                        ortp_debug("rtp_getq: Found packet with ts=%i",tmprtp->timestamp);
176                        old=ret;
177                }
178                else
179                {
180                        break;
181                }
182        }
183        return ret;
184}
185
186mblk_t *rtp_getq_permissive(queue_t *q,uint32_t timestamp, int *rejected)
187{
188        mblk_t *tmp,*ret=NULL;
189        rtp_header_t *tmprtp;
190       
191        *rejected=0;
192        ortp_debug("rtp_getq_permissive(): Timestamp %i wanted.",timestamp);
193
194        if (qempty(q))
195        {
196                /*ortp_debug("rtp_getq: q is empty.");*/
197                return NULL;
198        }
199        /* return the packet with the older timestamp (provided that it is older than
200        the asked timestamp) */
201        tmp=qfirst(q);
202        tmprtp=(rtp_header_t*)tmp->b_rptr;
203        ortp_debug("rtp_getq_permissive: Seeing packet with ts=%i",tmprtp->timestamp);
204        if ( RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,tmprtp->timestamp) )
205        {
206                ret=getq(q); /* dequeue the packet, since it has an interesting timestamp*/
207                ortp_debug("rtp_getq_permissive: Found packet with ts=%i",tmprtp->timestamp);
208        }
209        return ret;
210}
211
212
213void
214rtp_session_init (RtpSession * session, int mode)
215{
216        JBParameters jbp;
217        memset (session, 0, sizeof (RtpSession));
218        session->mode = (RtpSessionMode) mode;
219        if ((mode == RTP_SESSION_RECVONLY) || (mode == RTP_SESSION_SENDRECV))
220        {
221                rtp_session_set_flag (session, RTP_SESSION_RECV_SYNC);
222                rtp_session_set_flag (session, RTP_SESSION_RECV_NOT_STARTED);
223               
224        }
225        if ((mode == RTP_SESSION_SENDONLY) || (mode == RTP_SESSION_SENDRECV))
226        {
227                rtp_session_set_flag (session, RTP_SESSION_SEND_NOT_STARTED);
228                session->snd.ssrc=uint32_t_random();
229                /* set default source description */
230                rtp_session_set_source_description(session,"unknown@unknown",NULL,NULL,
231                                NULL,NULL,"oRTP-" ORTP_VERSION,"This is free sofware (LGPL) !");
232        }
233        session->snd.telephone_events_pt=-1;    /* not defined a priori */
234        session->rcv.telephone_events_pt=-1;    /* not defined a priori */
235        rtp_session_set_profile (session, &av_profile); /*the default profile to work with */
236        session->rtp.socket=-1;
237        session->rtcp.socket=-1;
238#ifndef WIN32
239        session->rtp.snd_socket_size=0; /*use OS default value unless on windows where they are definitely too short*/
240        session->rtp.rcv_socket_size=0;
241#else
242        session->rtp.snd_socket_size=session->rtp.rcv_socket_size=65536;
243#endif
244        session->dscp=RTP_DEFAULT_DSCP;
245        session->multicast_ttl=RTP_DEFAULT_MULTICAST_TTL;
246        session->multicast_loopback=RTP_DEFAULT_MULTICAST_LOOPBACK;
247        qinit(&session->rtp.rq);
248        qinit(&session->rtp.tev_rq);
249        qinit(&session->contributing_sources);
250        session->eventqs=NULL;
251        /* init signal tables */
252        rtp_signal_table_init (&session->on_ssrc_changed, session,"ssrc_changed");
253        rtp_signal_table_init (&session->on_payload_type_changed, session,"payload_type_changed");
254        rtp_signal_table_init (&session->on_telephone_event, session,"telephone-event");
255        rtp_signal_table_init (&session->on_telephone_event_packet, session,"telephone-event_packet");
256        rtp_signal_table_init (&session->on_timestamp_jump,session,"timestamp_jump");
257        rtp_signal_table_init (&session->on_network_error,session,"network_error");
258        rtp_signal_table_init (&session->on_rtcp_bye,session,"rtcp_bye");
259        wait_point_init(&session->snd.wp);
260        wait_point_init(&session->rcv.wp);
261        /*defaults send payload type to 0 (pcmu)*/
262        rtp_session_set_send_payload_type(session,0);
263        /*sets supposed recv payload type to undefined */
264        rtp_session_set_recv_payload_type(session,-1);
265        /* configure jitter buffer with working default parameters */
266        jbp.min_size=RTP_DEFAULT_JITTER_TIME;
267        jbp.nom_size=RTP_DEFAULT_JITTER_TIME;
268        jbp.max_size=-1;
269        jbp.max_packets= 100;/* maximum number of packet allowed to be queued */
270        jbp.adaptive=TRUE;
271        rtp_session_enable_jitter_buffer(session,TRUE);
272        rtp_session_set_jitter_buffer_params(session,&jbp);
273        rtp_session_set_time_jump_limit(session,5000);
274        rtp_session_enable_rtcp(session,TRUE);
275        session->recv_buf_size = UDP_MAX_SIZE;
276        session->symmetric_rtp = FALSE;
277        session->permissive=FALSE;
278        msgb_allocator_init(&session->allocator);
279}
280
281
282/**
283 * Creates a new rtp session.
284 * If the session is able to send data (RTP_SESSION_SENDONLY or
285 * RTP_SESSION_SENDRECV), then a random SSRC number is choosed for
286 * the outgoing stream.
287 * @param mode One of the RtpSessionMode flags.
288 *
289 * @return the newly created rtp session.
290**/
291RtpSession *
292rtp_session_new (int mode)
293{
294        RtpSession *session;
295        session = (RtpSession *) ortp_malloc (sizeof (RtpSession));
296        rtp_session_init (session, mode);
297        return session;
298}
299
300/**
301 * Sets the scheduling mode of the rtp session. If @yesno is TRUE, the rtp session is in
302 *      the scheduled mode, that means that you can use session_set_select() to block until it's time
303 *      to receive or send on this session according to the timestamp passed to the respective functions.
304 *  You can also use blocking mode (see rtp_session_set_blocking_mode() ), to simply block within
305 *      the receive and send functions.
306 *      If @yesno is FALSE, the ortp scheduler will not manage those sessions, meaning that blocking mode
307 *  and the use of session_set_select() for this session are disabled.
308 *@param session a rtp session.
309 *@param yesno  a boolean to indicate the scheduling mode.
310 *
311 *
312**/
313void
314rtp_session_set_scheduling_mode (RtpSession * session, int yesno)
315{
316        if (yesno)
317        {
318                RtpScheduler *sched;
319                sched = ortp_get_scheduler ();
320                if (sched != NULL)
321                {
322                        rtp_session_set_flag (session, RTP_SESSION_SCHEDULED);
323                        session->sched = sched;
324                        rtp_scheduler_add_session (sched, session);
325                }
326                else
327                        ortp_warning
328                                ("rtp_session_set_scheduling_mode: Cannot use scheduled mode because the "
329                                 "scheduler is not started. Use ortp_scheduler_init() before.");
330        }
331        else
332                rtp_session_unset_flag (session, RTP_SESSION_SCHEDULED);
333}
334
335
336/**
337 *      This function implicitely enables the scheduling mode if yesno is TRUE.
338 *      rtp_session_set_blocking_mode() defines the behaviour of the rtp_session_recv_with_ts() and
339 *      rtp_session_send_with_ts() functions. If @yesno is TRUE, rtp_session_recv_with_ts()
340 *      will block until it is time for the packet to be received, according to the timestamp
341 *      passed to the function. After this time, the function returns.
342 *      For rtp_session_send_with_ts(), it will block until it is time for the packet to be sent.
343 *      If @yesno is FALSE, then the two functions will return immediately.
344 *
345 *  @param session a rtp session
346 *  @param yesno a boolean
347**/
348void
349rtp_session_set_blocking_mode (RtpSession * session, int yesno)
350{
351        if (yesno){
352                rtp_session_set_scheduling_mode(session,TRUE);
353                rtp_session_set_flag (session, RTP_SESSION_BLOCKING_MODE);
354        }else
355                rtp_session_unset_flag (session, RTP_SESSION_BLOCKING_MODE);
356}
357
358/**
359 *      Set the RTP profile to be used for the session. By default, all session are created by
360 *      rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application
361 *      can set any other profile instead using that function.
362 *
363 * @param session a rtp session
364 * @param profile a rtp profile
365**/
366
367void
368rtp_session_set_profile (RtpSession * session, RtpProfile * profile)
369{
370        session->snd.profile = profile;
371        session->rcv.profile = profile;
372        rtp_session_telephone_events_supported(session);
373}
374
375/**
376 *      By default oRTP automatically sends RTCP SR or RR packets. If
377 *      yesno is set to FALSE, the RTCP sending of packet is disabled.
378 *      This functionnality might be needed for some equipments that do not
379 *      support RTCP, leading to a traffic of ICMP errors on the network.
380 *      It can also be used to save bandwidth despite the RTCP bandwidth is
381 *      actually and usually very very low.
382**/
383void rtp_session_enable_rtcp(RtpSession *session, bool_t yesno){
384        session->rtcp.enabled=yesno;
385}
386
387/**
388 *      Set the RTP profile to be used for the sending by this session. By default, all session are created by
389 *      rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application
390 *      can set any other profile instead using that function.
391 * @param session a rtp session
392 * @param profile a rtp profile
393 *
394**/
395
396void
397rtp_session_set_send_profile (RtpSession * session, RtpProfile * profile)
398{
399        session->snd.profile = profile;
400        rtp_session_send_telephone_events_supported(session);
401}
402
403
404
405/**
406 *      Set the RTP profile to be used for the receiveing by this session. By default, all session are created by
407 *      rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application
408 *      can set any other profile instead using that function.
409 *
410 * @param session a rtp session
411 * @param profile a rtp profile
412**/
413
414void
415rtp_session_set_recv_profile (RtpSession * session, RtpProfile * profile)
416{
417        session->rcv.profile = profile;
418        rtp_session_recv_telephone_events_supported(session);
419}
420
421/**
422 *@param session a rtp session
423 *
424 *      DEPRECATED! Returns current send profile.
425 *      Use rtp_session_get_send_profile() or rtp_session_get_recv_profile()
426 *
427**/
428RtpProfile *rtp_session_get_profile(RtpSession *session){
429        return session->snd.profile;
430}
431
432
433/**
434 *@param session a rtp session
435 *
436 *      Returns current send profile.
437 *
438**/
439RtpProfile *rtp_session_get_send_profile(RtpSession *session){
440        return session->snd.profile;
441}
442
443/**
444 *@param session a rtp session
445 *
446 *      Returns current receive profile.
447 *
448**/
449RtpProfile *rtp_session_get_recv_profile(RtpSession *session){
450        return session->rcv.profile;
451}
452
453/**
454 *      The default value is UDP_MAX_SIZE bytes, a value which is working for mostly everyone.
455 *      However if your application can make assumption on the sizes of received packet,
456 *      it can be interesting to set it to a lower value in order to save memory.
457 *
458 * @param session a rtp session
459 * @param bufsize max size in bytes for receiving packets
460**/
461void rtp_session_set_recv_buf_size(RtpSession *session, int bufsize){
462        session->recv_buf_size=bufsize;
463}
464
465/**
466 *      Set kernel send maximum buffer size for the rtp socket.
467 *      A value of zero defaults to the operating system default.
468**/
469void rtp_session_set_rtp_socket_send_buffer_size(RtpSession * session, unsigned int size){
470        session->rtp.snd_socket_size=size;
471}
472
473/**
474 *      Set kernel recv maximum buffer size for the rtp socket.
475 *      A value of zero defaults to the operating system default.
476**/
477void rtp_session_set_rtp_socket_recv_buffer_size(RtpSession * session, unsigned int size){
478        session->rtp.rcv_socket_size=size;
479}
480
481/**
482 *      This function provides the way for an application to be informed of various events that
483 *      may occur during a rtp session. @signal is a string identifying the event, and @cb is
484 *      a user supplied function in charge of processing it. The application can register
485 *      several callbacks for the same signal, in the limit of #RTP_CALLBACK_TABLE_MAX_ENTRIES.
486 *      Here are name and meaning of supported signals types:
487 *
488 *      "ssrc_changed" : the SSRC of the incoming stream has changed.
489 *
490 *      "payload_type_changed" : the payload type of the incoming stream has changed.
491 *
492 *      "telephone-event_packet" : a telephone-event rtp packet (RFC2833) is received.
493 *
494 *      "telephone-event" : a telephone event has occured. This is a high-level shortcut for "telephone-event_packet".
495 *
496 *      "network_error" : a network error happened on a socket. Arguments of the callback functions are
497 *                                              a const char * explaining the error, an int errno error code and the user_data as usual.
498 *
499 *      "timestamp_jump" : we have received a packet with timestamp in far future compared to last timestamp received.
500 *                                              The farness of far future is set by rtp_sesssion_set_time_jump_limit()
501 *  "rtcp_bye": we have received a RTCP bye packet. Arguments of the callback
502 *              functions are a const char * containing the leaving reason and
503 *              the user_data.
504 *
505 *      Returns: 0 on success, -EOPNOTSUPP if the signal does not exists, -1 if no more callbacks
506 *      can be assigned to the signal type.
507 *
508 * @param session       a rtp session
509 * @param signal_name   the name of a signal
510 * @param cb            a RtpCallback
511 * @param user_data     a pointer to any data to be passed when invoking the callback.
512 *
513**/
514int
515rtp_session_signal_connect (RtpSession * session, const char *signal_name,
516                            RtpCallback cb, unsigned long user_data)
517{
518        OList *elem;
519        for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){
520                RtpSignalTable *s=(RtpSignalTable*) elem->data;
521                if (strcmp(signal_name,s->signal_name)==0){
522                        return rtp_signal_table_add(s,cb,user_data);
523                }
524        }
525        ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal_name);
526        return -1;
527}
528
529
530/**
531 *      Removes callback function @cb to the list of callbacks for signal @signal.
532 *
533 * @param session a rtp session
534 * @param signal_name   a signal name
535 * @param cb    a callback function.
536 * @return: 0 on success, a negative value if the callback was not found.
537**/
538int
539rtp_session_signal_disconnect_by_callback (RtpSession * session, const char *signal_name,
540                                           RtpCallback cb)
541{
542        OList *elem;
543        for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){
544                RtpSignalTable *s=(RtpSignalTable*) elem->data;
545                if (strcmp(signal_name,s->signal_name)==0){
546                        return rtp_signal_table_remove_by_callback(s,cb);
547                }
548        }
549        ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal_name);
550        return -1;
551}
552
553
554/**
555 * sets the initial sequence number of a sending session.
556 * @param session               a rtp session freshly created.
557 * @param addr                  a 16 bit unsigned number.
558 *
559**/
560void rtp_session_set_seq_number(RtpSession *session, uint16_t seq){
561        session->rtp.snd_seq=seq;
562}
563
564
565uint16_t rtp_session_get_seq_number(RtpSession *session){
566        return session->rtp.snd_seq;
567}
568
569
570/**
571 *      Sets the SSRC for the outgoing stream.
572 *  If not done, a random ssrc is used.
573 *
574 * @param session a rtp session.
575 * @param ssrc an unsigned 32bit integer representing the synchronisation source identifier (SSRC).
576**/
577void
578rtp_session_set_ssrc (RtpSession * session, uint32_t ssrc)
579{
580        session->snd.ssrc = ssrc;
581}
582
583
584void rtp_session_update_payload_type(RtpSession *session, int paytype){
585        /* check if we support this payload type */
586        PayloadType *pt=rtp_profile_get_payload(session->rcv.profile,paytype);
587        session->hw_recv_pt=paytype;
588        if (pt!=0){
589                ortp_message ("payload type changed to %i(%s) !",
590                                 paytype,pt->mime_type);
591                payload_type_changed(session,pt);
592        }else{
593                ortp_warning("Receiving packet with unknown payload type %i.",paytype);
594        }
595}
596/**
597 *      Sets the payload type of the rtp session. It decides of the payload types written in the
598 *      of the rtp header for the outgoing stream, if the session is SENDRECV or SENDONLY.
599 *      For payload type in incoming packets, the application can be informed by registering
600 *      for the "payload_type_changed" signal, so that it can make the necessary changes
601 *      on the downstream decoder that deals with the payload of the packets.
602 *
603 * @param session a rtp session
604 * @param paytype the payload type number
605 * @return 0 on success, -1 if the payload is not defined.
606**/
607
608int
609rtp_session_set_send_payload_type (RtpSession * session, int paytype)
610{
611        session->snd.pt=paytype;
612        return 0;
613}
614
615/**
616 *@param session a rtp session
617 *
618 *@return the payload type currently used in outgoing rtp packets
619**/
620int rtp_session_get_send_payload_type(const RtpSession *session){
621        return session->snd.pt;
622}
623
624/**
625 *
626 *      Sets the expected payload type for incoming packets.
627 *      If the actual payload type in incoming packets is different that this expected payload type, thus
628 *      the "payload_type_changed" signal is emitted.
629 *
630 *@param session a rtp session
631 *@param paytype the payload type number
632 *@return 0 on success, -1 if the payload is not defined.
633**/
634
635int
636rtp_session_set_recv_payload_type (RtpSession * session, int paytype)
637{
638        PayloadType *pt;
639        session->rcv.pt=paytype;
640        session->hw_recv_pt=paytype;
641        pt=rtp_profile_get_payload(session->rcv.profile,paytype);
642        if (pt!=NULL){
643                payload_type_changed(session,pt);
644        }
645        return 0;
646}
647
648/**
649 *@param session a rtp session
650 *
651 * @return the payload type currently used in incoming rtp packets
652**/
653int rtp_session_get_recv_payload_type(const RtpSession *session){
654        return session->rcv.pt;
655}
656
657/**
658 *      Sets the expected payload type for incoming packets and payload type to be used for outgoing packets.
659 *      If the actual payload type in incoming packets is different that this expected payload type, thus
660 *      the "payload_type_changed" signal is emitted.
661 *
662 * @param session a rtp session
663 * @param paytype the payload type number
664 * @return 0 on success, -1 if the payload is not defined.
665**/
666int rtp_session_set_payload_type(RtpSession *session, int pt){
667        if (rtp_session_set_send_payload_type(session,pt)<0) return -1;
668        if (rtp_session_set_recv_payload_type(session,pt)<0) return -1;
669        return 0;
670}
671
672
673static void rtp_header_init_from_session(rtp_header_t *rtp, RtpSession *session){
674        rtp->version = 2;
675        rtp->padbit = 0;
676        rtp->extbit = 0;
677        rtp->markbit= 0;
678        rtp->cc = 0;
679        rtp->paytype = session->snd.pt;
680        rtp->ssrc = session->snd.ssrc;
681        rtp->timestamp = 0;     /* set later, when packet is sended */
682        /* set a seq number */
683        rtp->seq_number=session->rtp.snd_seq;
684}
685
686/**
687 *      Allocates a new rtp packet. In the header, ssrc and payload_type according to the session's
688 *      context. Timestamp and seq number are not set, there will be set when the packet is going to be
689 *      sent with rtp_session_sendm_with_ts().
690 *      If payload_size is zero, thus an empty packet (just a RTP header) is returned.
691 *
692 *@param session a rtp session.
693 *@param header_size the rtp header size. For standart size (without extensions), it is RTP_FIXED_HEADER_SIZE
694 *@param payload data to be copied into the rtp packet.
695 *@param payload_size size of data carried by the rtp packet.
696 *@return a rtp packet in a mblk_t (message block) structure.
697**/
698mblk_t * rtp_session_create_packet(RtpSession *session,int header_size, const uint8_t *payload, int payload_size)
699{
700        mblk_t *mp;
701        int msglen=header_size+payload_size;
702        rtp_header_t *rtp;
703       
704        mp=allocb(msglen,BPRI_MED);
705        rtp=(rtp_header_t*)mp->b_rptr;
706        rtp_header_init_from_session(rtp,session);
707        /*copy the payload, if any */
708        mp->b_wptr+=header_size;
709        if (payload_size){
710                memcpy(mp->b_wptr,payload,payload_size);
711                mp->b_wptr+=payload_size;
712        }
713        return mp;
714}
715
716/**
717 *      Creates a new rtp packet using the given payload buffer (no copy). The header will be allocated separetely.
718 *  In the header, ssrc and payload_type according to the session's
719 *      context. Timestamp and seq number are not set, there will be set when the packet is going to be
720 *      sent with rtp_session_sendm_with_ts().
721 *      oRTP will send this packet using libc's sendmsg() (if this function is availlable!) so that there will be no
722 *      packet concatenation involving copies to be done in user-space.
723 *  @freefn can be NULL, in that case payload will be kept untouched.
724 *
725 * @param session a rtp session.
726 * @param payload the data to be sent with this packet
727 * @param payload_size size of data
728 * @param freefn a function that will be called when the payload buffer is no more needed.
729 * @return: a rtp packet in a mblk_t (message block) structure.
730**/
731
732mblk_t * rtp_session_create_packet_with_data(RtpSession *session, uint8_t *payload, int payload_size, void (*freefn)(void*))
733{
734        mblk_t *mp,*mpayload;
735        int header_size=RTP_FIXED_HEADER_SIZE; /* revisit when support for csrc is done */
736        rtp_header_t *rtp;
737       
738        mp=allocb(header_size,BPRI_MED);
739        rtp=(rtp_header_t*)mp->b_rptr;
740        rtp_header_init_from_session(rtp,session);
741        mp->b_wptr+=header_size;
742        /* create a mblk_t around the user supplied payload buffer */
743        mpayload=esballoc(payload,payload_size,BPRI_MED,freefn);
744        mpayload->b_wptr+=payload_size;
745        /* link it with the header */
746        mp->b_cont=mpayload;
747        return mp;
748}
749
750
751/**
752 * Creates a new rtp packet using the buffer given in arguments (no copy).
753 * In the header, ssrc and payload_type according to the session's
754 *context. Timestamp and seq number are not set, there will be set when the packet is going to be
755 *      sent with rtp_session_sendm_with_ts().
756 *  @freefn can be NULL, in that case payload will be kept untouched.
757 *
758 * @param session a rtp session.
759 * @param buffer a buffer that contains first just enough place to write a RTP header, then the data to send.
760 * @param size the size of the buffer
761 * @param freefn a function that will be called once the buffer is no more needed (the data has been sent).
762 * @return a rtp packet in a mblk_t (message block) structure.
763**/
764mblk_t * rtp_session_create_packet_in_place(RtpSession *session,uint8_t *buffer, int size, void (*freefn)(void*) )
765{
766        mblk_t *mp;
767        rtp_header_t *rtp;
768       
769        mp=esballoc(buffer,size,BPRI_MED,freefn);
770
771        rtp=(rtp_header_t*)mp->b_rptr;
772        rtp_header_init_from_session(rtp,session);
773        return mp;
774}
775
776
777int
778__rtp_session_sendm_with_ts (RtpSession * session, mblk_t *mp, uint32_t packet_ts, uint32_t send_ts)
779{
780        rtp_header_t *rtp;
781        uint32_t packet_time;
782        int error = 0;
783        int packsize;
784        RtpScheduler *sched=session->sched;
785        RtpStream *stream=&session->rtp;
786
787        if (session->flags & RTP_SESSION_SEND_NOT_STARTED)
788        {
789                session->rtp.snd_ts_offset = send_ts;
790                /* Set initial last_rcv_time to first send time. */
791                if ((session->flags & RTP_SESSION_RECV_NOT_STARTED)
792                || session->mode == RTP_SESSION_SENDONLY)
793                {
794                gettimeofday(&session->last_recv_time, NULL);
795                }
796                if (session->flags & RTP_SESSION_SCHEDULED)
797                {
798                        session->rtp.snd_time_offset = sched->time_;
799                }
800                rtp_session_unset_flag (session,RTP_SESSION_SEND_NOT_STARTED);
801        }
802        /* if we are in blocking mode, then suspend the process until the scheduler it's time to send  the
803         * next packet */
804        /* if the timestamp of the packet queued is older than current time, then you we must
805         * not block */
806        if (session->flags & RTP_SESSION_SCHEDULED)
807        {
808                packet_time =
809                        rtp_session_ts_to_time (session,
810                                     send_ts -
811                                     session->rtp.snd_ts_offset) +
812                                        session->rtp.snd_time_offset;
813                /*ortp_message("rtp_session_send_with_ts: packet_time=%i time=%i",packet_time,sched->time_);*/
814                wait_point_lock(&session->snd.wp);
815                if (TIME_IS_STRICTLY_NEWER_THAN (packet_time, sched->time_))
816                {
817                        wait_point_wakeup_at(&session->snd.wp,packet_time,(session->flags & RTP_SESSION_BLOCKING_MODE)!=0);     
818                        session_set_clr(&sched->w_sessions,session);    /* the session has written */
819                }
820                else session_set_set(&sched->w_sessions,session);       /*to indicate select to return immediately */
821                wait_point_unlock(&session->snd.wp);
822        }
823       
824        if(mp==NULL) {/*for people who just want to be blocked but
825                 do not want to send anything.*/
826                session->rtp.snd_last_ts = packet_ts;
827                return 0;
828        }
829
830        rtp=(rtp_header_t*)mp->b_rptr;
831       
832        packsize = msgdsize(mp) ;
833       
834        rtp->timestamp=packet_ts;
835        if (session->snd.telephone_events_pt==rtp->paytype)
836        {
837                session->rtp.snd_seq++;
838                rtp->seq_number = session->rtp.snd_seq;
839        }
840        else
841                session->rtp.snd_seq=rtp->seq_number+1;
842        session->rtp.snd_last_ts = packet_ts;
843
844
845        ortp_global_stats.sent += packsize;
846        stream->sent_payload_bytes+=packsize-RTP_FIXED_HEADER_SIZE;
847        stream->stats.sent += packsize;
848        ortp_global_stats.packet_sent++;
849        stream->stats.packet_sent++;
850
851        error = rtp_session_rtp_send (session, mp);
852        /*send RTCP packet if needed */
853        rtp_session_rtcp_process_send(session);
854        /* receives rtcp packet if session is send-only*/
855        /*otherwise it is done in rtp_session_recvm_with_ts */
856        if (session->mode==RTP_SESSION_SENDONLY) rtp_session_rtcp_recv(session);
857        return error;
858}
859
860/**
861 *      Send the rtp datagram @mp to the destination set by rtp_session_set_remote_addr()
862 *      with timestamp @timestamp. For audio data, the timestamp is the number
863 *      of the first sample resulting of the data transmitted. See rfc1889 for details.
864 *  The packet (@mp) is freed once it is sended.
865 *
866 *@param session a rtp session.
867 *@param mp a rtp packet presented as a mblk_t.
868 *@param timestamp the timestamp of the data to be sent.
869 * @return the number of bytes sent over the network.
870**/
871
872int rtp_session_sendm_with_ts(RtpSession *session, mblk_t *packet, uint32_t timestamp){
873        return __rtp_session_sendm_with_ts(session,packet,timestamp,timestamp);
874}
875
876
877
878
879/**
880 *      Send a rtp datagram to the destination set by rtp_session_set_remote_addr() containing
881 *      the data from @buffer with timestamp @userts. This is a high level function that uses
882 *      rtp_session_create_packet() and rtp_session_sendm_with_ts() to send the data.
883 *
884 *@param session a rtp session.
885 *@param buffer a buffer containing the data to be sent in a rtp packet.
886 *@param len the length of the data buffer, in bytes.
887 *@param userts the timestamp of the data to be sent. Refer to the rfc to know what it is.
888 *
889 *@param return the number of bytes sent over the network.
890**/
891int
892rtp_session_send_with_ts (RtpSession * session, const uint8_t * buffer, int len,
893                          uint32_t userts)
894{
895        mblk_t *m;
896        int err;
897#ifdef USE_SENDMSG
898        m=rtp_session_create_packet_with_data(session,(uint8_t*)buffer,len,NULL);
899#else
900        m = rtp_session_create_packet(session,RTP_FIXED_HEADER_SIZE,(uint8_t*)buffer,len);
901#endif
902        err=rtp_session_sendm_with_ts(session,m,userts);
903        return err;
904}
905
906
907
908extern void rtcp_parse(RtpSession *session, mblk_t *mp);
909
910
911
912static void payload_type_changed_notify(RtpSession *session, int paytype){
913        session->rcv.pt = paytype;
914        rtp_signal_table_emit (&session->on_payload_type_changed);     
915}
916
917
918/**
919 *      Try to get a rtp packet presented as a mblk_t structure from the rtp session.
920 *      The @user_ts parameter is relative to the first timestamp of the incoming stream. In other
921 *      words, the application does not have to know the first timestamp of the stream, it can
922 *      simply call for the first time this function with @user_ts=0, and then incrementing it
923 *      as it want. The RtpSession takes care of synchronisation between the stream timestamp
924 *      and the user timestamp given here.
925 *
926 *      This function returns the entire packet (with header).
927 *
928 *      The behaviour of this function has changed since version 0.15.0. Previously the payload data could be
929 *      accessed using  mblk_t::b_cont::b_rptr field of the returned mblk_t.
930 *      This is no more the case.
931 *      The convenient way of accessing the payload data is to use rtp_get_payload() :
932 *      @code
933 *      unsigned char *payload;
934 *      int payload_size;
935 *      payload_size=rtp_get_payload(mp,&payload);
936 *      @endcode
937 *      OR simply skip the header this way, the data is then comprised between mp->b_rptr and mp->b_wptr:
938 *      @code
939 *      rtp_get_payload(mp,&mp->b_rptr);
940 *      @endcode
941 *
942 *
943 * @param session a rtp session.
944 * @param user_ts a timestamp.
945 *
946 * @return a rtp packet presented as a mblk_t.
947**/
948
949mblk_t *
950rtp_session_recvm_with_ts (RtpSession * session, uint32_t user_ts)
951{
952        mblk_t *mp = NULL;
953        rtp_header_t *rtp;
954        uint32_t ts;
955        uint32_t packet_time;
956        RtpScheduler *sched=session->sched;
957        RtpStream *stream=&session->rtp;
958        int rejected=0;
959        bool_t read_socket=TRUE;
960
961        /* if we are scheduled, remember the scheduler time at which the application has
962         * asked for its first timestamp */
963
964        if (session->flags & RTP_SESSION_RECV_NOT_STARTED)
965        {
966                session->rtp.rcv_query_ts_offset = user_ts;
967                /* Set initial last_rcv_time to first recv time. */
968                if ((session->flags & RTP_SESSION_SEND_NOT_STARTED)
969                || session->mode == RTP_SESSION_RECVONLY){
970                        gettimeofday(&session->last_recv_time, NULL);
971                }
972                if (session->flags & RTP_SESSION_SCHEDULED)
973                {
974                        session->rtp.rcv_time_offset = sched->time_;
975                        //ortp_message("setting snd_time_offset=%i",session->rtp.snd_time_offset);
976                }
977                rtp_session_unset_flag (session,RTP_SESSION_RECV_NOT_STARTED);
978        }else{
979                /*prevent reading from the sockets when two
980                consecutives calls for a same timestamp*/
981                if (user_ts==session->rtp.rcv_last_app_ts)
982                        read_socket=FALSE;
983        }
984        session->rtp.rcv_last_app_ts = user_ts;
985        if (read_socket){
986                rtp_session_rtp_recv (session, user_ts);
987                rtp_session_rtcp_recv(session);
988        }
989        /* check for telephone event first */
990        mp=getq(&session->rtp.tev_rq);
991        if (mp!=NULL){
992                int msgsize=msgdsize(mp);
993                ortp_global_stats.recv += msgsize;
994                stream->stats.recv += msgsize;
995                rtp_signal_table_emit2(&session->on_telephone_event_packet,(long)mp);
996                rtp_session_check_telephone_events(session,mp);
997                freemsg(mp);
998                mp=NULL;
999        }
1000       
1001        /* then now try to return a media packet, if possible */
1002        /* first condition: if the session is starting, don't return anything
1003         * until the queue size reaches jitt_comp */
1004       
1005        if (session->flags & RTP_SESSION_RECV_SYNC)
1006        {
1007                queue_t *q = &session->rtp.rq;
1008                if (qempty(q))
1009                {
1010                        ortp_debug ("Queue is empty.");
1011                        goto end;
1012                }
1013                rtp = (rtp_header_t *) qfirst(q)->b_rptr;
1014                session->rtp.rcv_ts_offset = rtp->timestamp;
1015                session->rtp.rcv_last_ret_ts = user_ts; /* just to have an init value */
1016                session->rcv.ssrc = rtp->ssrc;
1017                /* delete the recv synchronisation flag */
1018                rtp_session_unset_flag (session, RTP_SESSION_RECV_SYNC);
1019        }
1020
1021        /*calculate the stream timestamp from the user timestamp */
1022        ts = jitter_control_get_compensated_timestamp(&session->rtp.jittctl,user_ts);
1023        if (session->rtp.jittctl.enabled==TRUE){
1024                if (session->permissive)
1025                        mp = rtp_getq_permissive(&session->rtp.rq, ts,&rejected);
1026                else{
1027                        mp = rtp_getq(&session->rtp.rq, ts,&rejected);
1028                }
1029        }else mp=getq(&session->rtp.rq);/*no jitter buffer at all*/
1030       
1031        stream->stats.outoftime+=rejected;
1032        ortp_global_stats.outoftime+=rejected;
1033
1034        goto end;
1035
1036      end:
1037        if (mp != NULL)
1038        {
1039                int msgsize = msgdsize (mp);    /* evaluate how much bytes (including header) is received by app */
1040                uint32_t packet_ts;
1041                ortp_global_stats.recv += msgsize;
1042                stream->stats.recv += msgsize;
1043                rtp = (rtp_header_t *) mp->b_rptr;
1044                packet_ts=rtp->timestamp;
1045                ortp_debug("Returning mp with ts=%i", packet_ts);
1046                /* check for payload type changes */
1047                if (session->rcv.pt != rtp->paytype)
1048                {
1049                        payload_type_changed_notify(session, rtp->paytype);
1050                }
1051                /* update the packet's timestamp so that it corrected by the
1052                adaptive jitter buffer mechanism */
1053                if (session->rtp.jittctl.adaptive){
1054                        uint32_t changed_ts;
1055                        /* only update correction offset between packets of different
1056                        timestamps*/
1057                        if (packet_ts!=session->rtp.rcv_last_ts)
1058                                jitter_control_update_corrective_slide(&session->rtp.jittctl);
1059                        changed_ts=packet_ts+session->rtp.jittctl.corrective_slide;
1060                        rtp->timestamp=changed_ts;
1061                        /*ortp_debug("Returned packet has timestamp %u, with clock slide compensated it is %u",packet_ts,rtp->timestamp);*/
1062                }
1063                session->rtp.rcv_last_ts = packet_ts;
1064                if (!(session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED)){
1065                        rtp_session_set_flag(session,RTP_SESSION_FIRST_PACKET_DELIVERED);
1066                }
1067        }
1068        else
1069        {
1070                ortp_debug ("No mp for timestamp queried");
1071                stream->stats.unavaillable++;
1072                ortp_global_stats.unavaillable++;
1073        }
1074        rtp_session_rtcp_process_recv(session);
1075       
1076        if (session->flags & RTP_SESSION_SCHEDULED)
1077        {
1078                /* if we are in blocking mode, then suspend the calling process until timestamp
1079                 * wanted expires */
1080                /* but we must not block the process if the timestamp wanted by the application is older
1081                 * than current time */
1082                packet_time =
1083                        rtp_session_ts_to_time (session,
1084                                     user_ts -
1085                                     session->rtp.rcv_query_ts_offset) +
1086                        session->rtp.rcv_time_offset;
1087                ortp_debug ("rtp_session_recvm_with_ts: packet_time=%i, time=%i",packet_time, sched->time_);
1088                wait_point_lock(&session->rcv.wp);
1089                if (TIME_IS_STRICTLY_NEWER_THAN (packet_time, sched->time_))
1090                {
1091                        wait_point_wakeup_at(&session->rcv.wp,packet_time, (session->flags & RTP_SESSION_BLOCKING_MODE)!=0);
1092                        session_set_clr(&sched->r_sessions,session);
1093                }
1094                else session_set_set(&sched->r_sessions,session);       /*to unblock _select() immediately */
1095                wait_point_unlock(&session->rcv.wp);
1096        }
1097        return mp;
1098}
1099
1100
1101/**
1102 *      NOTE: use of this function is discouraged when sending payloads other than
1103 *      pcm/pcmu/pcma/adpcm types.
1104 *      rtp_session_recvm_with_ts() does better job.
1105 *
1106 *      Tries to read the bytes of the incoming rtp stream related to timestamp ts. In case
1107 *      where the user supplied buffer @buffer is not large enough to get all the data
1108 *      related to timestamp ts, then *( have_more) is set to 1 to indicate that the application
1109 *      should recall the function with the same timestamp to get more data.
1110 *     
1111 *  When the rtp session is scheduled (see rtp_session_set_scheduling_mode() ), and the
1112 *      blocking mode is on (see rtp_session_set_blocking_mode() ), then the calling thread
1113 *      is suspended until the timestamp given as argument expires, whatever a received packet
1114 *      fits the query or not.
1115 *
1116 *      Important note: it is clear that the application cannot know the timestamp of the first
1117 *      packet of the incoming stream, because it can be random. The @ts timestamp given to the
1118 *      function is used relatively to first timestamp of the stream. In simple words, 0 is a good
1119 *      value to start calling this function.
1120 *
1121 *      This function internally calls rtp_session_recvm_with_ts() to get a rtp packet. The content
1122 *      of this packet is then copied into the user supplied buffer in an intelligent manner:
1123 *      the function takes care of the size of the supplied buffer and the timestamp given in 
1124 *      argument. Using this function it is possible to read continous audio data (e.g. pcma,pcmu...)
1125 *      with for example a standart buffer of size of 160 with timestamp incrementing by 160 while the incoming
1126 *      stream has a different packet size.
1127 *
1128 *Returns: if a packet was availlable with the corresponding timestamp supplied in argument
1129 *      then the number of bytes written in the user supplied buffer is returned. If no packets
1130 *      are availlable, either because the sender has not started to send the stream, or either
1131 *      because silence packet are not transmitted, or either because the packet was lost during
1132 *      network transport, then the function returns zero.
1133 *@param session a rtp session.
1134 *@param buffer a user supplied buffer to write the data.
1135 *@param len the length in bytes of the user supplied buffer.
1136 *@param ts the timestamp wanted.
1137 *@param have_more the address of an integer to indicate if more data is availlable for the given timestamp.
1138 *
1139**/
1140int rtp_session_recv_with_ts (RtpSession * session, uint8_t * buffer,
1141                               int len, uint32_t ts, int * have_more){
1142        mblk_t *mp=NULL;
1143        int plen,blen=0;
1144        *have_more=0;
1145        while(1){
1146                if (session->pending){
1147                        mp=session->pending;
1148                        session->pending=NULL;
1149                }else {
1150                        mp=rtp_session_recvm_with_ts(session,ts);
1151                        if (mp!=NULL) rtp_get_payload(mp,&mp->b_rptr);
1152                }
1153                if (mp){
1154                        plen=mp->b_wptr-mp->b_rptr;
1155                        if (plen<=len){
1156                                memcpy(buffer,mp->b_rptr,plen);
1157                                buffer+=plen;
1158                                blen+=plen;
1159                                len-=plen;
1160                                freemsg(mp);
1161                                mp=NULL;
1162                        }else{
1163                                memcpy(buffer,mp->b_rptr,len);
1164                                mp->b_rptr+=len;
1165                                buffer+=len;
1166                                blen+=len;
1167                                len=0;
1168                                session->pending=mp;
1169                                *have_more=1;
1170                                break;
1171                        }
1172                }else break;
1173        }
1174        return blen;
1175}
1176/**
1177 *      When the rtp session is scheduled and has started to send packets, this function
1178 *      computes the timestamp that matches to the present time. Using this function can be
1179 *      usefull when sending discontinuous streams. Some time can be elapsed between the end
1180 *      of a stream burst and the begin of a new stream burst, and the application may be not
1181 *      not aware of this elapsed time. In order to get a valid (current) timestamp to pass to
1182 *      #rtp_session_send_with_ts() or #rtp_session_sendm_with_ts(), the application may
1183 *      use rtp_session_get_current_send_ts().
1184 *
1185 * @param session a rtp session.
1186 * @return the current send timestamp for the rtp session.
1187**/
1188uint32_t rtp_session_get_current_send_ts(RtpSession *session)
1189{
1190        uint32_t userts;
1191        uint32_t session_time;
1192        RtpScheduler *sched=session->sched;
1193        PayloadType *payload;
1194        payload=rtp_profile_get_payload(session->snd.profile,session->snd.pt);
1195        return_val_if_fail(payload!=NULL, 0);
1196        if ( (session->flags & RTP_SESSION_SCHEDULED)==0 ){
1197                ortp_warning("can't guess current timestamp because session is not scheduled.");
1198                return 0;
1199        }
1200        session_time=sched->time_-session->rtp.snd_time_offset;
1201        userts=  (uint32_t)( ( (double)(session_time) * (double) payload->clock_rate )/ 1000.0)
1202                                + session->rtp.snd_ts_offset;
1203        return userts;
1204}
1205
1206/**
1207 * Same thing as rtp_session_get_current_send_ts() except that it's for an incoming stream.
1208 * Works only on scheduled mode.
1209 *
1210 * @param session a rtp session.
1211 * @return the theoritical that would have to be receive now.
1212 *
1213**/
1214uint32_t rtp_session_get_current_recv_ts(RtpSession *session){
1215        uint32_t userts;
1216        uint32_t session_time;
1217        RtpScheduler *sched=ortp_get_scheduler();
1218        PayloadType *payload;
1219        payload=rtp_profile_get_payload(session->rcv.profile,session->rcv.pt);
1220        return_val_if_fail(payload!=NULL, 0);
1221        if ( (session->flags & RTP_SESSION_SCHEDULED)==0 ){
1222                ortp_warning("can't guess current timestamp because session is not scheduled.");
1223                return 0;
1224        }
1225        session_time=sched->time_-session->rtp.rcv_time_offset;
1226        userts=  (uint32_t)( ( (double)(session_time) * (double) payload->clock_rate )/ 1000.0)
1227                                + session->rtp.rcv_ts_offset;
1228        return userts;
1229}
1230
1231/**
1232 * oRTP has the possibility to inform the application through a callback registered
1233 * with rtp_session_signal_connect about crazy incoming RTP stream that jumps from
1234 * a timestamp N to N+some_crazy_value. This lets the opportunity for the application
1235 * to reset the session in order to resynchronize, or any other action like stopping the call
1236 * and reporting an error.
1237 * @param session the rtp session
1238 * @param ts_step a time interval in miliseconds
1239 *
1240**/
1241void rtp_session_set_time_jump_limit(RtpSession *session, int milisecs){
1242        uint32_t ts;
1243        session->rtp.time_jump=milisecs;
1244        ts=rtp_session_time_to_ts(session,milisecs);
1245        if (ts==0) session->rtp.ts_jump=1<<31;  /* do not detect ts jump */
1246        else session->rtp.ts_jump=ts;
1247}
1248
1249/**
1250 * Closes the rtp and rtcp sockets.
1251**/
1252void rtp_session_release_sockets(RtpSession *session){
1253        if (session->rtp.socket>=0) close_socket (session->rtp.socket);
1254        if (session->rtcp.socket>=0) close_socket (session->rtcp.socket);
1255        session->rtp.socket=-1;
1256        session->rtcp.socket=-1;
1257        if (session->rtp.tr!=NULL)
1258          ortp_free(session->rtp.tr);
1259        if (session->rtcp.tr!=NULL)
1260          ortp_free(session->rtcp.tr);
1261        session->rtp.tr = 0;
1262        session->rtcp.tr = 0;
1263
1264        /* don't discard remote addresses, then can be preserved for next use.
1265        session->rtp.rem_addrlen=0;
1266        session->rtcp.rem_addrlen=0;
1267        */
1268}
1269
1270ortp_socket_t rtp_session_get_rtp_socket(const RtpSession *session){
1271        return rtp_session_using_transport(session, rtp) ? (session->rtp.tr->t_getsocket)(session->rtp.tr) : session->rtp.socket;
1272}
1273
1274ortp_socket_t rtp_session_get_rtcp_socket(const RtpSession *session){
1275        return rtp_session_using_transport(session, rtcp) ? (session->rtcp.tr->t_getsocket)(session->rtcp.tr) : session->rtcp.socket;
1276}
1277
1278/**
1279 * Register an event queue.
1280 * An application can use an event queue to get informed about various RTP events.
1281**/
1282void rtp_session_register_event_queue(RtpSession *session, OrtpEvQueue *q){
1283        session->eventqs=o_list_append(session->eventqs,q);
1284}
1285
1286void rtp_session_unregister_event_queue(RtpSession *session, OrtpEvQueue *q){
1287        session->eventqs=o_list_remove(session->eventqs,q);
1288}
1289
1290void rtp_session_dispatch_event(RtpSession *session, OrtpEvent *ev){
1291        OList *it;
1292        int i;
1293        for(i=0,it=session->eventqs;it!=NULL;it=it->next,++i){
1294                ortp_ev_queue_put((OrtpEvQueue*)it->data,ortp_event_dup(ev));
1295        }       
1296        ortp_event_destroy(ev);
1297}
1298
1299
1300void rtp_session_uninit (RtpSession * session)
1301{
1302        /* first of all remove the session from the scheduler */
1303        if (session->flags & RTP_SESSION_SCHEDULED)
1304        {
1305                rtp_scheduler_remove_session (session->sched,session);
1306        }
1307        /*flush all queues */
1308        flushq(&session->rtp.rq, FLUSHALL);
1309        flushq(&session->rtp.tev_rq, FLUSHALL);
1310
1311        if (session->eventqs!=NULL) o_list_free(session->eventqs);
1312        /* close sockets */
1313        rtp_session_release_sockets(session);
1314
1315        wait_point_uninit(&session->snd.wp);
1316        wait_point_uninit(&session->rcv.wp);
1317        if (session->current_tev!=NULL) freemsg(session->current_tev);
1318        if (session->rtp.cached_mp!=NULL) freemsg(session->rtp.cached_mp);
1319        if (session->rtcp.cached_mp!=NULL) freemsg(session->rtcp.cached_mp);
1320        if (session->sd!=NULL) freemsg(session->sd);
1321
1322        session->signal_tables = o_list_free(session->signal_tables);
1323        msgb_allocator_uninit(&session->allocator);
1324}
1325
1326/**
1327 * Resynchronize to the incoming RTP streams.
1328 * This can be useful to handle discoutinuous timestamps.
1329 * For example, call this function from the timestamp_jump signal handler.
1330 * @param session the rtp session
1331**/
1332void rtp_session_resync(RtpSession *session){
1333        flushq (&session->rtp.rq, FLUSHALL);
1334        rtp_session_set_flag(session, RTP_SESSION_RECV_SYNC);
1335        rtp_session_unset_flag(session,RTP_SESSION_FIRST_PACKET_DELIVERED);
1336        jitter_control_init(&session->rtp.jittctl,-1,NULL);
1337}
1338
1339/**
1340 * Reset the session: local and remote addresses are kept. It resets timestamp, sequence
1341 * number, and calls rtp_session_resync().
1342 *
1343 * @param session a rtp session.
1344**/
1345void rtp_session_reset (RtpSession * session)
1346{
1347        rtp_session_set_flag (session, RTP_SESSION_RECV_NOT_STARTED);
1348        rtp_session_set_flag (session, RTP_SESSION_SEND_NOT_STARTED);
1349        //session->ssrc=0;
1350        session->rtp.snd_time_offset = 0;
1351        session->rtp.snd_ts_offset = 0;
1352        session->rtp.snd_rand_offset = 0;
1353        session->rtp.snd_last_ts = 0;
1354        session->rtp.rcv_time_offset = 0;
1355        session->rtp.rcv_ts_offset = 0;
1356        session->rtp.rcv_query_ts_offset = 0;
1357        session->rtp.rcv_last_ts = 0;
1358        session->rtp.rcv_last_app_ts = 0;
1359        session->rtp.hwrcv_extseq = 0;
1360        session->rtp.hwrcv_since_last_SR=0;
1361        session->rtp.snd_seq = 0;
1362        session->rtp.sent_payload_bytes=0;
1363        rtp_session_clear_send_error_code(session);
1364        rtp_session_clear_recv_error_code(session);
1365        rtp_stats_reset(&session->rtp.stats);
1366        rtp_session_resync(session);
1367        session->ssrc_set=FALSE;
1368}
1369
1370/**
1371 * Retrieve the session's statistics.
1372**/
1373const rtp_stats_t * rtp_session_get_stats(const RtpSession *session){
1374        return &session->rtp.stats;
1375}
1376
1377void rtp_session_reset_stats(RtpSession *session){
1378        memset(&session->rtp.stats,0,sizeof(rtp_stats_t));
1379}
1380
1381/**
1382 * Stores some application specific data into the session, so that it is easy to retrieve it from the signal callbacks using rtp_session_get_data().
1383 * @param session a rtp session
1384 * @param data an opaque pointer to be stored in the session
1385**/
1386
1387void rtp_session_set_data(RtpSession *session, void *data){
1388        session->user_data=data;
1389}
1390
1391/**
1392 * @param session a rtp session
1393 * @return the void pointer previously set using rtp_session_set_data()
1394**/
1395void *rtp_session_get_data(const RtpSession *session){
1396        return session->user_data;
1397}
1398
1399/**
1400 * Enable or disable the "rtp symmetric" hack which consists of the following:
1401 * after the first packet is received, the source address of the packet
1402 * is set to be the destination address for all next packets.
1403 * This is useful to pass-through firewalls.
1404 * @param session a rtp session
1405 * @param yesno a boolean to enable or disable the feature
1406 *
1407**/
1408void
1409rtp_session_set_symmetric_rtp (RtpSession * session, bool_t yesno)
1410{
1411        session->symmetric_rtp =yesno;
1412}
1413
1414/**
1415 *      If yesno is TRUE, thus a connect() syscall is done on the socket to
1416 *      the destination address set by rtp_session_set_remote_addr(), or
1417 *      if the session does symmetric rtp (see rtp_session_set_symmetric_rtp())
1418 *      a the connect() is done to the source address of the first packet received.
1419 *      Connecting a socket has effect of rejecting all incoming packets that
1420 *      don't come from the address specified in connect().
1421 *      It also makes ICMP errors (such as connection refused) available to the
1422 *      application.
1423 *      @param session a rtp session
1424 *      @param yesno a boolean to enable or disable the feature
1425 *
1426**/
1427void rtp_session_set_connected_mode(RtpSession *session, bool_t yesno){
1428        session->use_connect=yesno;
1429}
1430
1431static float compute_bw(struct timeval *orig, unsigned int bytes){
1432        struct timeval current;
1433        float bw;
1434        float time;
1435        if (bytes==0) return 0;
1436        gettimeofday(&current,NULL);
1437        time=(float)(current.tv_sec - orig->tv_sec) +
1438                ((float)(current.tv_usec - orig->tv_usec)*1e-6);
1439        bw=((float)bytes)*8/(time+0.001); 
1440        /*+0.0001 avoids a division by zero without changing the results significatively*/
1441        return bw;
1442}
1443
1444float rtp_session_compute_recv_bandwidth(RtpSession *session){
1445        float bw;
1446        bw=compute_bw(&session->rtp.recv_bw_start,session->rtp.recv_bytes);
1447        session->rtp.recv_bytes=0;
1448        return bw;
1449}
1450
1451float rtp_session_compute_send_bandwidth(RtpSession *session){
1452        float bw;
1453        bw=compute_bw(&session->rtp.send_bw_start,session->rtp.sent_bytes);
1454        session->rtp.sent_bytes=0;
1455        return bw;
1456}
1457
1458int rtp_session_get_last_send_error_code(RtpSession *session){
1459        return session->rtp.send_errno;
1460}
1461
1462void rtp_session_clear_send_error_code(RtpSession *session){
1463        session->rtp.send_errno=0;
1464}
1465
1466int rtp_session_get_last_recv_error_code(RtpSession *session){
1467        return session->rtp.recv_errno;
1468}
1469
1470void rtp_session_clear_recv_error_code(RtpSession *session){
1471        session->rtp.send_errno=0;
1472}
1473
1474/**
1475 * Destroys a rtp session.
1476 * All memory allocated for the RtpSession is freed.
1477 *
1478 * @param session a rtp session.
1479**/
1480void rtp_session_destroy (RtpSession * session)
1481{
1482        rtp_session_uninit (session);
1483        ortp_free (session);
1484}
1485
1486void rtp_session_make_time_distorsion(RtpSession *session, int milisec)
1487{
1488        session->rtp.snd_time_offset+=milisec;
1489}
1490
1491
1492/* packet api */
1493
1494void rtp_add_csrc(mblk_t *mp, uint32_t csrc)
1495{
1496        rtp_header_t *hdr=(rtp_header_t*)mp->b_rptr;
1497        hdr->csrc[hdr->cc]=csrc;
1498        hdr->cc++;
1499}
1500
1501/**
1502 * Get a pointer to the beginning of the payload data of the RTP packet.
1503 * @param packet a RTP packet represented as a mblk_t
1504 * @param start a pointer to the beginning of the payload data, pointing inside the packet.
1505 * @return the length of the payload data.
1506**/
1507int rtp_get_payload(mblk_t *packet, unsigned char **start){
1508        unsigned char *tmp;
1509        int header_len=RTP_FIXED_HEADER_SIZE+(rtp_get_cc(packet)*4);
1510        tmp=packet->b_rptr+header_len;
1511        if (tmp>packet->b_wptr){
1512                if (packet->b_cont!=NULL){
1513                        tmp=packet->b_cont->b_rptr+(header_len- (packet->b_wptr-packet->b_rptr));
1514                        if (tmp<=packet->b_cont->b_wptr){
1515                                *start=tmp;
1516                                return packet->b_cont->b_wptr-tmp;
1517                        }
1518                }
1519                ortp_warning("Invalid RTP packet");
1520                return -1;
1521        }
1522        *start=tmp;
1523        return packet->b_wptr-tmp;
1524}
1525
1526
1527/**
1528 *  Gets last time a valid RTP or RTCP packet was received.
1529 * @param session RtpSession to get last receive time from.
1530 * @param tv Pointer to struct timeval to fill.
1531 *
1532**/
1533void
1534rtp_session_get_last_recv_time(RtpSession *session, struct timeval *tv)
1535{
1536#ifdef PERF
1537        ortp_error("rtp_session_get_last_recv_time() feature disabled.");
1538#else
1539        *tv = session->last_recv_time;
1540#endif
1541}
1542
1543
1544
1545uint32_t rtp_session_time_to_ts(RtpSession *session, int millisecs){
1546        PayloadType *payload;
1547        payload =
1548                rtp_profile_get_payload (session->snd.profile,
1549                                         session->snd.pt);
1550        if (payload == NULL)
1551        {
1552                ortp_warning
1553                        ("rtp_session_ts_to_t: use of unsupported payload type %d.", session->snd.pt);
1554                return 0;
1555        }
1556        /* the return value is in milisecond */
1557        return (uint32_t) (payload->clock_rate*(double) (millisecs/1000.0f));
1558}
1559
1560/* function used by the scheduler only:*/
1561uint32_t rtp_session_ts_to_time (RtpSession * session, uint32_t timestamp)
1562{
1563        PayloadType *payload;
1564        payload =
1565                rtp_profile_get_payload (session->snd.profile,
1566                                         session->snd.pt);
1567        if (payload == NULL)
1568        {
1569                ortp_warning
1570                        ("rtp_session_ts_to_t: use of unsupported payload type %d.", session->snd.pt);
1571                return 0;
1572        }
1573        /* the return value is in milisecond */
1574        return (uint32_t) (1000.0 *
1575                          ((double) timestamp /
1576                           (double) payload->clock_rate));
1577}
1578
1579
1580/* time is the number of miliseconds elapsed since the start of the scheduler */
1581void rtp_session_process (RtpSession * session, uint32_t time, RtpScheduler *sched)
1582{
1583        wait_point_lock(&session->snd.wp);
1584        if (wait_point_check(&session->snd.wp,time)){
1585                session_set_set(&sched->w_sessions,session);
1586                wait_point_wakeup(&session->snd.wp);
1587        }
1588        wait_point_unlock(&session->snd.wp);
1589       
1590        wait_point_lock(&session->rcv.wp);
1591        if (wait_point_check(&session->rcv.wp,time)){
1592                session_set_set(&sched->r_sessions,session);
1593                wait_point_wakeup(&session->rcv.wp);
1594        }
1595        wait_point_unlock(&session->rcv.wp);
1596}
1597
Note: See TracBrowser for help on using the repository browser.