I’ve been working in an IP telephony project with PJSIP, and had to implement a few features here and there. Here’s a couple of snippets I used all over the place.
Extract header value
pj_str_t event_hdr_name = pj_str("Event");
pjsip_generic_string_hdr *event_hdr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(message, &event_hdr_name, NULL);
if (event_hdr == NULL)
return NULL;
pj_str_t event_value = event_hdr->vhalue;
Add header to list
struct pjsip_generic_string_hdr header;
pj_str_t name = pj_str("Name");
pj_str_t value = pj_str("value");
pjsip_generic_string_hdr_init2(& header, &name, &value);
pj_list_push_back(&cfg.reg_hdr_list, &header);
Clone header
// Set the "Contact" header
pj_str_t contact_hdr_name = pj_str("");
pj_str_t contact_hdr_value = pj_str("");
const pj_str_t *name = pj_cstr(&contact_hdr_name, "Contact");
const pj_str_t *value = pj_cstr(&contact_hdr_value, "<sip:alice@192.168.7.12;transport=TCP;ob>");
pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, name, value);
// Clone the "Contact" header
pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr*)pjsip_msg_find_hdr_by_name(last_data_received->msg_info.msg, &contact_hdr_name, NULL);
pjsip_contact_hdr *clone_hdr = (pjsip_contact_hdr*)pjsip_hdr_clone(pool, contact_hdr);
Add User-Agent header
pj_str_t ua_hdr_name = pj_str("User-Agent");
pj_str_t ua_hdr_value = pj_str("CSTAEngine");
status = csta_tdata_add_header(pool, *tdata, &ua_hdr_name, &ua_hdr_value);
Get origin IP address
// Requires a memory pool
pjsip_response_addr res_addr;
pjsip_get_response_addr(pool, rdata, &res_addr);
Build response to a server request outside of dialog
Keep a reference to the data:
static pjsip_rx_data *last_data_received;
// ...later, on the module callback functions...
pjsip_rx_data_clone(rdata, 0, &last_data_received);
Use it to create a response outside of a dialog:
// Respond to the original message
pjsip_endpt_respond(endpoint, NULL, last_data_received, PJSIP_SC_OK, NULL, &hdr_list, body, NULL);
Minimal PJSIP Stack
Custom thread worker:
static pj_bool_t quit_flag = PJ_FALSE;
static int worker_thread(void *arg)
{
PJ_UNUSED_ARG(arg);
while (!quit_flag) {
pj_time_val timeout = {0, 500};
pjsip_endpt_handle_events(endpoint, &timeout);
}
return 0;
}
Custom stack setup:
pj_init();
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
pj_sockaddr addr;
pj_status_t status;
pj_log_set_level(3);
status = pjlib_util_init();
csta_log_assert(status);
status = pjsip_endpt_create(&cp.factory, NULL, &endpoint);
csta_log_assert(status);
pj_uint16_t sip_af = pj_AF_INET();
pj_sockaddr_init(sip_af, &addr, NULL, sip_port);
if (sip_af == pj_AF_INET()) {
if (sip_tcp) {
status = pjsip_tcp_transport_start(endpoint, &addr.ipv4, 1, NULL);
}
else {
status = pjsip_udp_transport_start(endpoint, &addr.ipv4, NULL, 1, NULL);
}
}
else if (sip_af == pj_AF_INET6()) {
status = pjsip_udp_transport_start6(endpoint, &addr.ipv6, NULL, 1, NULL);
}
else {
status = PJ_EAFNOTSUP;
}
csta_log_assert(status);
status = pjsip_tsx_layer_init_module(endpoint);
csta_log_assert(status);
status = pjsip_ua_init_module(endpoint, NULL);
csta_log_assert(status);
// pj_bzero(&inv_cb, sizeof(inv_cb));
// inv_cb.on_state_changed = &call_on_state_changed;
// inv_cb.on_new_session = &call_on_forked;
// inv_cb.on_media_update = &call_on_media_update;
// inv_cb.on_rx_offer = &call_on_rx_offer;
// status = pjsip_inv_usage_init(endpoint, &inv_cb);
// csta_log_assert(status);
status = pjsip_100rel_init_module(endpoint);
csta_log_assert(status);
pj_pool_t *pool = pjsip_endpt_create_pool(endpoint, "", 1000, 1000);
status = pj_thread_create(pool, "", &worker_thread, NULL, 0, 0, &thread);
csta_log_assert(status);
Remember to add a module to be notified of events:
pj_status_t status = pjsip_endpt_register_module(endpoint, &csta_module);
Minimal PJSUA Stack
Much simpler than using bare bones PJSIP:
pj_status_t status;
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
status = pjsua_create();
csta_log_assert(status);
pjsua_config cfg;
pjsua_config_default (&cfg);
NSString *userAgentString = [PJSUALibraryManager userAgentString];
cfg.user_agent = pj_str((char*)[userAgentString cStringUsingEncoding:NSUTF8StringEncoding]);
pjsua_logging_config log_cfg;
pjsua_logging_config_default(&log_cfg);
log_cfg.console_level = 4;
log_cfg.decor &= ~(PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC);
// Init the pjsua
status = pjsua_init(&cfg, &log_cfg, NULL);
csta_log_assert(status);
pjsua_transport_config cfg2;
pjsua_transport_config_default(&cfg2);
cfg2.port = 0;
// Add UDP transport.
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg2, NULL);
csta_log_assert(status);
pjsua_transport_config cfg3;
pjsua_transport_config_default(&cfg3);
// Add TCP transport.
status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &cfg3, NULL);
csta_log_assert(status);
// Initialization is done, now start pjsua
status = pjsua_start();
csta_log_assert(status);