static int print_media_desc( pjmedia_sdp_media *m, char *buf, int len) { char *p = buf; char *end = buf+len; unsigned i; int printed; /* check length for the "m=" line. */ if (len < m->desc.media.slen+m->desc.transport.slen+12+24) { return -1; } *p++ = 'm'; /* m= */ *p++ = '='; pj_memcpy(p, m->desc.media.ptr, m->desc.media.slen); p += m->desc.media.slen; *p++ = ' '; printed = pj_utoa(m->desc.port, p); p += printed; if (m->desc.port_count > 1) { *p++ = '/'; printed = pj_utoa(m->desc.port_count, p); p += printed; } *p++ = ' '; pj_memcpy(p, m->desc.transport.ptr, m->desc.transport.slen); p += m->desc.transport.slen; for (i=0; i<m->desc.fmt_count; ++i) { *p++ = ' '; pj_memcpy(p, m->desc.fmt[i].ptr, m->desc.fmt[i].slen); p += m->desc.fmt[i].slen; } *p++ = '\r'; *p++ = '\n'; /* print connection info, if present. */ if (m->conn) { printed = print_connection_info(m->conn, p, end-p); if (printed < 0) { return -1; } p += printed; } /* print attributes. */ for (i=0; i<m->attr_count; ++i) { printed = print_attr(m->attr[i], p, end-p); if (printed < 0) { return -1; } p += printed; } return p-buf; }
/* * Min-SE header vptr. */ static int min_se_hdr_print(pjsip_min_se_hdr *hdr, char *buf, pj_size_t size) { char *p = buf; char *endbuf = buf+size; pj_ssize_t printed; const pjsip_parser_const_t *pc = pjsip_parser_const(); /* Print header name and value */ if ((endbuf - p) < (hdr->name.slen + 16)) return -1; copy_advance(p, hdr->name); *p++ = ':'; *p++ = ' '; printed = pj_utoa(hdr->min_se, p); p += printed; /* Print generic params */ printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p, &pc->pjsip_TOKEN_SPEC, &pc->pjsip_TOKEN_SPEC, ';'); if (printed < 0) return (int)printed; p += printed; return (int)(p - buf); }
/** * Apply opus settings to dec_fmtp parameters */ void apply_opus_codec_params(pj_pool_t *pool, pjmedia_codec_param *attr) { attr->setting.dec_fmtp.cnt = 0; if (attr->setting.plc == 0) { attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].name = pj_str("useinbandfec"); attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].val = pj_str("0"); attr->setting.dec_fmtp.cnt++; } if (attr->setting.vad == 1) { attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].name = pj_str("usedtx"); attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].val = pj_str("1"); attr->setting.dec_fmtp.cnt++; } if (attr->info.channel_cnt == 2) { attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].name = pj_str("stereo"); attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].val = pj_str("1"); attr->setting.dec_fmtp.cnt++; } if (attr->info.clock_rate < 48000) { attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].name = pj_str("maxplaybackrate"); char clock_rate_char[8]; pj_utoa(attr->info.clock_rate, clock_rate_char); pj_strdup2(pool, &attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].val, clock_rate_char); attr->setting.dec_fmtp.cnt++; } }
void SIPPresence::updateStatus(bool status, const std::string ¬e) { //char* pj_note = (char*) pj_pool_alloc(pool_, "50"); pjrpid_element rpid = { PJRPID_ELEMENT_TYPE_PERSON, CONST_PJ_STR("0"), PJRPID_ACTIVITY_UNKNOWN, pj_str((char *) note.c_str()) }; /* fill activity if user not available. */ if (note == "away") rpid.activity = PJRPID_ACTIVITY_AWAY; else if (note == "busy") rpid.activity = PJRPID_ACTIVITY_BUSY; /* else // TODO: is there any other possibilities DEBUG("Presence : no activity"); */ pj_bzero(&status_data_, sizeof(status_data_)); status_data_.info_cnt = 1; status_data_.info[0].basic_open = status; // at most we will have 3 digits + NULL termination char buf[4]; pj_utoa(rand() % 1000, buf); status_data_.info[0].id = pj_strdup3(pool_, buf); pj_memcpy(&status_data_.info[0].rpid, &rpid, sizeof(pjrpid_element)); /* "contact" field is optionnal */ }
PJ_DEF(pj_xml_node*) pjsip_iscomposing_create_xml( pj_pool_t *pool, pj_bool_t is_composing, const pj_time_val *lst_actv, const pj_str_t *content_tp, int refresh) { pj_xml_node *doc, *node; pj_xml_attr *attr; /* Root document. */ doc = pj_xml_node_new(pool, &STR_ISCOMPOSING); /* Add attributes */ attr = pj_xml_attr_new(pool, &STR_XMLNS_NAME, &STR_XMLNS_VAL); pj_xml_add_attr(doc, attr); attr = pj_xml_attr_new(pool, &STR_XMLNS_XSI_NAME, &STR_XMLNS_XSI_VAL); pj_xml_add_attr(doc, attr); attr = pj_xml_attr_new(pool, &STR_XSI_SLOC_NAME, &STR_XSI_SLOC_VAL); pj_xml_add_attr(doc, attr); /* Add state. */ node = pj_xml_node_new(pool, &STR_STATE); if (is_composing) node->content = STR_ACTIVE; else node->content = STR_IDLE; pj_xml_add_node(doc, node); /* Add lastactive, if any. */ PJ_UNUSED_ARG(lst_actv); //if (!is_composing && lst_actv) { // PJ_TODO(IMPLEMENT_LAST_ACTIVE_ATTRIBUTE); //} /* Add contenttype, if any. */ if (content_tp) { node = pj_xml_node_new(pool, &STR_CONTENTTYPE); pj_strdup(pool, &node->content, content_tp); pj_xml_add_node(doc, node); } /* Add refresh, if any. */ if (is_composing && refresh > 1 && refresh < 3601) { node = pj_xml_node_new(pool, &STR_REFRESH); node->content.ptr = (char*) pj_pool_alloc(pool, 10); node->content.slen = pj_utoa(refresh, node->content.ptr); pj_xml_add_node(doc, node); } /* Done! */ return doc; }
int pjsip_session_expires_hdr_print_on(void* h, char* buf, pj_size_t len) { char* p = buf; const pjsip_session_expires_hdr* hdr = (pjsip_session_expires_hdr*)h; const pjsip_parser_const_t *pc = pjsip_parser_const(); // As per pjsip_generic_int_hdr_print, integers are fewer then 15 characters long. if ((pj_ssize_t)len < hdr->name.slen + 15) { return -1; } pj_memcpy(p, hdr->name.ptr, hdr->name.slen); p += hdr->name.slen; *p++ = ':'; *p++ = ' '; p += pj_utoa(hdr->expires, p); if (hdr->refresher != SESSION_REFRESHER_UNKNOWN) { // Check the refresher parameter will fit. if (buf+len-p < 14) { return -1; } // Fill it in *p++ = ';'; pj_memcpy(p, "refresher=", 10); p += 10; if (hdr->refresher == SESSION_REFRESHER_UAC) { pj_memcpy(p, "uac", 3); } else { pj_memcpy(p, "uas", 3); } p += 3; } // Try to add the other params. pj_ssize_t printed = pjsip_param_print_on(&hdr->other_param, p, buf+len-p, &pc->pjsip_TOKEN_SPEC, &pc->pjsip_TOKEN_SPEC, ';'); if (printed < 0) { return -1; } p += printed; *p = '\0'; return p - buf; }
static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, char *buf, pj_size_t size) { char *p = buf; char *endbuf = buf+size; pj_ssize_t printed; const pjsip_parser_const_t *pc = pjsip_parser_const(); copy_advance(p, hdr->name); *p++ = ':'; *p++ = ' '; copy_advance_escape(p, hdr->sub_state, pc->pjsip_TOKEN_SPEC); copy_advance_pair_escape(p, ";reason=", 8, hdr->reason_param, pc->pjsip_TOKEN_SPEC); if (hdr->expires_param >= 0) { pj_memcpy(p, ";expires=", 9); p += 9; printed = pj_utoa(hdr->expires_param, p); p += printed; } if (hdr->retry_after >= 0) { pj_memcpy(p, ";retry-after=", 13); p += 13; printed = pj_utoa(hdr->retry_after, p); p += printed; } printed = pjsip_param_print_on( &hdr->other_param, p, endbuf-p, &pc->pjsip_TOKEN_SPEC, &pc->pjsip_TOKEN_SPEC, ';'); if (printed < 0) return (int)printed; p += printed; return (int)(p - buf); }
static pj_ssize_t print_bandw(const pjmedia_sdp_bandw *bandw, char *buf, pj_size_t len) { char *p = buf; if ((int)len < bandw->modifier.slen + 10 + 5) return -1; *p++ = 'b'; *p++ = '='; pj_memcpy(p, bandw->modifier.ptr, bandw->modifier.slen); p += bandw->modifier.slen; *p++ = ':'; p += pj_utoa(bandw->value, p); *p++ = '\r'; *p++ = '\n'; return p-buf; }
/* * Session-Expires header vptr. */ static int se_hdr_print(pjsip_sess_expires_hdr *hdr, char *buf, pj_size_t size) { char *p = buf; char *endbuf = buf+size; pj_ssize_t printed; const pjsip_parser_const_t *pc = pjsip_parser_const(); const pj_str_t *hname = pjsip_use_compact_form? &hdr->sname : &hdr->name; /* Print header name and value */ if ((endbuf - p) < (hname->slen + 16)) return -1; copy_advance(p, (*hname)); *p++ = ':'; *p++ = ' '; printed = pj_utoa(hdr->sess_expires, p); p += printed; /* Print 'refresher' param */ if (hdr->refresher.slen) { if ((endbuf - p) < (STR_REFRESHER.slen + 2 + hdr->refresher.slen)) return -1; *p++ = ';'; copy_advance(p, STR_REFRESHER); *p++ = '='; copy_advance(p, hdr->refresher); } /* Print generic params */ printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p, &pc->pjsip_TOKEN_SPEC, &pc->pjsip_TOKEN_SPEC, ';'); if (printed < 0) return (int)printed; p += printed; return (int)(p - buf); }
static int print_session(const pjmedia_sdp_session *ses, char *buf, pj_ssize_t len) { char *p = buf; char *end = buf+len; unsigned i; int printed; /* Check length for v= and o= lines. */ if (len < 5+ 2+ses->origin.user.slen+18+ ses->origin.net_type.slen+ses->origin.addr.slen + 2) { return -1; } /* SDP version (v= line) */ pj_memcpy(p, "v=0\r\n", 5); p += 5; /* Owner (o=) line. */ *p++ = 'o'; *p++ = '='; pj_memcpy(p, ses->origin.user.ptr, ses->origin.user.slen); p += ses->origin.user.slen; *p++ = ' '; printed = pj_utoa(ses->origin.id, p); p += printed; *p++ = ' '; printed = pj_utoa(ses->origin.version, p); p += printed; *p++ = ' '; pj_memcpy(p, ses->origin.net_type.ptr, ses->origin.net_type.slen); p += ses->origin.net_type.slen; *p++ = ' '; pj_memcpy(p, ses->origin.addr_type.ptr, ses->origin.addr_type.slen); p += ses->origin.addr_type.slen; *p++ = ' '; pj_memcpy(p, ses->origin.addr.ptr, ses->origin.addr.slen); p += ses->origin.addr.slen; *p++ = '\r'; *p++ = '\n'; /* Session name (s=) line. */ if ((end-p) < 8+ses->name.slen) { return -1; } *p++ = 's'; *p++ = '='; pj_memcpy(p, ses->name.ptr, ses->name.slen); p += ses->name.slen; *p++ = '\r'; *p++ = '\n'; /* Connection line (c=) if exist. */ if (ses->conn) { printed = print_connection_info(ses->conn, p, end-p); if (printed < 1) { return -1; } p += printed; } /* Time */ if ((end-p) < 24) { return -1; } *p++ = 't'; *p++ = '='; printed = pj_utoa(ses->time.start, p); p += printed; *p++ = ' '; printed = pj_utoa(ses->time.stop, p); p += printed; *p++ = '\r'; *p++ = '\n'; /* Print all attribute (a=) lines. */ for (i=0; i<ses->attr_count; ++i) { printed = print_attr(ses->attr[i], p, end-p); if (printed < 0) { return -1; } p += printed; } /* Print media (m=) lines. */ for (i=0; i<ses->media_count; ++i) { printed = print_media_desc(ses->media[i], p, end-p); if (printed < 0) { return -1; } p += printed; } return p-buf; }
static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context, const pjsip_sip_uri *url, char *buf, pj_size_t size) { int printed; char *startbuf = buf; char *endbuf = buf+size; const pj_str_t *scheme; *buf = '\0'; /* Print scheme ("sip:" or "sips:") */ scheme = pjsip_uri_get_scheme(url); copy_advance_check(buf, *scheme); *buf++ = ':'; /* Print "user:password@", if any. */ if (url->user.slen) { copy_advance_escape(buf, url->user, pjsip_USER_SPEC); if (url->passwd.slen) { *buf++ = ':'; copy_advance_escape(buf, url->passwd, pjsip_PASSWD_SPEC); } *buf++ = '@'; } /* Print host. */ pj_assert(url->host.slen != 0); copy_advance_check(buf, url->host); /* Only print port if it is explicitly specified. * Port is not allowed in To and From header. */ /* Unfortunately some UA requires us to send back the port * number exactly as it was sent. We don't remember whether an * UA has sent us port, so we'll just send the port indiscrimately */ //PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER) if (url->port && context != PJSIP_URI_IN_FROMTO_HDR) { if (endbuf - buf < 10) return -1; *buf++ = ':'; printed = pj_utoa(url->port, buf); buf += printed; } /* User param is allowed in all contexes */ copy_advance_pair_check(buf, ";user="******";method=", 8, url->method_param, pjsip_PARAM_CHAR_SPEC); } /* Transport is not allowed in From/To header. */ if (context != PJSIP_URI_IN_FROMTO_HDR) { copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param, pjsip_PARAM_CHAR_SPEC); } /* TTL param is not allowed in From, To, Route, and Record-Route header. */ if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR && context != PJSIP_URI_IN_ROUTING_HDR) { if (endbuf - buf < 15) return -1; pj_memcpy(buf, ";ttl=", 5); printed = pj_utoa(url->ttl_param, buf+5); buf += printed + 5; } /* maddr param is not allowed in From and To header. */ if (context != PJSIP_URI_IN_FROMTO_HDR) { copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param, pjsip_PARAM_CHAR_SPEC); } /* lr param is not allowed in From, To, and Contact header. */ if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR && context != PJSIP_URI_IN_CONTACT_HDR) { pj_str_t lr = { ";lr", 3 }; if (endbuf - buf < 3) return -1; copy_advance_check(buf, lr); } /* Other param. */ printed = pjsip_param_print_on(&url->other_param, buf, endbuf-buf, &pjsip_PARAM_CHAR_SPEC, &pjsip_PARAM_CHAR_SPEC, ';'); if (printed < 0) return -1; buf += printed; /* Header param. * Header param is only allowed in these contexts: * - PJSIP_URI_IN_CONTACT_HDR * - PJSIP_URI_IN_OTHER */ if (context == PJSIP_URI_IN_CONTACT_HDR || context == PJSIP_URI_IN_OTHER) { printed = pjsip_param_print_on(&url->header_param, buf, endbuf-buf, &pjsip_HDR_CHAR_SPEC, &pjsip_HDR_CHAR_SPEC, '?'); if (printed < 0) return -1; buf += printed; } *buf = '\0'; return buf-startbuf; }
/** * 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; }
/* 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; }
PJ_DEF(void) pj_log( const char *sender, int level, const char *format, va_list marker) { pj_time_val now; pj_parsed_time ptime; char *pre; #if PJ_LOG_USE_STACK_BUFFER char log_buffer[PJ_LOG_MAX_SIZE]; #endif int len, print_len; PJ_CHECK_STACK(); if (level > log_max_level) return; /* Get current date/time. */ pj_gettimeofday(&now); pj_time_decode(&now, &ptime); pre = log_buffer; if (log_decor & PJ_LOG_HAS_DAY_NAME) { static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; pj_ansi_strcpy(pre, wdays[ptime.wday]); pre += 3; } if (log_decor & PJ_LOG_HAS_YEAR) { *pre++ = ' '; pre += pj_utoa(ptime.year, pre); } if (log_decor & PJ_LOG_HAS_MONTH) { *pre++ = '-'; pre += pj_utoa_pad(ptime.mon, pre, 2, '0'); } if (log_decor & PJ_LOG_HAS_DAY_OF_MON) { *pre++ = ' '; pre += pj_utoa_pad(ptime.day, pre, 2, '0'); } if (log_decor & PJ_LOG_HAS_TIME) { *pre++ = ' '; pre += pj_utoa_pad(ptime.hour, pre, 2, '0'); *pre++ = ':'; pre += pj_utoa_pad(ptime.min, pre, 2, '0'); *pre++ = ':'; pre += pj_utoa_pad(ptime.sec, pre, 2, '0'); } if (log_decor & PJ_LOG_HAS_MICRO_SEC) { *pre++ = '.'; pre += pj_utoa_pad(ptime.msec, pre, 3, '0'); } if (log_decor & PJ_LOG_HAS_SENDER) { enum { SENDER_WIDTH = 14 }; int sender_len = strlen(sender); *pre++ = ' '; if (sender_len <= SENDER_WIDTH) { while (sender_len < SENDER_WIDTH) *pre++ = ' ', ++sender_len; while (*sender) *pre++ = *sender++; } else { int i; for (i=0; i<SENDER_WIDTH; ++i) *pre++ = *sender++; } } if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE) *pre++ = ' '; len = pre - log_buffer; /* Print the whole message to the string log_buffer. */ print_len = pj_ansi_vsnprintf(pre, sizeof(log_buffer)-len, format, marker); if (print_len < 0) { level = 1; print_len = pj_ansi_snprintf(pre, sizeof(log_buffer)-len, "<logging error: msg too long>"); } len = len + print_len; if (len > 0 && len < (int)sizeof(log_buffer)-2) { if (log_decor & PJ_LOG_HAS_CR) { log_buffer[len++] = '\r'; } if (log_decor & PJ_LOG_HAS_NEWLINE) { log_buffer[len++] = '\n'; } log_buffer[len] = '\0'; } else { len = sizeof(log_buffer)-1; if (log_decor & PJ_LOG_HAS_CR) { log_buffer[sizeof(log_buffer)-3] = '\r'; } if (log_decor & PJ_LOG_HAS_NEWLINE) { log_buffer[sizeof(log_buffer)-2] = '\n'; } log_buffer[sizeof(log_buffer)-1] = '\0'; } if (log_writer) (*log_writer)(level, log_buffer, len); }
/** * 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; }
static int multipart_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size) { const struct multipart_data *m_data; pj_str_t clen_hdr = { "Content-Length: ", 16}; pjsip_multipart_part *part; char *p = buf, *end = buf+size; #define SIZE_LEFT() (end-p) m_data = (const struct multipart_data*)msg_body->data; PJ_ASSERT_RETURN(m_data && !pj_list_empty(&m_data->part_head), PJ_EINVAL); part = m_data->part_head.next; while (part != &m_data->part_head) { enum { CLEN_SPACE = 5 }; char *clen_pos; const pjsip_hdr *hdr; clen_pos = NULL; /* Print delimiter */ if (SIZE_LEFT() <= (m_data->boundary.slen+8) << 1) return -1; *p++ = 13; *p++ = 10; *p++ = '-'; *p++ = '-'; pj_memcpy(p, m_data->boundary.ptr, m_data->boundary.slen); p += m_data->boundary.slen; *p++ = 13; *p++ = 10; /* Print optional headers */ hdr = part->hdr.next; while (hdr != &part->hdr) { int printed = pjsip_hdr_print_on((pjsip_hdr*)hdr, p, SIZE_LEFT()-2); if (printed < 0) return -1; p += printed; *p++ = '\r'; *p++ = '\n'; hdr = hdr->next; } /* Automaticly adds Content-Type and Content-Length headers, only * if content_type is set in the message body. */ if (part->body && part->body->content_type.type.slen) { pj_str_t ctype_hdr = { "Content-Type: ", 14}; const pjsip_media_type *media = &part->body->content_type; if (pjsip_use_compact_form) { ctype_hdr.ptr = "c: "; ctype_hdr.slen = 3; } /* Add Content-Type header. */ if ( (end-p) < 24 + media->type.slen + media->subtype.slen) { return -1; } pj_memcpy(p, ctype_hdr.ptr, ctype_hdr.slen); p += ctype_hdr.slen; p += pjsip_media_type_print(p, (unsigned)(end-p), media); *p++ = '\r'; *p++ = '\n'; /* Add Content-Length header. */ if ((end-p) < clen_hdr.slen + 12 + 2) { return -1; } pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen); p += clen_hdr.slen; /* Print blanks after "Content-Length:", this is where we'll put * the content length value after we know the length of the * body. */ pj_memset(p, ' ', CLEN_SPACE); clen_pos = p; p += CLEN_SPACE; *p++ = '\r'; *p++ = '\n'; } /* Empty newline */ *p++ = 13; *p++ = 10; /* Print the body */ pj_assert(part->body != NULL); if (part->body) { int printed = part->body->print_body(part->body, p, SIZE_LEFT()); if (printed < 0) return -1; p += printed; /* Now that we have the length of the body, print this to the * Content-Length header. */ if (clen_pos) { char tmp[16]; int len; len = pj_utoa(printed, tmp); if (len > CLEN_SPACE) len = CLEN_SPACE; pj_memcpy(clen_pos+CLEN_SPACE-len, tmp, len); } } part = part->next; } /* Print closing delimiter */ if (SIZE_LEFT() < m_data->boundary.slen+8) return -1; *p++ = 13; *p++ = 10; *p++ = '-'; *p++ = '-'; pj_memcpy(p, m_data->boundary.ptr, m_data->boundary.slen); p += m_data->boundary.slen; *p++ = '-'; *p++ = '-'; *p++ = 13; *p++ = 10; #undef SIZE_LEFT return (int)(p - buf); }
// // Convert from unsigned long. // void from_ulong(unsigned long value) { slen = pj_utoa(value, ptr); }
PJ_DEF(void) pj_log( const char *sender, int level, const char *format, va_list marker) { pj_time_val now; pj_parsed_time ptime; char *pre; #if PJ_LOG_USE_STACK_BUFFER char log_buffer[PJ_LOG_MAX_SIZE]; #endif int saved_level, len, print_len; PJ_CHECK_STACK(); if (level > pj_log_max_level) return; if (is_logging_suspended()) return; /* Temporarily disable logging for this thread. Some of PJLIB APIs that * this function calls below will recursively call the logging function * back, hence it will cause infinite recursive calls if we allow that. */ suspend_logging(&saved_level); /* Get current date/time. */ pj_gettimeofday(&now); pj_time_decode(&now, &ptime); pre = log_buffer; if (log_decor & PJ_LOG_HAS_LEVEL_TEXT) { static const char *ltexts[] = { "FATAL:", "ERROR:", " WARN:", " INFO:", "DEBUG:", "TRACE:", "DETRC:"}; pj_ansi_strcpy(pre, ltexts[level]); pre += 6; } if (log_decor & PJ_LOG_HAS_DAY_NAME) { static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; pj_ansi_strcpy(pre, wdays[ptime.wday]); pre += 3; } if (log_decor & PJ_LOG_HAS_YEAR) { *pre++ = ' '; pre += pj_utoa(ptime.year, pre); } if (log_decor & PJ_LOG_HAS_MONTH) { *pre++ = '-'; pre += pj_utoa_pad(ptime.mon+1, pre, 2, '0'); } if (log_decor & PJ_LOG_HAS_DAY_OF_MON) { *pre++ = '-'; pre += pj_utoa_pad(ptime.day, pre, 2, '0'); } if (log_decor & PJ_LOG_HAS_TIME) { *pre++ = ' '; pre += pj_utoa_pad(ptime.hour, pre, 2, '0'); *pre++ = ':'; pre += pj_utoa_pad(ptime.min, pre, 2, '0'); *pre++ = ':'; pre += pj_utoa_pad(ptime.sec, pre, 2, '0'); } if (log_decor & PJ_LOG_HAS_MICRO_SEC) { *pre++ = '.'; pre += pj_utoa_pad(ptime.msec, pre, 3, '0'); } if (log_decor & PJ_LOG_HAS_SENDER) { enum { SENDER_WIDTH = 14 }; int sender_len = strlen(sender); *pre++ = ' '; if (sender_len <= SENDER_WIDTH) { while (sender_len < SENDER_WIDTH) *pre++ = ' ', ++sender_len; while (*sender) *pre++ = *sender++; } else { int i; for (i=0; i<SENDER_WIDTH; ++i) *pre++ = *sender++; } } if (log_decor & PJ_LOG_HAS_THREAD_ID) { enum { THREAD_WIDTH = 12 }; const char *thread_name = pj_thread_get_name(pj_thread_this()); int thread_len = strlen(thread_name); *pre++ = ' '; if (thread_len <= THREAD_WIDTH) { while (thread_len < THREAD_WIDTH) *pre++ = ' ', ++thread_len; while (*thread_name) *pre++ = *thread_name++; } else { int i; for (i=0; i<THREAD_WIDTH; ++i) *pre++ = *thread_name++; } } if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE) *pre++ = ' '; if (log_decor & PJ_LOG_HAS_SPACE) { *pre++ = ' '; } len = pre - log_buffer; /* Print the whole message to the string log_buffer. */ print_len = pj_ansi_vsnprintf(pre, sizeof(log_buffer)-len, format, marker); if (print_len < 0) { level = 1; print_len = pj_ansi_snprintf(pre, sizeof(log_buffer)-len, "<logging error: msg too long>"); } len = len + print_len; if (len > 0 && len < (int)sizeof(log_buffer)-2) { if (log_decor & PJ_LOG_HAS_CR) { log_buffer[len++] = '\r'; } if (log_decor & PJ_LOG_HAS_NEWLINE) { log_buffer[len++] = '\n'; } log_buffer[len] = '\0'; } else { len = sizeof(log_buffer)-1; if (log_decor & PJ_LOG_HAS_CR) { log_buffer[sizeof(log_buffer)-3] = '\r'; } if (log_decor & PJ_LOG_HAS_NEWLINE) { log_buffer[sizeof(log_buffer)-2] = '\n'; } log_buffer[sizeof(log_buffer)-1] = '\0'; } /* It should be safe to resume logging at this point. Application can * recursively call the logging function inside the callback. */ resume_logging(&saved_level); if (log_writer) (*log_writer)(level, log_buffer, len); }
static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context, const pjsip_sip_uri *url, char *buf, pj_size_t size) { int printed; char *startbuf = buf; char *endbuf = buf+size; const pj_str_t *scheme; const pjsip_parser_const_t *pc = pjsip_parser_const(); *buf = '\0'; /* Print scheme ("sip:" or "sips:") */ scheme = pjsip_uri_get_scheme(url); copy_advance_check(buf, *scheme); *buf++ = ':'; /* Print "user:password@", if any. */ if (url->user.slen) { copy_advance_escape(buf, url->user, pc->pjsip_USER_SPEC); if (url->passwd.slen) { *buf++ = ':'; copy_advance_escape(buf, url->passwd, pc->pjsip_PASSWD_SPEC); } *buf++ = '@'; } /* Print host. */ pj_assert(url->host.slen != 0); /* Detect IPv6 IP address */ if (pj_memchr(url->host.ptr, ':', url->host.slen)) { copy_advance_pair_quote_cond(buf, "", 0, url->host, '[', ']'); } else { copy_advance_check(buf, url->host); } /* Only print port if it is explicitly specified. * Port is not allowed in To and From header, see Table 1 in * RFC 3261 Section 19.1.1 */ /* Note: ticket #1141 adds run-time setting to allow port number to * appear in From/To header. Default is still false. */ if (url->port && (context != PJSIP_URI_IN_FROMTO_HDR || pjsip_cfg()->endpt.allow_port_in_fromto_hdr)) { if (endbuf - buf < 10) return -1; *buf++ = ':'; printed = pj_utoa(url->port, buf); buf += printed; } /* User param is allowed in all contexes */ copy_advance_pair_check(buf, ";user="******";method=", 8, url->method_param, pc->pjsip_PARAM_CHAR_SPEC); } /* Transport is not allowed in From/To header. */ if (context != PJSIP_URI_IN_FROMTO_HDR) { copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param, pc->pjsip_PARAM_CHAR_SPEC); } /* TTL param is not allowed in From, To, Route, and Record-Route header. */ if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR && context != PJSIP_URI_IN_ROUTING_HDR) { if (endbuf - buf < 15) return -1; pj_memcpy(buf, ";ttl=", 5); printed = pj_utoa(url->ttl_param, buf+5); buf += printed + 5; } /* maddr param is not allowed in From and To header. */ if (context != PJSIP_URI_IN_FROMTO_HDR && url->maddr_param.slen) { /* Detect IPv6 IP address */ if (pj_memchr(url->maddr_param.ptr, ':', url->maddr_param.slen)) { copy_advance_pair_quote_cond(buf, ";maddr=", 7, url->maddr_param, '[', ']'); } else { copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param, pc->pjsip_PARAM_CHAR_SPEC); } } /* lr param is not allowed in From, To, and Contact header. */ if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR && context != PJSIP_URI_IN_CONTACT_HDR) { pj_str_t lr = { ";lr", 3 }; if (endbuf - buf < 3) return -1; copy_advance_check(buf, lr); } /* Other param. */ printed = pjsip_param_print_on(&url->other_param, buf, endbuf-buf, &pc->pjsip_PARAM_CHAR_SPEC, &pc->pjsip_PARAM_CHAR_SPEC, ';'); if (printed < 0) return -1; buf += printed; /* Header param. * Header param is only allowed in these contexts: * - PJSIP_URI_IN_CONTACT_HDR * - PJSIP_URI_IN_OTHER */ if (context == PJSIP_URI_IN_CONTACT_HDR || context == PJSIP_URI_IN_OTHER) { printed = pjsip_param_print_on(&url->header_param, buf, endbuf-buf, &pc->pjsip_HDR_CHAR_SPEC, &pc->pjsip_HDR_CHAR_SPEC, '?'); if (printed < 0) return -1; buf += printed; } *buf = '\0'; return buf-startbuf; }
PJ_DEF(pj_status_t) pjmedia_codec_silk_init(pjmedia_endpt *endpt) { pjmedia_codec_mgr *codec_mgr; pj_status_t status; if (silk_factory.endpt != NULL) { /* Already initialized. */ return PJ_SUCCESS; } /* Init factory */ silk_factory.base.op = &silk_factory_op; silk_factory.base.factory_data = NULL; silk_factory.endpt = endpt; /* Create pool */ silk_factory.pool = pjmedia_endpt_create_pool(endpt, "silk codecs", 4000, 4000); if (!silk_factory.pool) return PJ_ENOMEM; /* Init list */ pj_list_init(&silk_factory.codec_list); /* Create mutex. */ status = pj_mutex_create_simple(silk_factory.pool, "silk codecs", &silk_factory.mutex); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(5, (THIS_FILE, "Init silk")); /* Table from silk docs | fs (Hz) | BR (kbps) ----------------+---------+---------- Narrowband | 8000 | 5 - 20 Mediumband | 12000 | 7 - 25 Wideband | 16000 | 8 - 30 Super Wideband | 24000 | 20 - 40 */ // The max_bitrate is based on the maximum bitrate that can be used for the encoder. // BTW, if a remote side send us something very big, we will not get lost. // If such a remote side send us big packets it could be considered unefficient. // On our side we set for bitrate the medium value of bitrate for each clock rate based // on table above. struct silk_param *silk_param; silk_param = &silk_factory.silk_param[PARAM_NB]; silk_param->pt = PJMEDIA_RTP_PT_SILK_NB; silk_param->clock_rate = 8000; silk_param->bitrate = 13000; pj_utoa(silk_param->bitrate, silk_param->bitrate_str); silk_param->max_bitrate = SILK_MAX_CODER_BITRATE; silk_param->packet_size_ms = FRAME_LENGTH_MS; silk_param->complexity = 2; silk_param->enabled = 1; silk_param = &silk_factory.silk_param[PARAM_MB]; silk_param->pt = PJMEDIA_RTP_PT_SILK_MB; silk_param->clock_rate = 12000; silk_param->bitrate = 16000; pj_utoa(silk_param->bitrate, silk_param->bitrate_str); silk_param->max_bitrate = SILK_MAX_CODER_BITRATE; silk_param->packet_size_ms = FRAME_LENGTH_MS; silk_param->complexity = 2; silk_param->enabled = 1; silk_param = &silk_factory.silk_param[PARAM_WB]; silk_param->pt = PJMEDIA_RTP_PT_SILK_WB; silk_param->clock_rate = 16000; silk_param->bitrate = 19000; pj_utoa(silk_param->bitrate, silk_param->bitrate_str); silk_param->max_bitrate = SILK_MAX_CODER_BITRATE; silk_param->packet_size_ms = FRAME_LENGTH_MS; silk_param->complexity = 2; silk_param->enabled = 1; silk_param = &silk_factory.silk_param[PARAM_UWB]; silk_param->pt = PJMEDIA_RTP_PT_SILK_UWB; silk_param->clock_rate = 24000; silk_param->bitrate = 30000; pj_utoa(silk_param->bitrate, silk_param->bitrate_str); silk_param->max_bitrate = SILK_MAX_CODER_BITRATE; silk_param->packet_size_ms = FRAME_LENGTH_MS; silk_param->complexity = 2; silk_param->enabled = 1; /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); if (!codec_mgr) { return PJ_EINVALIDOP; } PJ_LOG(5, (THIS_FILE, "Init silk > DONE")); /* Register codec factory to endpoint. */ status = pjmedia_codec_mgr_register_factory(codec_mgr, &silk_factory.base); if (status != PJ_SUCCESS) return status; return PJ_SUCCESS; on_error: if (silk_factory.mutex) { pj_mutex_destroy(silk_factory.mutex); silk_factory.mutex = NULL; } if (silk_factory.pool) { pj_pool_release(silk_factory.pool); silk_factory.pool = NULL; } return status; }
/* 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; }
int string_test(void) { const pj_str_t hello_world = { HELLO_WORLD, HELLO_WORLD_LEN }; const pj_str_t just_hello = { JUST_HELLO, JUST_HELLO_LEN }; pj_str_t s1, s2, s3, s4, s5; enum { RCOUNT = 10, RLEN = 16 }; pj_str_t random[RCOUNT]; pj_pool_t *pool; int i; pool = pj_pool_create(mem, SNULL, 4096, 0, SNULL); if (!pool) return -5; /* * pj_str(), pj_strcmp(), pj_stricmp(), pj_strlen(), * pj_strncmp(), pj_strchr() */ s1 = pj_str(HELLO_WORLD); if (pj_strcmp(&s1, &hello_world) != 0) return -10; if (pj_stricmp(&s1, &hello_world) != 0) return -20; if (pj_strcmp(&s1, &just_hello) <= 0) return -30; if (pj_stricmp(&s1, &just_hello) <= 0) return -40; if (pj_strlen(&s1) != strlen(HELLO_WORLD)) return -50; if (pj_strncmp(&s1, &hello_world, 5) != 0) return -60; if (pj_strnicmp(&s1, &hello_world, 5) != 0) return -70; if (pj_strchr(&s1, HELLO_WORLD[1]) != s1.ptr+1) return -80; /* * pj_strdup() */ if (!pj_strdup(pool, &s2, &s1)) return -100; if (pj_strcmp(&s1, &s2) != 0) return -110; /* * pj_strcpy(), pj_strcat() */ s3.ptr = (char*) pj_pool_alloc(pool, 256); if (!s3.ptr) return -200; pj_strcpy(&s3, &s2); pj_strcat(&s3, &just_hello); if (pj_strcmp2(&s3, HELLO_WORLD JUST_HELLO) != 0) return -210; /* * pj_strdup2(), pj_strtrim(). */ pj_strdup2(pool, &s4, " " HELLO_WORLD "\t "); pj_strtrim(&s4); if (pj_strcmp2(&s4, HELLO_WORLD) != 0) return -250; /* * pj_utoa() */ s5.ptr = (char*) pj_pool_alloc(pool, 16); if (!s5.ptr) return -270; s5.slen = pj_utoa(UL_VALUE, s5.ptr); /* * pj_strtoul() */ if (pj_strtoul(&s5) != UL_VALUE) return -280; /* * pj_strtoul2() */ s5 = pj_str("123456"); pj_strtoul2(&s5, SNULL, 10); /* Crash test */ if (pj_strtoul2(&s5, &s4, 10) != 123456UL) return -290; if (s4.slen != 0) return -291; if (pj_strtoul2(&s5, &s4, 16) != 0x123456UL) return -292; s5 = pj_str("0123ABCD"); if (pj_strtoul2(&s5, &s4, 10) != 123) return -293; if (s4.slen != 4) return -294; if (s4.ptr == SNULL || *s4.ptr != 'A') return -295; if (pj_strtoul2(&s5, &s4, 16) != 0x123ABCDUL) return -296; if (s4.slen != 0) return -297; /* * pj_create_random_string() * Check that no duplicate strings are returned. */ for (i=0; i<RCOUNT; ++i) { int j; random[i].ptr = (char*) pj_pool_alloc(pool, RLEN); if (!random[i].ptr) return -320; random[i].slen = RLEN; pj_create_random_string(random[i].ptr, RLEN); for (j=0; j<i; ++j) { if (pj_strcmp(&random[i], &random[j])==0) return -330; } } /* Done. */ pj_pool_release(pool); /* Case sensitive comparison test. */ i = strcmp_test(); if (i != 0) return i; /* Caseless comparison test. */ i = stricmp_test(); if (i != 0) return i; return 0; }