PJ_DECL(pj_status_t) vid_set_android_renderer(pjsua_call_id call_id, jobject window) { pj_status_t status = PJ_ENOTFOUND; pjsua_call *call; int i; if( !(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls) ){ return PJ_ENOTFOUND; } PJ_LOG(4, (THIS_FILE, "Setup android renderer for call %d", call_id)); PJSUA_LOCK(); // Retrieve the stream if (pjsua_call_has_media(call_id)) { call = &pjsua_var.calls[call_id]; for (i = 0; i < call->med_cnt; ++i) { pjsua_call_media *call_med = &call->media[i]; vid_set_stream_window(call_med, PJMEDIA_DIR_RENDER, window); status = PJ_SUCCESS; } } PJSUA_UNLOCK(); return status; }
/* * Update buddy's presence. */ PJ_DEF(pj_status_t) pjsua_buddy_update_pres(pjsua_buddy_id buddy_id) { pjsua_buddy *buddy; PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_EINVAL); PJSUA_LOCK(); buddy = &pjsua_var.buddy[buddy_id]; /* Return error if buddy's presence monitoring is not enabled */ if (!buddy->monitor) { PJSUA_UNLOCK(); return PJ_EINVALIDOP; } /* Ignore if presence is already active for the buddy */ if (buddy->sub) { PJSUA_UNLOCK(); return PJ_SUCCESS; } /* Initiate presence subscription */ subscribe_buddy_presence(buddy_id); PJSUA_UNLOCK(); return PJ_SUCCESS; }
/* * Delete buddy. */ PJ_DEF(pj_status_t) pjsua_buddy_del(pjsua_buddy_id buddy_id) { PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_EINVAL); if (pjsua_var.buddy[buddy_id].uri.slen == 0) { return PJ_SUCCESS; } /* Unsubscribe presence */ pjsua_buddy_subscribe_pres(buddy_id, PJ_FALSE); PJSUA_LOCK(); /* Not interested with further events for this buddy */ if (pjsua_var.buddy[buddy_id].sub) { pjsip_evsub_set_mod_data(pjsua_var.buddy[buddy_id].sub, pjsua_var.mod.id, NULL); } /* Remove buddy */ pjsua_var.buddy[buddy_id].uri.slen = 0; pjsua_var.buddy_cnt--; /* Reset buddy struct */ reset_buddy(buddy_id); PJSUA_UNLOCK(); return PJ_SUCCESS; }
/* Callback called when we receive NOTIFY */ static void pjsua_evsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) { pjsua_buddy *buddy; PJSUA_LOCK(); buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); if (buddy) { /* Update our info. */ pjsip_pres_get_status(sub, &buddy->status); } /* The default is to send 200 response to NOTIFY. * Just leave it there.. */ PJ_UNUSED_ARG(rdata); PJ_UNUSED_ARG(p_st_code); PJ_UNUSED_ARG(p_st_text); PJ_UNUSED_ARG(res_hdr); PJ_UNUSED_ARG(p_body); PJSUA_UNLOCK(); }
PJ_DECL(pj_status_t) vid_set_android_capturer(jobject window) { unsigned ci, i, count; pj_status_t status = PJ_ENOTFOUND; pjsua_call *call; pjsua_call_id calls_id[PJSUA_MAX_ACC]; count = PJ_ARRAY_SIZE(calls_id); status = pjsua_enum_calls(calls_id, &count); if(status != PJ_SUCCESS){ return status; } PJ_LOG(4, (THIS_FILE, "Setup android capturer for all calls")); PJSUA_LOCK(); for(ci = 0; ci < count; ++ci){ pjsua_call_id call_id = calls_id[ci]; if(pjsua_call_is_active(call_id) && pjsua_call_has_media(call_id)){ call = &pjsua_var.calls[call_id]; for (i = 0; i < call->med_cnt; ++i) { pjsua_call_media *call_med = &call->media[i]; vid_set_stream_window(call_med, PJMEDIA_DIR_CAPTURE, window); status = PJ_SUCCESS; } } } PJSUA_UNLOCK(); return status; }
PJ_DECL(zrtp_state_info) jzrtp_getInfoFromCall(pjsua_call_id call_id){ PJSUA_LOCK(); struct jzrtp_allContext ctxt = jzrtp_getContext(call_id); zrtp_state_info info = jzrtp_getInfoFromContext(ctxt); PJSUA_UNLOCK(); return info; }
/* Callback called when *server* subscription state has changed. */ static void pres_evsub_on_srv_state( pjsip_evsub *sub, pjsip_event *event) { pjsua_srv_pres *uapres; PJ_UNUSED_ARG(event); PJSUA_LOCK(); uapres = (pjsua_srv_pres*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); if (uapres) { pjsip_evsub_state state; PJ_LOG(4,(THIS_FILE, "Server subscription to %s is %s", uapres->remote, pjsip_evsub_get_state_name(sub))); state = pjsip_evsub_get_state(sub); if (pjsua_var.ua_cfg.cb.on_srv_subscribe_state) { pj_str_t from; from = uapres->dlg->remote.info_str; (*pjsua_var.ua_cfg.cb.on_srv_subscribe_state)(uapres->acc_id, uapres, &from, state, event); } if (state == PJSIP_EVSUB_STATE_TERMINATED) { pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); pj_list_erase(uapres); } } PJSUA_UNLOCK(); }
/* * Add a new account to pjsua. */ PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg, pj_bool_t is_default, pjsua_acc_id *p_acc_id) { pjsua_acc *acc; unsigned id; pj_status_t status; PJ_ASSERT_RETURN(pjsua_var.acc_cnt < PJ_ARRAY_SIZE(pjsua_var.acc), PJ_ETOOMANY); /* Must have a transport */ PJ_ASSERT_RETURN(pjsua_var.tpdata[0].data.ptr != NULL, PJ_EINVALIDOP); PJSUA_LOCK(); /* Find empty account id. */ for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.acc); ++id) { if (pjsua_var.acc[id].valid == PJ_FALSE) break; } /* Expect to find a slot */ PJ_ASSERT_ON_FAIL( id < PJ_ARRAY_SIZE(pjsua_var.acc), {PJSUA_UNLOCK(); return PJ_EBUG;});
zrtp_state_info jzrtp_getInfoFromTransport(pjmedia_transport* tp){ PJSUA_LOCK(); struct jzrtp_allContext ctxt; ctxt.zrtpContext = pjmedia_transport_zrtp_getZrtpContext(tp); ctxt.cbUserData = (zrtp_cb_user_data*) pjmedia_transport_zrtp_getUserData(tp); zrtp_state_info info = jzrtp_getInfoFromContext(ctxt); PJSUA_UNLOCK(); return info; }
/* Callback when transaction state has changed. */ static void pjsua_evsub_on_tsx_state(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) { pjsua_buddy *buddy; pjsip_contact_hdr *contact_hdr; PJSUA_LOCK(); buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); if (!buddy) { PJSUA_UNLOCK(); return; } /* We only use this to update buddy's Contact, when it's not * set. */ if (buddy->contact.slen != 0) { /* Contact already set */ PJSUA_UNLOCK(); return; } /* Only care about 2xx response to outgoing SUBSCRIBE */ if (tsx->status_code/100 != 2 || tsx->role != PJSIP_UAC_ROLE || event->type != PJSIP_EVENT_RX_MSG || pjsip_method_cmp(&tsx->method, pjsip_get_subscribe_method())!=0) { PJSUA_UNLOCK(); return; } /* Find contact header. */ contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); if (!contact_hdr) { PJSUA_UNLOCK(); return; } buddy->contact.ptr = (char*) pj_pool_alloc(buddy->pool, PJSIP_MAX_URL_SIZE); buddy->contact.slen = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri, buddy->contact.ptr, PJSIP_MAX_URL_SIZE); if (buddy->contact.slen < 0) buddy->contact.slen = 0; PJSUA_UNLOCK(); }
/** * Is call using a secure transport method (No (0) / TLS (1) / SIPS (2)) */ PJ_DECL(int) call_secure_sig_level(pjsua_call_id call_id) { int value = 0; pjsua_call *call; PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, value); PJSUA_LOCK(); call = &pjsua_var.calls[call_id]; value = call->secure_level; PJSUA_UNLOCK(); return value; }
/* * Set the user data associated with the buddy object. */ PJ_DEF(pj_status_t) pjsua_buddy_set_user_data( pjsua_buddy_id buddy_id, void *user_data) { PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_EINVAL); PJSUA_LOCK(); pjsua_var.buddy[buddy_id].user_data = user_data; PJSUA_UNLOCK(); return PJ_SUCCESS; }
/* * Get the user data associated with the budy object. */ PJ_DEF(void*) pjsua_buddy_get_user_data(pjsua_buddy_id buddy_id) { void *user_data; PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), NULL); PJSUA_LOCK(); user_data = pjsua_var.buddy[buddy_id].user_data; PJSUA_UNLOCK(); return user_data; }
PJ_DECL(pj_status_t) update_transport(const pj_str_t *new_ip_addr) { PJSUA_LOCK(); PJ_LOG(4, (THIS_FILE,"update_transport to addr = %s", new_ip_addr->ptr)); // No need ot check thread cause csipsimple use handler thread /* pjsua_transport_config cfg; pjsua_transport_config_default(&cfg); cfg.port = 0; pjsua_media_transports_create(&cfg); */ update_active_calls(new_ip_addr); PJSUA_UNLOCK(); return PJ_SUCCESS; }
/* Callback called when *client* subscription state has changed. */ static void pjsua_evsub_on_state( pjsip_evsub *sub, pjsip_event *event) { pjsua_buddy *buddy; PJ_UNUSED_ARG(event); PJSUA_LOCK(); buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); if (buddy) { PJ_LOG(4,(THIS_FILE, "Presence subscription to %.*s is %s", (int)pjsua_var.buddy[buddy->index].uri.slen, pjsua_var.buddy[buddy->index].uri.ptr, pjsip_evsub_get_state_name(sub))); if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { if (buddy->term_reason.ptr == NULL) { buddy->term_reason.ptr = (char*) pj_pool_alloc(buddy->pool, PJSUA_BUDDY_SUB_TERM_REASON_LEN); } pj_strncpy(&buddy->term_reason, pjsip_evsub_get_termination_reason(sub), PJSUA_BUDDY_SUB_TERM_REASON_LEN); } else { buddy->term_reason.slen = 0; } /* Call callback */ if (pjsua_var.ua_cfg.cb.on_buddy_state) (*pjsua_var.ua_cfg.cb.on_buddy_state)(buddy->index); /* Clear subscription */ if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { buddy->sub = NULL; buddy->status.info_cnt = 0; pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); } } PJSUA_UNLOCK(); }
/* * Enable/disable buddy's presence monitoring. */ PJ_DEF(pj_status_t) pjsua_buddy_subscribe_pres( pjsua_buddy_id buddy_id, pj_bool_t subscribe) { pjsua_buddy *buddy; PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_EINVAL); PJSUA_LOCK(); buddy = &pjsua_var.buddy[buddy_id]; buddy->monitor = subscribe; PJSUA_UNLOCK(); pjsua_pres_refresh(); return PJ_SUCCESS; }
/* * Enum buddy IDs. */ PJ_DEF(pj_status_t) pjsua_enum_buddies( pjsua_buddy_id ids[], unsigned *count) { unsigned i, c; PJ_ASSERT_RETURN(ids && count, PJ_EINVAL); PJSUA_LOCK(); for (i=0, c=0; c<*count && i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { if (!pjsua_var.buddy[i].uri.slen) continue; ids[c] = i; ++c; } *count = c; PJSUA_UNLOCK(); return PJ_SUCCESS; }
/* * Destroy recorder (this will complete recording). */ PJ_DEF(pj_status_t) pjsua_sxs_switcher_destroy(pjsua_recorder_id id) { PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.recorder), PJ_EINVAL); PJ_ASSERT_RETURN(pjsua_var.recorder[id].port != NULL, PJ_EINVAL); PJSUA_LOCK(); if (pjsua_var.recorder[id].port) { pjsua_conf_remove_port(pjsua_var.recorder[id].slot); pjmedia_port_destroy(pjsua_var.recorder[id].port); pjsua_var.recorder[id].port = NULL; pjsua_var.recorder[id].slot = 0xFFFF; pj_pool_release(pjsua_var.recorder[id].pool); pjsua_var.recorder[id].pool = NULL; pjsua_var.rec_cnt--; } PJSUA_UNLOCK(); return PJ_SUCCESS; }
/** * Is call using a secure RTP method (SRTP/ZRTP) */ PJ_DECL(pj_str_t) call_secure_info(pjsua_call_id call_id) { pjsua_call *call; pj_status_t status; unsigned i; pjmedia_transport_info tp_info; pj_str_t result = pj_str(""); PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, result); PJSUA_LOCK(); if (pjsua_call_has_media(call_id)) { call = &pjsua_var.calls[call_id]; for (i = 0; i < call->med_cnt; ++i) { pjsua_call_media *call_med = &call->media[i]; PJ_LOG(4, (THIS_FILE, "Get secure for media type %d", call_med->type)); if (call_med->tp && call_med->type == PJMEDIA_TYPE_AUDIO) { pjmedia_transport_info tp_info; pjmedia_transport_info_init(&tp_info); pjmedia_transport_get_info(call_med->tp, &tp_info); if (tp_info.specific_info_cnt > 0) { unsigned j; for (j = 0; j < tp_info.specific_info_cnt; ++j) { if (tp_info.spc_info[j].type == PJMEDIA_TRANSPORT_TYPE_SRTP) { pjmedia_srtp_info *srtp_info = (pjmedia_srtp_info*) tp_info.spc_info[j].buffer; if (srtp_info->active) { result = pj_str("SRTP"); break; } } #if defined(PJMEDIA_HAS_ZRTP) && PJMEDIA_HAS_ZRTP!=0 else if (tp_info.spc_info[j].type == PJMEDIA_TRANSPORT_TYPE_ZRTP) { zrtp_state_info info = jzrtp_getInfoFromTransport(call_med->tp); if(info.secure){ char msg[512]; PJ_LOG(4, (THIS_FILE, "ZRTP :: V %d", info.sas_verified)); PJ_LOG(4, (THIS_FILE, "ZRTP :: S L %d", info.sas.slen)); PJ_LOG(4, (THIS_FILE, "ZRTP :: C L %d", info.cipher.slen)); pj_ansi_snprintf(msg, sizeof(msg), "ZRTP - %s\n%.*s\n%.*s", info.sas_verified ? "Verified": "Not verified", info.sas.slen, info.sas.ptr, info.cipher.slen, info.cipher.ptr); pj_strdup2_with_null(css_var.pool, &result, msg); break; } } #endif } } } } } PJSUA_UNLOCK(); return result; }
/* * Get detailed buddy info. */ PJ_DEF(pj_status_t) pjsua_buddy_get_info( pjsua_buddy_id buddy_id, pjsua_buddy_info *info) { unsigned total=0; pjsua_buddy *buddy; PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_EINVAL); PJSUA_LOCK(); pj_bzero(info, sizeof(pjsua_buddy_info)); buddy = &pjsua_var.buddy[buddy_id]; info->id = buddy->index; if (pjsua_var.buddy[buddy_id].uri.slen == 0) { PJSUA_UNLOCK(); return PJ_SUCCESS; } /* uri */ info->uri.ptr = info->buf_ + total; pj_strncpy(&info->uri, &buddy->uri, sizeof(info->buf_)-total); total += info->uri.slen; /* contact */ info->contact.ptr = info->buf_ + total; pj_strncpy(&info->contact, &buddy->contact, sizeof(info->buf_)-total); total += info->contact.slen; /* status and status text */ if (buddy->sub == NULL || buddy->status.info_cnt==0) { info->status = PJSUA_BUDDY_STATUS_UNKNOWN; info->status_text = pj_str("?"); } else if (pjsua_var.buddy[buddy_id].status.info[0].basic_open) { info->status = PJSUA_BUDDY_STATUS_ONLINE; /* copy RPID information */ info->rpid = buddy->status.info[0].rpid; if (info->rpid.note.slen) info->status_text = info->rpid.note; else info->status_text = pj_str("Online"); } else { info->status = PJSUA_BUDDY_STATUS_OFFLINE; info->status_text = pj_str("Offline"); } /* monitor pres */ info->monitor_pres = buddy->monitor; /* subscription state and termination reason */ if (buddy->sub) { info->sub_state = pjsip_evsub_get_state(buddy->sub); if (info->sub_state == PJSIP_EVSUB_STATE_TERMINATED && total < sizeof(info->buf_)) { info->sub_term_reason.ptr = info->buf_ + total; pj_strncpy(&info->sub_term_reason, pjsip_evsub_get_termination_reason(buddy->sub), sizeof(info->buf_) - total); total += info->sub_term_reason.slen; } else { info->sub_term_reason = pj_str(""); } } else if (total < sizeof(info->buf_)) { info->sub_term_reason.ptr = info->buf_ + total; pj_strncpy(&info->sub_term_reason, &buddy->term_reason, sizeof(info->buf_) - total); total += info->sub_term_reason.slen; } else { info->sub_term_reason = pj_str(""); } PJSUA_UNLOCK(); return PJ_SUCCESS; }
/* * 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; }
/* * Create a file recorder, and automatically connect this recorder to * the conference bridge. */ PJ_DEF(pj_status_t) pjsua_sxs_switcher_create( // const pj_str_t *filename, int direct_type, unsigned enc_type, void *enc_param, unsigned options, pjsua_recorder_id *p_id) { enum Format { FMT_UNKNOWN, FMT_WAV, FMT_MP3, }; unsigned slot, file_id; char path[PJ_MAXPATH]; pj_str_t ext; int file_format; pjmedia_port *port; pj_status_t status; /* Filename must present */ // PJ_ASSERT_RETURN(filename != NULL, PJ_EINVAL); /* Don't support encoding type at present */ PJ_ASSERT_RETURN(enc_type == 0, PJ_EINVAL); if (pjsua_var.rec_cnt >= PJ_ARRAY_SIZE(pjsua_var.recorder)) return PJ_ETOOMANY; file_format = FMT_WAV; PJSUA_LOCK(); for (file_id=0; file_id<PJ_ARRAY_SIZE(pjsua_var.recorder); ++file_id) { if (pjsua_var.recorder[file_id].port == NULL) break; } if (file_id == PJ_ARRAY_SIZE(pjsua_var.recorder)) { /* This is unexpected */ PJSUA_UNLOCK(); pj_assert(0); return PJ_EBUG; } if (file_format == FMT_WAV) { status = pjmedia_sxs_port_server_create( pjsua_var.media_cfg.clock_rate, pjsua_var.mconf_cfg.channel_count, pjsua_var.mconf_cfg.samples_per_frame, pjsua_var.mconf_cfg.bits_per_sample, options, 0, &port); fprintf(stderr, "samples_per_frame=%d, bits_per_samples=%d\n", pjsua_var.mconf_cfg.samples_per_frame, pjsua_var.mconf_cfg.bits_per_sample); } else { PJ_UNUSED_ARG(enc_param); port = NULL; status = PJ_ENOTSUP; } if (status != PJ_SUCCESS) { PJSUA_UNLOCK(); pjsua_perror(THIS_FILE, "Unable to open file for recording", status); return status; } pjmedia_sxs_port_outgoing_server_get_port(port, 0); if (direct_type == SUA_SWITCHER_SERVER) { } else { } // const pj_str_t filename = pj_str(path); assert(g_param->pool); status = pjmedia_conf_add_port(pjsua_var.mconf, g_param->pool, port, 0, &slot); if (status != PJ_SUCCESS) { pjmedia_port_destroy(port); PJSUA_UNLOCK(); return status; } pjsua_var.recorder[file_id].port = port; pjsua_var.recorder[file_id].slot = slot; if (p_id) *p_id = file_id; ++pjsua_var.rec_cnt; PJSUA_UNLOCK(); return PJ_SUCCESS; }
/* * This is an internal function to find the most appropriate account to be * used to handle incoming calls. */ void on_acc_find_for_incoming_wrapper(const pjsip_rx_data *rdata, pjsua_acc_id* out_acc_id) { pjsip_uri *uri; pjsip_sip_uri *sip_uri; unsigned i; int current_matching_score = 0; int matching_scores[PJSUA_MAX_ACC]; pjsua_acc_id best_matching = pjsua_var.default_acc; /* Check that there's at least one account configured */ PJ_ASSERT_RETURN(pjsua_var.acc_cnt!=0, pjsua_var.default_acc); uri = rdata->msg_info.to->uri; /* Just return if To URI is not SIP: */ if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) { return; } PJSUA_LOCK(); sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri); /* Find account which has matching username and domain. */ for (i=0; i < pjsua_var.acc_cnt; ++i) { unsigned acc_id = pjsua_var.acc_ids[i]; pjsua_acc *acc = &pjsua_var.acc[acc_id]; if (acc->valid && pj_stricmp(&acc->user_part, &sip_uri->user)==0 && pj_stricmp(&acc->srv_domain, &sip_uri->host)==0) { /* Match ! */ PJSUA_UNLOCK(); *out_acc_id = acc_id; return; } } /* No exact matching, try fuzzy matching */ pj_bzero(matching_scores, sizeof(matching_scores)); /* No matching account, try match domain part only. */ for (i=0; i < pjsua_var.acc_cnt; ++i) { unsigned acc_id = pjsua_var.acc_ids[i]; pjsua_acc *acc = &pjsua_var.acc[acc_id]; if (acc->valid && pj_stricmp(&acc->srv_domain, &sip_uri->host)==0) { /* Match ! */ /* We apply 100 weight if account has reg uri * Because in pragmatic case we are more looking * for these one than for the local acc */ matching_scores[i] += (acc->cfg.reg_uri.slen > 0) ? (300 * sip_uri->host.slen) : 1; } } /* No matching account, try match user part (and transport type) only. */ for (i=0; i < pjsua_var.acc_cnt; ++i) { unsigned acc_id = pjsua_var.acc_ids[i]; pjsua_acc *acc = &pjsua_var.acc[acc_id]; if (acc->valid) { /* We apply 100 weight if account has reg uri * Because in pragmatic case we are more looking * for these one than for the local acc */ unsigned weight = (acc->cfg.reg_uri.slen > 0) ? 100 : 1; if (acc->cfg.transport_id != PJSUA_INVALID_ID) { pjsip_transport_type_e type; type = pjsip_transport_get_type_from_name(&sip_uri->transport_param); if (type == PJSIP_TRANSPORT_UNSPECIFIED) type = PJSIP_TRANSPORT_UDP; if (pjsua_var.tpdata[acc->cfg.transport_id].type != type) continue; } /* Match ! */ matching_scores[i] += (max_common_substr_len(&acc->user_part, &sip_uri->user) * weight); } } /* Still no match, use default account */ PJSUA_UNLOCK(); for(i=0; i<pjsua_var.acc_cnt; i++) { if(current_matching_score < matching_scores[i]) { best_matching = pjsua_var.acc_ids[i]; current_matching_score = matching_scores[i]; } } *out_acc_id = best_matching; }
/** * Is call using a secure RTP method (SRTP/ZRTP) */ PJ_DECL(pj_str_t) call_secure_info(pjsua_call_id call_id) { pjsua_call *call; pjsip_dialog *dlg; pj_status_t status; unsigned i; pjmedia_transport_info tp_info; pj_str_t result = pj_str(""); PJ_LOG(3, (THIS_FILE, "Get call secure info...")); PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, result); /* Use PJSUA_LOCK() instead of acquire_call(): * https://trac.pjsip.org/repos/ticket/1371 */ PJSUA_LOCK(); if (pjsua_call_has_media(call_id)) { call = &pjsua_var.calls[call_id]; for (i = 0; i < call->med_cnt; ++i) { pjsua_call_media *call_med = &call->media[i]; PJ_LOG(4, (THIS_FILE, "Get secure for media type %d", call_med->type)); /* Get and ICE SRTP status */ if (call_med->tp && call_med->type == PJMEDIA_TYPE_AUDIO) { pjmedia_transport_info tp_info; pjmedia_transport_info_init(&tp_info); pjmedia_transport_get_info(call_med->tp, &tp_info); if (tp_info.specific_info_cnt > 0) { unsigned j; for (j = 0; j < tp_info.specific_info_cnt; ++j) { if (tp_info.spc_info[j].type == PJMEDIA_TRANSPORT_TYPE_SRTP) { pjmedia_srtp_info *srtp_info = (pjmedia_srtp_info*) tp_info.spc_info[j].buffer; if (srtp_info->active) { result = pj_str("SRTP"); break; } } #if defined(PJMEDIA_HAS_ZRTP) && PJMEDIA_HAS_ZRTP!=0 else if (tp_info.spc_info[j].type == PJMEDIA_TRANSPORT_TYPE_ZRTP) { pjmedia_zrtp_info *zrtp_info = (pjmedia_zrtp_info*) tp_info.spc_info[j].buffer; // if(zrtp_info->active){ result = jzrtp_getInfo(call_med->tp); break; // } } #endif } } } } } PJSUA_UNLOCK(); return result; }
/* * Send NOTIFY. */ PJ_DEF(pj_status_t) pjsua_pres_notify( pjsua_acc_id acc_id, pjsua_srv_pres *srv_pres, pjsip_evsub_state ev_state, const pj_str_t *state_str, const pj_str_t *reason, pj_bool_t with_body, const pjsua_msg_data *msg_data) { pjsua_acc *acc; pjsip_pres_status pres_status; pjsua_buddy_id buddy_id; pjsip_tx_data *tdata; pj_status_t status; /* Check parameters */ PJ_ASSERT_RETURN(acc_id!=-1 && srv_pres, PJ_EINVAL); /* Check that account ID is valid */ PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc), PJ_EINVAL); /* Check that account is valid */ PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP); PJSUA_LOCK(); acc = &pjsua_var.acc[acc_id]; /* Check that the server presence subscription is still valid */ if (pj_list_find_node(&acc->pres_srv_list, srv_pres) == NULL) { /* Subscription has been terminated */ PJSUA_UNLOCK(); return PJ_EINVALIDOP; } /* Set our online status: */ pj_bzero(&pres_status, sizeof(pres_status)); pres_status.info_cnt = 1; pres_status.info[0].basic_open = acc->online_status; pres_status.info[0].id = acc->cfg.pidf_tuple_id; //Both pjsua_var.local_uri and pjsua_var.contact_uri are enclosed in "<" and ">" //causing XML parsing to fail. //pres_status.info[0].contact = pjsua_var.local_uri; /* add RPID information */ pj_memcpy(&pres_status.info[0].rpid, &acc->rpid, sizeof(pjrpid_element)); pjsip_pres_set_status(srv_pres->sub, &pres_status); /* Check expires value. If it's zero, send our presense state but * set subscription state to TERMINATED. */ if (srv_pres->expires == 0) ev_state = PJSIP_EVSUB_STATE_TERMINATED; /* Create and send the NOTIFY to active subscription: */ status = pjsip_pres_notify(srv_pres->sub, ev_state, state_str, reason, &tdata); if (status == PJ_SUCCESS) { /* Force removal of message body if msg_body==FALSE */ if (!with_body) { tdata->msg->body = NULL; } pjsua_process_msg_data(tdata, msg_data); status = pjsip_pres_send_request( srv_pres->sub, tdata); } if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create/send NOTIFY", status); pj_list_erase(srv_pres); pjsip_pres_terminate(srv_pres->sub, PJ_FALSE); PJSUA_UNLOCK(); return status; } /* Subscribe to buddy's presence if we're not subscribed */ buddy_id = pjsua_find_buddy(srv_pres->dlg->remote.info->uri); if (buddy_id != PJSUA_INVALID_ID) { pjsua_buddy *b = &pjsua_var.buddy[buddy_id]; if (b->monitor && b->sub == NULL) { PJ_LOG(4,(THIS_FILE, "Received SUBSCRIBE from buddy %d, " "activating outgoing subscription", buddy_id)); subscribe_buddy_presence(buddy_id); } } PJSUA_UNLOCK(); return PJ_SUCCESS; }
/* This is called when request is received. * We need to check for incoming SUBSCRIBE request. */ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata) { int acc_id; pjsua_acc *acc; pj_str_t contact; pjsip_method *req_method = &rdata->msg_info.msg->line.req.method; pjsua_srv_pres *uapres; pjsip_evsub *sub; pjsip_evsub_user pres_cb; pjsip_dialog *dlg; pjsip_status_code st_code; pj_str_t reason; pjsip_expires_hdr *expires_hdr; pjsua_msg_data msg_data; pj_status_t status; if (pjsip_method_cmp(req_method, pjsip_get_subscribe_method()) != 0) return PJ_FALSE; /* Incoming SUBSCRIBE: */ PJSUA_LOCK(); /* Find which account for the incoming request. */ acc_id = pjsua_acc_find_for_incoming(rdata); acc = &pjsua_var.acc[acc_id]; PJ_LOG(4,(THIS_FILE, "Creating server subscription, using account %d", acc_id)); /* Create suitable Contact header */ if (acc->contact.slen) { contact = acc->contact; } else { status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact, acc_id, rdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); PJSUA_UNLOCK(); pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, NULL, NULL, NULL); return PJ_TRUE; } } /* Create UAS dialog: */ status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create UAS dialog for subscription", status); PJSUA_UNLOCK(); pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, NULL, NULL, NULL); return PJ_TRUE; } /* Set credentials and preference. */ pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->cred_cnt, acc->cred); pjsip_auth_clt_set_prefs(&dlg->auth_sess, &acc->cfg.auth_pref); /* Init callback: */ pj_bzero(&pres_cb, sizeof(pres_cb)); pres_cb.on_evsub_state = &pres_evsub_on_srv_state; /* Create server presence subscription: */ status = pjsip_pres_create_uas( dlg, &pres_cb, rdata, &sub); if (status != PJ_SUCCESS) { int code = PJSIP_ERRNO_TO_SIP_STATUS(status); pjsip_tx_data *tdata; pjsua_perror(THIS_FILE, "Unable to create server subscription", status); if (code==599 || code > 699 || code < 300) { code = 400; } status = pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata); if (status == PJ_SUCCESS) { status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); } PJSUA_UNLOCK(); return PJ_TRUE; } /* If account is locked to specific transport, then lock dialog * to this transport too. */ if (acc->cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); pjsip_dlg_set_transport(dlg, &tp_sel); } /* Attach our data to the subscription: */ uapres = PJ_POOL_ALLOC_T(dlg->pool, pjsua_srv_pres); uapres->sub = sub; uapres->remote = (char*) pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE); uapres->acc_id = acc_id; uapres->dlg = dlg; status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri, uapres->remote, PJSIP_MAX_URL_SIZE); if (status < 1) pj_ansi_strcpy(uapres->remote, "<-- url is too long-->"); else uapres->remote[status] = '\0'; pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, uapres); /* Add server subscription to the list: */ pj_list_push_back(&pjsua_var.acc[acc_id].pres_srv_list, uapres); /* Capture the value of Expires header. */ expires_hdr = (pjsip_expires_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); if (expires_hdr) uapres->expires = expires_hdr->ivalue; else uapres->expires = -1; st_code = (pjsip_status_code)200; reason = pj_str("OK"); pjsua_msg_data_init(&msg_data); /* Notify application callback, if any */ if (pjsua_var.ua_cfg.cb.on_incoming_subscribe) { pjsua_buddy_id buddy_id; buddy_id = pjsua_find_buddy(rdata->msg_info.from->uri); (*pjsua_var.ua_cfg.cb.on_incoming_subscribe)(acc_id, uapres, buddy_id, &dlg->remote.info_str, rdata, &st_code, &reason, &msg_data); } /* Handle rejection case */ if (st_code >= 300) { pjsip_tx_data *tdata; /* Create response */ status = pjsip_dlg_create_response(dlg, rdata, st_code, &reason, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error creating response", status); pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_FALSE; } /* Add header list, if any */ pjsua_process_msg_data(tdata, &msg_data); /* Send the response */ status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error sending response", status); /* This is not fatal */ } /* Terminate presence subscription */ pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_TRUE; } /* Create and send 2xx response to the SUBSCRIBE request: */ status = pjsip_pres_accept(sub, rdata, st_code, &msg_data.hdr_list); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to accept presence subscription", status); pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_FALSE; } /* If code is 200, send NOTIFY now */ if (st_code == 200) { pjsua_pres_notify(acc_id, uapres, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, PJ_TRUE, &msg_data); } /* Done: */ PJSUA_UNLOCK(); return PJ_TRUE; }
/* * Dump presence subscriptions to log file. */ PJ_DEF(void) pjsua_pres_dump(pj_bool_t verbose) { unsigned acc_id; unsigned i; PJSUA_LOCK(); /* * When no detail is required, just dump number of server and client * subscriptions. */ if (verbose == PJ_FALSE) { int count = 0; for (acc_id=0; acc_id<PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) { if (!pjsua_var.acc[acc_id].valid) continue; if (!pj_list_empty(&pjsua_var.acc[acc_id].pres_srv_list)) { struct pjsua_srv_pres *uapres; uapres = pjsua_var.acc[acc_id].pres_srv_list.next; while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { ++count; uapres = uapres->next; } } } PJ_LOG(3,(THIS_FILE, "Number of server/UAS subscriptions: %d", count)); count = 0; for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { if (pjsua_var.buddy[i].uri.slen == 0) continue; if (pjsua_var.buddy[i].sub) { ++count; } } PJ_LOG(3,(THIS_FILE, "Number of client/UAC subscriptions: %d", count)); PJSUA_UNLOCK(); return; } /* * Dumping all server (UAS) subscriptions */ PJ_LOG(3,(THIS_FILE, "Dumping pjsua server subscriptions:")); for (acc_id=0; acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) { if (!pjsua_var.acc[acc_id].valid) continue; PJ_LOG(3,(THIS_FILE, " %.*s", (int)pjsua_var.acc[acc_id].cfg.id.slen, pjsua_var.acc[acc_id].cfg.id.ptr)); if (pj_list_empty(&pjsua_var.acc[acc_id].pres_srv_list)) { PJ_LOG(3,(THIS_FILE, " - none - ")); } else { struct pjsua_srv_pres *uapres; uapres = pjsua_var.acc[acc_id].pres_srv_list.next; while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { PJ_LOG(3,(THIS_FILE, " %10s %s", pjsip_evsub_get_state_name(uapres->sub), uapres->remote)); uapres = uapres->next; } } } /* * Dumping all client (UAC) subscriptions */ PJ_LOG(3,(THIS_FILE, "Dumping pjsua client subscriptions:")); if (pjsua_var.buddy_cnt == 0) { PJ_LOG(3,(THIS_FILE, " - no buddy list - ")); } else { for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { if (pjsua_var.buddy[i].uri.slen == 0) continue; if (pjsua_var.buddy[i].sub) { PJ_LOG(3,(THIS_FILE, " %10s %.*s", pjsip_evsub_get_state_name(pjsua_var.buddy[i].sub), (int)pjsua_var.buddy[i].uri.slen, pjsua_var.buddy[i].uri.ptr)); } else { PJ_LOG(3,(THIS_FILE, " %10s %.*s", "(null)", (int)pjsua_var.buddy[i].uri.slen, pjsua_var.buddy[i].uri.ptr)); } } } PJSUA_UNLOCK(); }