rtpsession.c
来自「linphone源码-1.3.5.tar.gz,linphone源码-1.3.5」· C语言 代码 · 共 1,957 行 · 第 1/4 页
C
1,957 行
* * Specify the local addr to be use to listen for rtp packets or to send rtp packet from. * In case where the rtp session is send-only, then it is not required to call this function: * when calling rtp_session_set_remote_addr(), if no local address has been set, then the * default INADRR_ANY (0.0.0.0) IP address with a random port will be used. Calling * rtp_sesession_set_local_addr() is mandatory when the session is recv-only or duplex. * * Returns: 0 on success.**/intrtp_session_set_local_addr (RtpSession * session, const char * addr, int port){ ortp_socket_t sock; int sockfamily; if (session->rtp.socket>=0){ /* don't rebind, but close before*/ rtp_session_release_sockets(session); } /* try to bind the rtp port */ if (port>0) sock=create_and_bind(addr,port,&sockfamily); else sock=create_and_bind_random(addr,&sockfamily,&port); if (sock>=0){ session->rtp.sockfamily=sockfamily; session->rtp.socket=sock; session->rtp.loc_port=port; /*try to bind rtcp port */ sock=create_and_bind(addr,port+1,&sockfamily); if (sock>=0){ session->rtcp.sockfamily=sockfamily; session->rtcp.socket=sock; }else{ ortp_warning("Could not create and bind rtcp socket."); } return 0; } return -1;}/** *rtp_session_get_local_port: *@session: a rtp session for which rtp_session_set_local_addr() or rtp_session_set_remote_addr() has been called * * This function can be useful to retrieve the local port that was randomly choosen by * rtp_session_set_remote_addr() when rtp_session_set_local_addr() was not called. * * Returns: the local port used to listen for rtp packets, -1 if not set.**/int rtp_session_get_local_port(const RtpSession *session){ return (session->rtp.loc_port>0) ? session->rtp.loc_port : -1;}static char * ortp_inet_ntoa(struct sockaddr *addr, int addrlen, char *dest, int destlen){#ifdef ORTP_INET6 int err; dest[0]=0; err=getnameinfo(addr,addrlen,dest,destlen,NULL,0,NI_NUMERICHOST); if (err!=0){ ortp_warning("getnameinfo error: %s",gai_strerror(err)); }#else char *tmp=inet_ntoa(((struct sockaddr_in*)addr)->sin_addr); strncpy(dest,tmp,destlen); dest[destlen-1]='\0';#endif return dest;}/** *rtp_session_set_remote_addr: *@session: a rtp session freshly created. *@addr: a local IP address in the xxx.xxx.xxx.xxx form. *@port: a local port. * * Sets the remote address of the rtp session, ie the destination address where rtp packet * are sent. If the session is recv-only or duplex, it also sets the origin of incoming RTP * packets. Rtp packets that don't come from addr:port are discarded. * * Returns: 0 on success.**/intrtp_session_set_remote_addr (RtpSession * session, const char * addr, int port){ int err;#ifdef ORTP_INET6 struct addrinfo hints, *res0, *res; char num[8]; 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) { ortp_warning ("Error in socket address: %s", gai_strerror(err)); return -1; }#endif if (session->rtp.socket == -1){ /* the session has not its socket bound, do it */ ortp_message ("Setting random local addresses.");#ifdef ORTP_INET6 /* bind to an address type that matches the destination address */ if (res0->ai_addr->sa_family==AF_INET6) err = rtp_session_set_local_addr (session, "::", -1); else err=rtp_session_set_local_addr (session, "0.0.0.0", -1);#else err = rtp_session_set_local_addr (session, "0.0.0.0", -1);#endif if (err<0) return -1; }#ifdef ORTP_INET6 err=1; for (res = res0; res; res = res->ai_next) { /* set a destination address that has the same type as the local address */ if (res->ai_family==session->rtp.sockfamily ) { memcpy( &session->rtp.rem_addr, res->ai_addr, res->ai_addrlen); session->rtp.rem_addrlen=res->ai_addrlen; err=0; break; } } freeaddrinfo(res0); if (err) { ortp_warning("Could not set destination for RTP socket to %s:%i.",addr,port); return -1; } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; snprintf(num, sizeof(num), "%d", (port + 1)); err = getaddrinfo(addr, num, &hints, &res0); if (err) { ortp_warning ("Error: %s", gai_strerror(err)); return err; } err=1; for (res = res0; res; res = res->ai_next) { /* set a destination address that has the same type as the local address */ if (res->ai_family==session->rtp.sockfamily ) { err=0; memcpy( &session->rtcp.rem_addr, res->ai_addr, res->ai_addrlen); session->rtcp.rem_addrlen=res->ai_addrlen; break; } } freeaddrinfo(res0); if (err) { ortp_warning("Could not set destination for RCTP socket to %s:%i.",addr,port+1); return -1; }#else session->rtp.rem_addrlen=sizeof(session->rtp.rem_addr); session->rtp.rem_addr.sin_family = AF_INET; err = inet_aton (addr, &session->rtp.rem_addr.sin_addr); if (err < 0) { ortp_warning ("Error in socket address:%s.", getSocketError()); return err; } session->rtp.rem_addr.sin_port = htons (port); memcpy (&session->rtcp.rem_addr, &session->rtp.rem_addr, sizeof (struct sockaddr_in)); session->rtcp.rem_addr.sin_port = htons (port + 1); session->rtcp.rem_addrlen=sizeof(session->rtp.rem_addr);#endif return 0;}void rtp_session_set_sockets(RtpSession *session, int rtpfd, int rtcpfd){ if (rtpfd>=0) set_non_blocking_socket(rtpfd); if (rtcpfd>=0) set_non_blocking_socket(rtcpfd); session->rtp.socket=rtpfd; session->rtcp.socket=rtcpfd; session->flags|=RTP_SESSION_USING_EXT_SOCKETS;}/** *rtp_session_flush_sockets: *@session: a rtp session * * Flushes the sockets for all pending incoming packets. * This can be usefull if you did not listen to the stream for a while * and wishes to start to receive again. During the time no receive is made * packets get bufferised into the internal kernel socket structure. ***/void rtp_session_flush_sockets(RtpSession *session){ char trash[4096];#ifdef ORTP_INET6 struct sockaddr_storage from;#else struct sockaddr from;#endif socklen_t fromlen=sizeof(from); if (session->rtp.socket>=0){ while (recvfrom(session->rtp.socket,trash,sizeof(trash),0,(struct sockaddr *)&from,&fromlen)>0){}; } if (session->rtcp.socket>=0){ while (recvfrom(session->rtcp.socket,trash,sizeof(trash),0,(struct sockaddr*)&from,&fromlen)>0){}; }}/** *rtp_session_set_seq_number: *@session: a rtp session freshly created. *@addr: a 16 bit unsigned number. * * sets the initial sequence number of a sending session. ***/void rtp_session_set_seq_number(RtpSession *session, uint16_t seq){ session->rtp.snd_seq=seq;}uint16_t rtp_session_get_seq_number(RtpSession *session){ return session->rtp.snd_seq;}#ifdef USE_SENDMSG #define MAX_IOV 10static int rtp_sendmsg(int sock,mblk_t *m, struct sockaddr *rem_addr, int addr_len){ int error; struct msghdr msg; struct iovec iov[MAX_IOV]; int iovlen; for(iovlen=0; iovlen<MAX_IOV && m!=NULL; m=m->b_cont,iovlen++){ iov[iovlen].iov_base=m->b_rptr; iov[iovlen].iov_len=m->b_wptr-m->b_rptr; } msg.msg_name=(void*)rem_addr; msg.msg_namelen=addr_len; msg.msg_iov=&iov[0]; msg.msg_iovlen=iovlen; msg.msg_control=NULL; msg.msg_controllen=0; msg.msg_flags=0; error=sendmsg(sock,&msg,0); return error;}#endif static intortp_rtp_send (RtpSession * session, mblk_t * m){ int error; int i; rtp_header_t *hdr; hdr = (rtp_header_t *) m->b_rptr; /* perform host to network conversions */ hdr->ssrc = htonl (hdr->ssrc); hdr->timestamp = htonl (hdr->timestamp); hdr->seq_number = htons (hdr->seq_number); for (i = 0; i < hdr->cc; i++) hdr->csrc[i] = htonl (hdr->csrc[i]); #ifdef USE_SENDMSG if (session->flags & RTP_SESSION_USING_EXT_SOCKETS){ error=rtp_sendmsg(session->rtp.socket,m,(struct sockaddr *)NULL,0); }else { error=rtp_sendmsg(session->rtp.socket,m,(struct sockaddr *) &session->rtp.rem_addr, session->rtp.rem_addrlen); }#else if (m->b_cont!=NULL){ msgpullup(m,-1); } if (session->flags & RTP_SESSION_USING_EXT_SOCKETS){ error=send(session->rtp.socket, m->b_rptr, (int) (m->b_wptr - m->b_rptr),0); }else error = sendto (session->rtp.socket, m->b_rptr, (int) (m->b_wptr - m->b_rptr), 0, (struct sockaddr *) &session->rtp.rem_addr, session->rtp.rem_addrlen);#endif if (error < 0){ if (session->on_network_error.count>0){ rtp_signal_table_emit3(&session->on_network_error,(long)"Error sending RTP packet",INT_TO_POINTER(getSocketErrorCode())); }else ortp_warning ("Error sending rtp packet: %s ; socket=%i", getSocketError(), session->rtp.socket); } freemsg (m); return error;}intortp_rtcp_send (RtpSession * session, mblk_t * m){ int error=0; bool_t using_ext_socket=(session->flags & RTP_SESSION_USING_EXT_SOCKETS)!=0; if ( (using_ext_socket && session->rtcp.socket>0 ) || session->rtcp.rem_addrlen>0){ #ifndef USE_SENDMSG if (m->b_cont!=NULL){ msgpullup(m,-1); }#endif if (using_ext_socket && session->rtcp.socket>0 ){#ifdef USE_SENDMSG error=rtp_sendmsg(session->rtcp.socket,m,(struct sockaddr *)NULL,0);#else error=send(session->rtcp.socket, m->b_rptr, (int) (m->b_wptr - m->b_rptr),0);#endif }else {#ifdef USE_SENDMSG error=rtp_sendmsg(session->rtcp.socket,m,(struct sockaddr *) &session->rtcp.rem_addr, session->rtcp.rem_addrlen);#else error = sendto (session->rtcp.socket, m->b_rptr, (int) (m->b_wptr - m->b_rptr), 0, (struct sockaddr *) &session->rtcp.rem_addr, session->rtcp.rem_addrlen);#endif } if (error < 0){ char host[50]; if (session->on_network_error.count>0){ rtp_signal_table_emit3(&session->on_network_error,(long)"Error sending RTCP packet",INT_TO_POINTER(getSocketErrorCode())); }else ortp_warning ("Error sending rtcp packet: %s ; socket=%i; addr=%s", getSocketError(), session->rtcp.socket, ortp_inet_ntoa((struct sockaddr*)&session->rtcp.rem_addr,session->rtcp.rem_addrlen,host,sizeof(host)) ); } }else ortp_warning("Cannot send rtcp report because I don't know the remote address."); freemsg (m); return error;}/** *rtp_session_set_ssrc: *@session: a rtp session. *@ssrc: an unsigned 32bit integer representing the synchronisation source identifier (SSRC). * * Sets the SSRC for the outgoing stream. * If not done, a random ssrc is used. ***/voidrtp_session_set_ssrc (RtpSession * session, uint32_t ssrc){ session->send_ssrc = ssrc;}void rtp_session_update_payload_type(RtpSession *session, int paytype){ /* check if we support this payload type */ PayloadType *pt=rtp_profile_get_payload(session->profile,paytype); session->hw_recv_pt=paytype; if (pt!=0){ ortp_message ("payload type changed to %i(%s) !", paytype,pt->mime_type); payload_type_changed(session,pt); }else{ ortp_warning("Receiving packet with unknown payload type %i.",paytype); }}/** *rtp_session_set_send_payload_type: *@session: a rtp session *@paytype: the payload type * * Sets the payload type of the rtp session. It decides of the payload types written in the * of the rtp header for the outgoing stream, if the session is SENDRECV or SENDONLY. * For payload type in incoming packets, the application can be informed by registering * for the "payload_type_changed" signal, so that it can make the necessary changes * on the downstream decoder that deals with the payload of the packets. * *Returns: 0 on success, -1 if the payload is not defined.**/intrtp_session_set_send_payload_type (RtpSession * session, int paytype){ session->send_pt=paytype; return 0;}/** *rtp_session_get_send_payload_type: *@session: a rtp session * * Returns: the payload type currently used in outgoing rtp packets**/int rtp_session_get_send_payload_type(const RtpSession *session){ return session->send_pt;}/** *rtp_session_set_recv_payload_type: *@session: a rtp session *@paytype: the payload type * * Sets the expected payload type for incoming packets. * If the actual payload type in incoming packets is different that this expected payload type, thus * the "payload_type_changed" signal is emitted. * *Returns: 0 on success, -1 if the payload is not defined.**/intrtp_session_set_recv_payload_type (RtpSession * session, int paytype){ PayloadType *pt; session->recv_pt=paytype; session->hw_recv_pt=paytype; pt=rtp_profile_get_payload(session->profile,paytype); if (pt!=NULL){ payload_type_changed(session,pt); } return 0;}/** *rtp_session_get_recv_payload_type: *@session: a rtp session * * Returns: the payload type currently used in incoming rtp packets**/int rtp_session_get_recv_payload_type(const RtpSession *session){ return session->recv_pt;}/** *rtp_session_set_payload_type: *@session: a rtp session *@paytype: the payload type * * Sets the expected payload type for incoming packets and payload type to be used for outgoing packets. * If the actual payload type in incoming packets is different that this expected payload type, thus * the "payload_type_changed" signal is emitted. * *Returns: 0 on success, -1 if the payload is not defined.**/int rtp_session_set_payload_type(RtpSession *session, int pt){ if (rtp_session_set_send_payload_type(session,pt)<0) return -1; if (rtp_session_set_recv_payload_type(session,pt)<0) return -1; return 0;}/** *rtp_session_create_packet: *@session: a rtp session. *@header_size: the rtp header size. For standart size (without extensions), it is #RTP_FIXED_HEADER_SIZE *@payload :data to be copied into the rtp packet. *@payload_size : size of data carried by the rtp packet. * * Allocates a new rtp packet. In the header, ssrc and payload_type according to the session's * context. Timestamp and seq number are not set, there will be set when the packet is going to be * sent with rtp_session_sendm_with_ts(). * If payload_size is zero, thus an empty packet (just a RTP header) is returned. * *Returns: a rtp packet in a mblk_t (message block) structure.**/mblk_t * rtp_session_create_packet(RtpSession *session,int header_size, const char *payload, int payload_size){ mblk_t *mp; int msglen=header_size+payload_size; rtp_header_t *rtp; mp=allocb(msglen,BPRI_MED); rtp=(rtp_header_t*)mp->b_rptr; rtp->version = 2; rtp->padbit = 0; rtp->extbit = 0; rtp->markbit= 0; rtp->cc = 0; rtp->paytype = session->send_pt; rtp->ssrc = session->send_ssrc; rtp->timestamp = 0; /* set later, when packet is sended */ rtp->seq_number = 0; /*set later, when packet is sended */ /*copy the payload, if any */ mp->b_wptr+=header_size; if (payload_size){ memcpy(mp->b_wptr,payload,payload_size); mp->b_wptr+=payload_size; } return mp;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?