rtpsession.c
来自「linphone源码-1.3.5.tar.gz,linphone源码-1.3.5」· C语言 代码 · 共 1,957 行 · 第 1/4 页
C
1,957 行
/* The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include "ortp/ortp.h"#include "ortp/telephonyevents.h"#include "rtpmod.h"#include "jitterctl.h"#include "scheduler.h"#include "utils.h"#include "ortp-config.h"#if defined(HAVE_POLL_H)#include <poll.h>#elif defined(HAVE_SYS_POLL_H)#include <sys/poll.h>#endif#ifdef HAVE_SYS_UIO_H#include <sys/uio.h>#define USE_SENDMSG 1#endif/* this function initialize all session parameter's that depend on the payload type */static void payload_type_changed(RtpSession *session, PayloadType *pt){ jitter_control_set_payload(&session->rtp.jittctl,pt); session->rtp.rtcp_report_snt_interval=RTCP_DEFAULT_REPORT_INTERVAL*pt->clock_rate; rtp_session_set_time_jump_limit(session,session->rtp.time_jump);}void wait_point_init(WaitPoint *wp){ ortp_mutex_init(&wp->lock,NULL); ortp_cond_init(&wp->cond,NULL); wp->time=0; wp->wakeup=FALSE;}void wait_point_uninit(WaitPoint *wp){ ortp_cond_destroy(&wp->cond); ortp_mutex_destroy(&wp->lock);}#define wait_point_lock(wp) ortp_mutex_lock(&(wp)->lock)#define wait_point_unlock(wp) ortp_mutex_unlock(&(wp)->lock)void wait_point_wakeup_at(WaitPoint *wp, uint32_t t, bool_t dosleep){ wp->time=t; wp->wakeup=TRUE; if (dosleep) ortp_cond_wait(&wp->cond,&wp->lock);}bool_t wait_point_check(WaitPoint *wp, uint32_t t){ bool_t ok=FALSE; if (wp->wakeup){ if (TIME_IS_NEWER_THAN(t,wp->time)){ wp->wakeup=FALSE; ok=TRUE; } } return ok;}#define wait_point_wakeup(wp) ortp_cond_signal(&(wp)->cond);extern void rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts);static uint32_t uint32_t_random(){ return random();}voidrtp_session_init (RtpSession * session, int mode){ memset (session, 0, sizeof (RtpSession)); ortp_mutex_init(&session->lock,NULL); session->rtp.max_rq_size = 100;/* maximum number of packet allowed to be queued */ session->mode = (RtpSessionMode) mode; if ((mode == RTP_SESSION_RECVONLY) || (mode == RTP_SESSION_SENDRECV)) { rtp_session_set_flag (session, RTP_SESSION_RECV_SYNC); rtp_session_set_flag (session, RTP_SESSION_RECV_NOT_STARTED); } if ((mode == RTP_SESSION_SENDONLY) || (mode == RTP_SESSION_SENDRECV)) { rtp_session_set_flag (session, RTP_SESSION_SEND_NOT_STARTED); rtp_session_set_flag (session, RTP_SESSION_SEND_SYNC); session->send_ssrc=uint32_t_random(); /* set default source description */ rtp_session_set_source_description(session,"unknown@unknown",NULL,NULL, NULL,NULL,"oRTP-" ORTP_VERSION,"This is free sofware (LGPL) !"); } session->telephone_events_pt=-1; /* not defined a priori */ rtp_session_set_profile (session, &av_profile); /*the default profile to work with */ session->rtp.socket=-1; session->rtcp.socket=-1; qinit(&session->rtp.rq); qinit(&session->rtp.tev_rq); qinit(&session->contributing_sources); /* init signal tables */ rtp_signal_table_init (&session->on_ssrc_changed, session,"ssrc_changed"); rtp_signal_table_init (&session->on_payload_type_changed, session,"payload_type_changed"); rtp_signal_table_init (&session->on_telephone_event, session,"telephone-event"); rtp_signal_table_init (&session->on_telephone_event_packet, session,"telephone-event_packet"); rtp_signal_table_init (&session->on_timestamp_jump,session,"timestamp_jump"); rtp_signal_table_init (&session->on_network_error,session,"network_error"); rtp_signal_table_init (&session->on_rtcp_bye,session,"rtcp_bye"); wait_point_init(&session->send_wp); wait_point_init(&session->recv_wp); /*defaults send payload type to 0 (pcmu)*/ rtp_session_set_send_payload_type(session,0); /*sets supposed recv payload type to undefined */ rtp_session_set_recv_payload_type(session,-1); rtp_session_set_jitter_compensation(session,RTP_DEFAULT_JITTER_TIME); rtp_session_enable_adaptive_jitter_compensation(session,FALSE); rtp_session_set_time_jump_limit(session,5000); session->recv_buf_size = UDP_MAX_SIZE; session->symmetric_rtp = 0;}/** *rtp_session_new: *@mode: One of the #RtpSessionMode flags. * * Creates a new rtp session. * If the session is able to send data (RTP_SESSION_SENDONLY or RTP_SESSION_SENDRECV), then a * random SSRC number is choosed for the outgoing stream. * *Returns: the newly created rtp session.**/RtpSession *rtp_session_new (int mode){ RtpSession *session; session = (RtpSession *) ortp_malloc (sizeof (RtpSession)); rtp_session_init (session, mode); return session;}/** *rtp_session_set_scheduling_mode: *@session: a rtp session. *@yesno: a boolean to indicate the scheduling mode. * * Sets the scheduling mode of the rtp session. If @yesno is TRUE, the rtp session is in * the scheduled mode, that means that you can use session_set_select() to block until it's time * to receive or send on this session according to the timestamp passed to the respective functions. * You can also use blocking mode (see rtp_session_set_blocking_mode() ), to simply block within * the receive and send functions. * If @yesno is FALSE, the ortp scheduler will not manage those sessions, meaning that blocking mode * and the use of session_set_select() for this session are disabled. ***/voidrtp_session_set_scheduling_mode (RtpSession * session, int yesno){ if (yesno) { RtpScheduler *sched; sched = ortp_get_scheduler (); if (sched != NULL) { rtp_session_set_flag (session, RTP_SESSION_SCHEDULED); session->sched = sched; rtp_scheduler_add_session (sched, session); } else ortp_warning ("rtp_session_set_scheduling_mode: Cannot use scheduled mode because the " "scheduler is not started. Use ortp_scheduler_init() before."); } else rtp_session_unset_flag (session, RTP_SESSION_SCHEDULED);}/** *rtp_session_set_blocking_mode: *@session: a rtp session *@yesno: a boolean * * Using this function implies that you previously enabled scheduled mode on the session * (see rtp_session_set_scheduling_mode() ). * rtp_session_set_blocking_mode() defines the behaviour of the rtp_session_recv_with_ts() and * rtp_session_send_with_ts() functions. If @yesno is TRUE, rtp_session_recv_with_ts() * will block until it is time for the packet to be received, according to the timestamp * passed to the function. After this time, the function returns. * For rtp_session_send_with_ts(), it will block until it is time for the packet to be sent. * If @yesno is FALSE, then the two functions will return immediately. ***/voidrtp_session_set_blocking_mode (RtpSession * session, int yesno){ if (yesno) rtp_session_set_flag (session, RTP_SESSION_BLOCKING_MODE); else rtp_session_unset_flag (session, RTP_SESSION_BLOCKING_MODE);}/** *rtp_session_set_profile: *@session: a rtp session *@profile: a rtp profile * * Set the RTP profile to be used for the session. By default, all session are created by * rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application * can set any other profile instead using that function. * ***/voidrtp_session_set_profile (RtpSession * session, RtpProfile * profile){ session->profile = profile; rtp_session_telephone_events_supported(session);}/** *rtp_session_get_profile: *@session: a rtp session * * Returns current profile. ***/RtpProfile *rtp_session_get_profile(RtpSession *session){ return session->profile;}/** *rtp_session_set_recv_buf_size: *@session: a rtp session *@bufsize: buffer size in bytes for receiving packets * * The default value is 65535 bytes, a big value which is working for everyone. * However if your application can make assumption on the MTU, it can be interesting * to set it to a lower value in order to save memory. ***/void rtp_session_set_recv_buf_size(RtpSession *session, int bufsize){ session->recv_buf_size=bufsize;}/** *rtp_session_signal_connect: *@session: a rtp session *@signal: the name of a signal *@cb: a #RtpCallback *@user_data: a pointer to any data to be passed when invoking the callback. * * This function provides the way for an application to be informed of various events that * may occur during a rtp session. @signal is a string identifying the event, and @cb is * a user supplied function in charge of processing it. The application can register * several callbacks for the same signal, in the limit of #RTP_CALLBACK_TABLE_MAX_ENTRIES. * Here are name and meaning of supported signals types: * * "ssrc_changed" : the SSRC of the incoming stream has changed. * * "payload_type_changed" : the payload type of the incoming stream has changed. * * "telephone-event_packet" : a telephone-event rtp packet (RFC2833) is received. * * "telephone-event" : a telephone event has occured. This is a high-level shortcut for "telephone-event_packet". * * "network_error" : a network error happened on a socket. Arguments of the callback functions are * a const char * explaining the error, an int errno error code and the user_data as usual. * * "timestamp_jump" : we have received a packet with timestamp in far future compared to last timestamp received. * The farness of far future is set by rtp_sesssion_set_time_jump_limit() * "rtcp_bye": we have received a RTCP bye packet. Arguments of the callback * functions are a const char * containing the leaving reason and * the user_data. * * Returns: 0 on success, -EOPNOTSUPP if the signal does not exists, -1 if no more callbacks * can be assigned to the signal type.**/intrtp_session_signal_connect (RtpSession * session, const char *signal, RtpCallback cb, unsigned long user_data){ OList *elem; for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){ RtpSignalTable *s=(RtpSignalTable*) elem->data; if (strcmp(signal,s->signal_name)==0){ return rtp_signal_table_add(s,cb,user_data); } } ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal); return -1;}/** *rtp_session_signal_disconnect_by_callback: *@session: a rtp session *@signal: a signal name *@cb: a callback function. * * Removes callback function @cb to the list of callbacks for signal @signal. * *Returns: 0 on success, -ENOENT if the callbacks was not found.**/intrtp_session_signal_disconnect_by_callback (RtpSession * session, const char *signal, RtpCallback cb){ OList *elem; for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){ RtpSignalTable *s=(RtpSignalTable*) elem->data; if (strcmp(signal,s->signal_name)==0){ return rtp_signal_table_remove_by_callback(s,cb); } } ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal); return -1;}static ortp_socket_t create_and_bind(const char *addr, int port, int *sock_family){ int err; int optval = 1; ortp_socket_t sock=-1;#ifdef ORTP_INET6 char num[8]; struct addrinfo hints, *res0, *res;#else struct sockaddr_in saddr;#endif #ifdef ORTP_INET6 memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; snprintf(num, sizeof(num), "%d",port); err = getaddrinfo(addr,num, &hints, &res0); if (err!=0) { ortp_warning ("Error: %s", gai_strerror(err)); return -1; } for (res = res0; res; res = res->ai_next) { sock = socket(res->ai_family, res->ai_socktype, 0); if (sock < 0) continue; err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&optval, sizeof (optval)); if (err < 0) { ortp_warning ("Fail to set rtp address reusable: %s.", getSocketError()); } *sock_family=res->ai_family; err = bind (sock, res->ai_addr, res->ai_addrlen); if (err != 0) { ortp_warning ("Fail to bind rtp socket to %s:%i : %s.", addr,port, getSocketError()); close_socket (sock); sock=-1; continue; }#ifndef __hpux switch (res->ai_family) { case AF_INET: if (IN_MULTICAST(ntohl(((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr))) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr; mreq.imr_interface.s_addr = INADDR_ANY; err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (SOCKET_OPTION_VALUE) &mreq, sizeof(mreq)); if (err < 0) { ortp_warning ("Fail to join address group: %s.", getSocketError()); close_socket (sock); sock=-1; continue; } } break; case AF_INET6: if (IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr))) { struct ipv6_mreq mreq; mreq.ipv6mr_multiaddr = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; mreq.ipv6mr_interface = 0; err = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (SOCKET_OPTION_VALUE)&mreq, sizeof(mreq)); if (err < 0) { ortp_warning ("Fail to join address group: %s.", getSocketError()); close_socket (sock); sock=-1; continue; } } break; }#endif /*hpux*/ break; } freeaddrinfo(res0);#else saddr.sin_family = AF_INET; *sock_family=AF_INET; err = inet_aton (addr, &saddr.sin_addr); if (err < 0) { ortp_warning ("Error in socket address:%s.", getSocketError()); return err; } saddr.sin_port = htons (port); sock = socket (PF_INET, SOCK_DGRAM, 0); if (sock<0) return -1; err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&optval, sizeof (optval)); if (err < 0) { ortp_warning ("Fail to set rtp address reusable: %s.",getSocketError()); } err = bind (sock, (struct sockaddr *) &saddr, sizeof (saddr)); if (err != 0) { ortp_warning ("Fail to bind rtp socket to port %i: %s.", port, getSocketError()); close_socket (sock); return -1; }#endif if (sock>=0) set_non_blocking_socket (sock); return sock;}static ortp_socket_t create_and_bind_random(const char *localip, int *sock_family, int *port){ int retry; ortp_socket_t sock = -1; for (retry=0;retry<100;retry++) { int localport; do { localport = (rand () + 5000) & 0xfffe; } while ((localport < 5000) || (localport > 0xffff)); sock = create_and_bind(localip, localport, sock_family); if (sock>=0) { *port=localport; return sock; } } ortp_warning("create_and_bind_random: Could not find a random port for %s !",localip); return -1;}/** *rtp_session_set_local_addr: *@session: a rtp session freshly created. *@addr: a local IP address in the xxx.xxx.xxx.xxx form. *@port: a local port or -1 to let oRTP choose the port randomly
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?