session.c

来自「基于sip协议的网络电话源码」· C语言 代码 · 共 776 行 · 第 1/2 页

C
776
字号
/* $Id: session.c 1107 2007-03-27 10:53:57Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */#include <pjmedia/session.h>#include <pjmedia/errno.h>#include <pj/log.h>#include <pj/os.h> #include <pj/pool.h>#include <pj/string.h>#include <pj/assert.h>#include <pj/ctype.h>#include <pj/rand.h>struct pjmedia_session{    pj_pool_t		   *pool;    pjmedia_endpt	   *endpt;    unsigned		    stream_cnt;    pjmedia_stream_info	    stream_info[PJMEDIA_MAX_SDP_MEDIA];    pjmedia_stream	   *stream[PJMEDIA_MAX_SDP_MEDIA];    void		   *user_data;};#define THIS_FILE		"session.c"#define PJMEDIA_SESSION_SIZE	(48*1024)#define PJMEDIA_SESSION_INC	1024static const pj_str_t ID_AUDIO = { "audio", 5};static const pj_str_t ID_VIDEO = { "video", 5};static const pj_str_t ID_IN = { "IN", 2 };static const pj_str_t ID_IP4 = { "IP4", 3};static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 };static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 };static const pj_str_t ID_RTPMAP = { "rtpmap", 6 };static const pj_str_t ID_TELEPHONE_EVENT = { "telephone-event", 15 };static const pj_str_t STR_INACTIVE = { "inactive", 8 };static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };static const pj_str_t STR_SENDONLY = { "sendonly", 8 };static const pj_str_t STR_RECVONLY = { "recvonly", 8 };/* * Get fmtp mode parameter associated with the codec. */static pj_status_t get_fmtp_mode(const pjmedia_sdp_media *m,				 const pj_str_t *fmt,				 int *p_mode){    const pjmedia_sdp_attr *attr;    pjmedia_sdp_fmtp fmtp;    const pj_str_t str_mode = { "mode=", 5 };    char *pos;    /* Get "fmtp" attribute for the format */    attr = pjmedia_sdp_media_find_attr2(m, "fmtp", fmt);    if (attr == NULL)	return -1;    /* Parse "fmtp" attribute */    if (pjmedia_sdp_attr_get_fmtp(attr, &fmtp) != PJ_SUCCESS)	return -1;    /* Look for "mode=" string in the fmtp */    while (fmtp.fmt_param.slen >= str_mode.slen + 1) {	if (pj_strnicmp(&fmtp.fmt_param, &str_mode, str_mode.slen)==0) {	    /* Found "mode=" string */	    break;	}	fmtp.fmt_param.ptr++;	fmtp.fmt_param.slen--;    }    if (fmtp.fmt_param.slen < str_mode.slen + 1) {	/* "mode=" param not found */	return -1;    }    /* Get the mode */    pos = fmtp.fmt_param.ptr + str_mode.slen;    *p_mode = 0;    while (pj_isdigit(*pos)) {	*p_mode = *p_mode * 10 + (*pos - '0');	++pos;    }    return PJ_SUCCESS;}/* * Create stream info from SDP media line. */PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(					   pjmedia_stream_info *si,					   pj_pool_t *pool,					   pjmedia_endpt *endpt,					   const pjmedia_sdp_session *local,					   const pjmedia_sdp_session *remote,					   unsigned stream_idx){    pjmedia_codec_mgr *mgr;    const pjmedia_sdp_attr *attr;    const pjmedia_sdp_media *local_m;    const pjmedia_sdp_media *rem_m;    const pjmedia_sdp_conn *local_conn;    const pjmedia_sdp_conn *rem_conn;    pjmedia_sdp_rtpmap *rtpmap;    int local_fmtp_mode = 0, rem_fmtp_mode = 0;    unsigned i, pt, fmti;    pj_status_t status;        /* Validate arguments: */    PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL);    PJ_ASSERT_RETURN(stream_idx < local->media_count, PJ_EINVAL);    PJ_ASSERT_RETURN(stream_idx < remote->media_count, PJ_EINVAL);    /* Get codec manager. */    mgr = pjmedia_endpt_get_codec_mgr(endpt);    /* Keep SDP shortcuts */    local_m = local->media[stream_idx];    rem_m = remote->media[stream_idx];    local_conn = local_m->conn ? local_m->conn : local->conn;    if (local_conn == NULL)	return PJMEDIA_SDP_EMISSINGCONN;    rem_conn = rem_m->conn ? rem_m->conn : remote->conn;    if (rem_conn == NULL)	return PJMEDIA_SDP_EMISSINGCONN;    /* Reset: */    pj_bzero(si, sizeof(*si));    /* Media type: */    if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) == 0) {	si->type = PJMEDIA_TYPE_AUDIO;    } else if (pj_stricmp(&local_m->desc.media, &ID_VIDEO) == 0) {	si->type = PJMEDIA_TYPE_VIDEO;    } else {	si->type = PJMEDIA_TYPE_UNKNOWN;	return PJMEDIA_EINVALIMEDIATYPE;    }    /* Transport type must be equal */    if (pj_stricmp(&rem_m->desc.transport, 		   &local_m->desc.transport) != 0)     {	si->type = PJMEDIA_TYPE_UNKNOWN;	return PJMEDIA_SDPNEG_EINVANSTP;    }    /* Media direction: */    if (local_m->desc.port == 0 || 	pj_inet_addr(&local_conn->addr).s_addr==0 ||	pj_inet_addr(&rem_conn->addr).s_addr==0 ||	pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL)    {	/* Inactive stream. */	si->dir = PJMEDIA_DIR_NONE;    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) {	/* Send only stream. */	si->dir = PJMEDIA_DIR_ENCODING;    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) {	/* Recv only stream. */	si->dir = PJMEDIA_DIR_DECODING;    } else {	/* Send and receive stream. */	si->dir = PJMEDIA_DIR_ENCODING_DECODING;    }    /* Set remote address: */    status = pj_sockaddr_in_init(&si->rem_addr, &rem_conn->addr, 				 rem_m->desc.port);    if (status != PJ_SUCCESS) {	/* Invalid IP address. */	return PJMEDIA_EINVALIDIP;    }    /* If "rtcp" attribute is present in the SDP, set the RTCP address     * from that attribute. Otherwise, calculate from RTP address.     */    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,				  "rtcp", NULL);    if (attr) {	pjmedia_sdp_rtcp_attr rtcp;	status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp);	if (status == PJ_SUCCESS) {	    if (rtcp.addr.slen) {		status = pj_sockaddr_in_init(&si->rem_rtcp, &rtcp.addr,					     (pj_uint16_t)rtcp.port);	    } else {		pj_sockaddr_in_init(&si->rem_rtcp, NULL, 				    (pj_uint16_t)rtcp.port);		si->rem_rtcp.sin_addr.s_addr = si->rem_addr.sin_addr.s_addr;	    }	}    }        if (si->rem_rtcp.sin_addr.s_addr == 0) {	int rtcp_port;	pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr_in));	rtcp_port = pj_ntohs(si->rem_addr.sin_port) + 1;	si->rem_rtcp.sin_port = pj_htons((pj_uint16_t)rtcp_port);    }    /* Get the payload number for receive channel. */    /*       Previously we used to rely on fmt[0] being the selected codec,       but some UA sends telephone-event as fmt[0] and this would       cause assert failure below.       Thanks Chris Hamilton <chamilton .at. cs.dal.ca> for this patch.    // And codec must be numeric!    if (!pj_isdigit(*local_m->desc.fmt[0].ptr) || 	!pj_isdigit(*rem_m->desc.fmt[0].ptr))    {	return PJMEDIA_EINVALIDPT;    }    pt = pj_strtoul(&local_m->desc.fmt[0]);    pj_assert(PJMEDIA_RTP_PT_TELEPHONE_EVENTS==0 ||	      pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS);    */    /* This is to suppress MSVC warning about uninitialized var */    pt = 0;    /* Find the first codec which is not telephone-event */    for ( fmti = 0; fmti < local_m->desc.fmt_count; ++fmti ) {	if ( !pj_isdigit(*local_m->desc.fmt[fmti].ptr) )	    return PJMEDIA_EINVALIDPT;	pt = pj_strtoul(&local_m->desc.fmt[fmti]);	if ( PJMEDIA_RTP_PT_TELEPHONE_EVENTS == 0 ||		pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS )		break;    }    if ( fmti >= local_m->desc.fmt_count )	return PJMEDIA_EINVALIDPT;    /* Get codec info.     * For static payload types, get the info from codec manager.     * For dynamic payload types, MUST get the rtpmap.     */    if (pt < 96) {	pj_bool_t has_rtpmap;	rtpmap = NULL;	has_rtpmap = PJ_TRUE;	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 					   &local_m->desc.fmt[fmti]);	if (attr == NULL) {	    has_rtpmap = PJ_FALSE;	}	if (attr != NULL) {	    status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);	    if (status != PJ_SUCCESS)		has_rtpmap = PJ_FALSE;	}	/* Build codec format info: */	if (has_rtpmap) {	    si->fmt.type = si->type;	    si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);	    pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name);	    si->fmt.clock_rate = rtpmap->clock_rate;	    	    /* For audio codecs, rtpmap parameters denotes the number of	     * channels.	     */	    if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) {				if (rtpmap->param.slen == 2) {		    si->fmt.channel_cnt = rtpmap->param.ptr[1] - '0';		} else {		    pj_str_t cnt;		    cnt.ptr = rtpmap->param.ptr + 1;		    cnt.slen = rtpmap->param.slen - 1;		    si->fmt.channel_cnt = (unsigned) pj_strtoul(&cnt);		}	    } else {		si->fmt.channel_cnt = 1;	    }	} else {	    	    const pjmedia_codec_info *p_info;	    status = pjmedia_codec_mgr_get_codec_info( mgr, pt, &p_info);	    if (status != PJ_SUCCESS)		return status;	    pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info));	}	/* For static payload type, pt's are symetric */	si->tx_pt = pt;    } else {	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 					   &local_m->desc.fmt[fmti]);	if (attr == NULL)	    return PJMEDIA_EMISSINGRTPMAP;	status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);	if (status != PJ_SUCCESS)	    return status;	/* Build codec format info: */	si->fmt.type = si->type;	si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);	pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name);	si->fmt.clock_rate = rtpmap->clock_rate;	/* For audio codecs, rtpmap parameters denotes the number of	 * channels.	 */	if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) {	    	    if (rtpmap->param.slen == 2) {		si->fmt.channel_cnt = rtpmap->param.ptr[1] - '0';	    } else {		pj_str_t cnt;		cnt.ptr = rtpmap->param.ptr + 1;		cnt.slen = rtpmap->param.slen - 1;		si->fmt.channel_cnt = (unsigned) pj_strtoul(&cnt);	    }	} else {	    si->fmt.channel_cnt = 1;	}	/* Get fmtp mode= param in local SDP, if any */	get_fmtp_mode(local_m, &local_m->desc.fmt[fmti], &local_fmtp_mode);	/* Determine payload type for outgoing channel, by finding	 * dynamic payload type in remote SDP that matches the answer.	 */	si->tx_pt = 0xFFFF;	for (i=0; i<rem_m->desc.fmt_count; ++i) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?