/* * Finds out if qop offer contains "auth" token. */ static pj_bool_t has_auth_qop( pj_pool_t *pool, const pj_str_t *qop_offer) { pj_str_t qop; char *p; pj_strdup_with_null( pool, &qop, qop_offer); p = qop.ptr; while (*p) { *p = (char)tolower(*p); ++p; } p = qop.ptr; while (*p) { if (*p=='a' && *(p+1)=='u' && *(p+2)=='t' && *(p+3)=='h') { int e = *(p+4); if (e=='"' || e==',' || e==0) return PJ_TRUE; else p += 4; } else { ++p; } } return PJ_FALSE; }
PJ_DEF(void) pjsip_cred_info_dup(pj_pool_t *pool, pjsip_cred_info *dst, const pjsip_cred_info *src) { pj_memcpy(dst, src, sizeof(pjsip_cred_info)); pj_strdup_with_null(pool, &dst->realm, &src->realm); pj_strdup_with_null(pool, &dst->scheme, &src->scheme); pj_strdup_with_null(pool, &dst->username, &src->username); pj_strdup_with_null(pool, &dst->data, &src->data); if ((dst->data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) { dup_bin(pool, &dst->ext.aka.k, &src->ext.aka.k); dup_bin(pool, &dst->ext.aka.op, &src->ext.aka.op); dup_bin(pool, &dst->ext.aka.amf, &src->ext.aka.amf); } }
pjsip_messaging_create_session( pjsip_endpoint *endpt, const pj_str_t *param_from, const pj_str_t *param_to ) { pj_pool_t *pool; pjsip_messaging_session *ses; pj_str_t tmp, to; pool = pjsip_endpt_create_pool(endpt, "imsess", 1024, 1024); if (!pool) return NULL; ses = pj_pool_calloc(pool, 1, sizeof(pjsip_messaging_session)); ses->pool = pool; ses->endpt = endpt; ses->call_id = pjsip_cid_hdr_create(pool); pj_create_unique_string(pool, &ses->call_id->id); ses->cseq = pjsip_cseq_hdr_create(pool); ses->cseq->cseq = pj_rand(); ses->cseq->method = message_method; ses->from = pjsip_from_hdr_create(pool); pj_strdup_with_null(pool, &tmp, param_from); ses->from->uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (ses->from->uri == NULL) { pjsip_endpt_destroy_pool(endpt, pool); return NULL; } pj_create_unique_string(pool, &ses->from->tag); ses->to = pjsip_to_hdr_create(pool); pj_strdup_with_null(pool, &to, param_from); ses->to->uri = pjsip_parse_uri(pool, to.ptr, to.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (ses->to->uri == NULL) { pjsip_endpt_destroy_pool(endpt, pool); return NULL; } PJ_LOG(4,(THIS_FILE, "IM session created: recipient=%s", to.ptr)); return ses; }
PJ_DECL(pj_status_t) set_turn_credentials(const pj_str_t username, const pj_str_t password, const pj_str_t realm, pj_stun_auth_cred *turn_auth_cred) { PJ_ASSERT_RETURN(turn_auth_cred, PJ_EINVAL); /* Create memory pool for application. */ if(css_var.pool == NULL){ css_var.pool = pjsua_pool_create("css", 1000, 1000); PJ_ASSERT_RETURN(css_var.pool, PJ_ENOMEM); } if (username.slen) { turn_auth_cred->type = PJ_STUN_AUTH_CRED_STATIC; pj_strdup_with_null(css_var.pool, &turn_auth_cred->data.static_cred.username, &username); } else { turn_auth_cred->data.static_cred.username.slen = 0; } if(password.slen) { turn_auth_cred->data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; pj_strdup_with_null(css_var.pool, &turn_auth_cred->data.static_cred.data, &password); }else{ turn_auth_cred->data.static_cred.data.slen = 0; } if(realm.slen) { pj_strdup_with_null(css_var.pool, &turn_auth_cred->data.static_cred.realm, &realm); } else { turn_auth_cred->data.static_cred.realm = pj_str("*"); } return PJ_SUCCESS; }
/* * Duplicate SSL socket parameter. */ PJ_DEF(void) pj_ssl_sock_param_copy( pj_pool_t *pool, pj_ssl_sock_param *dst, const pj_ssl_sock_param *src) { /* Init secure socket param */ pj_memcpy(dst, src, sizeof(*dst)); if (src->ciphers_num > 0) { unsigned i; dst->ciphers = (pj_ssl_cipher*) pj_pool_calloc(pool, src->ciphers_num, sizeof(pj_ssl_cipher)); for (i = 0; i < src->ciphers_num; ++i) dst->ciphers[i] = src->ciphers[i]; } if (src->curves_num > 0) { unsigned i; dst->curves = (pj_ssl_curve *)pj_pool_calloc(pool, src->curves_num, sizeof(pj_ssl_curve)); for (i = 0; i < src->curves_num; ++i) dst->curves[i] = src->curves[i]; } if (src->server_name.slen) { /* Server name must be null-terminated */ pj_strdup_with_null(pool, &dst->server_name, &src->server_name); } if (src->sigalgs.slen) { /* Sigalgs name must be null-terminated */ pj_strdup_with_null(pool, &dst->sigalgs, &src->sigalgs); } if (src->entropy_path.slen) { /* Path name must be null-terminated */ pj_strdup_with_null(pool, &dst->entropy_path, &src->entropy_path); } }
PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_clone(pj_pool_t *pool, const pjmedia_sdp_attr *rhs) { pjmedia_sdp_attr *attr; PJ_ASSERT_RETURN(pool && rhs, NULL); attr = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_attr); pj_strdup(pool, &attr->name, &rhs->name); pj_strdup_with_null(pool, &attr->value, &rhs->value); return attr; }
PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_clone(pj_pool_t *pool, const pjmedia_sdp_attr *rhs) { pjmedia_sdp_attr *attr; PJ_ASSERT_RETURN(pool && rhs, NULL); attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); pj_strdup(pool, &attr->name, &rhs->name); pj_strdup_with_null(pool, &attr->value, &rhs->value); return attr; }
/// Get the URI (either name-addr or addr-spec) from the string header /// (e.g., P-Served-User), ignoring any parameters. If it's a bare /// addr-spec, assume (like Contact) that parameters belong to the /// header, not to the URI. /// /// @return URI, or NULL if cannot be parsed. pjsip_uri* PJUtils::uri_from_string_header(pjsip_generic_string_hdr* hdr, pj_pool_t *pool) { // We must duplicate the string into memory from the specified pool first as // pjsip_parse_uri does not clone the actual strings within the URI. pj_str_t hvalue; pj_strdup_with_null(pool, &hvalue, &hdr->hvalue); char* end = strchr(hvalue.ptr, '>'); if (end != NULL) { *(end + 1) = '\0'; hvalue.slen = (end + 1 - hvalue.ptr); } return pjsip_parse_uri(pool, hvalue.ptr, hvalue.slen, 0); }
static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata) { static const pj_str_t from_name = { "From", 4 }; pjsip_generic_string_hdr *hdr; pj_str_t value; int size; if (!(hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &diversion_name, NULL))) { return NULL; } pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue); /* parse as a fromto header */ return pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr, pj_strlen(&value), &size); }
Jt_Station::Jt_Station(jt_station_config_t *cfg) { PJ_LOG(3, ("station.cpp", "Jt_Station: build a station. id: %d, name: %s", cfg->id, cfg->name.ptr)); _pool = pj_pool_create(&g_cp.factory, cfg->name.ptr, INIT_POOL_STATION_SIZE, INC_POOL_STATION_SIZE, NULL); pj_strdup_with_null(_pool, &_name, &cfg->name); _id = cfg->id; _fin = cfg->fin; _rtinfo = pj_hash_create(_pool, MAX_SIGNAL_KIND_COUNTS); jt_neighbour_config_t *nb = (jt_neighbour_config_t*)pj_pool_calloc(_pool, cfg->link_cnts, sizeof(jt_neighbour_config_t)); for(pj_uint32_t i=0; i<cfg->link_cnts; i++) { nb[i].event = cfg->link_cfg[i]->event; nb[i].stt_id = cfg->link_cfg[i]->stt_id; pj_hash_set(_pool, _rtinfo, &(nb[i].event), sizeof(pj_uint32_t), 0, &(nb[i])); } _car_tbl = pj_hash_create(_pool, MAX_CAR_COUNTS_PER_STATION); _ops_tbl = pj_hash_create(_pool, MAX_SIGNAL_KIND_COUNTS); }
PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_create( pj_pool_t *pool, const char *name, const pj_str_t *value) { pjmedia_sdp_attr *attr; PJ_ASSERT_RETURN(pool && name, NULL); attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); pj_strdup2(pool, &attr->name, name); if (value) pj_strdup_with_null(pool, &attr->value, value); else { attr->value.ptr = NULL; attr->value.slen = 0; } return attr; }
/* * Find buddy. */ PJ_DEF(pjsua_buddy_id) pjsua_buddy_find(const pj_str_t *uri_str) { pj_str_t input; pj_pool_t *pool; pjsip_uri *uri; pjsua_buddy_id buddy_id; pool = pjsua_pool_create("buddyfind", 512, 512); pj_strdup_with_null(pool, &input, uri_str); uri = pjsip_parse_uri(pool, input.ptr, input.slen, 0); if (!uri) buddy_id = PJSUA_INVALID_ID; else buddy_id = pjsua_find_buddy(uri); pj_pool_release(pool); return buddy_id; }
/*! * \internal * \brief Get a P-Asserted-Identity or Remote-Party-ID header from an incoming message * * This function will parse the header as if it were a From header. This allows for us * to easily manipulate the URI, as well as add, modify, or remove parameters from the * header * * \param rdata The incoming message * \param header_name The name of the ID header to find * \retval NULL No ID header present or unable to parse ID header * \retval non-NULL The parsed ID header */ static pjsip_fromto_hdr *get_id_header(pjsip_rx_data *rdata, const pj_str_t *header_name) { static const pj_str_t from = { "From", 4 }; pj_str_t header_content; pjsip_fromto_hdr *parsed_hdr; pjsip_generic_string_hdr *ident = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, header_name, NULL); int parsed_len; if (!ident) { return NULL; } pj_strdup_with_null(rdata->tp_info.pool, &header_content, &ident->hvalue); parsed_hdr = pjsip_parse_hdr(rdata->tp_info.pool, &from, header_content.ptr, pj_strlen(&header_content), &parsed_len); if (!parsed_hdr) { return NULL; } return parsed_hdr; }
/* Set the published address of the transport */ static void udp_set_pub_name(struct udp_transport *tp, const pjsip_host_port *a_name) { enum { INFO_LEN = 80 }; char local_addr[PJ_INET6_ADDRSTRLEN+10]; pj_assert(a_name->host.slen != 0); pj_strdup_with_null(tp->base.pool, &tp->base.local_name.host, &a_name->host); tp->base.local_name.port = a_name->port; /* Update transport info. */ if (tp->base.info == NULL) { tp->base.info = (char*) pj_pool_alloc(tp->base.pool, INFO_LEN); } pj_sockaddr_print(&tp->base.local_addr, local_addr, sizeof(local_addr), 3); pj_ansi_snprintf( tp->base.info, INFO_LEN, "udp %s [published as %s:%d]", local_addr, tp->base.local_name.host.ptr, tp->base.local_name.port); }
/* * Send instant messaging outside dialog, using the specified account for * route set and authentication. */ PJ_DEF(pj_status_t) pjsua_im_send( pjsua_acc_id acc_id, const pj_str_t *to, const pj_str_t *mime_type, const pj_str_t *content, const pjsua_msg_data *msg_data, void *user_data) { pjsip_tx_data *tdata; const pj_str_t mime_text_plain = pj_str("text/plain"); pjsip_media_type media_type; pjsua_im_data *im_data; pjsua_acc *acc; pj_status_t status; /* To and message body must be specified. */ PJ_ASSERT_RETURN(to && content, PJ_EINVAL); acc = &pjsua_var.acc[acc_id]; /* Create request. */ status = pjsip_endpt_create_request(pjsua_var.endpt, &pjsip_message_method, (msg_data && msg_data->target_uri.slen? &msg_data->target_uri: to), &acc->cfg.id, to, NULL, NULL, -1, NULL, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create request", status); return status; } /* If account is locked to specific transport, then set transport to * the request. */ if (acc->cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); pjsip_tx_data_set_transport(tdata, &tp_sel); } /* Add accept header. */ pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)pjsua_im_create_accept(tdata->pool)); /* Create suitable Contact header unless a Contact header has been * set in the account. */ /* Ticket #1632: According to RFC 3428: * MESSAGE requests do not initiate dialogs. * User Agents MUST NOT insert Contact header fields into MESSAGE requests */ /* if (acc->contact.slen) { contact = acc->contact; } else { status = pjsua_acc_create_uac_contact(tdata->pool, &contact, acc_id, to); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); pjsip_tx_data_dec_ref(tdata); return status; } } pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_CONTACT, &contact)); */ /* Create IM data to keep message details and give it back to * application on the callback */ im_data = PJ_POOL_ZALLOC_T(tdata->pool, pjsua_im_data); im_data->acc_id = acc_id; im_data->call_id = PJSUA_INVALID_ID; pj_strdup_with_null(tdata->pool, &im_data->to, to); pj_strdup_with_null(tdata->pool, &im_data->body, content); im_data->user_data = user_data; /* Set default media type if none is specified */ if (mime_type == NULL) { mime_type = &mime_text_plain; } /* Parse MIME type */ pjsua_parse_media_type(tdata->pool, mime_type, &media_type); /* Add message body */ tdata->msg->body = pjsip_msg_body_create( tdata->pool, &media_type.type, &media_type.subtype, &im_data->body); if (tdata->msg->body == NULL) { pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM); pjsip_tx_data_dec_ref(tdata); return PJ_ENOMEM; } /* Add additional headers etc. */ pjsua_process_msg_data(tdata, msg_data); /* Add route set */ pjsua_set_msg_route_set(tdata, &acc->route_set); /* If via_addr is set, use this address for the Via header. */ if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) { tdata->via_addr = acc->via_addr; tdata->via_tp = acc->via_tp; } /* Send request (statefully) */ status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1, im_data, &im_callback); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to send request", status); return status; } return PJ_SUCCESS; }
//Wrap start & stop PJ_DECL(pj_status_t) csipsimple_init(pjsua_config *ua_cfg, pjsua_logging_config *log_cfg, pjsua_media_config *media_cfg, csipsimple_config *css_cfg, jobject context) { pj_status_t result; unsigned i; /* Create memory pool for application. */ if(css_var.pool == NULL){ css_var.pool = pjsua_pool_create("css", 1000, 1000); PJ_ASSERT_RETURN(css_var.pool, PJ_ENOMEM); } // Finalize configuration log_cfg->cb = &pj_android_log_msg; // Static cfg extern pj_bool_t pjsip_use_compact_form; extern pj_bool_t pjsip_include_allow_hdr_in_dlg; extern pj_bool_t pjmedia_add_rtpmap_for_static_pt; extern pj_bool_t pjmedia_add_bandwidth_tias_in_sdp; extern pj_bool_t pjsua_no_update; extern pj_bool_t pjmedia_webrtc_use_ns; pjsua_no_update = css_cfg->use_no_update ? PJ_TRUE : PJ_FALSE; pjsip_use_compact_form = css_cfg->use_compact_form_headers ? PJ_TRUE : PJ_FALSE; /* do not transmit Allow header */ pjsip_include_allow_hdr_in_dlg = css_cfg->use_compact_form_headers ? PJ_FALSE : PJ_TRUE; /* Do not include rtpmap for static payload types (<96) */ pjmedia_add_rtpmap_for_static_pt = css_cfg->use_compact_form_sdp ? PJ_FALSE : PJ_TRUE; /* Do not enable bandwidth information inclusion in sdp */ pjmedia_add_bandwidth_tias_in_sdp = css_cfg->add_bandwidth_tias_in_sdp ? PJ_TRUE : PJ_FALSE; /* Use noise suppressor ? */ pjmedia_webrtc_use_ns = css_cfg->use_noise_suppressor ? PJ_TRUE : PJ_FALSE; css_tcp_keep_alive_interval = css_cfg->tcp_keep_alive_interval; css_tls_keep_alive_interval = css_cfg->tls_keep_alive_interval; // Transaction timeouts pjsip_sip_cfg_var.tsx.t1 = css_cfg->tsx_t1_timeout; pjsip_sip_cfg_var.tsx.t2 = css_cfg->tsx_t2_timeout; pjsip_sip_cfg_var.tsx.t4 = css_cfg->tsx_t4_timeout; pjsip_sip_cfg_var.tsx.td = css_cfg->tsx_td_timeout; pjsip_sip_cfg_var.endpt.disable_tcp_switch = css_cfg->disable_tcp_switch; pjsip_sip_cfg_var.endpt.disable_rport = css_cfg->disable_rport; // Audio codec cfg css_var.extra_aud_codecs_cnt = css_cfg->extra_aud_codecs_cnt; for (i = 0; i < css_cfg->extra_aud_codecs_cnt; i++) { dynamic_factory *css_codec = &css_var.extra_aud_codecs[i]; dynamic_factory *cfg_codec = &css_cfg->extra_aud_codecs[i]; pj_strdup_with_null(css_var.pool, &css_codec->shared_lib_path, &cfg_codec->shared_lib_path); pj_strdup_with_null(css_var.pool, &css_codec->init_factory_name, &cfg_codec->init_factory_name); } // Video codec cfg -- For now only destroy is useful but for future // hopefully vid codec mgr will behaves as audio does // Also in this case destroy will become obsolete css_var.extra_vid_codecs_cnt = css_cfg->extra_vid_codecs_cnt; for (i = 0; i < css_cfg->extra_vid_codecs_cnt; i++) { dynamic_factory *css_codec = &css_var.extra_vid_codecs[i]; dynamic_factory *cfg_codec = &css_cfg->extra_vid_codecs[i]; pj_strdup_with_null(css_var.pool, &css_codec->shared_lib_path, &cfg_codec->shared_lib_path); pj_strdup_with_null(css_var.pool, &css_codec->init_factory_name, &cfg_codec->init_factory_name); css_codec = &css_var.extra_vid_codecs_destroy[i]; cfg_codec = &css_cfg->extra_vid_codecs_destroy[i]; pj_strdup_with_null(css_var.pool, &css_codec->shared_lib_path, &cfg_codec->shared_lib_path); pj_strdup_with_null(css_var.pool, &css_codec->init_factory_name, &cfg_codec->init_factory_name); } // ZRTP cfg css_var.default_use_zrtp = css_cfg->use_zrtp; ua_cfg->cb.on_create_media_transport = &on_transport_created_wrapper; #if defined(PJMEDIA_HAS_ZRTP) && PJMEDIA_HAS_ZRTP!=0 pj_ansi_snprintf(css_var.zid_file, sizeof(css_var.zid_file), "%.*s/simple.zid", css_cfg->storage_folder.slen, css_cfg->storage_folder.ptr); #endif JNIEnv *jni_env = 0; ATTACH_JVM(jni_env); css_var.context = (*jni_env)->NewGlobalRef(jni_env, context); DETACH_JVM(jni_env); result = (pj_status_t) pjsua_init(ua_cfg, log_cfg, media_cfg); if (result == PJ_SUCCESS) { /* Ringback tone */ init_ringback_tone(); /* Init audio device */ pj_status_t added_audio = PJ_ENOTFOUND; if (css_cfg->audio_implementation.init_factory_name.slen > 0) { pjmedia_aud_dev_factory* (*init_factory)( pj_pool_factory *pf) = get_library_factory(&css_cfg->audio_implementation); if(init_factory != NULL) { pjmedia_aud_register_factory(init_factory); added_audio = PJ_SUCCESS; PJ_LOG(4, (THIS_FILE, "Loaded audio dev")); } } // Fallback to default audio dev if no one found if (added_audio != PJ_SUCCESS) { pjmedia_aud_register_factory(&pjmedia_android_factory); } // Init video device #if PJMEDIA_HAS_VIDEO // load renderer if (css_cfg->video_render_implementation.init_factory_name.slen > 0) { pjmedia_vid_dev_factory* (*init_factory)( pj_pool_factory *pf) = get_library_factory(&css_cfg->video_render_implementation); if(init_factory != NULL) { pjmedia_vid_register_factory(init_factory, NULL); PJ_LOG(4, (THIS_FILE, "Loaded video render dev")); } } // load capture if (css_cfg->video_capture_implementation.init_factory_name.slen > 0) { pjmedia_vid_dev_factory* (*init_factory)( pj_pool_factory *pf) = get_library_factory(&css_cfg->video_capture_implementation); if(init_factory != NULL) { pjmedia_vid_register_factory(init_factory, NULL); PJ_LOG(4, (THIS_FILE, "Loaded video capture dev")); } } // Load ffmpeg converter pjmedia_converter_mgr* cvrt_mgr = pjmedia_converter_mgr_instance(); if(css_cfg->vid_converter.init_factory_name.slen > 0){ pj_status_t (*init_factory)(pjmedia_converter_mgr* cvrt_mgr) = get_library_factory(&css_cfg->vid_converter); if(init_factory != NULL) { init_factory(cvrt_mgr); PJ_LOG(4, (THIS_FILE, "Loaded video converter")); } } // Load video codecs pjmedia_vid_codec_mgr* vid_mgr = pjmedia_vid_codec_mgr_instance(); for (i = 0; i < css_var.extra_vid_codecs_cnt; i++) { dynamic_factory *codec = &css_var.extra_vid_codecs[i]; pj_status_t (*init_factory)(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf) = get_library_factory(codec); if(init_factory != NULL){ pj_status_t status = init_factory(vid_mgr, &pjsua_var.cp.factory); if(status != PJ_SUCCESS) { PJ_LOG(2, (THIS_FILE,"Error loading dynamic codec plugin")); } } } #endif } return result; }
PJ_DEF(pj_status_t) pjsip_regc_init( pjsip_regc *regc, const pj_str_t *srv_url, const pj_str_t *from_url, const pj_str_t *to_url, int contact_cnt, const pj_str_t contact[], pj_uint32_t expires) { pj_str_t tmp; pj_status_t status; PJ_ASSERT_RETURN(regc && srv_url && from_url && to_url && expires, PJ_EINVAL); /* Copy server URL. */ pj_strdup_with_null(regc->pool, ®c->str_srv_url, srv_url); /* Set server URL. */ tmp = regc->str_srv_url; regc->srv_url = pjsip_parse_uri( regc->pool, tmp.ptr, tmp.slen, 0); if (regc->srv_url == NULL) { return PJSIP_EINVALIDURI; } /* Set "From" header. */ pj_strdup_with_null(regc->pool, ®c->from_uri, from_url); tmp = regc->from_uri; regc->from_hdr = pjsip_from_hdr_create(regc->pool); regc->from_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (!regc->from_hdr->uri) { PJ_LOG(4,(THIS_FILE, "regc: invalid source URI %.*s", from_url->slen, from_url->ptr)); return PJSIP_EINVALIDURI; } /* Set "To" header. */ pj_strdup_with_null(regc->pool, &tmp, to_url); regc->to_hdr = pjsip_to_hdr_create(regc->pool); regc->to_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (!regc->to_hdr->uri) { PJ_LOG(4,(THIS_FILE, "regc: invalid target URI %.*s", to_url->slen, to_url->ptr)); return PJSIP_EINVALIDURI; } /* Set "Contact" header. */ status = set_contact( regc, contact_cnt, contact); if (status != PJ_SUCCESS) return status; /* Set "Expires" header, if required. */ set_expires( regc, expires); regc->delay_before_refresh = DELAY_BEFORE_REFRESH; /* Set "Call-ID" header. */ regc->cid_hdr = pjsip_cid_hdr_create(regc->pool); pj_create_unique_string(regc->pool, ®c->cid_hdr->id); /* Set "CSeq" header. */ regc->cseq_hdr = pjsip_cseq_hdr_create(regc->pool); regc->cseq_hdr->cseq = pj_rand() % 0xFFFF; pjsip_method_set( ®c->cseq_hdr->method, PJSIP_REGISTER_METHOD); /* Done. */ return PJ_SUCCESS; }
static pj_status_t set_contact( pjsip_regc *regc, int contact_cnt, const pj_str_t contact[] ) { const pj_str_t CONTACT = { "Contact", 7 }; pjsip_contact_hdr *h; int i; /* Save existing contact list to removed_contact_hdr_list and * clear contact_hdr_list. */ pj_list_merge_last(®c->removed_contact_hdr_list, ®c->contact_hdr_list); /* Set the expiration of Contacts in to removed_contact_hdr_list * zero. */ h = regc->removed_contact_hdr_list.next; while (h != ®c->removed_contact_hdr_list) { h->expires = 0; h = h->next; } /* Process new contacts */ for (i=0; i<contact_cnt; ++i) { pjsip_contact_hdr *hdr; pj_str_t tmp; pj_strdup_with_null(regc->pool, &tmp, &contact[i]); hdr = (pjsip_contact_hdr*) pjsip_parse_hdr(regc->pool, &CONTACT, tmp.ptr, tmp.slen, NULL); if (hdr == NULL) { PJ_LOG(4,(THIS_FILE, "Invalid Contact: \"%.*s\"", (int)tmp.slen, tmp.ptr)); return PJSIP_EINVALIDURI; } /* Find the new contact in old contact list. If found, remove * the old header from the old header list. */ h = regc->removed_contact_hdr_list.next; while (h != ®c->removed_contact_hdr_list) { int rc; rc = pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, h->uri, hdr->uri); if (rc == 0) { /* Match */ pj_list_erase(h); break; } h = h->next; } /* If add_xuid_param option is enabled and Contact URI is sip/sips, * add xuid parameter to assist matching the Contact URI in the * REGISTER response later. */ if (regc->add_xuid_param && (PJSIP_URI_SCHEME_IS_SIP(hdr->uri) || PJSIP_URI_SCHEME_IS_SIPS(hdr->uri))) { pjsip_param *xuid_param; pjsip_sip_uri *sip_uri; xuid_param = PJ_POOL_ZALLOC_T(regc->pool, pjsip_param); xuid_param->name = XUID_PARAM_NAME; pj_create_unique_string(regc->pool, &xuid_param->value); sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(hdr->uri); pj_list_push_back(&sip_uri->other_param, xuid_param); } pj_list_push_back(®c->contact_hdr_list, hdr); } return PJ_SUCCESS; }
/* * Send instant messaging outside dialog, using the specified account for * route set and authentication. */ PJ_DEF(pj_status_t) pjsua_im_send( pjsua_acc_id acc_id, const pj_str_t *to, const pj_str_t *mime_type, const pj_str_t *content, const pjsua_msg_data *msg_data, void *user_data) { pjsip_tx_data *tdata; const pj_str_t mime_text_plain = pj_str("text/plain"); const pj_str_t STR_CONTACT = { "Contact", 7 }; pjsip_media_type media_type; pjsua_im_data *im_data; pj_str_t contact; pj_status_t status; /* To and message body must be specified. */ PJ_ASSERT_RETURN(to && content, PJ_EINVAL); /* Create request. */ status = pjsip_endpt_create_request(pjsua_var.endpt, &pjsip_message_method, to, &pjsua_var.acc[acc_id].cfg.id, to, NULL, NULL, -1, NULL, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create request", status); return status; } /* If account is locked to specific transport, then set transport to * the request. */ if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel); pjsip_tx_data_set_transport(tdata, &tp_sel); } /* Add accept header. */ pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)pjsua_im_create_accept(tdata->pool)); /* Add contact. */ status = pjsua_acc_create_uac_contact(tdata->pool, &contact, acc_id, to); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); pjsip_tx_data_dec_ref(tdata); return status; } pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_CONTACT, &contact)); /* Create IM data to keep message details and give it back to * application on the callback */ im_data = PJ_POOL_ZALLOC_T(tdata->pool, pjsua_im_data); im_data->acc_id = acc_id; im_data->call_id = PJSUA_INVALID_ID; pj_strdup_with_null(tdata->pool, &im_data->to, to); pj_strdup_with_null(tdata->pool, &im_data->body, content); im_data->user_data = user_data; /* Set default media type if none is specified */ if (mime_type == NULL) { mime_type = &mime_text_plain; } /* Parse MIME type */ pjsua_parse_media_type(tdata->pool, mime_type, &media_type); /* Add message body */ tdata->msg->body = pjsip_msg_body_create( tdata->pool, &media_type.type, &media_type.subtype, &im_data->body); if (tdata->msg->body == NULL) { pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM); pjsip_tx_data_dec_ref(tdata); return PJ_ENOMEM; } /* Add additional headers etc. */ pjsua_process_msg_data(tdata, msg_data); /* Add route set */ pjsua_set_msg_route_set(tdata, &pjsua_var.acc[acc_id].route_set); /* Send request (statefully) */ status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1, im_data, &im_callback); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to send request", status); return status; } return PJ_SUCCESS; }
/* Parse crypto attribute line */ static pj_status_t parse_attr_crypto(pj_pool_t *pool, const pjmedia_sdp_attr *attr, pjmedia_srtp_crypto *crypto, int *tag) { pj_str_t input; char *token; pj_str_t tmp; pj_status_t status; int itmp; pj_bzero(crypto, sizeof(*crypto)); pj_strdup_with_null(pool, &input, &attr->value); /* Tag */ token = strtok(input.ptr, " "); if (!token) { PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting tag")); return PJMEDIA_SDP_EINATTR; } *tag = atoi(token); if (*tag == 0) return PJMEDIA_SDP_EINATTR; /* Crypto-suite */ token = strtok(NULL, " "); if (!token) { PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting crypto suite")); return PJMEDIA_SDP_EINATTR; } crypto->name = pj_str(token); /* Key method */ token = strtok(NULL, ":"); if (!token) { PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key method")); return PJMEDIA_SDP_EINATTR; } if (pj_ansi_stricmp(token, "inline")) { PJ_LOG(4,(THIS_FILE, "Attribute crypto key method '%s' not supported!", token)); return PJMEDIA_SDP_EINATTR; } /* Key */ token = strtok(NULL, "| "); if (!token) { PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key")); return PJMEDIA_SDP_EINATTR; } tmp = pj_str(token); crypto->key.ptr = (char*) pj_pool_zalloc(pool, MAX_KEY_LEN); /* Decode key */ itmp = MAX_KEY_LEN; status = pj_base64_decode(&tmp, (pj_uint8_t*)crypto->key.ptr, &itmp); if (status != PJ_SUCCESS) { PJ_LOG(4,(THIS_FILE, "Failed decoding crypto key from base64")); return status; } crypto->key.slen = itmp; return PJ_SUCCESS; }
/* Parse crypto attribute line */ static pj_status_t parse_attr_crypto(pj_pool_t *pool, const pjmedia_sdp_attr *attr, pjmedia_srtp_crypto *crypto, int *tag) { pj_str_t input; char *token; int token_len; pj_str_t tmp; pj_status_t status; int itmp; pj_bzero(crypto, sizeof(*crypto)); pj_strdup_with_null(pool, &input, &attr->value); /* Tag */ token = strtok(input.ptr, " "); if (!token) { PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting tag")); return PJMEDIA_SDP_EINATTR; } token_len = pj_ansi_strlen(token); /* Tag must not use leading zeroes. */ if (token_len > 1 && *token == '0') return PJMEDIA_SDP_EINATTR; /* Tag must be decimal, i.e: contains only digit '0'-'9'. */ for (itmp = 0; itmp < token_len; ++itmp) if (!pj_isdigit(token[itmp])) return PJMEDIA_SDP_EINATTR; /* Get tag value. */ *tag = atoi(token); /* Crypto-suite */ token = strtok(NULL, " "); if (!token) { PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting crypto suite")); return PJMEDIA_SDP_EINATTR; } crypto->name = pj_str(token); /* Key method */ token = strtok(NULL, ":"); if (!token) { PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key method")); return PJMEDIA_SDP_EINATTR; } if (pj_ansi_stricmp(token, "inline")) { PJ_LOG(4,(THIS_FILE, "Attribute crypto key method '%s' not supported!", token)); return PJMEDIA_SDP_EINATTR; } /* Key */ token = strtok(NULL, "| "); if (!token) { PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key")); return PJMEDIA_SDP_EINATTR; } tmp = pj_str(token); crypto->key.ptr = (char*) pj_pool_zalloc(pool, MAX_KEY_LEN); /* Decode key */ itmp = MAX_KEY_LEN; status = pj_base64_decode(&tmp, (pj_uint8_t*)crypto->key.ptr, &itmp); if (status != PJ_SUCCESS) { PJ_LOG(4,(THIS_FILE, "Failed decoding crypto key from base64")); return status; } crypto->key.slen = itmp; return PJ_SUCCESS; }
/* * Initialize a new account (after configuration is set). */ static pj_status_t initialize_acc(unsigned acc_id) { pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg; pjsua_acc *acc = &pjsua_var.acc[acc_id]; pjsip_name_addr *name_addr; pjsip_sip_uri *sip_uri, *sip_reg_uri; pj_status_t status; unsigned i; /* Need to parse local_uri to get the elements: */ name_addr = (pjsip_name_addr*) pjsip_parse_uri(acc->pool, acc_cfg->id.ptr, acc_cfg->id.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (name_addr == NULL) { pjsua_perror(THIS_FILE, "Invalid local URI", PJSIP_EINVALIDURI); return PJSIP_EINVALIDURI; } /* Local URI MUST be a SIP or SIPS: */ if (!PJSIP_URI_SCHEME_IS_SIP(name_addr) && !PJSIP_URI_SCHEME_IS_SIPS(name_addr)) { pjsua_perror(THIS_FILE, "Invalid local URI", PJSIP_EINVALIDSCHEME); return PJSIP_EINVALIDSCHEME; } /* Get the SIP URI object: */ sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(name_addr); /* Parse registrar URI, if any */ if (acc_cfg->reg_uri.slen) { pjsip_uri *reg_uri; reg_uri = pjsip_parse_uri(acc->pool, acc_cfg->reg_uri.ptr, acc_cfg->reg_uri.slen, 0); if (reg_uri == NULL) { pjsua_perror(THIS_FILE, "Invalid registrar URI", PJSIP_EINVALIDURI); return PJSIP_EINVALIDURI; } /* Registrar URI MUST be a SIP or SIPS: */ if (!PJSIP_URI_SCHEME_IS_SIP(reg_uri) && !PJSIP_URI_SCHEME_IS_SIPS(reg_uri)) { pjsua_perror(THIS_FILE, "Invalid registar URI", PJSIP_EINVALIDSCHEME); return PJSIP_EINVALIDSCHEME; } sip_reg_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(reg_uri); } else { sip_reg_uri = NULL; } /* Save the user and domain part. These will be used when finding an * account for incoming requests. */ acc->display = name_addr->display; acc->user_part = sip_uri->user; acc->srv_domain = sip_uri->host; acc->srv_port = 0; if (sip_reg_uri) { acc->srv_port = sip_reg_uri->port; } /* Create Contact header if not present. */ //if (acc_cfg->contact.slen == 0) { // acc_cfg->contact = acc_cfg->id; //} /* Build account route-set from outbound proxies and route set from * account configuration. */ pj_list_init(&acc->route_set); for (i=0; i<pjsua_var.ua_cfg.outbound_proxy_cnt; ++i) { pj_str_t hname = { "Route", 5}; pjsip_route_hdr *r; pj_str_t tmp; pj_strdup_with_null(acc->pool, &tmp, &pjsua_var.ua_cfg.outbound_proxy[i]); r = (pjsip_route_hdr*) pjsip_parse_hdr(acc->pool, &hname, tmp.ptr, tmp.slen, NULL); if (r == NULL) { pjsua_perror(THIS_FILE, "Invalid outbound proxy URI", PJSIP_EINVALIDURI); return PJSIP_EINVALIDURI; } pj_list_push_back(&acc->route_set, r); } for (i=0; i<acc_cfg->proxy_cnt; ++i) { pj_str_t hname = { "Route", 5}; pjsip_route_hdr *r; pj_str_t tmp; pj_strdup_with_null(acc->pool, &tmp, &acc_cfg->proxy[i]); r = (pjsip_route_hdr*) pjsip_parse_hdr(acc->pool, &hname, tmp.ptr, tmp.slen, NULL); if (r == NULL) { pjsua_perror(THIS_FILE, "Invalid URI in account route set", PJ_EINVAL); return PJ_EINVAL; } pj_list_push_back(&acc->route_set, r); } /* Concatenate credentials from account config and global config */ acc->cred_cnt = 0; for (i=0; i<acc_cfg->cred_count; ++i) { acc->cred[acc->cred_cnt++] = acc_cfg->cred_info[i]; } for (i=0; i<pjsua_var.ua_cfg.cred_count && acc->cred_cnt < PJ_ARRAY_SIZE(acc->cred); ++i) { acc->cred[acc->cred_cnt++] = pjsua_var.ua_cfg.cred_info[i]; } status = pjsua_pres_init_acc(acc_id); if (status != PJ_SUCCESS) return status; /* Mark account as valid */ pjsua_var.acc[acc_id].valid = PJ_TRUE; /* Insert account ID into account ID array, sorted by priority */ for (i=0; i<pjsua_var.acc_cnt; ++i) { if ( pjsua_var.acc[pjsua_var.acc_ids[i]].cfg.priority < pjsua_var.acc[acc_id].cfg.priority) { break; } } pj_array_insert(pjsua_var.acc_ids, sizeof(pjsua_var.acc_ids[0]), pjsua_var.acc_cnt, i, &acc_id); return PJ_SUCCESS; }
/* Parse a=candidate line */ static pj_status_t parse_cand(const char *obj_name, pj_pool_t *pool, const pj_str_t *orig_input, pj_ice_sess_cand *cand) { pj_str_t input; char *token, *host; int af; pj_str_t s; pj_status_t status = PJNATH_EICEINCANDSDP; pj_bzero(cand, sizeof(*cand)); pj_strdup_with_null(pool, &input, orig_input); PJ_UNUSED_ARG(obj_name); /* Foundation */ token = strtok(input.ptr, " "); if (!token) { TRACE__((obj_name, "Expecting ICE foundation in candidate")); goto on_return; } pj_strdup2(pool, &cand->foundation, token); /* Component ID */ token = strtok(NULL, " "); if (!token) { TRACE__((obj_name, "Expecting ICE component ID in candidate")); goto on_return; } cand->comp_id = (pj_uint8_t) atoi(token); /* Transport */ token = strtok(NULL, " "); if (!token) { TRACE__((obj_name, "Expecting ICE transport in candidate")); goto on_return; } if (pj_ansi_stricmp(token, "UDP") != 0) { TRACE__((obj_name, "Expecting ICE UDP transport only in candidate")); goto on_return; } /* Priority */ token = strtok(NULL, " "); if (!token) { TRACE__((obj_name, "Expecting ICE priority in candidate")); goto on_return; } cand->prio = atoi(token); /* Host */ host = strtok(NULL, " "); if (!host) { TRACE__((obj_name, "Expecting ICE host in candidate")); goto on_return; } /* Detect address family */ if (pj_ansi_strchr(host, ':')) af = pj_AF_INET6(); else af = pj_AF_INET(); /* Assign address */ if (pj_sockaddr_init(af, &cand->addr, pj_cstr(&s, host), 0)) { TRACE__((obj_name, "Invalid ICE candidate address")); goto on_return; } /* Port */ token = strtok(NULL, " "); if (!token) { TRACE__((obj_name, "Expecting ICE port number in candidate")); goto on_return; } pj_sockaddr_set_port(&cand->addr, (pj_uint16_t)atoi(token)); /* typ */ token = strtok(NULL, " "); if (!token) { TRACE__((obj_name, "Expecting ICE \"typ\" in candidate")); goto on_return; } if (pj_ansi_stricmp(token, "typ") != 0) { TRACE__((obj_name, "Expecting ICE \"typ\" in candidate")); goto on_return; } /* candidate type */ token = strtok(NULL, " "); if (!token) { TRACE__((obj_name, "Expecting ICE candidate type in candidate")); goto on_return; } if (pj_ansi_stricmp(token, "host") == 0) { cand->type = PJ_ICE_CAND_TYPE_HOST; } else if (pj_ansi_stricmp(token, "srflx") == 0) { cand->type = PJ_ICE_CAND_TYPE_SRFLX; } else if (pj_ansi_stricmp(token, "relay") == 0) { cand->type = PJ_ICE_CAND_TYPE_RELAYED; } else if (pj_ansi_stricmp(token, "prflx") == 0) { cand->type = PJ_ICE_CAND_TYPE_PRFLX; } else { PJ_LOG(5,(obj_name, "Invalid ICE candidate type %s in candidate", token)); goto on_return; } status = PJ_SUCCESS; on_return: return status; }
/* * Add new buddy. */ PJ_DEF(pj_status_t) pjsua_buddy_add( const pjsua_buddy_config *cfg, pjsua_buddy_id *p_buddy_id) { pjsip_name_addr *url; pjsua_buddy *buddy; pjsip_sip_uri *sip_uri; int index; pj_str_t tmp; PJ_ASSERT_RETURN(pjsua_var.buddy_cnt <= PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_ETOOMANY); PJSUA_LOCK(); /* Find empty slot */ for (index=0; index<(int)PJ_ARRAY_SIZE(pjsua_var.buddy); ++index) { if (pjsua_var.buddy[index].uri.slen == 0) break; } /* Expect to find an empty slot */ if (index == PJ_ARRAY_SIZE(pjsua_var.buddy)) { PJSUA_UNLOCK(); /* This shouldn't happen */ pj_assert(!"index < PJ_ARRAY_SIZE(pjsua_var.buddy)"); return PJ_ETOOMANY; } buddy = &pjsua_var.buddy[index]; /* Create pool for this buddy */ if (buddy->pool) { pj_pool_reset(buddy->pool); } else { char name[PJ_MAX_OBJ_NAME]; pj_ansi_snprintf(name, sizeof(name), "buddy%03d", index); buddy->pool = pjsua_pool_create(name, 512, 256); } /* Init buffers for presence subscription status */ buddy->term_reason.ptr = (char*) pj_pool_alloc(buddy->pool, PJSUA_BUDDY_SUB_TERM_REASON_LEN); /* Get name and display name for buddy */ pj_strdup_with_null(buddy->pool, &tmp, &cfg->uri); url = (pjsip_name_addr*)pjsip_parse_uri(buddy->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (url == NULL) { pjsua_perror(THIS_FILE, "Unable to add buddy", PJSIP_EINVALIDURI); pj_pool_release(buddy->pool); buddy->pool = NULL; PJSUA_UNLOCK(); return PJSIP_EINVALIDURI; } /* Only support SIP schemes */ if (!PJSIP_URI_SCHEME_IS_SIP(url) && !PJSIP_URI_SCHEME_IS_SIPS(url)) { pj_pool_release(buddy->pool); buddy->pool = NULL; PJSUA_UNLOCK(); return PJSIP_EINVALIDSCHEME; } /* Reset buddy, to make sure everything is cleared with default * values */ reset_buddy(index); /* Save URI */ pjsua_var.buddy[index].uri = tmp; sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(url->uri); pjsua_var.buddy[index].name = sip_uri->user; pjsua_var.buddy[index].display = url->display; pjsua_var.buddy[index].host = sip_uri->host; pjsua_var.buddy[index].port = sip_uri->port; pjsua_var.buddy[index].monitor = cfg->subscribe; if (pjsua_var.buddy[index].port == 0) pjsua_var.buddy[index].port = 5060; /* Save user data */ pjsua_var.buddy[index].user_data = (void*)cfg->user_data; if (p_buddy_id) *p_buddy_id = index; pjsua_var.buddy_cnt++; PJSUA_UNLOCK(); pjsua_buddy_subscribe_pres(index, cfg->subscribe); return PJ_SUCCESS; }
/* API: configure the AVI */ PJ_DEF(pj_status_t) pjmedia_avi_dev_alloc( pjmedia_vid_dev_factory *f, pjmedia_avi_dev_param *p, pjmedia_vid_dev_index *p_id) { pjmedia_vid_dev_index id; struct avi_factory *cf = (struct avi_factory*)f; unsigned local_idx; struct avi_dev_info *adi = NULL; pjmedia_format avi_fmt; const pjmedia_video_format_info *vfi; pj_status_t status; PJ_ASSERT_RETURN(f && p && p_id, PJ_EINVAL); if (p_id) *p_id = PJMEDIA_VID_INVALID_DEV; /* Get a free dev */ for (local_idx=0; local_idx<cf->dev_count; ++local_idx) { if (cf->dev_info[local_idx].avi == NULL) { adi = &cf->dev_info[local_idx]; break; } } if (!adi) return PJ_ETOOMANY; /* Convert local ID to global id */ status = pjmedia_vid_dev_get_global_index(&cf->base, local_idx, &id); if (status != PJ_SUCCESS) return status; /* Reset */ if (adi->pool) { pj_pool_release(adi->pool); } pj_bzero(adi, sizeof(*adi)); /* Reinit */ PJ_ASSERT_RETURN(p->path.slen, PJ_EINVAL); adi->pool = pj_pool_create(cf->pf, "avidi%p", 512, 512, NULL); /* Open the AVI */ pj_strdup_with_null(adi->pool, &adi->fpath, &p->path); status = pjmedia_avi_player_create_streams(adi->pool, adi->fpath.ptr, 0, &adi->avi); if (status != PJ_SUCCESS) { goto on_error; } adi->vid = pjmedia_avi_streams_get_stream_by_media(adi->avi, 0, PJMEDIA_TYPE_VIDEO); if (!adi->vid) { status = PJMEDIA_EVID_BADFORMAT; PJ_LOG(4,(THIS_FILE, "Error: cannot find video in AVI %s", adi->fpath.ptr)); goto on_error; } pjmedia_format_copy(&avi_fmt, &adi->vid->info.fmt); vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id); /* Check whether the frame is encoded. */ if (!vfi || vfi->bpp == 0) { /* Yes, prepare codec */ const pjmedia_vid_codec_info *codec_info; pjmedia_vid_codec_param codec_param; pjmedia_video_apply_fmt_param vafp; /* Lookup codec */ status = pjmedia_vid_codec_mgr_get_codec_info2(NULL, avi_fmt.id, &codec_info); if (status != PJ_SUCCESS || !codec_info) goto on_error; status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, &codec_param); if (status != PJ_SUCCESS) goto on_error; /* Open codec */ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &adi->codec); if (status != PJ_SUCCESS) goto on_error; status = pjmedia_vid_codec_init(adi->codec, adi->pool); if (status != PJ_SUCCESS) goto on_error; codec_param.dir = PJMEDIA_DIR_DECODING; codec_param.packing = PJMEDIA_VID_PACKING_WHOLE; status = pjmedia_vid_codec_open(adi->codec, &codec_param); if (status != PJ_SUCCESS) goto on_error; /* Allocate buffer */ avi_fmt.id = codec_info->dec_fmt_id[0]; vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id); pj_bzero(&vafp, sizeof(vafp)); vafp.size = avi_fmt.det.vid.size; status = vfi->apply_fmt(vfi, &vafp); if (status != PJ_SUCCESS) goto on_error; adi->enc_buf = pj_pool_alloc(adi->pool, vafp.framebytes); adi->enc_buf_size = vafp.framebytes; } /* Calculate title */ if (p->title.slen) { pj_strdup_with_null(adi->pool, &adi->title, &p->title); } else { char *start = p->path.ptr + p->path.slen; pj_str_t tmp; while (start >= p->path.ptr) { if (*start == '/' || *start == '\\') break; --start; } tmp.ptr = start + 1; tmp.slen = p->path.ptr + p->path.slen - tmp.ptr; pj_strdup_with_null(adi->pool, &adi->title, &tmp); } /* Init device info */ pj_ansi_strncpy(adi->info.name, adi->title.ptr, sizeof(adi->info.name)-1); pj_ansi_strncpy(adi->info.driver, DRIVER_NAME, sizeof(adi->info.driver)-1); adi->info.dir = PJMEDIA_DIR_CAPTURE; adi->info.has_callback = PJ_FALSE; adi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT; adi->info.fmt_cnt = 1; pjmedia_format_copy(&adi->info.fmt[0], &avi_fmt); /* Set out vars */ if (p_id) *p_id = id; p->avi_streams = adi->avi; if (p->title.slen == 0) p->title = adi->title; return PJ_SUCCESS; on_error: if (adi->codec) { pjmedia_vid_codec_close(adi->codec); adi->codec = NULL; } if (adi->pool) { pj_pool_release(adi->pool); adi->pool = NULL; } pjmedia_avi_dev_free(id); return status; }
/* Double terminate test. */ static int double_terminate(void) { pj_str_t target, from, tsx_key; pjsip_tx_data *tdata; pjsip_transaction *tsx; pj_status_t status; PJ_LOG(3,(THIS_FILE, " double terminate test")); target = pj_str(TARGET_URI); from = pj_str(FROM_URI); /* Create request. */ status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, &from, &target, NULL, NULL, -1, NULL, &tdata); if (status != PJ_SUCCESS) { app_perror(" error: unable to create request", status); return -10; } /* Create transaction. */ status = pjsip_tsx_create_uac(NULL, tdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); return -20; } /* Save transaction key for later. */ pj_strdup_with_null(tdata->pool, &tsx_key, &tsx->transaction_key); /* Add reference to transmit buffer (tsx_send_msg() will dec txdata). */ pjsip_tx_data_add_ref(tdata); /* Send message to start timeout timer. */ status = pjsip_tsx_send_msg(tsx, NULL); /* Terminate transaction. */ status = pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); if (status != PJ_SUCCESS) { app_perror(" error: unable to terminate transaction", status); return -30; } tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); if (tsx) { /* Terminate transaction again. */ pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); if (status != PJ_SUCCESS) { app_perror(" error: unable to terminate transaction", status); return -40; } pj_mutex_unlock(tsx->mutex); } flush_events(500); if (pjsip_tx_data_dec_ref(tdata) != PJSIP_EBUFDESTROYED) { return -50; } return PJ_SUCCESS; }
/* * This callback called when we receive incoming NOTIFY request. */ static void on_notify_request(pjsip_transaction *tsx, pjsip_rx_data *rdata) { pjsip_event_sub *sub; pjsip_tx_data *tdata; int status = 200; int old_state; pj_str_t reason = { NULL, 0 }; pj_str_t reason_phrase = { NULL, 0 }; int new_state = PJSIP_EVENT_SUB_STATE_NULL; /* Find subscription based on Call-ID and From tag. * This will also automatically lock the subscription, if it's found. */ sub = find_sub(rdata); if (!sub) { /* RFC 3265: Section 3.2 Description of NOTIFY Behavior: * Answer with 481 Subscription does not exist. */ PJ_LOG(4,(THIS_FILE, "Unable to find subscription for incoming NOTIFY!")); status = 481; reason_phrase = pj_str("Subscription does not exist"); } else { pj_assert(sub->role == PJSIP_ROLE_UAC); PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received NOTIFY", sub, state[sub->state].ptr)); } new_state = old_state = sub->state; /* RFC 3265: Section 3.2.1 * Check that the Event header match the subscription. */ if (status == 200) { pjsip_event_hdr *hdr; pj_str_t hname = { "Event", 5 }; hdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL); if (!hdr) { status = PJSIP_SC_BAD_REQUEST; reason_phrase = pj_str("No Event header found"); } else if (pj_stricmp(&hdr->event_type, &sub->event->event_type) != 0 || pj_stricmp(&hdr->id_param, &sub->event->id_param) != 0) { status = 481; reason_phrase = pj_str("Subscription does not exist"); } } /* Update subscription state and timer. */ if (status == 200) { pjsip_sub_state_hdr *hdr; const pj_str_t hname = { "Subscription-State", 18 }; const pj_str_t state_active = { "active", 6 }, state_pending = { "pending", 7}, state_terminated = { "terminated", 10 }; hdr = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL); if (!hdr) { status = PJSIP_SC_BAD_REQUEST; reason_phrase = pj_str("No Subscription-State header found"); goto process; } /* * Update subscription state. */ if (pj_stricmp(&hdr->sub_state, &state_active) == 0) { if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) new_state = PJSIP_EVENT_SUB_STATE_ACTIVE; } else if (pj_stricmp(&hdr->sub_state, &state_pending) == 0) { if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) new_state = PJSIP_EVENT_SUB_STATE_PENDING; } else if (pj_stricmp(&hdr->sub_state, &state_terminated) == 0) { new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; } else { new_state = PJSIP_EVENT_SUB_STATE_UNKNOWN; } reason = hdr->reason_param; if (new_state != sub->state && new_state != PJSIP_EVENT_SUB_STATE_NULL && sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) { sub_set_state(sub, new_state); if (new_state == PJSIP_EVENT_SUB_STATE_UNKNOWN) { pj_strdup_with_null(sub->pool, &sub->state_str, &hdr->sub_state); } else { sub->state_str = state[new_state]; } } /* * Update timeout timer in required, just in case notifier changed the * expiration to shorter time. * Section 3.2.2: the expires param can only shorten the interval. */ if ((sub->state==PJSIP_EVENT_SUB_STATE_ACTIVE || sub->state==PJSIP_EVENT_SUB_STATE_PENDING) && hdr->expires_param > 0) { pj_time_val now, new_expiry; pj_gettimeofday(&now); new_expiry.sec = now.sec + hdr->expires_param; if (sub->timer.id==0 || new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2) { update_next_refresh(sub, hdr->expires_param); } } } process: /* Note: here we sub MAY BE NULL! */ /* Send response to NOTIFY */ tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status ); if (tdata) { if (reason_phrase.slen) tdata->msg->line.status.reason = reason_phrase; if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { pjsip_hdr *hdr; hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events); pjsip_msg_add_hdr( tdata->msg, hdr); } pjsip_tsx_on_tx_msg(tsx, tdata); } /* Call NOTIFY callback, if any. */ if (sub && PJSIP_IS_STATUS_IN_CLASS(status,200) && sub->cb.on_received_notify) { sub->pending_tsx++; (*sub->cb.on_received_notify)(sub, rdata); sub->pending_tsx--; } /* Check if subscription is terminated and call callback. */ if (sub && new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { if (sub->cb.on_sub_terminated) { sub->pending_tsx++; (*sub->cb.on_sub_terminated)(sub, &reason); sub->pending_tsx--; } } /* Check if application has requested deletion. */ if (sub && sub->delete_flag && sub->pending_tsx <= 0) { pjsip_event_sub_destroy(sub); } else if (sub) { pj_mutex_unlock(sub->mutex); } }