/*! * \internal * \brief Adds a path header to an outgoing 2XX response * * \param endpoint The endpoint to which the INVITE response is to be sent * \param contact The contact to which the INVITE response is to be sent * \param tdata The outbound INVITE response */ static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata) { struct pjsip_status_line status = tdata->msg->line.status; pj_str_t path_dup; pjsip_generic_string_hdr *path_hdr; pjsip_contact_hdr *contact_hdr; RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup); pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); const pj_str_t REGISTER_METHOD = {"REGISTER", 8}; if (!endpoint || !pj_stristr(®ISTER_METHOD, &cseq->method.name) || !PJSIP_IS_STATUS_IN_CLASS(status.code, 200)) { return; } contact_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL); if (!contact_hdr) { return; } aor = find_aor(endpoint, contact_hdr->uri); if (!aor || !aor->support_path || add_supported(tdata) || path_get_string(tdata->pool, contact, &path_dup)) { return; } path_hdr = pjsip_generic_string_hdr_create(tdata->pool, &PATH_NAME, &path_dup); if (!path_hdr) { return; } pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)path_hdr); }
/* Get platform info, returned format will be "Series60vX.X" */ unsigned pj_symbianos_get_platform_info(char *buf, unsigned buf_size) { /* OS info */ _LIT(KS60ProductIDFile, "Series60v*.sis"); _LIT(KROMInstallDir, "z:\\system\\install\\"); RFs fs; TFindFile ff(fs); CDir* result; pj_str_t plat_info = {NULL, 0}; TInt err; fs.Connect(1); err = ff.FindWildByDir(KS60ProductIDFile, KROMInstallDir, result); if (err == KErrNone) { err = result->Sort(ESortByName|EDescending); if (err == KErrNone) { TPtr8 tmp_ptr8((TUint8*)buf, buf_size); const pj_str_t tmp_ext = {".sis", 4}; char *p; tmp_ptr8.Copy((*result)[0].iName); pj_strset(&plat_info, buf, (pj_size_t)tmp_ptr8.Length()); p = pj_stristr(&plat_info, &tmp_ext); if (p) plat_info.slen -= (p - plat_info.ptr); } delete result; } fs.Close(); buf[plat_info.slen] = '\0'; return plat_info.slen; }
/* Toggle AMR octet-align setting in the fmtp. */ static pj_status_t amr_toggle_octet_align(pj_pool_t *pool, pjmedia_sdp_media *media, unsigned fmt_idx) { pjmedia_sdp_attr *attr; pjmedia_sdp_fmtp fmtp; const pj_str_t STR_OCTET_ALIGN = {"octet-align=", 12}; enum { MAX_FMTP_STR_LEN = 160 }; attr = pjmedia_sdp_media_find_attr2(media, "fmtp", &media->desc.fmt[fmt_idx]); /* Check if the AMR media format has FMTP attribute */ if (attr) { char *p; pj_status_t status; status = pjmedia_sdp_attr_get_fmtp(attr, &fmtp); if (status != PJ_SUCCESS) return status; /* Check if the fmtp has octet-align field. */ p = pj_stristr(&fmtp.fmt_param, &STR_OCTET_ALIGN); if (p) { /* It has, just toggle the value */ unsigned octet_align; pj_str_t s; pj_strset(&s, p + STR_OCTET_ALIGN.slen, fmtp.fmt_param.slen - (p - fmtp.fmt_param.ptr) - STR_OCTET_ALIGN.slen); octet_align = pj_strtoul(&s); *(p + STR_OCTET_ALIGN.slen) = (char)(octet_align? '0' : '1'); } else { /* It doesn't, append octet-align field */ char buf[MAX_FMTP_STR_LEN]; pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN, "%.*s;octet-align=1", (int)fmtp.fmt_param.slen, fmtp.fmt_param.ptr); attr->value = pj_strdup3(pool, buf); } } else { /* Add new attribute for the AMR media format with octet-align * field set. */ char buf[MAX_FMTP_STR_LEN]; attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); attr->name = pj_str("fmtp"); pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN, "%.*s octet-align=1", (int)media->desc.fmt[fmt_idx].slen, media->desc.fmt[fmt_idx].ptr); attr->value = pj_strdup3(pool, buf); media->attr[media->attr_count++] = attr; } return PJ_SUCCESS; }
/* Matching G722.1 bitrates between offer and answer. */ static pj_bool_t match_g7221( const pjmedia_sdp_media *offer, unsigned o_fmt_idx, const pjmedia_sdp_media *answer, unsigned a_fmt_idx) { const pjmedia_sdp_attr *a_ans; const pjmedia_sdp_attr *a_off; pjmedia_sdp_fmtp fmtp; unsigned a_bitrate = 0, o_bitrate = 0; const pj_str_t bitrate = {"bitrate=", 8}; const char *p; a_ans = pjmedia_sdp_media_find_attr2(answer, "fmtp", &answer->desc.fmt[a_fmt_idx]); if (!a_ans) return PJ_FALSE; if (pjmedia_sdp_attr_get_fmtp(a_ans, &fmtp) != PJ_SUCCESS) return PJ_FALSE; p = pj_stristr(&fmtp.fmt_param, &bitrate); if (p == NULL) return PJ_FALSE; a_bitrate = atoi(p + bitrate.slen); a_off = pjmedia_sdp_media_find_attr2(offer, "fmtp", &offer->desc.fmt[o_fmt_idx]); if (!a_off) return PJ_FALSE; if (pjmedia_sdp_attr_get_fmtp(a_off, &fmtp) != PJ_SUCCESS) return PJ_FALSE; p = pj_stristr(&fmtp.fmt_param, &bitrate); if (p == NULL) return PJ_FALSE; o_bitrate = atoi(p + bitrate.slen); return (a_bitrate == o_bitrate); }
static pjmedia_sdp_attr* opus_sdp_get_opus_rtpmap_attr(pjmedia_sdp_session* sdp_session){ unsigned media_idx; unsigned attr_idx; for(media_idx = 0; media_idx < sdp_session->media_count; media_idx++){ pjmedia_sdp_media *media = sdp_session->media[media_idx]; if(pj_stricmp(&media->desc.media, &STR_AUDIO)==0){ for(attr_idx=0; attr_idx < media->attr_count; attr_idx++){ if(pj_stricmp(&media->attr[attr_idx]->name, &STR_RTPMAP)==0){ char* found_opus = pj_stristr(&media->attr[attr_idx]->value, &STR_OPUS); if(found_opus != NULL){ return media->attr[attr_idx]; } } } } } return NULL; }
/* Notification on incoming messages */ static pj_bool_t opus_sdp_on_rx_msg(pjsip_rx_data *rdata) { if(rdata && rdata->msg_info.msg){ pjsip_msg_body* body = rdata->msg_info.msg->body; if(opus_sdp_body_is_sdp(body)){ pj_str_t body_str = {body->data, body->len}; char* found_opus = pj_stristr(&body_str, &STR_OPUS_RFC_FMT); if(found_opus != NULL){ pj_str_t new_value; new_value.ptr = (char*) pj_pool_alloc(rdata->tp_info.pool, STR_OPUS_RFC_FMT.slen+1); new_value.slen = pj_ansi_snprintf(new_value.ptr, STR_OPUS_RFC_FMT.slen+1, "opus/%d/1", pjopus_internal_clockrate); while(new_value.slen < STR_OPUS_RFC_FMT.slen+1){ new_value.ptr[new_value.slen ++] = ' '; } pj_memcpy(found_opus, new_value.ptr, new_value.slen - 1); } } } /* Always return false, otherwise messages will not get processed! */ return PJ_FALSE; }
/* Notification on outgoing messages */ static pj_status_t opus_sdp_on_tx_msg(pjsip_tx_data *tdata) { if(tdata && tdata->msg){ pjsip_msg_body* body = tdata->msg->body; if (opus_sdp_body_is_sdp(body)) { pjsip_msg_body* new_body = pjsip_msg_body_clone(tdata->pool, body); pjmedia_sdp_attr* opus_attr = opus_sdp_get_opus_rtpmap_attr((pjmedia_sdp_session*) new_body->data); if(opus_attr != NULL){ pj_str_t new_value; char* found_opus = pj_stristr(&opus_attr->value, &STR_OPUS); new_value.ptr = (char*) pj_pool_alloc(tdata->pool, 20); new_value.slen = pj_ansi_snprintf(new_value.ptr, 20, "%.*s%.*s", found_opus - opus_attr->value.ptr, opus_attr->value.ptr, STR_OPUS_RFC_FMT.slen, STR_OPUS_RFC_FMT.ptr); opus_attr->value = new_value; tdata->msg->body = new_body; } } } /* Always return success, otherwise message will not get sent! */ return PJ_SUCCESS; }
PJ_END_DECL /* Get Symbian phone model info, returning length of model info */ unsigned pj_symbianos_get_model_info(char *buf, unsigned buf_size) { pj_str_t model_name; /* Get machine UID */ TInt hal_val; HAL::Get(HAL::EMachineUid, hal_val); pj_ansi_snprintf(buf, buf_size, "0x%08X", hal_val); pj_strset2(&model_name, buf); /* Get model name */ const pj_str_t st_copyright = {"(C)", 3}; const pj_str_t st_nokia = {"Nokia", 5}; char tmp_buf[64]; pj_str_t tmp_str; _LIT(KModelFilename,"Z:\\resource\\versions\\model.txt"); RFile file; RFs fs; TInt err; fs.Connect(1); err = file.Open(fs, KModelFilename, EFileRead); if (err == KErrNone) { TFileText text; text.Set(file); TBuf16<64> ModelName16; err = text.Read(ModelName16); if (err == KErrNone) { TPtr8 ptr8((TUint8*)tmp_buf, sizeof(tmp_buf)); ptr8.Copy(ModelName16); pj_strset(&tmp_str, tmp_buf, ptr8.Length()); pj_strtrim(&tmp_str); } file.Close(); } fs.Close(); if (err != KErrNone) goto on_return; /* The retrieved model name is usually in long format, e.g: * "© Nokia N95 (01.01)", "(C) Nokia E52". As we need only * the short version, let's clean it up. */ /* Remove preceding non-ASCII chars, e.g: "©" */ char *p = tmp_str.ptr; while (!pj_isascii(*p)) { p++; } pj_strset(&tmp_str, p, tmp_str.slen - (p - tmp_str.ptr)); /* Remove "(C)" */ p = pj_stristr(&tmp_str, &st_copyright); if (p) { p += st_copyright.slen; pj_strset(&tmp_str, p, tmp_str.slen - (p - tmp_str.ptr)); } /* Remove "Nokia" */ p = pj_stristr(&tmp_str, &st_nokia); if (p) { p += st_nokia.slen; pj_strset(&tmp_str, p, tmp_str.slen - (p - tmp_str.ptr)); } /* Remove language version, e.g: "(01.01)" */ p = pj_strchr(&tmp_str, '('); if (p) { tmp_str.slen = p - tmp_str.ptr; } pj_strtrim(&tmp_str); if (tmp_str.slen == 0) goto on_return; if ((unsigned)tmp_str.slen > buf_size - model_name.slen - 3) tmp_str.slen = buf_size - model_name.slen - 3; pj_strcat2(&model_name, "("); pj_strcat(&model_name, &tmp_str); pj_strcat2(&model_name, ")"); /* Zero terminate */ buf[model_name.slen] = '\0'; on_return: return model_name.slen; }
static void pcap2wav(const pj_str_t *codec, const pj_str_t *wav_filename, pjmedia_aud_dev_index dev_id, const pj_str_t *srtp_crypto, const pj_str_t *srtp_key) { const pj_str_t WAV = {".wav", 4}; struct pkt { pj_uint8_t buffer[320]; pjmedia_rtp_hdr *rtp; pj_uint8_t *payload; unsigned payload_len; } pkt0; pjmedia_codec_mgr *cmgr; const pjmedia_codec_info *ci; pjmedia_codec_param param; unsigned samples_per_frame; pj_status_t status; /* Initialize all codecs */ T( pjmedia_codec_register_audio_codecs(app.mept, NULL) ); /* Create SRTP transport is needed */ #if PJMEDIA_HAS_SRTP if (srtp_crypto->slen) { pjmedia_srtp_crypto crypto; pj_bzero(&crypto, sizeof(crypto)); crypto.key = *srtp_key; crypto.name = *srtp_crypto; T( pjmedia_transport_srtp_create(app.mept, NULL, NULL, &app.srtp) ); T( pjmedia_transport_srtp_start(app.srtp, &crypto, &crypto) ); } #else PJ_UNUSED_ARG(srtp_crypto); PJ_UNUSED_ARG(srtp_key); #endif /* Read first packet */ read_rtp(pkt0.buffer, sizeof(pkt0.buffer), &pkt0.rtp, &pkt0.payload, &pkt0.payload_len, PJ_FALSE); cmgr = pjmedia_endpt_get_codec_mgr(app.mept); /* Get codec info and param for the specified payload type */ app.pt = pkt0.rtp->pt; if (app.pt >=0 && app.pt < 96) { T( pjmedia_codec_mgr_get_codec_info(cmgr, pkt0.rtp->pt, &ci) ); } else { unsigned cnt = 2; const pjmedia_codec_info *info[2]; T( pjmedia_codec_mgr_find_codecs_by_id(cmgr, codec, &cnt, info, NULL) ); if (cnt != 1) err_exit("Codec ID must be specified and unique!", 0); ci = info[0]; } T( pjmedia_codec_mgr_get_default_param(cmgr, ci, ¶m) ); /* Alloc and init codec */ T( pjmedia_codec_mgr_alloc_codec(cmgr, ci, &app.codec) ); T( pjmedia_codec_init(app.codec, app.pool) ); T( pjmedia_codec_open(app.codec, ¶m) ); /* Init audio device or WAV file */ samples_per_frame = ci->clock_rate * param.info.frm_ptime / 1000; if (pj_strcmp2(wav_filename, "-") == 0) { pjmedia_aud_param aud_param; /* Open audio device */ T( pjmedia_aud_dev_default_param(dev_id, &aud_param) ); aud_param.dir = PJMEDIA_DIR_PLAYBACK; aud_param.channel_count = ci->channel_cnt; aud_param.clock_rate = ci->clock_rate; aud_param.samples_per_frame = samples_per_frame; T( pjmedia_aud_stream_create(&aud_param, NULL, &play_cb, NULL, &app.aud_strm) ); T( pjmedia_aud_stream_start(app.aud_strm) ); } else if (pj_stristr(wav_filename, &WAV)) { /* Open WAV file */ T( pjmedia_wav_writer_port_create(app.pool, wav_filename->ptr, ci->clock_rate, ci->channel_cnt, samples_per_frame, param.info.pcm_bits_per_sample, 0, 0, &app.wav) ); } else { err_exit("invalid output file", PJ_EINVAL); } /* Loop reading PCAP and writing WAV file */ for (;;) { struct pkt pkt1; pj_timestamp ts; pjmedia_frame frames[16], pcm_frame; short pcm[320]; unsigned i, frame_cnt; long samples_cnt, ts_gap; pj_assert(sizeof(pcm) >= samples_per_frame); /* Parse first packet */ ts.u64 = 0; frame_cnt = PJ_ARRAY_SIZE(frames); T( pjmedia_codec_parse(app.codec, pkt0.payload, pkt0.payload_len, &ts, &frame_cnt, frames) ); /* Decode and write to WAV file */ samples_cnt = 0; for (i=0; i<frame_cnt; ++i) { pjmedia_frame pcm_frame; pcm_frame.buf = pcm; pcm_frame.size = samples_per_frame * 2; T( pjmedia_codec_decode(app.codec, &frames[i], (unsigned)pcm_frame.size, &pcm_frame) ); if (app.wav) { T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); } if (app.aud_strm) { T( wait_play(&pcm_frame) ); } samples_cnt += samples_per_frame; } /* Read next packet */ read_rtp(pkt1.buffer, sizeof(pkt1.buffer), &pkt1.rtp, &pkt1.payload, &pkt1.payload_len, PJ_TRUE); /* Fill in the gap (if any) between pkt0 and pkt1 */ ts_gap = pj_ntohl(pkt1.rtp->ts) - pj_ntohl(pkt0.rtp->ts) - samples_cnt; while (ts_gap >= (long)samples_per_frame) { pcm_frame.buf = pcm; pcm_frame.size = samples_per_frame * 2; if (app.codec->op->recover) { T( pjmedia_codec_recover(app.codec, (unsigned)pcm_frame.size, &pcm_frame) ); } else { pj_bzero(pcm_frame.buf, pcm_frame.size); } if (app.wav) { T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); } if (app.aud_strm) { T( wait_play(&pcm_frame) ); } ts_gap -= samples_per_frame; } /* Next */ pkt0 = pkt1; pkt0.rtp = (pjmedia_rtp_hdr*)pkt0.buffer; pkt0.payload = pkt0.buffer + (pkt1.payload - pkt1.buffer); } }