📄 pjsua_pres.c
字号:
}
}
uapres = uapres->next;
}
/* Send PUBLISH if required. We only do this when we have a PUBLISH
* session. If we don't have a PUBLISH session, then it could be
* that we're waiting until registration has completed before we
* send the first PUBLISH.
*/
if (acc_cfg->publish_enabled && acc->publish_sess) {
if (acc->publish_state != acc->online_status) {
send_publish(acc_id, PJ_TRUE);
}
}
}
/***************************************************************************
* Client subscription.
*/
/* 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(3,(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) {
buddy->sub = NULL;
buddy->status.info_cnt = 0;
pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL);
}
/* Call callback */
if (pjsua_var.ua_cfg.cb.on_buddy_state)
(*pjsua_var.ua_cfg.cb.on_buddy_state)(buddy->index);
}
PJSUA_UNLOCK();
}
/* 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_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(pjsua_var.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();
}
/* 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();
}
/* Event subscription callback. */
static pjsip_evsub_user pres_callback =
{
&pjsua_evsub_on_state,
&pjsua_evsub_on_tsx_state,
NULL, /* on_rx_refresh: don't care about SUBSCRIBE refresh, unless
* we want to authenticate
*/
&pjsua_evsub_on_rx_notify,
NULL, /* on_client_refresh: Use default behaviour, which is to
* refresh client subscription. */
NULL, /* on_server_timeout: Use default behaviour, which is to send
* NOTIFY to terminate.
*/
};
/* It does what it says.. */
static void subscribe_buddy_presence(unsigned index)
{
pjsua_buddy *buddy;
int acc_id;
pjsua_acc *acc;
pj_str_t contact;
pjsip_dialog *dlg;
pjsip_tx_data *tdata;
pj_status_t status;
buddy = &pjsua_var.buddy[index];
acc_id = pjsua_acc_find_for_outgoing(&buddy->uri);
acc = &pjsua_var.acc[acc_id];
PJ_LOG(4,(THIS_FILE, "Using account %d for buddy %d subscription",
acc_id, index));
/* Generate suitable Contact header */
status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,
acc_id, &buddy->uri);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
return;
}
/* Create UAC dialog */
status = pjsip_dlg_create_uac( pjsip_ua_instance(),
&acc->cfg.id,
&contact,
&buddy->uri,
NULL, &dlg);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create dialog",
status);
return;
}
status = pjsip_pres_create_uac( dlg, &pres_callback,
PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub);
if (status != PJ_SUCCESS) {
pjsua_var.buddy[index].sub = NULL;
pjsua_perror(THIS_FILE, "Unable to create presence client",
status);
pjsip_dlg_terminate(dlg);
return;
}
/* 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);
}
/* Set route-set */
if (!pj_list_empty(&acc->route_set)) {
pjsip_dlg_set_route_set(dlg, &acc->route_set);
}
/* Set credentials */
if (acc->cred_cnt) {
pjsip_auth_clt_set_credentials( &dlg->auth_sess,
acc->cred_cnt, acc->cred);
}
pjsip_evsub_set_mod_data(buddy->sub, pjsua_var.mod.id, buddy);
status = pjsip_pres_initiate(buddy->sub, -1, &tdata);
if (status != PJ_SUCCESS) {
pjsip_pres_terminate(buddy->sub, PJ_FALSE);
buddy->sub = NULL;
pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE",
status);
return;
}
pjsua_process_msg_data(tdata, NULL);
status = pjsip_pres_send_request(buddy->sub, tdata);
if (status != PJ_SUCCESS) {
pjsip_pres_terminate(buddy->sub, PJ_FALSE);
buddy->sub = NULL;
pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE",
status);
return;
}
}
/* It does what it says... */
static void unsubscribe_buddy_presence(unsigned index)
{
pjsua_buddy *buddy;
pjsip_tx_data *tdata;
pj_status_t status;
buddy = &pjsua_var.buddy[index];
if (buddy->sub == NULL)
return;
if (pjsip_evsub_get_state(buddy->sub) == PJSIP_EVSUB_STATE_TERMINATED) {
pjsua_var.buddy[index].sub = NULL;
return;
}
status = pjsip_pres_initiate( buddy->sub, 0, &tdata);
if (status == PJ_SUCCESS) {
pjsua_process_msg_data(tdata, NULL);
status = pjsip_pres_send_request( buddy->sub, tdata );
}
if (status != PJ_SUCCESS && buddy->sub) {
pjsip_pres_terminate(buddy->sub, PJ_FALSE);
buddy->sub = NULL;
pjsua_perror(THIS_FILE, "Unable to unsubscribe presence",
status);
}
}
/* It does what it says.. */
static void refresh_client_subscriptions(void)
{
unsigned i;
for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
if (!pjsua_var.buddy[i].uri.slen)
continue;
if (pjsua_var.buddy[i].monitor && !pjsua_var.buddy[i].sub) {
subscribe_buddy_presence(i);
} else if (!pjsua_var.buddy[i].monitor && pjsua_var.buddy[i].sub) {
unsubscribe_buddy_presence(i);
}
}
}
/* Timer callback to re-create client subscription */
static void pres_timer_cb(pj_timer_heap_t *th,
pj_timer_entry *entry)
{
pj_time_val delay = { PJSUA_PRES_TIMER, 0 };
PJ_UNUSED_ARG(th);
PJSUA_LOCK();
entry->id = PJ_FALSE;
refresh_client_subscriptions();
pjsip_endpt_schedule_timer(pjsua_var.endpt, entry, &delay);
entry->id = PJ_TRUE;
PJSUA_UNLOCK();
}
/*
* Init presence
*/
pj_status_t pjsua_pres_init()
{
unsigned i;
pj_status_t status;
status = pjsip_endpt_register_module( pjsua_var.endpt, &mod_pjsua_pres);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to register pjsua presence module",
status);
}
for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
reset_buddy(i);
}
return status;
}
/*
* Start presence subsystem.
*/
pj_status_t pjsua_pres_start(void)
{
/* Start presence timer to re-subscribe to buddy's presence when
* subscription has failed.
*/
if (pjsua_var.pres_timer.id == PJ_FALSE) {
pj_time_val pres_interval = {PJSUA_PRES_TIMER, 0};
pjsua_var.pres_timer.cb = &pres_timer_cb;
pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.pres_timer,
&pres_interval);
}
return PJ_SUCCESS;
}
/*
* Refresh presence subscriptions
*/
void pjsua_pres_refresh()
{
unsigned i;
refresh_client_subscriptions();
for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
if (pjsua_var.acc[i].valid)
refresh_server_subscription(i);
}
}
/*
* Shutdown presence.
*/
void pjsua_pres_shutdown(void)
{
unsigned i;
if (pjsua_var.pres_timer.id != 0) {
pjsip_endpt_cancel_timer(pjsua_var.endpt, &pjsua_var.pres_timer);
pjsua_var.pres_timer.id = PJ_FALSE;
}
for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
if (!pjsua_var.acc[i].valid)
continue;
pjsua_pres_delete_acc(i);
}
for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
pjsua_var.buddy[i].monitor = 0;
}
pjsua_pres_refresh();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -