/** * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr) * This file is part of CSipSimple. * * CSipSimple 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 3 of the License, or * (at your option) any later version. * If you own a pjsip commercial license you can also redistribute it * and/or modify it under the terms of the GNU Lesser General Public License * as an android library. * * CSipSimple 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 CSipSimple. If not, see <http://www.gnu.org/licenses/>. */ package com.csipsimple.pjsip; import android.content.Context; import android.text.TextUtils; import com.csipsimple.api.SipConfigManager; import com.csipsimple.api.SipProfile; import com.csipsimple.api.SipUri; import com.csipsimple.api.SipUri.ParsedSipContactInfos; import com.csipsimple.utils.Log; import com.csipsimple.utils.PreferencesProviderWrapper; import org.pjsip.pjsua.SWIGTYPE_p_pj_stun_auth_cred; import org.pjsip.pjsua.csipsimple_acc_config; import org.pjsip.pjsua.pj_qos_params; import org.pjsip.pjsua.pj_qos_type; import org.pjsip.pjsua.pj_str_t; import org.pjsip.pjsua.pjmedia_srtp_use; import org.pjsip.pjsua.pjsip_auth_clt_pref; import org.pjsip.pjsua.pjsip_cred_info; import org.pjsip.pjsua.pjsua; import org.pjsip.pjsua.pjsuaConstants; import org.pjsip.pjsua.pjsua_acc_config; import org.pjsip.pjsua.pjsua_ice_config; import org.pjsip.pjsua.pjsua_ice_config_use; import org.pjsip.pjsua.pjsua_ipv6_use; import org.pjsip.pjsua.pjsua_stun_use; import org.pjsip.pjsua.pjsua_transport_config; import org.pjsip.pjsua.pjsua_turn_config; import org.pjsip.pjsua.pjsua_turn_config_use; public class PjSipAccount { //private static final String THIS_FILE = "PjSipAcc"; private String displayName; // For now everything is public, easiest to manage public String wizard; public boolean active; public pjsua_acc_config cfg; public csipsimple_acc_config css_cfg; public Long id; public Integer transport = 0; private int profile_vid_auto_show = -1; private int profile_vid_auto_transmit = -1; private int profile_enable_qos; private int profile_qos_dscp; private boolean profile_default_rtp_port = true; //private boolean hasZrtpValue = false; public PjSipAccount() { cfg = new pjsua_acc_config(); pjsua.acc_config_default(cfg); css_cfg = new csipsimple_acc_config(); pjsua.csipsimple_acc_config_default(css_cfg); } /** * Initialize from a SipProfile (public api) object * @param profile the sip profile to use */ public PjSipAccount(SipProfile profile) { this(); if(profile.id != SipProfile.INVALID_ID) { id = profile.id; } displayName = profile.display_name; wizard = profile.wizard; transport = profile.transport; active = profile.active; transport = profile.transport; cfg.setPriority(profile.priority); if(profile.acc_id != null) { cfg.setId(pjsua.pj_str_copy(profile.acc_id)); } if(profile.reg_uri != null) { cfg.setReg_uri(pjsua.pj_str_copy(profile.reg_uri)); } if(profile.publish_enabled != -1) { cfg.setPublish_enabled(profile.publish_enabled); } if(profile.reg_timeout != -1) { cfg.setReg_timeout(profile.reg_timeout); } if(profile.reg_delay_before_refresh != -1) { cfg.setReg_delay_before_refresh(profile.reg_delay_before_refresh); } if(profile.ka_interval != -1) { cfg.setKa_interval(profile.ka_interval); } if(profile.pidf_tuple_id != null) { cfg.setPidf_tuple_id(pjsua.pj_str_copy(profile.pidf_tuple_id)); } if(profile.force_contact != null) { cfg.setForce_contact(pjsua.pj_str_copy(profile.force_contact)); } cfg.setAllow_contact_rewrite(profile.allow_contact_rewrite ? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); cfg.setContact_rewrite_method(profile.contact_rewrite_method); cfg.setAllow_via_rewrite(profile.allow_via_rewrite ? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); cfg.setAllow_sdp_nat_rewrite(profile.allow_sdp_nat_rewrite ? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); if(profile.use_srtp != -1) { cfg.setUse_srtp(pjmedia_srtp_use.swigToEnum(profile.use_srtp)); cfg.setSrtp_secure_signaling(0); } css_cfg.setUse_zrtp(profile.use_zrtp); if(profile.proxies != null) { Log.d("PjSipAccount", "Create proxy "+profile.proxies.length); cfg.setProxy_cnt(profile.proxies.length); pj_str_t[] proxies = cfg.getProxy(); int i = 0; for(String proxy : profile.proxies) { Log.d("PjSipAccount", "Add proxy "+proxy); proxies[i] = pjsua.pj_str_copy(proxy); i += 1; } cfg.setProxy(proxies); }else { cfg.setProxy_cnt(0); } cfg.setReg_use_proxy(profile.reg_use_proxy); if(profile.username != null || profile.data != null) { cfg.setCred_count(1); pjsip_cred_info cred_info = cfg.getCred_info(); if(profile.realm != null) { cred_info.setRealm(pjsua.pj_str_copy(profile.realm)); } if(profile.username != null) { cred_info.setUsername(pjsua.pj_str_copy(profile.username)); } if(profile.datatype != -1) { cred_info.setData_type(profile.datatype); } if(profile.data != null) { cred_info.setData(pjsua.pj_str_copy(profile.data)); } }else { cfg.setCred_count(0); } // Auth prefs { pjsip_auth_clt_pref authPref = cfg.getAuth_pref(); authPref.setInitial_auth(profile.initial_auth ? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); if(!TextUtils.isEmpty(profile.auth_algo)) { authPref.setAlgorithm(pjsua.pj_str_copy(profile.auth_algo)); } cfg.setAuth_pref(authPref); } cfg.setMwi_enabled(profile.mwi_enabled ? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); cfg.setIpv6_media_use(profile.ipv6_media_use == 1 ? pjsua_ipv6_use.PJSUA_IPV6_ENABLED : pjsua_ipv6_use.PJSUA_IPV6_DISABLED); // RFC5626 cfg.setUse_rfc5626(profile.use_rfc5626? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); if(!TextUtils.isEmpty(profile.rfc5626_instance_id)) { cfg.setRfc5626_instance_id(pjsua.pj_str_copy(profile.rfc5626_instance_id)); } if(!TextUtils.isEmpty(profile.rfc5626_reg_id)) { cfg.setRfc5626_reg_id(pjsua.pj_str_copy(profile.rfc5626_reg_id)); } // Video profile_vid_auto_show = profile.vid_in_auto_show; profile_vid_auto_transmit = profile.vid_out_auto_transmit; // Rtp cfg pjsua_transport_config rtpCfg = cfg.getRtp_cfg(); if(profile.rtp_port >= 0) { rtpCfg.setPort(profile.rtp_port); profile_default_rtp_port = false; } if(!TextUtils.isEmpty(profile.rtp_public_addr)) { rtpCfg.setPublic_addr(pjsua.pj_str_copy(profile.rtp_public_addr)); } if(!TextUtils.isEmpty(profile.rtp_bound_addr)) { rtpCfg.setBound_addr(pjsua.pj_str_copy(profile.rtp_bound_addr)); } profile_enable_qos = profile.rtp_enable_qos; profile_qos_dscp = profile.rtp_qos_dscp; cfg.setSip_stun_use(profile.sip_stun_use == 0 ? pjsua_stun_use.PJSUA_STUN_USE_DISABLED : pjsua_stun_use.PJSUA_STUN_USE_DEFAULT); cfg.setMedia_stun_use(profile.media_stun_use == 0 ? pjsua_stun_use.PJSUA_STUN_USE_DISABLED : pjsua_stun_use.PJSUA_STUN_USE_DEFAULT); if(profile.ice_cfg_use == 1) { cfg.setIce_cfg_use(pjsua_ice_config_use.PJSUA_ICE_CONFIG_USE_CUSTOM); pjsua_ice_config iceCfg = cfg.getIce_cfg(); iceCfg.setEnable_ice( (profile.ice_cfg_enable == 1 )? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); }else { cfg.setIce_cfg_use(pjsua_ice_config_use.PJSUA_ICE_CONFIG_USE_DEFAULT); } if(profile.turn_cfg_use == 1) { cfg.setTurn_cfg_use(pjsua_turn_config_use.PJSUA_TURN_CONFIG_USE_CUSTOM); pjsua_turn_config turnCfg = cfg.getTurn_cfg(); SWIGTYPE_p_pj_stun_auth_cred creds = turnCfg.getTurn_auth_cred(); turnCfg.setEnable_turn( (profile.turn_cfg_enable == 1) ? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); turnCfg.setTurn_server( pjsua.pj_str_copy(profile.turn_cfg_server) ); pjsua.set_turn_credentials( pjsua.pj_str_copy(profile.turn_cfg_user), pjsua.pj_str_copy(profile.turn_cfg_password), pjsua.pj_str_copy("*"), creds); // Normally this step is useless as manipulating a pointer in C memory at this point, but in case this changes reassign turnCfg.setTurn_auth_cred(creds); }else { cfg.setTurn_cfg_use(pjsua_turn_config_use.PJSUA_TURN_CONFIG_USE_DEFAULT); } } /** * Automatically apply csipsimple specific parameters to the account * @param ctxt */ public void applyExtraParams(Context ctxt) { // Transport String regUri = ""; String argument = ""; switch (transport) { case SipProfile.TRANSPORT_UDP: argument = ";transport=udp;lr"; break; case SipProfile.TRANSPORT_TCP: argument = ";transport=tcp;lr"; break; case SipProfile.TRANSPORT_TLS: //TODO : differentiate ssl/tls ? argument = ";transport=tls;lr"; break; default: break; } if (!TextUtils.isEmpty(argument)) { regUri = PjSipService.pjStrToString(cfg.getReg_uri()); if(!TextUtils.isEmpty(regUri)) { long initialProxyCnt = cfg.getProxy_cnt(); pj_str_t[] proxies = cfg.getProxy(); //TODO : remove lr and transport from uri // cfg.setReg_uri(pjsua.pj_str_copy(proposed_server)); String firstProxy = PjSipService.pjStrToString(proxies[0]); if (initialProxyCnt == 0 || TextUtils.isEmpty(firstProxy)) { cfg.setReg_uri(pjsua.pj_str_copy(regUri + argument)); cfg.setProxy_cnt(0); } else { proxies[0] = pjsua.pj_str_copy(firstProxy + argument); cfg.setProxy(proxies); } // } else { // proxies[0] = pjsua.pj_str_copy(proxies[0].getPtr() + argument); // cfg.setProxy(proxies); // } } } //Caller id PreferencesProviderWrapper prefs = new PreferencesProviderWrapper(ctxt); String defaultCallerid = prefs.getPreferenceStringValue(SipConfigManager.DEFAULT_CALLER_ID); // If one default caller is set if (!TextUtils.isEmpty(defaultCallerid)) { String accId = PjSipService.pjStrToString(cfg.getId()); ParsedSipContactInfos parsedInfos = SipUri.parseSipContact(accId); if (TextUtils.isEmpty(parsedInfos.displayName)) { // Apply new display name parsedInfos.displayName = defaultCallerid; cfg.setId(pjsua.pj_str_copy(parsedInfos.toString())); } } // Keep alive cfg.setKa_interval(prefs.getUdpKeepAliveInterval()); // Video if(profile_vid_auto_show >= 0) { cfg.setVid_in_auto_show((profile_vid_auto_show == 1) ? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); }else { cfg.setVid_in_auto_show(pjsuaConstants.PJ_TRUE); } if(profile_vid_auto_transmit >= 0) { cfg.setVid_out_auto_transmit((profile_vid_auto_transmit == 1) ? pjsuaConstants.PJ_TRUE : pjsuaConstants.PJ_FALSE); }else { cfg.setVid_out_auto_transmit(pjsuaConstants.PJ_TRUE); } // RTP cfg pjsua_transport_config rtpCfg = cfg.getRtp_cfg(); if(profile_default_rtp_port) { rtpCfg.setPort(prefs.getRTPPort()); } boolean hasQos = prefs.getPreferenceBooleanValue(SipConfigManager.ENABLE_QOS); if(profile_enable_qos >= 0) { hasQos = (profile_enable_qos == 1); } if(hasQos) { // TODO - video? rtpCfg.setQos_type(pj_qos_type.PJ_QOS_TYPE_VOICE); pj_qos_params qosParam = rtpCfg.getQos_params(); // Default for RTP layer is different than default for SIP layer. short dscpVal = (short) prefs.getPreferenceIntegerValue(SipConfigManager.DSCP_RTP_VAL); if(profile_qos_dscp >= 0) { // If not set, we don't need to change dscp value dscpVal = (short) profile_qos_dscp; qosParam.setDscp_val(dscpVal); qosParam.setFlags((short) 1); // DSCP } } } /** * @return the displayName */ public String getDisplayName() { return displayName; } @Override public boolean equals(Object o) { if(o != null && o.getClass() == PjSipAccount.class) { PjSipAccount oAccount = (PjSipAccount) o; return oAccount.id == id; } return super.equals(o); } }