Android Studio集成PJSIP连接SIP服务器问题求助
我之前在Android上集成PJSIP连接SIP服务器时也踩过不少坑,参考Csipsimple的时候也遇到过适配问题,给你整理一套实用的步骤和排查要点,应该能帮你解决连接难题:
一、Android Studio中PJSIP的基础集成步骤
- 自行编译PJSIP库:预编译库容易出现兼容性问题,建议自己编译源码。先拉取PJSIP最新稳定版源码,配置Android Studio自带的NDK(推荐r21e~r25版本,太新可能不兼容),修改
pjlib/include/pj/config_site.h开启Android支持、禁用不需要的模块(比如不需要视频功能可关闭)。执行编译命令:
编译完成后会得到./configure-android make dep && makelibpjsua2.so等架构对应的SO文件,以及pjsua2.jar绑定类。 - 导入项目配置:在
app/src/main/jniLibs下创建对应架构文件夹(如armeabi-v7a、arm64-v8a),放入SO文件;将pjsua2.jar复制到app/libs,在Module级build.gradle添加依赖:
同时指定支持的ABI:implementation files('libs/pjsua2.jar')android { defaultConfig { ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' } } } - 配置权限:在
AndroidManifest.xml添加必要权限,Android 6+还需动态申请录音等危险权限:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
二、连接SIP服务器的核心代码实现
用pjsua2的面向对象API封装SIP管理逻辑(避免Csipsimple旧版低级API的适配问题):
import org.pjsip.pjsua2.*; import android.util.Log; public class SipManager { private Endpoint sipEndpoint; private Account sipAccount; public void initSipFramework() throws Exception { // 初始化Endpoint核心实例 sipEndpoint = new Endpoint(); sipEndpoint.libCreate(); // 配置日志(开启详细日志方便排查) EpConfig epConfig = new EpConfig(); epConfig.getLogConfig().setLevel(5); epConfig.getLogConfig().setConsoleLevel(5); sipEndpoint.libInit(epConfig); // 创建UDP传输通道(SIP默认用UDP) TransportConfig transportConfig = new TransportConfig(); transportConfig.setPort(5060); sipEndpoint.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, transportConfig); // 启动SIP框架 sipEndpoint.libStart(); } public void registerSipAccount(String sipUri, String username, String password, String serverIp) throws Exception { AccountConfig accConfig = new AccountConfig(); // 设置账号唯一标识 accConfig.getIdUri().setUri(sipUri); // 格式:sip:your_name@server_ip // 设置注册服务器地址 accConfig.getRegConfig().getRegistrarUri().setUri("sip:" + serverIp); // 添加认证信息(大部分服务器用digest认证) AuthCredInfo authCred = new AuthCredInfo("digest", "*", username, 0, password); accConfig.getSipConfig().getAuthCreds().add(authCred); // 设置代理服务器地址 SipServerAddress proxyAddr = new SipServerAddress(); proxyAddr.setUri("sip:" + serverIp + ":5060"); accConfig.getSipConfig().getSipProxies().add(proxyAddr); // 创建账号并发起注册 sipAccount = new Account(); sipAccount.create(accConfig); Log.d("SIP_DEBUG", "注册请求已发送"); } // 销毁时释放资源,避免内存泄漏 public void releaseSipResources() { if (sipAccount != null) sipAccount.delete(); if (sipEndpoint != null) { sipEndpoint.libDestroy(); sipEndpoint.delete(); } } }
在Activity中调用(注意在子线程执行SIP操作,避免阻塞主线程):
import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; public class MainActivity extends AppCompatActivity { private SipManager sipManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 动态申请录音权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1001); } else { initSipConnection(); } } private void initSipConnection() { new Thread(() -> { try { sipManager = new SipManager(); sipManager.initSipFramework(); // 替换为你的SIP服务器信息 sipManager.registerSipAccount( "sip:test_user@192.168.1.100", "test_user", "test_pass", "192.168.1.100" ); } catch (Exception e) { e.printStackTrace(); Log.e("SIP_ERROR", "连接失败:" + e.getMessage()); } }).start(); } @Override protected void onDestroy() { super.onDestroy(); if (sipManager != null) sipManager.releaseSipResources(); } }
三、连接失败的常见排查要点
- 库兼容性问题:如果编译时用了不匹配的NDK版本,或架构不对,会导致运行时崩溃或连接无响应,建议严格按照PJSIP官方推荐的NDK版本编译。
- SIP参数错误:先拿第三方SIP客户端(如Linphone)测试账号是否能正常注册,排除服务器端问题。重点检查:SIP URI格式是否正确、服务器IP/端口是否开放、认证密码是否匹配。
- 网络问题:真机测试确保和服务器在同一网络,或服务器有公网IP且开放5060 UDP端口;模拟器测试用
10.0.2.2替代本地IP。 - 日志分析:开启PJSIP详细日志,查看错误信息:
401 Unauthorized是认证信息错误、Connection refused是服务器地址/端口错误、DNS resolution failed是域名解析问题。 - Csipsimple适配坑:Csipsimple用的是旧版pjsua低级API,和现在推荐的pjsua2面向对象API写法差异很大,不要直接照搬代码,需适配pjsua2的逻辑。
四、额外调试技巧
用Wireshark抓包分析SIP消息,查看注册请求是否正常发送、服务器返回的响应码,这是定位问题的高效方法;同时捕获PjException,根据错误码查PJSIP官方文档的对应说明。
内容的提问来源于stack exchange,提问作者Dhananjay Gupta
相关产品推荐
相关产品推荐

