diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h index 3b1f7cd33..f14e35996 100644 --- a/pjmedia/include/pjmedia/errno.h +++ b/pjmedia/include/pjmedia/errno.h @@ -148,6 +148,11 @@ PJ_BEGIN_DECL * Invalid SDP "rtcp" attribute. */ #define PJMEDIA_SDP_EINRTCP (PJMEDIA_ERRNO_START+35) /* 220035 */ +/** + * @hideinitializer + * Invalid SDP media transport protocol. + */ +#define PJMEDIA_SDP_EINPROTO (PJMEDIA_ERRNO_START+36) /* 220036 */ /************************************************************ diff --git a/pjmedia/include/pjmedia/stream.h b/pjmedia/include/pjmedia/stream.h index 4967c3800..64082a8b4 100644 --- a/pjmedia/include/pjmedia/stream.h +++ b/pjmedia/include/pjmedia/stream.h @@ -89,6 +89,7 @@ typedef struct pjmedia_channel pjmedia_channel; struct pjmedia_stream_info { pjmedia_type type; /**< Media type (audio, video) */ + pjmedia_tp_proto proto; /**< Transport protocol (RTP/AVP, etc.) */ pjmedia_dir dir; /**< Media direction. */ pj_sockaddr rem_addr; /**< Remote RTP address */ pj_sockaddr rem_rtcp; /**< Optional remote RTCP address. If diff --git a/pjmedia/include/pjmedia/types.h b/pjmedia/include/pjmedia/types.h index ed080d271..cf7725dfc 100644 --- a/pjmedia/include/pjmedia/types.h +++ b/pjmedia/include/pjmedia/types.h @@ -68,6 +68,25 @@ typedef enum pjmedia_type } pjmedia_type; +/** + * Media transport protocol. + */ +typedef enum pjmedia_tp_proto +{ + /** No transport type */ + PJMEDIA_TP_PROTO_NONE = 0, + + /** RTP using A/V profile */ + PJMEDIA_TP_PROTO_RTP_AVP, + + /** Secure RTP */ + PJMEDIA_TP_PROTO_RTP_SAVP, + + /** Unknown */ + PJMEDIA_TP_PROTO_UNKNOWN + +} pjmedia_tp_proto; + /** * Media direction. diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c index c2093430e..300cbd446 100644 --- a/pjmedia/src/pjmedia/errno.c +++ b/pjmedia/src/pjmedia/errno.c @@ -58,6 +58,7 @@ static const struct PJ_BUILD_ERR( PJMEDIA_SDP_EINPT, "Invalid SDP payload type in media line" ), PJ_BUILD_ERR( PJMEDIA_SDP_EINFMTP, "Invalid SDP fmtp attribute" ), PJ_BUILD_ERR( PJMEDIA_SDP_EINRTCP, "Invalid SDP rtcp attribyte" ), + PJ_BUILD_ERR( PJMEDIA_SDP_EINPROTO, "Invalid SDP media transport protocol" ), /* SDP negotiator errors. */ PJ_BUILD_ERR( PJMEDIA_SDPNEG_EINSTATE, "Invalid SDP negotiator state for operation" ), diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c index d0784a696..5c2833542 100644 --- a/pjmedia/src/pjmedia/session.c +++ b/pjmedia/src/pjmedia/session.c @@ -53,8 +53,9 @@ 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_IP6 = { "IP6", 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_RTP_AVP = { "RTP/AVP", 7 }; +static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 }; +//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 }; @@ -180,6 +181,8 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp( return PJMEDIA_EINVALIMEDIATYPE; } + /* Transport protocol */ + /* Transport type must be equal */ if (pj_stricmp(&rem_m->desc.transport, &local_m->desc.transport) != 0) @@ -188,6 +191,21 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp( return PJMEDIA_SDPNEG_EINVANSTP; } + if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) { + + si->proto = PJMEDIA_TP_PROTO_RTP_AVP; + + } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) { + + si->proto = PJMEDIA_TP_PROTO_RTP_SAVP; + + } else { + + si->proto = PJMEDIA_TP_PROTO_UNKNOWN; + return PJMEDIA_SDP_EINPROTO; + } + + /* Check address family in remote SDP */ rem_af = pj_AF_UNSPEC(); if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) { diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 3a5772470..1d1e727f2 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -884,9 +884,11 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, const pjmedia_sdp_session *local_sdp, const pjmedia_sdp_session *remote_sdp) { + unsigned i; int prev_media_st = 0; pjsua_call *call = &pjsua_var.calls[call_id]; pjmedia_session_info sess_info; + pjmedia_stream_info *si = NULL; pjmedia_port *media_port; pj_str_t port_name; char tmp[PJSIP_MAX_URL_SIZE]; @@ -897,19 +899,37 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, stop_media_session(call->index); /* Create media session info based on SDP parameters. - * We only support one stream per session at the moment */ status = pjmedia_session_info_from_sdp( call->inv->dlg->pool, pjsua_var.med_endpt, - 1,&sess_info, + PJMEDIA_MAX_SDP_MEDIA, &sess_info, local_sdp, remote_sdp); if (status != PJ_SUCCESS) return status; + /* Find which session is audio (we only support audio for now) */ + for (i=0; i < sess_info.stream_cnt; ++i) { + if (sess_info.stream_info[i].type == PJMEDIA_TYPE_AUDIO && + sess_info.stream_info[i].proto == PJMEDIA_TP_PROTO_RTP_AVP) + { + si = &sess_info.stream_info[i]; + break; + } + } + + if (si == NULL) { + /* Not found */ + return PJMEDIA_EINVALIMEDIATYPE; + } + + + /* Reset session info with only one media stream */ + sess_info.stream_cnt = 1; + if (si != &sess_info.stream_info[0]) + pj_memcpy(&sess_info.stream_info[0], si, sizeof(pjmedia_stream_info)); /* Check if media is put on-hold */ - if (sess_info.stream_cnt == 0 || - sess_info.stream_info[0].dir == PJMEDIA_DIR_NONE) + if (sess_info.stream_cnt == 0 || si->dir == PJMEDIA_DIR_NONE) { /* Determine who puts the call on-hold */ @@ -943,28 +963,28 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, /* Override ptime, if this option is specified. */ if (pjsua_var.media_cfg.ptime != 0) { - sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t) - (pjsua_var.media_cfg.ptime / sess_info.stream_info[0].param->info.frm_ptime); - if (sess_info.stream_info[0].param->setting.frm_per_pkt == 0) - sess_info.stream_info[0].param->setting.frm_per_pkt = 1; + si->param->setting.frm_per_pkt = (pj_uint8_t) + (pjsua_var.media_cfg.ptime / si->param->info.frm_ptime); + if (si->param->setting.frm_per_pkt == 0) + si->param->setting.frm_per_pkt = 1; } /* Disable VAD, if this option is specified. */ if (pjsua_var.media_cfg.no_vad) { - sess_info.stream_info[0].param->setting.vad = 0; + si->param->setting.vad = 0; } /* Optionally, application may modify other stream settings here * (such as jitter buffer parameters, codec ptime, etc.) */ - sess_info.stream_info[0].jb_init = pjsua_var.media_cfg.jb_init; - sess_info.stream_info[0].jb_min_pre = pjsua_var.media_cfg.jb_min_pre; - sess_info.stream_info[0].jb_max_pre = pjsua_var.media_cfg.jb_max_pre; - sess_info.stream_info[0].jb_max = pjsua_var.media_cfg.jb_max; + si->jb_init = pjsua_var.media_cfg.jb_init; + si->jb_min_pre = pjsua_var.media_cfg.jb_min_pre; + si->jb_max_pre = pjsua_var.media_cfg.jb_max_pre; + si->jb_max = pjsua_var.media_cfg.jb_max; /* Set SSRC */ - sess_info.stream_info[0].ssrc = call->ssrc; + si->ssrc = call->ssrc; /* Create session based on session info. */ status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, @@ -1009,7 +1029,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, /* Call's media state is active */ call->media_st = PJSUA_CALL_MEDIA_ACTIVE; - call->media_dir = sess_info.stream_info[0].dir; + call->media_dir = si->dir; } /* Print info. */