/* $Id$ */ /* * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "util.hpp" using namespace pj; using namespace std; #define THIS_FILE "account.cpp" /////////////////////////////////////////////////////////////////////////////// void AccountRegConfig::readObject(const ContainerNode &node) throw(Error) { ContainerNode this_node = node.readContainer("AccountRegConfig"); NODE_READ_STRING (this_node, registrarUri); NODE_READ_BOOL (this_node, registerOnAdd); NODE_READ_UNSIGNED (this_node, timeoutSec); NODE_READ_UNSIGNED (this_node, retryIntervalSec); NODE_READ_UNSIGNED (this_node, firstRetryIntervalSec); NODE_READ_UNSIGNED (this_node, delayBeforeRefreshSec); NODE_READ_BOOL (this_node, dropCallsOnFail); NODE_READ_UNSIGNED (this_node, unregWaitSec); NODE_READ_UNSIGNED (this_node, proxyUse); readSipHeaders(this_node, "headers", headers); } void AccountRegConfig::writeObject(ContainerNode &node) const throw(Error) { ContainerNode this_node = node.writeNewContainer("AccountRegConfig"); NODE_WRITE_STRING (this_node, registrarUri); NODE_WRITE_BOOL (this_node, registerOnAdd); NODE_WRITE_UNSIGNED (this_node, timeoutSec); NODE_WRITE_UNSIGNED (this_node, retryIntervalSec); NODE_WRITE_UNSIGNED (this_node, firstRetryIntervalSec); NODE_WRITE_UNSIGNED (this_node, delayBeforeRefreshSec); NODE_WRITE_BOOL (this_node, dropCallsOnFail); NODE_WRITE_UNSIGNED (this_node, unregWaitSec); NODE_WRITE_UNSIGNED (this_node, proxyUse); writeSipHeaders(this_node, "headers", headers); } /////////////////////////////////////////////////////////////////////////////// void AccountSipConfig::readObject(const ContainerNode &node) throw(Error) { ContainerNode this_node = node.readContainer("AccountSipConfig"); NODE_READ_STRINGV (this_node, proxies); NODE_READ_STRING (this_node, contactForced); NODE_READ_STRING (this_node, contactParams); NODE_READ_STRING (this_node, contactUriParams); NODE_READ_BOOL (this_node, authInitialEmpty); NODE_READ_STRING (this_node, authInitialAlgorithm); NODE_READ_INT (this_node, transportId); ContainerNode creds_node = this_node.readArray("authCreds"); authCreds.resize(0); while (creds_node.hasUnread()) { AuthCredInfo cred; cred.readObject(creds_node); authCreds.push_back(cred); } } void AccountSipConfig::writeObject(ContainerNode &node) const throw(Error) { ContainerNode this_node = node.writeNewContainer("AccountSipConfig"); NODE_WRITE_STRINGV (this_node, proxies); NODE_WRITE_STRING (this_node, contactForced); NODE_WRITE_STRING (this_node, contactParams); NODE_WRITE_STRING (this_node, contactUriParams); NODE_WRITE_BOOL (this_node, authInitialEmpty); NODE_WRITE_STRING (this_node, authInitialAlgorithm); NODE_WRITE_INT (this_node, transportId); ContainerNode creds_node = this_node.writeNewArray("authCreds"); for (unsigned i=0; i PJ_ARRAY_SIZE(ret.cred_info)) PJSUA2_RAISE_ERROR(PJ_ETOOMANY); for (i=0; irealm = str2Pj(src.realm); dst->scheme = str2Pj(src.scheme); dst->username = str2Pj(src.username); dst->data_type = src.dataType; dst->data = str2Pj(src.data); dst->ext.aka.k = str2Pj(src.akaK); dst->ext.aka.op = str2Pj(src.akaOp); dst->ext.aka.amf= str2Pj(src.akaAmf); ret.cred_count++; } ret.proxy_cnt = 0; if (sipConfig.proxies.size() > PJ_ARRAY_SIZE(ret.proxy)) PJSUA2_RAISE_ERROR(PJ_ETOOMANY); for (i=0; inext; } // AccountSipConfig sipConfig.authCreds.clear(); for (i=0; inext; } presConfig.publishEnabled = PJ2BOOL(prm.publish_enabled); presConfig.publishQueue = PJ2BOOL(prm.publish_opt.queue_request); presConfig.publishShutdownWaitMsec = prm.unpublish_max_wait_time_msec; presConfig.pidfTupleId = pj2Str(prm.pidf_tuple_id); // AccountMwiConfig mwiConfig.enabled = PJ2BOOL(prm.mwi_enabled); mwiConfig.expirationSec = prm.mwi_expires; // AccountNatConfig natConfig.sipStunUse = prm.sip_stun_use; natConfig.mediaStunUse = prm.media_stun_use; if (prm.ice_cfg_use == PJSUA_ICE_CONFIG_USE_CUSTOM) { natConfig.iceEnabled = PJ2BOOL(prm.ice_cfg.enable_ice); natConfig.iceMaxHostCands = prm.ice_cfg.ice_max_host_cands; natConfig.iceAggressiveNomination = PJ2BOOL(prm.ice_cfg.ice_opt.aggressive); natConfig.iceNominatedCheckDelayMsec = prm.ice_cfg.ice_opt.nominated_check_delay; natConfig.iceWaitNominationTimeoutMsec = prm.ice_cfg.ice_opt.controlled_agent_want_nom_timeout; natConfig.iceNoRtcp = PJ2BOOL(prm.ice_cfg.ice_no_rtcp); natConfig.iceAlwaysUpdate = PJ2BOOL(prm.ice_cfg.ice_always_update); } else { pjsua_media_config default_mcfg; if (!mcfg) { pjsua_media_config_default(&default_mcfg); mcfg = &default_mcfg; } natConfig.iceEnabled = PJ2BOOL(mcfg->enable_ice); natConfig.iceMaxHostCands= mcfg->ice_max_host_cands; natConfig.iceAggressiveNomination = PJ2BOOL(mcfg->ice_opt.aggressive); natConfig.iceNominatedCheckDelayMsec = mcfg->ice_opt.nominated_check_delay; natConfig.iceWaitNominationTimeoutMsec = mcfg->ice_opt.controlled_agent_want_nom_timeout; natConfig.iceNoRtcp = PJ2BOOL(mcfg->ice_no_rtcp); natConfig.iceAlwaysUpdate = PJ2BOOL(mcfg->ice_always_update); } if (prm.turn_cfg_use == PJSUA_TURN_CONFIG_USE_CUSTOM) { natConfig.turnEnabled = PJ2BOOL(prm.turn_cfg.enable_turn); natConfig.turnServer = pj2Str(prm.turn_cfg.turn_server); natConfig.turnConnType = prm.turn_cfg.turn_conn_type; natConfig.turnUserName = pj2Str(prm.turn_cfg.turn_auth_cred.data.static_cred.username); natConfig.turnPasswordType = prm.turn_cfg.turn_auth_cred.data.static_cred.data_type; natConfig.turnPassword = pj2Str(prm.turn_cfg.turn_auth_cred.data.static_cred.data); } else { pjsua_media_config default_mcfg; if (!mcfg) { pjsua_media_config_default(&default_mcfg); mcfg = &default_mcfg; } natConfig.turnEnabled = PJ2BOOL(mcfg->enable_turn); natConfig.turnServer = pj2Str(mcfg->turn_server); natConfig.turnConnType = mcfg->turn_conn_type; natConfig.turnUserName = pj2Str(mcfg->turn_auth_cred.data.static_cred.username); natConfig.turnPasswordType = mcfg->turn_auth_cred.data.static_cred.data_type; natConfig.turnPassword = pj2Str(mcfg->turn_auth_cred.data.static_cred.data); } natConfig.contactRewriteUse = prm.allow_contact_rewrite; natConfig.contactRewriteMethod = prm.contact_rewrite_method; natConfig.viaRewriteUse = prm.allow_via_rewrite; natConfig.sdpNatRewriteUse = prm.allow_sdp_nat_rewrite; natConfig.sipOutboundUse = prm.use_rfc5626; natConfig.sipOutboundInstanceId = pj2Str(prm.rfc5626_instance_id); natConfig.sipOutboundRegId = pj2Str(prm.rfc5626_reg_id); natConfig.udpKaIntervalSec = prm.ka_interval; natConfig.udpKaData = pj2Str(prm.ka_data); // AccountMediaConfig mediaConfig.transportConfig.fromPj(prm.rtp_cfg); mediaConfig.lockCodecEnabled= PJ2BOOL(prm.lock_codec); #if defined(PJMEDIA_STREAM_ENABLE_KA) && (PJMEDIA_STREAM_ENABLE_KA != 0) mediaConfig.streamKaEnabled = PJ2BOOL(prm.use_stream_ka); #else mediaConfig.streamKaEnabled = false; #endif mediaConfig.srtpUse = prm.use_srtp; mediaConfig.srtpSecureSignaling = prm.srtp_secure_signaling; mediaConfig.ipv6Use = prm.ipv6_media_use; // AccountVideoConfig videoConfig.autoShowIncoming = PJ2BOOL(prm.vid_in_auto_show); videoConfig.autoTransmitOutgoing = PJ2BOOL(prm.vid_out_auto_transmit); videoConfig.windowFlags = prm.vid_wnd_flags; videoConfig.defaultCaptureDevice = prm.vid_cap_dev; videoConfig.defaultRenderDevice = prm.vid_rend_dev; videoConfig.rateControlMethod = prm.vid_stream_rc_cfg.method; videoConfig.rateControlBandwidth = prm.vid_stream_rc_cfg.bandwidth; } void AccountConfig::readObject(const ContainerNode &node) throw(Error) { ContainerNode this_node = node.readContainer("AccountConfig"); NODE_READ_INT ( this_node, priority); NODE_READ_STRING ( this_node, idUri); NODE_READ_OBJ ( this_node, regConfig); NODE_READ_OBJ ( this_node, sipConfig); NODE_READ_OBJ ( this_node, callConfig); NODE_READ_OBJ ( this_node, presConfig); NODE_READ_OBJ ( this_node, mwiConfig); NODE_READ_OBJ ( this_node, natConfig); NODE_READ_OBJ ( this_node, mediaConfig); NODE_READ_OBJ ( this_node, videoConfig); } void AccountConfig::writeObject(ContainerNode &node) const throw(Error) { ContainerNode this_node = node.writeNewContainer("AccountConfig"); NODE_WRITE_INT ( this_node, priority); NODE_WRITE_STRING ( this_node, idUri); NODE_WRITE_OBJ ( this_node, regConfig); NODE_WRITE_OBJ ( this_node, sipConfig); NODE_WRITE_OBJ ( this_node, callConfig); NODE_WRITE_OBJ ( this_node, presConfig); NODE_WRITE_OBJ ( this_node, mwiConfig); NODE_WRITE_OBJ ( this_node, natConfig); NODE_WRITE_OBJ ( this_node, mediaConfig); NODE_WRITE_OBJ ( this_node, videoConfig); } /////////////////////////////////////////////////////////////////////////////// void AccountInfo::fromPj(const pjsua_acc_info &pai) { id = pai.id; isDefault = pai.is_default != 0; uri = pj2Str(pai.acc_uri); regIsConfigured = pai.has_registration != 0; regIsActive = pai.has_registration && pai.expires > 0 && (pai.status / 100 == 2); regExpiresSec = pai.expires; regStatus = pai.status; regStatusText = pj2Str(pai.status_text); regLastErr = pai.reg_last_err; onlineStatus = pai.online_status != 0; onlineStatusText = pj2Str(pai.online_status_text); } /////////////////////////////////////////////////////////////////////////////// Account::Account() : id(PJSUA_INVALID_ID) { } Account::~Account() { /* If this instance is deleted, also delete the corresponding account in * PJSUA library. */ if (isValid() && pjsua_get_state() < PJSUA_STATE_CLOSING) { // Cleanup buddies in the buddy list while(buddyList.size() > 0) { Buddy *b = buddyList[0]; delete b; /* this will remove itself from the list */ } pjsua_acc_set_user_data(id, NULL); pjsua_acc_del(id); } } void Account::create(const AccountConfig &acc_cfg, bool make_default) throw(Error) { pjsua_acc_config pj_acc_cfg; acc_cfg.toPj(pj_acc_cfg); pj_acc_cfg.user_data = (void*)this; PJSUA2_CHECK_EXPR( pjsua_acc_add(&pj_acc_cfg, make_default, &id) ); } void Account::modify(const AccountConfig &acc_cfg) throw(Error) { pjsua_acc_config pj_acc_cfg; acc_cfg.toPj(pj_acc_cfg); pj_acc_cfg.user_data = (void*)this; PJSUA2_CHECK_EXPR( pjsua_acc_modify(id, &pj_acc_cfg) ); } bool Account::isValid() const { return pjsua_acc_is_valid(id) != 0; } void Account::setDefault() throw(Error) { PJSUA2_CHECK_EXPR( pjsua_acc_set_default(id) ); } bool Account::isDefault() const { return pjsua_acc_get_default() == id; } int Account::getId() const { return id; } Account *Account::lookup(int acc_id) { return (Account*)pjsua_acc_get_user_data(acc_id); } AccountInfo Account::getInfo() const throw(Error) { pjsua_acc_info pj_ai; AccountInfo ai; PJSUA2_CHECK_EXPR( pjsua_acc_get_info(id, &pj_ai) ); ai.fromPj(pj_ai); return ai; } void Account::setRegistration(bool renew) throw(Error) { PJSUA2_CHECK_EXPR( pjsua_acc_set_registration(id, renew) ); } void Account::setOnlineStatus(const PresenceStatus &pres_st) throw(Error) { pjrpid_element pj_rpid; pj_bzero(&pj_rpid, sizeof(pj_rpid)); pj_rpid.type = PJRPID_ELEMENT_TYPE_PERSON; pj_rpid.activity = pres_st.activity; pj_rpid.id = str2Pj(pres_st.rpidId); pj_rpid.note = str2Pj(pres_st.note); PJSUA2_CHECK_EXPR( pjsua_acc_set_online_status2( id, pres_st.status == PJSUA_BUDDY_STATUS_ONLINE, &pj_rpid) ); } void Account::setTransport(TransportId tp_id) throw(Error) { PJSUA2_CHECK_EXPR( pjsua_acc_set_transport(id, tp_id) ); } void Account::presNotify(const PresNotifyParam &prm) throw(Error) { pj_str_t pj_state_str = str2Pj(prm.stateStr); pj_str_t pj_reason = str2Pj(prm.reason); pjsua_msg_data msg_data; prm.txOption.toPj(msg_data); PJSUA2_CHECK_EXPR( pjsua_pres_notify(id, (pjsua_srv_pres*)prm.srvPres, prm.state, &pj_state_str, &pj_reason, prm.withBody, &msg_data) ); } const BuddyVector& Account::enumBuddies() const throw(Error) { return buddyList; } Buddy* Account::findBuddy(string uri, FindBuddyMatch *buddy_match) const throw(Error) { if (!buddy_match) { static FindBuddyMatch def_bm; buddy_match = &def_bm; } for (unsigned i = 0; i < buddyList.size(); i++) { if (buddy_match->match(uri, *buddyList[i])) return buddyList[i]; } PJSUA2_RAISE_ERROR(PJ_ENOTFOUND); } void Account::addBuddy(Buddy *buddy) { pj_assert(buddy); buddyList.push_back(buddy); } void Account::removeBuddy(Buddy *buddy) { pj_assert(buddy); BuddyVector::iterator it; for (it = buddyList.begin(); it != buddyList.end(); it++) { if (*it == buddy) { buddyList.erase(it); return; } } pj_assert(!"Bug! Buddy to be removed is not in the buddy list!"); }