static void apply_packetization(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *remote_stream) { pjmedia_sdp_attr *attr; pj_str_t value; unsigned long framing; int codec; struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session_media->rtp)->pref; /* Apply packetization if available and configured to do so */ if (!session->endpoint->media.rtp.use_ptime || !(attr = pjmedia_sdp_media_find_attr2(remote_stream, "ptime", NULL))) { return; } value = attr->value; framing = pj_strtoul(pj_strltrim(&value)); for (codec = 0; codec < AST_RTP_MAX_PT; codec++) { struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs( session_media->rtp), codec); if (!format.asterisk_format) { continue; } ast_codec_pref_setsize(pref, &format.format, framing); } ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session_media->rtp), session_media->rtp, pref); }
PJ_DEF(pj_status_t) pj_strtol2(const pj_str_t *str, long *value) { pj_str_t s; unsigned long retval = 0; pj_bool_t is_negative = PJ_FALSE; int rc = 0; PJ_CHECK_STACK(); if (!str || !value) { return PJ_EINVAL; } s = *str; pj_strltrim(&s); if (s.slen == 0) return PJ_EINVAL; if (s.ptr[0] == '+' || s.ptr[0] == '-') { is_negative = (s.ptr[0] == '-'); s.ptr += 1; s.slen -= 1; } rc = pj_strtoul3(&s, &retval, 10); if (rc == PJ_EINVAL) { return rc; } else if (rc != PJ_SUCCESS) { *value = is_negative ? PJ_MINLONG : PJ_MAXLONG; return is_negative ? PJ_ETOOSMALL : PJ_ETOOBIG; } if (retval > PJ_MAXLONG && !is_negative) { *value = PJ_MAXLONG; return PJ_ETOOBIG; } if (retval > (PJ_MAXLONG + 1UL) && is_negative) { *value = PJ_MINLONG; return PJ_ETOOSMALL; } *value = is_negative ? -(long)retval : retval; return PJ_SUCCESS; }
static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs, struct ast_sip_session_media *session_media) { pjmedia_sdp_attr *attr; pjmedia_sdp_rtpmap *rtpmap; pjmedia_sdp_fmtp fmtp; struct ast_format *format; int i, num = 0, tel_event = 0; char name[256]; char media[20]; char fmt_param[256]; enum ast_rtp_options options = session->endpoint->media.g726_non_standard ? AST_RTP_OPT_G726_NONSTANDARD : 0; ast_rtp_codecs_payloads_initialize(codecs); /* Iterate through provided formats */ for (i = 0; i < stream->desc.fmt_count; ++i) { /* The payload is kept as a string for things like t38 but for video it is always numerical */ ast_rtp_codecs_payloads_set_m_type(codecs, NULL, pj_strtoul(&stream->desc.fmt[i])); /* Look for the optional rtpmap attribute */ if (!(attr = pjmedia_sdp_media_find_attr2(stream, "rtpmap", &stream->desc.fmt[i]))) { continue; } /* Interpret the attribute as an rtpmap */ if ((pjmedia_sdp_attr_to_rtpmap(session->inv_session->pool_prov, attr, &rtpmap)) != PJ_SUCCESS) { continue; } ast_copy_pj_str(name, &rtpmap->enc_name, sizeof(name)); if (strcmp(name,"telephone-event") == 0) { tel_event++; } ast_copy_pj_str(media, (pj_str_t*)&stream->desc.media, sizeof(media)); ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]), media, name, options, rtpmap->clock_rate); /* Look for an optional associated fmtp attribute */ if (!(attr = pjmedia_sdp_media_find_attr2(stream, "fmtp", &rtpmap->pt))) { continue; } if ((pjmedia_sdp_attr_get_fmtp(attr, &fmtp)) == PJ_SUCCESS) { ast_copy_pj_str(fmt_param, &fmtp.fmt, sizeof(fmt_param)); if (sscanf(fmt_param, "%30d", &num) != 1) { continue; } if ((format = ast_rtp_codecs_get_payload_format(codecs, num))) { struct ast_format *format_parsed; ast_copy_pj_str(fmt_param, &fmtp.fmt_param, sizeof(fmt_param)); format_parsed = ast_format_parse_sdp_fmtp(format, fmt_param); if (format_parsed) { ast_rtp_codecs_payload_replace_format(codecs, num, format_parsed); ao2_ref(format_parsed, -1); } ao2_ref(format, -1); } } } if ((tel_event==0) && (session->endpoint->dtmf == AST_SIP_DTMF_AUTO)) { ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND); } /* Get the packetization, if it exists */ if ((attr = pjmedia_sdp_media_find_attr2(stream, "ptime", NULL))) { unsigned long framing = pj_strtoul(pj_strltrim(&attr->value)); if (framing && session->endpoint->media.rtp.use_ptime) { ast_rtp_codecs_set_framing(codecs, framing); } } }
/* * 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; int rem_af, local_af; pj_sockaddr local_addr; pjmedia_sdp_rtpmap *rtpmap; 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)); #if PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR /* Set default RTCP XR enabled/disabled */ si->rtcp_xr_enabled = PJ_TRUE; #endif /* 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; /* Avoid rejecting call because of unrecognized media, * just return PJ_SUCCESS, this media will be deactivated later. */ //return PJMEDIA_EINVALIMEDIATYPE; return PJ_SUCCESS; } /* Transport protocol */ /* At this point, transport type must be compatible, * the transport instance will do more validation later. */ status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport, &local_m->desc.transport); if (status != PJ_SUCCESS) 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 PJ_SUCCESS; } /* Check address family in remote SDP */ rem_af = pj_AF_UNSPEC(); if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) { if (pj_stricmp(&rem_conn->addr_type, &ID_IP4)==0) { rem_af = pj_AF_INET(); } else if (pj_stricmp(&rem_conn->addr_type, &ID_IP6)==0) { rem_af = pj_AF_INET6(); } } if (rem_af==pj_AF_UNSPEC()) { /* Unsupported address family */ return PJ_EAFNOTSUP; } /* Set remote address: */ status = pj_sockaddr_init(rem_af, &si->rem_addr, &rem_conn->addr, rem_m->desc.port); if (status != PJ_SUCCESS) { /* Invalid IP address. */ return PJMEDIA_EINVALIDIP; } /* Check address family of local info */ local_af = pj_AF_UNSPEC(); if (pj_stricmp(&local_conn->net_type, &ID_IN)==0) { if (pj_stricmp(&local_conn->addr_type, &ID_IP4)==0) { local_af = pj_AF_INET(); } else if (pj_stricmp(&local_conn->addr_type, &ID_IP6)==0) { local_af = pj_AF_INET6(); } } if (local_af==pj_AF_UNSPEC()) { /* Unsupported address family */ return PJ_SUCCESS; } /* Set remote address: */ status = pj_sockaddr_init(local_af, &local_addr, &local_conn->addr, local_m->desc.port); if (status != PJ_SUCCESS) { /* Invalid IP address. */ return PJMEDIA_EINVALIDIP; } /* Local and remote address family must match */ if (local_af != rem_af) return PJ_EAFNOTSUP; /* Media direction: */ if (local_m->desc.port == 0 || pj_sockaddr_has_addr(&local_addr)==PJ_FALSE || pj_sockaddr_has_addr(&si->rem_addr)==PJ_FALSE || 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; } /* No need to do anything else if stream is rejected */ if (local_m->desc.port == 0) { return PJ_SUCCESS; } /* 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_init(rem_af, &si->rem_rtcp, &rtcp.addr, (pj_uint16_t)rtcp.port); } else { pj_sockaddr_init(rem_af, &si->rem_rtcp, NULL, (pj_uint16_t)rtcp.port); pj_memcpy(pj_sockaddr_get_addr(&si->rem_rtcp), pj_sockaddr_get_addr(&si->rem_addr), pj_sockaddr_get_addr_len(&si->rem_addr)); } } } if (!pj_sockaddr_has_addr(&si->rem_rtcp)) { int rtcp_port; pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr)); rtcp_port = pj_sockaddr_get_port(&si->rem_addr) + 1; pj_sockaddr_set_port(&si->rem_rtcp, (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; #if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0) /* The session info should have the actual clock rate, because * this info is used for calculationg buffer size, etc in stream */ if (si->fmt.pt == PJMEDIA_RTP_PT_G722) si->fmt.clock_rate = 16000; #endif /* For audio codecs, rtpmap parameters denotes the number of * channels. */ if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) { si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param); } 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) { si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param); } else { si->fmt.channel_cnt = 1; } /* 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) { unsigned rpt; pjmedia_sdp_attr *r_attr; pjmedia_sdp_rtpmap r_rtpmap; rpt = pj_strtoul(&rem_m->desc.fmt[i]); if (rpt < 96) continue; r_attr = pjmedia_sdp_media_find_attr(rem_m, &ID_RTPMAP, &rem_m->desc.fmt[i]); if (!r_attr) continue; if (pjmedia_sdp_attr_get_rtpmap(r_attr, &r_rtpmap) != PJ_SUCCESS) continue; if (!pj_stricmp(&rtpmap->enc_name, &r_rtpmap.enc_name) && rtpmap->clock_rate == r_rtpmap.clock_rate) { /* Found matched codec. */ si->tx_pt = rpt; break; } } if (si->tx_pt == 0xFFFF) return PJMEDIA_EMISSINGRTPMAP; } /* Now that we have codec info, get the codec param. */ si->param = PJ_POOL_ALLOC_T(pool, pjmedia_codec_param); status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt, si->param); /* Get remote fmtp for our encoder. */ parse_fmtp(pool, rem_m, si->tx_pt, &si->param->setting.enc_fmtp); /* Get local fmtp for our decoder. */ parse_fmtp(pool, local_m, si->fmt.pt, &si->param->setting.dec_fmtp); /* Get remote maxptime for our encoder. */ attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, "maxptime", NULL); if (attr) { pj_str_t tmp_val = attr->value; pj_strltrim(&tmp_val); si->tx_maxptime = pj_strtoul(&tmp_val); } /* When direction is NONE (it means SDP negotiation has failed) we don't * need to return a failure here, as returning failure will cause * the whole SDP to be rejected. See ticket #: * http:// * * Thanks Alain Totouom */ if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE) return status; /* Get incomming payload type for telephone-events */ si->rx_event_pt = -1; for (i=0; i<local_m->attr_count; ++i) { pjmedia_sdp_rtpmap r; attr = local_m->attr[i]; if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) continue; if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) continue; if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { si->rx_event_pt = pj_strtoul(&r.pt); break; } } /* Get outgoing payload type for telephone-events */ si->tx_event_pt = -1; for (i=0; i<rem_m->attr_count; ++i) { pjmedia_sdp_rtpmap r; attr = rem_m->attr[i]; if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) continue; if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) continue; if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { si->tx_event_pt = pj_strtoul(&r.pt); break; } } /* Leave SSRC to random. */ si->ssrc = pj_rand(); /* Set default jitter buffer parameter. */ si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1; return PJ_SUCCESS; }
/* * Internal function for collecting codec info and param from the SDP media. */ static pj_status_t get_audio_codec_info_param(pjmedia_stream_info *si, pj_pool_t *pool, pjmedia_codec_mgr *mgr, const pjmedia_sdp_media *local_m, const pjmedia_sdp_media *rem_m) { const pjmedia_sdp_attr *attr; pjmedia_sdp_rtpmap *rtpmap; unsigned i, fmti, pt = 0; pj_status_t status; /* Find the first codec which is not telephone-event */ for ( fmti = 0; fmti < local_m->desc.fmt_count; ++fmti ) { pjmedia_sdp_rtpmap r; if ( !pj_isdigit(*local_m->desc.fmt[fmti].ptr) ) return PJMEDIA_EINVALIDPT; pt = pj_strtoul(&local_m->desc.fmt[fmti]); if (pt < 96) { /* This is known static PT. Skip rtpmap checking because it is * optional. */ break; } attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, &local_m->desc.fmt[fmti]); if (attr == NULL) continue; status = pjmedia_sdp_attr_get_rtpmap(attr, &r); if (status != PJ_SUCCESS) continue; if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) != 0) break; } if ( fmti >= local_m->desc.fmt_count ) return PJMEDIA_EINVALIDPT; /* Get payload type for receiving direction */ si->rx_pt = pt; /* 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; #if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0) /* The session info should have the actual clock rate, because * this info is used for calculationg buffer size, etc in stream */ if (si->fmt.pt == PJMEDIA_RTP_PT_G722) si->fmt.clock_rate = 16000; #endif /* For audio codecs, rtpmap parameters denotes the number of * channels. */ if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) { si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param); } 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 { pjmedia_codec_id codec_id; pj_str_t codec_id_st; const pjmedia_codec_info *p_info; 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]); 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) { si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param); } else { si->fmt.channel_cnt = 1; } /* Normalize the codec info from codec manager. Note that the * payload type will be resetted to its default (it might have * been rewritten by the SDP negotiator to match to the remote * offer), this is intentional as currently some components may * prefer (or even require) the default PT in codec info. */ pjmedia_codec_info_to_id(&si->fmt, codec_id, sizeof(codec_id)); i = 1; codec_id_st = pj_str(codec_id); status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id_st, &i, &p_info, NULL); if (status != PJ_SUCCESS) return status; pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info)); /* 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) { if (pjmedia_sdp_neg_fmt_match(pool, (pjmedia_sdp_media*)local_m, fmti, (pjmedia_sdp_media*)rem_m, i, 0) == PJ_SUCCESS) { /* Found matched codec. */ si->tx_pt = pj_strtoul(&rem_m->desc.fmt[i]); break; } } if (si->tx_pt == 0xFFFF) return PJMEDIA_EMISSINGRTPMAP; } /* Now that we have codec info, get the codec param. */ si->param = PJ_POOL_ALLOC_T(pool, pjmedia_codec_param); status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt, si->param); /* Get remote fmtp for our encoder. */ pjmedia_stream_info_parse_fmtp(pool, rem_m, si->tx_pt, &si->param->setting.enc_fmtp); /* Get local fmtp for our decoder. */ pjmedia_stream_info_parse_fmtp(pool, local_m, si->rx_pt, &si->param->setting.dec_fmtp); if (!pj_stricmp2(&si->fmt.encoding_name, "opus")) { get_opus_channels_and_clock_rate(&si->param->setting.enc_fmtp, &si->param->setting.dec_fmtp, &si->fmt.channel_cnt, &si->fmt.clock_rate); } /* Get the remote ptime for our encoder. */ attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, "ptime", NULL); if (attr) { pj_str_t tmp_val = attr->value; unsigned frm_per_pkt; pj_strltrim(&tmp_val); /* Round up ptime when the specified is not multiple of frm_ptime */ frm_per_pkt = (pj_strtoul(&tmp_val) + si->param->info.frm_ptime/2) / si->param->info.frm_ptime; if (frm_per_pkt != 0) { si->param->setting.frm_per_pkt = (pj_uint8_t)frm_per_pkt; } } /* Get remote maxptime for our encoder. */ attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, "maxptime", NULL); if (attr) { pj_str_t tmp_val = attr->value; pj_strltrim(&tmp_val); si->tx_maxptime = pj_strtoul(&tmp_val); } /* When direction is NONE (it means SDP negotiation has failed) we don't * need to return a failure here, as returning failure will cause * the whole SDP to be rejected. See ticket #: * http:// * * Thanks Alain Totouom */ if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE) return status; /* Get incomming payload type for telephone-events */ si->rx_event_pt = -1; for (i=0; i<local_m->attr_count; ++i) { pjmedia_sdp_rtpmap r; attr = local_m->attr[i]; if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) continue; if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) continue; if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { si->rx_event_pt = pj_strtoul(&r.pt); break; } } /* Get outgoing payload type for telephone-events */ si->tx_event_pt = -1; for (i=0; i<rem_m->attr_count; ++i) { pjmedia_sdp_rtpmap r; attr = rem_m->attr[i]; if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) continue; if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) continue; if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { si->tx_event_pt = pj_strtoul(&r.pt); break; } } return PJ_SUCCESS; }
/** * This method is to parse and add the command attribute to command structure. **/ static pj_status_t add_cmd_node(pj_cli_t *cli, pj_cli_cmd_spec *group, pj_xml_node *xml_node, pj_cli_cmd_handler handler, pj_cli_cmd_spec **p_cmd, pj_cli_get_dyn_choice get_choice) { pj_xml_node *root = xml_node; pj_xml_attr *attr; pj_xml_node *sub_node; pj_cli_cmd_spec *cmd; pj_cli_arg_spec args[PJ_CLI_MAX_ARGS]; pj_str_t sc[PJ_CLI_MAX_SHORTCUTS]; pj_status_t status = PJ_SUCCESS; if (pj_stricmp2(&root->name, "CMD")) return PJ_EINVAL; /* Initialize the command spec */ cmd = PJ_POOL_ZALLOC_T(cli->pool, struct pj_cli_cmd_spec); /* Get the command attributes */ attr = root->attr_head.next; while (attr != &root->attr_head) { if (!pj_stricmp2(&attr->name, "name")) { pj_strltrim(&attr->value); if (!attr->value.slen || cmd_name_exists(cli, group, &attr->value)) { return PJ_CLI_EBADNAME; } pj_strdup(cli->pool, &cmd->name, &attr->value); } else if (!pj_stricmp2(&attr->name, "id")) { pj_bool_t is_valid = PJ_FALSE; if (attr->value.slen) { pj_cli_cmd_id cmd_id = pj_strtol(&attr->value); if (!pj_hash_get(cli->cmd_id_hash, &cmd_id, sizeof(pj_cli_cmd_id), NULL)) is_valid = PJ_TRUE; } if (!is_valid) return PJ_CLI_EBADID; cmd->id = (pj_cli_cmd_id)pj_strtol(&attr->value); } else if (!pj_stricmp2(&attr->name, "sc")) { pj_scanner scanner; pj_str_t str; PJ_USE_EXCEPTION; pj_scan_init(&scanner, attr->value.ptr, attr->value.slen, PJ_SCAN_AUTOSKIP_WS, &on_syntax_error); PJ_TRY { while (!pj_scan_is_eof(&scanner)) { pj_scan_get_until_ch(&scanner, ',', &str); pj_strrtrim(&str); if (!pj_scan_is_eof(&scanner)) pj_scan_advance_n(&scanner, 1, PJ_TRUE); if (!str.slen) continue; if (cmd->sc_cnt >= PJ_CLI_MAX_SHORTCUTS) { PJ_THROW(PJ_CLI_ETOOMANYARGS); } /* Check whether the shortcuts are already used */ if (cmd_name_exists(cli, group, &str)) { PJ_THROW(PJ_CLI_EBADNAME); } pj_strassign(&sc[cmd->sc_cnt++], &str); } } PJ_CATCH_ANY { pj_scan_fini(&scanner); return (PJ_GET_EXCEPTION()); } PJ_END; } else if (!pj_stricmp2(&attr->name, "desc")) {
// // Left trim. // void ltrim() { pj_strltrim(this); }
static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs) { pjmedia_sdp_attr *attr; pjmedia_sdp_rtpmap *rtpmap; pjmedia_sdp_fmtp fmtp; struct ast_format *format; int i, num = 0; char name[256]; char media[20]; char fmt_param[256]; ast_rtp_codecs_payloads_initialize(codecs); /* Iterate through provided formats */ for (i = 0; i < stream->desc.fmt_count; ++i) { /* The payload is kept as a string for things like t38 but for video it is always numerical */ ast_rtp_codecs_payloads_set_m_type(codecs, NULL, pj_strtoul(&stream->desc.fmt[i])); /* Look for the optional rtpmap attribute */ if (!(attr = pjmedia_sdp_media_find_attr2(stream, "rtpmap", &stream->desc.fmt[i]))) { continue; } /* Interpret the attribute as an rtpmap */ if ((pjmedia_sdp_attr_to_rtpmap(session->inv_session->pool_prov, attr, &rtpmap)) != PJ_SUCCESS) { continue; } ast_copy_pj_str(name, &rtpmap->enc_name, sizeof(name)); ast_copy_pj_str(media, (pj_str_t*)&stream->desc.media, sizeof(media)); ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]), media, name, 0, rtpmap->clock_rate); /* Look for an optional associated fmtp attribute */ if (!(attr = pjmedia_sdp_media_find_attr2(stream, "fmtp", &rtpmap->pt))) { continue; } if ((pjmedia_sdp_attr_get_fmtp(attr, &fmtp)) == PJ_SUCCESS) { sscanf(pj_strbuf(&fmtp.fmt), "%d", &num); if ((format = ast_rtp_codecs_get_payload_format(codecs, num))) { struct ast_format *format_parsed; ast_copy_pj_str(fmt_param, &fmtp.fmt_param, sizeof(fmt_param)); format_parsed = ast_format_parse_sdp_fmtp(format, fmt_param); if (format_parsed) { ast_rtp_codecs_payload_replace_format(codecs, num, format_parsed); ao2_ref(format_parsed, -1); } ao2_ref(format, -1); } } } /* Get the packetization, if it exists */ if ((attr = pjmedia_sdp_media_find_attr2(stream, "ptime", NULL))) { unsigned long framing = pj_strtoul(pj_strltrim(&attr->value)); if (framing && session->endpoint->media.rtp.use_ptime) { ast_rtp_codecs_set_framing(codecs, framing); } } }
PJ_DEF(pj_status_t) pj_strtoul3(const pj_str_t *str, unsigned long *value, unsigned base) { pj_str_t s; unsigned i; PJ_CHECK_STACK(); if (!str || !value) { return PJ_EINVAL; } s = *str; pj_strltrim(&s); if (s.slen == 0 || s.ptr[0] < '0' || (base <= 10 && (unsigned)s.ptr[0] > ('0' - 1) + base) || (base == 16 && !pj_isxdigit(s.ptr[0]))) { return PJ_EINVAL; } *value = 0; if (base <= 10) { for (i=0; i<(unsigned)s.slen; ++i) { unsigned c = s.ptr[i] - '0'; if (s.ptr[i] < '0' || (unsigned)s.ptr[i] > ('0' - 1) + base) { break; } if (*value > PJ_MAXULONG / base) { *value = PJ_MAXULONG; return PJ_ETOOBIG; } *value *= base; if ((PJ_MAXULONG - *value) < c) { *value = PJ_MAXULONG; return PJ_ETOOBIG; } *value += c; } } else if (base == 16) { for (i=0; i<(unsigned)s.slen; ++i) { unsigned c = pj_hex_digit_to_val(s.ptr[i]); if (!pj_isxdigit(s.ptr[i])) break; if (*value > PJ_MAXULONG / base) { *value = PJ_MAXULONG; return PJ_ETOOBIG; } *value *= base; if ((PJ_MAXULONG - *value) < c) { *value = PJ_MAXULONG; return PJ_ETOOBIG; } *value += c; } } else { pj_assert(!"Unsupported base"); return PJ_EINVAL; } return PJ_SUCCESS; }