예제 #1
0
파일: sdp.cpp 프로젝트: dyfet/sflphone
pjmedia_sdp_media *Sdp::setMediaDescriptorLine()
{
    pjmedia_sdp_media *med = PJ_POOL_ZALLOC_T(memPool_, pjmedia_sdp_media);

    med->desc.media = pj_str((char*)"audio");
    med->desc.port_count = 1;
    med->desc.port = localAudioPort_;
    // in case of sdes, media are tagged as "RTP/SAVP", RTP/AVP elsewhere
    med->desc.transport = pj_str(srtpCrypto_.empty() ? (char*)"RTP/AVP" : (char*)"RTP/SAVP");

    med->desc.fmt_count = codec_list_.size();

    for (unsigned i=0; i<med->desc.fmt_count; i++) {
        sfl::Codec *codec = codec_list_[i];

        std::ostringstream result;
        result << (int)codec->getPayloadType();

        pj_strdup2(memPool_, &med->desc.fmt[i], result.str().c_str());

        // Add a rtpmap field for each codec
        // We could add one only for dynamic payloads because the codecs with static RTP payloads
        // are entirely defined in the RFC 3351, but if we want to add other attributes like an asymmetric
        // connection, the rtpmap attribute will be useful to specify for which codec it is applicable
        pjmedia_sdp_rtpmap rtpmap;
        rtpmap.pt = med->desc.fmt[i];
        rtpmap.enc_name = pj_str((char*) codec->getMimeSubtype().c_str());

        // G722 require G722/8000 media description even if it is 16000 codec
        if (codec->getPayloadType() == 9) {
            rtpmap.clock_rate = 8000;
        } else {
            rtpmap.clock_rate = codec->getClockRate();
        }

        rtpmap.param.ptr = ((char* const)"");
        rtpmap.param.slen = 0;

        pjmedia_sdp_attr *attr;
        pjmedia_sdp_rtpmap_to_attr(memPool_, &rtpmap, &attr);

        med->attr[med->attr_count++] = attr;
    }

    med->attr[ med->attr_count++] = pjmedia_sdp_attr_create(memPool_, "sendrecv", NULL);

    if (!zrtpHelloHash_.empty())
        addZrtpAttribute(med, zrtpHelloHash_);

    setTelephoneEventRtpmap(med);

    return med;
}
static pjmedia_sdp_attr* generate_rtpmap_attr(pjmedia_sdp_media *media, pj_pool_t *pool, int rtp_code,
					      int asterisk_format, struct ast_format *format, int code)
{
	pjmedia_sdp_rtpmap rtpmap;
	pjmedia_sdp_attr *attr = NULL;
	char tmp[64];

	snprintf(tmp, sizeof(tmp), "%d", rtp_code);
	pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp);
	rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1];
	rtpmap.clock_rate = ast_rtp_lookup_sample_rate2(asterisk_format, format, code);
	pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, 0));
	rtpmap.param.slen = 0;
	rtpmap.param.ptr = NULL;

	pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);

	return attr;
}
예제 #3
0
static pjmedia_sdp_attr* generate_rtpmap_attr(struct ast_sip_session *session, pjmedia_sdp_media *media, pj_pool_t *pool,
					      int rtp_code, int asterisk_format, struct ast_format *format, int code)
{
	pjmedia_sdp_rtpmap rtpmap;
	pjmedia_sdp_attr *attr = NULL;
	char tmp[64];
	enum ast_rtp_options options = session->endpoint->media.g726_non_standard ?
		AST_RTP_OPT_G726_NONSTANDARD : 0;

	snprintf(tmp, sizeof(tmp), "%d", rtp_code);
	pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp);
	rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1];
	rtpmap.clock_rate = ast_rtp_lookup_sample_rate2(asterisk_format, format, code);
	pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, options));
	rtpmap.param.slen = 0;
	rtpmap.param.ptr = NULL;

	pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);

	return attr;
}
예제 #4
0
파일: endpoint.c 프로젝트: max3903/SFLphone
/**
 * Create a SDP session description that describes the endpoint
 * capability.
 */
PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
					      pj_pool_t *pool,
					      unsigned stream_cnt,
					      const pjmedia_sock_info sock_info[],
					      pjmedia_sdp_session **p_sdp )
{
    pj_time_val tv;
    unsigned i;
    const pj_sockaddr *addr0;
    pjmedia_sdp_session *sdp;
    pjmedia_sdp_media *m;
    pjmedia_sdp_attr *attr;

    /* Sanity check arguments */
    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);

    /* Check that there are not too many codecs */
    PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
		     PJ_ETOOMANY);

    /* Create and initialize basic SDP session */
    sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);

    addr0 = &sock_info[0].rtp_addr_name;

    pj_gettimeofday(&tv);
    sdp->origin.user = pj_str("-");
    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
    sdp->origin.net_type = STR_IN;

    if (addr0->addr.sa_family == pj_AF_INET()) {
	sdp->origin.addr_type = STR_IP4;
	pj_strdup2(pool, &sdp->origin.addr, 
		   pj_inet_ntoa(addr0->ipv4.sin_addr));
    } else if (addr0->addr.sa_family == pj_AF_INET6()) {
	char tmp_addr[PJ_INET6_ADDRSTRLEN];

	sdp->origin.addr_type = STR_IP6;
	pj_strdup2(pool, &sdp->origin.addr, 
		   pj_sockaddr_print(addr0, tmp_addr, sizeof(tmp_addr), 0));

    } else {
	pj_assert(!"Invalid address family");
	return PJ_EAFNOTSUP;
    }

    sdp->name = STR_SDP_NAME;

    /* Since we only support one media stream at present, put the
     * SDP connection line in the session level.
     */
    sdp->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
    sdp->conn->net_type = sdp->origin.net_type;
    sdp->conn->addr_type = sdp->origin.addr_type;
    sdp->conn->addr = sdp->origin.addr;


    /* SDP time and attributes. */
    sdp->time.start = sdp->time.stop = 0;
    sdp->attr_count = 0;

    /* Create media stream 0: */

    sdp->media_count = 1;
    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
    sdp->media[0] = m;

    /* Standard media info: */
    pj_strdup(pool, &m->desc.media, &STR_AUDIO);
    m->desc.port = pj_sockaddr_get_port(addr0);
    m->desc.port_count = 1;
    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);

    /* Init media line and attribute list. */
    m->desc.fmt_count = 0;
    m->attr_count = 0;

    /* Add "rtcp" attribute */
#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
    if (sock_info->rtcp_addr_name.addr.sa_family != 0) {
	attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name);
	if (attr)
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
    }
#endif

    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
    for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {

	pjmedia_codec_info *codec_info;
	pjmedia_sdp_rtpmap rtpmap;
	char tmp_param[3];
	pjmedia_sdp_attr *attr;
	pjmedia_codec_param codec_param;
	pj_str_t *fmt;

	if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
	    break;

	codec_info = &endpt->codec_mgr.codec_desc[i].info;
	pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
					    &codec_param);
	fmt = &m->desc.fmt[m->desc.fmt_count++];

	fmt->ptr = (char*) pj_pool_alloc(pool, 8);
	fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);

	rtpmap.pt = *fmt;
	rtpmap.enc_name = codec_info->encoding_name;

#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
	if (codec_info->pt == PJMEDIA_RTP_PT_G722)
	    rtpmap.clock_rate = 8000;
	else
	    rtpmap.clock_rate = codec_info->clock_rate;
#else
	rtpmap.clock_rate = codec_info->clock_rate;
#endif

	/* For audio codecs, rtpmap parameters denotes the number
	 * of channels, which can be omited if the value is 1.
	 */
	if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
	    codec_info->channel_cnt > 1)
	{
	    /* Can only support one digit channel count */
	    pj_assert(codec_info->channel_cnt < 10);

	    tmp_param[0] = (char)('0' + codec_info->channel_cnt);

	    rtpmap.param.ptr = tmp_param;
	    rtpmap.param.slen = 1;

	} else {
	    rtpmap.param.slen = 0;
	}

	if (codec_info->pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
	    pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
	    m->attr[m->attr_count++] = attr;
	}

	/* Add fmtp params */
	if (codec_param.setting.dec_fmtp.cnt > 0) {
	    enum { MAX_FMTP_STR_LEN = 160 };
	    char buf[MAX_FMTP_STR_LEN];
	    unsigned buf_len = 0, i;
	    pjmedia_codec_fmtp *dec_fmtp = &codec_param.setting.dec_fmtp;

	    /* Print codec PT */
	    buf_len += pj_ansi_snprintf(buf, 
					MAX_FMTP_STR_LEN - buf_len, 
					"%d", 
					codec_info->pt);

	    for (i = 0; i < dec_fmtp->cnt; ++i) {
		unsigned test_len = 2;

		/* Check if buf still available */
		test_len = dec_fmtp->param[i].val.slen + 
			   dec_fmtp->param[i].name.slen;
		if (test_len + buf_len >= MAX_FMTP_STR_LEN)
		    return PJ_ETOOBIG;

		/* Print delimiter */
		buf_len += pj_ansi_snprintf(&buf[buf_len], 
					    MAX_FMTP_STR_LEN - buf_len,
					    (i == 0?" ":";"));

		/* Print an fmtp param */
		if (dec_fmtp->param[i].name.slen)
		    buf_len += pj_ansi_snprintf(
					    &buf[buf_len],
					    MAX_FMTP_STR_LEN - buf_len,
					    "%.*s=%.*s",
					    (int)dec_fmtp->param[i].name.slen,
					    dec_fmtp->param[i].name.ptr,
					    (int)dec_fmtp->param[i].val.slen,
					    dec_fmtp->param[i].val.ptr);
		else
		    buf_len += pj_ansi_snprintf(&buf[buf_len], 
					    MAX_FMTP_STR_LEN - buf_len,
					    "%.*s", 
					    (int)dec_fmtp->param[i].val.slen,
					    dec_fmtp->param[i].val.ptr);
	    }

	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

	    attr->name = pj_str("fmtp");
	    attr->value = pj_strdup3(pool, buf);
	    m->attr[m->attr_count++] = attr;
	}
    }

    /* Add sendrecv attribute. */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = STR_SENDRECV;
    m->attr[m->attr_count++] = attr;

#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0

    /*
     * Add support telephony event
     */
    m->desc.fmt[m->desc.fmt_count++] = 
	pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR);

    /* Add rtpmap. */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = pj_str("rtpmap");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR 
			 " telephone-event/8000");
    m->attr[m->attr_count++] = attr;

    /* Add fmtp */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = pj_str("fmtp");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15");
    m->attr[m->attr_count++] = attr;
#endif

    /* Done */
    *p_sdp = sdp;

    return PJ_SUCCESS;

}
예제 #5
0
/* Create m=video SDP media line */
PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
																									 pj_pool_t *pool,
																									 const pjmedia_sock_info *si,
																									 unsigned options,
																									 pjmedia_sdp_media **p_m)
{


	const pj_str_t STR_VIDEO = { "video", 5 };
	pjmedia_sdp_media *m;
	pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
	unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
	pjmedia_sdp_attr *attr;
	unsigned cnt, i;
	unsigned max_bitrate = 0;
	pj_status_t status;

	PJ_UNUSED_ARG(options);

	/* Make sure video codec manager is instantiated */
	if (!pjmedia_vid_codec_mgr_instance())
		pjmedia_vid_codec_mgr_create(endpt->pool, NULL);

	/* Create and init basic SDP media */
	m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
	status = init_sdp_media(m, pool, &STR_VIDEO, si);
	if (status != PJ_SUCCESS)
		return status;

	cnt = PJ_ARRAY_SIZE(codec_info);
	status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, 
		codec_info, codec_prio);

	/* Check that there are not too many codecs */
	PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT,
		PJ_ETOOMANY);

	/* Add format, rtpmap, and fmtp (when applicable) for each codec */
	for (i=0; i<cnt; ++i) {
		pjmedia_sdp_rtpmap rtpmap;
		pjmedia_vid_codec_param codec_param;
		pj_str_t *fmt;
		pjmedia_video_format_detail *vfd;

		pj_bzero(&rtpmap, sizeof(rtpmap));

		if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED)
			break;

		if (i > PJMEDIA_MAX_SDP_FMT) {
			/* Too many codecs, perhaps it is better to tell application by
			* returning appropriate status code.
			*/
			PJ_PERROR(3,(THIS_FILE, PJ_ETOOMANY,
				"Skipping some video codecs"));
			break;
		}

		/* Must support RTP packetization and bidirectional */
		if ((codec_info[i].packings & PJMEDIA_VID_PACKING_PACKETS) == 0 ||
			codec_info[i].dir != PJMEDIA_DIR_ENCODING_DECODING)
		{
			continue;
		}

		pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i],
			&codec_param);

		fmt = &m->desc.fmt[m->desc.fmt_count++];
		fmt->ptr = (char*) pj_pool_alloc(pool, 8);
		fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr);
		rtpmap.pt = *fmt;

		/* Encoding name */
		rtpmap.enc_name = codec_info[i].encoding_name;

		/* Clock rate */
		rtpmap.clock_rate = codec_info[i].clock_rate;

		if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
			pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
			m->attr[m->attr_count++] = attr;
		}

		/* Add fmtp params */
		if (codec_param.dec_fmtp.cnt > 0) {
			enum { MAX_FMTP_STR_LEN = 160 };
			char buf[MAX_FMTP_STR_LEN];
			unsigned buf_len = 0, j;
			pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp;

			/* Print codec PT */
			buf_len += pj_ansi_snprintf(buf, 
				MAX_FMTP_STR_LEN - buf_len, 
				"%d", 
				codec_info[i].pt);

			for (j = 0; j < dec_fmtp->cnt; ++j) {
				unsigned test_len = 2;

				/* Check if buf still available */
				test_len = dec_fmtp->param[j].val.slen + 
					dec_fmtp->param[j].name.slen;
				if (test_len + buf_len >= MAX_FMTP_STR_LEN)
					return PJ_ETOOBIG;

				/* Print delimiter */
				buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					(j == 0?" ":";"));

				/* Print an fmtp param */
				if (dec_fmtp->param[j].name.slen)
					buf_len += pj_ansi_snprintf(
					&buf[buf_len],
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s=%.*s",
					(int)dec_fmtp->param[j].name.slen,
					dec_fmtp->param[j].name.ptr,
					(int)dec_fmtp->param[j].val.slen,
					dec_fmtp->param[j].val.ptr);
				else
					buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s", 
					(int)dec_fmtp->param[j].val.slen,
					dec_fmtp->param[j].val.ptr);
			}

			attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

			attr->name = pj_str("fmtp");
			attr->value = pj_strdup3(pool, buf);
			m->attr[m->attr_count++] = attr;
		}

		/* Find maximum bitrate in this media */
		vfd = pjmedia_format_get_video_format_detail(&codec_param.enc_fmt,
			PJ_TRUE);
		if (vfd && max_bitrate < vfd->max_bps)
			max_bitrate = vfd->max_bps;
	}

	/* Put bandwidth info in media level using bandwidth modifier "TIAS"
	* (RFC3890).
	*/
	if (max_bitrate) {
		const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
		pjmedia_sdp_bandw *b;

		b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
		b->modifier = STR_BANDW_MODIFIER;
		b->value = max_bitrate;
		m->bandw[m->bandw_count++] = b;
	}

	*p_m = m;
	return PJ_SUCCESS;
}
예제 #6
0
/* Create m=audio SDP media line */
PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
																									 pj_pool_t *pool,
																									 const pjmedia_sock_info *si,
																									 unsigned options,
																									 pjmedia_sdp_media **p_m)
{
	const pj_str_t STR_AUDIO = { "audio", 5 };
	pjmedia_sdp_media *m;
	pjmedia_sdp_attr *attr;
	unsigned i;
	unsigned max_bitrate = 0;
	pj_status_t status;

	PJ_UNUSED_ARG(options);

	/* Check that there are not too many codecs */
	PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
		PJ_ETOOMANY);

	/* Create and init basic SDP media */
	m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
	status = init_sdp_media(m, pool, &STR_AUDIO, si);
	if (status != PJ_SUCCESS)
		return status;

	/* Add format, rtpmap, and fmtp (when applicable) for each codec */
	for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {

		pjmedia_codec_info *codec_info;
		pjmedia_sdp_rtpmap rtpmap;
		char tmp_param[3];
		pjmedia_codec_param codec_param;
		pj_str_t *fmt;

		if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
			break;

		codec_info = &endpt->codec_mgr.codec_desc[i].info;
		pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
			&codec_param);
		fmt = &m->desc.fmt[m->desc.fmt_count++];

		fmt->ptr = (char*) pj_pool_alloc(pool, 8);
		fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);

		rtpmap.pt = *fmt;
		rtpmap.enc_name = codec_info->encoding_name;

#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
		if (codec_info->pt == PJMEDIA_RTP_PT_G722)
			rtpmap.clock_rate = 8000;
		else
			rtpmap.clock_rate = codec_info->clock_rate;
#else
		rtpmap.clock_rate = codec_info->clock_rate;
#endif

		/* For audio codecs, rtpmap parameters denotes the number
		* of channels, which can be omited if the value is 1.
		*/
		if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
			codec_info->channel_cnt > 1)
		{
			/* Can only support one digit channel count */
			pj_assert(codec_info->channel_cnt < 10);

			tmp_param[0] = (char)('0' + codec_info->channel_cnt);

			rtpmap.param.ptr = tmp_param;
			rtpmap.param.slen = 1;

		} else {
			rtpmap.param.ptr = "";
			rtpmap.param.slen = 0;
		}

		if (codec_info->pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
			pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
			m->attr[m->attr_count++] = attr;
		}

		/* Add fmtp params */
		if (codec_param.setting.dec_fmtp.cnt > 0) {
			enum { MAX_FMTP_STR_LEN = 160 };
			char buf[MAX_FMTP_STR_LEN];
			unsigned buf_len = 0, i;
			pjmedia_codec_fmtp *dec_fmtp = &codec_param.setting.dec_fmtp;

			/* Print codec PT */
			buf_len += pj_ansi_snprintf(buf, 
				MAX_FMTP_STR_LEN - buf_len, 
				"%d", 
				codec_info->pt);

			for (i = 0; i < dec_fmtp->cnt; ++i) {
				unsigned test_len = 2;

				/* Check if buf still available */
				test_len = dec_fmtp->param[i].val.slen + 
					dec_fmtp->param[i].name.slen;
				if (test_len + buf_len >= MAX_FMTP_STR_LEN)
					return PJ_ETOOBIG;

				/* Print delimiter */
				buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					(i == 0?" ":";"));

				/* Print an fmtp param */
				if (dec_fmtp->param[i].name.slen)
					buf_len += pj_ansi_snprintf(
					&buf[buf_len],
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s=%.*s",
					(int)dec_fmtp->param[i].name.slen,
					dec_fmtp->param[i].name.ptr,
					(int)dec_fmtp->param[i].val.slen,
					dec_fmtp->param[i].val.ptr);
				else
					buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s", 
					(int)dec_fmtp->param[i].val.slen,
					dec_fmtp->param[i].val.ptr);
			}

			attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

			attr->name = pj_str("fmtp");
			attr->value = pj_strdup3(pool, buf);
			m->attr[m->attr_count++] = attr;
		}

		/* Find maximum bitrate in this media */
		if (max_bitrate < codec_param.info.max_bps)
			max_bitrate = codec_param.info.max_bps;
	}

#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
	PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0
	/*
	* Add support telephony event
	*/
	if (endpt->has_telephone_event) {
		m->desc.fmt[m->desc.fmt_count++] =
			pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR);

		/* Add rtpmap. */
		attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
		attr->name = pj_str("rtpmap");
		attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR
			" telephone-event/8000");
		m->attr[m->attr_count++] = attr;

		/* Add fmtp */
		attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
		attr->name = pj_str("fmtp");
		attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15");
		m->attr[m->attr_count++] = attr;
	}
#endif

	/* Put bandwidth info in media level using bandwidth modifier "TIAS"
	* (RFC3890).
	*/
	if (max_bitrate) {
		const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
		pjmedia_sdp_bandw *b;

		b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
		b->modifier = STR_BANDW_MODIFIER;
		b->value = max_bitrate;
		m->bandw[m->bandw_count++] = b;
	}

	*p_m = m;
	return PJ_SUCCESS;
}
예제 #7
0
/**
 * Create a SDP session description that describes the endpoint
 * capability.
 */
PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
					      pj_pool_t *pool,
					      unsigned stream_cnt,
					      const pjmedia_sock_info sock_info[],
					      pjmedia_sdp_session **p_sdp )
{
    pj_time_val tv;
    unsigned i;
    pjmedia_sdp_session *sdp;
    pjmedia_sdp_media *m;
    pjmedia_sdp_attr *attr;

    /* Sanity check arguments */
    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);

    /* Check that there are not too many codecs */
    PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
		     PJ_ETOOMANY);

    /* Create and initialize basic SDP session */
    sdp = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_session));

    pj_gettimeofday(&tv);
    sdp->origin.user = pj_str("-");
    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
    sdp->origin.net_type = STR_IN;
    sdp->origin.addr_type = STR_IP4;
    pj_strdup2(pool, &sdp->origin.addr, 
	       pj_inet_ntoa(sock_info[0].rtp_addr_name.sin_addr));
    sdp->name = STR_SDP_NAME;

    /* Since we only support one media stream at present, put the
     * SDP connection line in the session level.
     */
    sdp->conn = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_conn));
    sdp->conn->net_type = STR_IN;
    sdp->conn->addr_type = STR_IP4;
    pj_strdup2(pool, &sdp->conn->addr, 
	       pj_inet_ntoa(sock_info[0].rtp_addr_name.sin_addr));


    /* SDP time and attributes. */
    sdp->time.start = sdp->time.stop = 0;
    sdp->attr_count = 0;

    /* Create media stream 0: */

    sdp->media_count = 1;
    m = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_media));
    sdp->media[0] = m;

    /* Standard media info: */
    pj_strdup(pool, &m->desc.media, &STR_AUDIO);
    m->desc.port = pj_ntohs(sock_info[0].rtp_addr_name.sin_port);
    m->desc.port_count = 1;
    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);

    /* Init media line and attribute list. */
    m->desc.fmt_count = 0;
    m->attr_count = 0;

    /* Add "rtcp" attribute */
#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
    {
	attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr));
	attr->name = pj_str("rtcp");
	attr->value.ptr = pj_pool_alloc(pool, 80);
	attr->value.slen = 
	    pj_ansi_snprintf(attr->value.ptr, 80,
			    "%u IN IP4 %s",
			    pj_ntohs(sock_info[0].rtcp_addr_name.sin_port),
			    pj_inet_ntoa(sock_info[0].rtcp_addr_name.sin_addr));
	pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
    }
#endif

    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
    for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {

	pjmedia_codec_info *codec_info;
	pjmedia_sdp_rtpmap rtpmap;
	char tmp_param[3];
	pjmedia_sdp_attr *attr;
	pjmedia_codec_param codec_param;
	pj_str_t *fmt;

	if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
	    break;

	codec_info = &endpt->codec_mgr.codec_desc[i].info;
	pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
					    &codec_param);
	fmt = &m->desc.fmt[m->desc.fmt_count++];

	fmt->ptr = pj_pool_alloc(pool, 8);
	fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);

	rtpmap.pt = *fmt;
	rtpmap.clock_rate = codec_info->clock_rate;
	rtpmap.enc_name = codec_info->encoding_name;
	
	/* For audio codecs, rtpmap parameters denotes the number
	 * of channels, which can be omited if the value is 1.
	 */
	if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
	    codec_info->channel_cnt > 1)
	{
	    /* Can only support one digit channel count */
	    pj_assert(codec_info->channel_cnt < 10);

	    tmp_param[0] = '/';
	    tmp_param[1] = (char)('0' + codec_info->channel_cnt);

	    rtpmap.param.ptr = tmp_param;
	    rtpmap.param.slen = 2;

	} else {
	    rtpmap.param.slen = 0;
	}

	pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
	m->attr[m->attr_count++] = attr;

	/* Add fmtp mode where applicable */
	if (codec_param.setting.dec_fmtp_mode != 0) {
	    const pj_str_t fmtp = { "fmtp", 4 };
	    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));

	    attr->name = fmtp;
	    attr->value.ptr = pj_pool_alloc(pool, 32);
	    attr->value.slen = 
		pj_ansi_snprintf( attr->value.ptr, 32,
				  "%d mode=%d",
				  codec_info->pt,
				  codec_param.setting.dec_fmtp_mode);
	    m->attr[m->attr_count++] = attr;
	}
    }

    /* Add sendrecv attribute. */
    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
    attr->name = STR_SENDRECV;
    m->attr[m->attr_count++] = attr;

#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0

    /*
     * Add support telephony event
     */
    m->desc.fmt[m->desc.fmt_count++] = 
	pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR);

    /* Add rtpmap. */
    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
    attr->name = pj_str("rtpmap");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR 
			 " telephone-event/8000");
    m->attr[m->attr_count++] = attr;

    /* Add fmtp */
    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
    attr->name = pj_str("fmtp");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15");
    m->attr[m->attr_count++] = attr;
#endif

    /* Done */
    *p_sdp = sdp;

    return PJ_SUCCESS;

}