安国市城乡建设局网站青海电商网站建设公司
2026/5/19 3:59:18 网站建设 项目流程
安国市城乡建设局网站,青海电商网站建设公司,如何添加wordpress主题,淮南58同城网手把手教你用 pjsip 搭出第一个 VoIP 通话应用#xff1a;从零开始的实战指南你有没有想过#xff0c;自己动手写一个能打电话的程序#xff1f;不是用微信、不是走运营商#xff0c;而是真正通过网络传输声音——哪怕只是两台电脑之间“喂喂”两声。这听起来像是黑科技从零开始的实战指南你有没有想过自己动手写一个能打电话的程序不是用微信、不是走运营商而是真正通过网络传输声音——哪怕只是两台电脑之间“喂喂”两声。这听起来像是黑科技但其实只要掌握pjsip这件事比你想象中简单得多。在实时通信领域VoIPVoice over IP早已不再是大厂专属的技术。无论是智能门禁对讲、工业调度系统还是定制化语音客户端底层都可能跑着一套基于 SIP 协议的通话逻辑。而在这其中pjsip就像是一位全能选手轻量、高效、跨平台还完全开源。本文不讲空话直接带你从环境准备到代码运行一步步搭建出你的第一个可接打电话的 pjsip 应用。无论你是嵌入式开发者、音视频新手还是想搞点 IoT 通信的小白这篇都能让你上手就用。为什么是 pjsip它到底强在哪市面上做 VoIP 的库不少比如 Linphone、Asterisk 客户端、甚至 WebRTC。那为啥选 pjsip因为它够“底层”又够“高阶”。它不是一个完整 App而是一个 C 语言写的多媒体通信库支持完整的 SIP 协议栈 SDP 媒体协商 RTP 流处理内建音频设备抽象层、NAT 穿透STUN/TURN/ICE、回声消除AEC等关键模块可以跑在 Linux、Windows、macOS、Android、iOS甚至是 ARM 开发板上。更重要的是你可以控制每一个细节什么时候发起呼叫、用什么编解码器、是否启用加密、如何处理来电……这种自由度是很多封装好的 SDK 给不了的。 简单说如果你不想被“黑盒 SDK”绑架pjsip 是一条通往自主可控通信系统的捷径。先搞明白一件事SIP 到底是怎么打上电话的在写代码之前我们得先理解最核心的机制 ——SIP 是怎么建立一次通话的别怕它不像 HTTP 那么复杂反而有点像打电话时的对话流程你喂我想跟你通话。INVITE 对方正在响铃…180 Ringing 对方好我接了200 OK 你收到开始说话吧。ACK → 双方进入通话状态整个过程就是三个信令来回INVITE→ 发起呼叫200 OK← 对方接听ACK→ 确认连接媒体流也就是你的声音并不走 SIP而是通过另一个叫RTP的协议独立传输。SIP 只负责“谈妥”双方地址和编码方式通过 SDP 协商然后让 RTP 自己去传数据。所以你可以把 SIP 想象成“订餐电话”RTP 就是“送外卖的小哥”。上手第一步用 pjsua 快速搭起通话框架pjsip 功能虽多但我们不需要从零造轮子。它的高层 API ——pjsua已经把账户管理、呼叫控制、音频处理全都打包好了。我们只需要四步就能跑通一个基本通话程序初始化 pjsua 环境设置监听端口通常是 5060添加本地 SIP 账户注册回调函数处理来电下面这段代码就是你能运行的最小可用版本。复制过去链接 pjsip 库就能变成一个可以拨打和接听的终端。#include pjsua-lib/pjsua.h #include stdio.h #include string.h // 来电自动接听 static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata) { pjsua_call_setting call_opt; pj_bzero(call_opt, sizeof(call_opt)); pjsua_call_answer(call_id, 200, call_opt); } int main() { pjsua_config cfg; pjsua_logging_config log_cfg; // 1. 创建并初始化 pjsua pjsua_create(); pjsua_config_default(cfg); pjsua_logging_config_default(log_cfg); log_cfg.level 4; // 日志级别调高方便调试 // 2. 注册事件回调 cfg.cb.on_incoming_call on_incoming_call; if (pjsua_init(cfg, log_cfg, NULL) ! PJ_SUCCESS) { puts(初始化失败); return -1; } // 3. 启动 TCP 监听端口 5060 pjsua_transport_config tcfg; pjsua_transport_config_default(tcfg); tcfg.port 5060; if (pjsua_transport_create(PJSIP_TRANSPORT_TCP, tcfg, NULL) ! PJ_SUCCESS) { puts(创建传输层失败); return -1; } // 4. 添加本地账户无需注册服务器 pjsua_acc_config acc_cfg; pjsua_acc_config_default(acc_cfg); acc_cfg.id pj_str(sip:1234192.168.1.100); // 本机身份 acc_cfg.reg_uri pj_str(sip:192.168.1.100); // 注册地址这里仅示意 acc_cfg.cred_count 0; // 不需要认证 if (pjsua_acc_add(acc_cfg, PJ_TRUE, NULL) ! PJ_SUCCESS) { puts(添加账户失败); return -1; } // 5. 启动 pjsua 核心 if (pjsua_start() ! PJ_SUCCESS) { puts(启动失败); return -1; } // 6. 主循环支持手动拨号 char input[10]; printf(输入 q 退出c 拨打 sip:5678192.168.1.101:\n); while (scanf(%s, input)) { if (input[0] q) break; else if (input[0] c) { pjsua_call_setting call_opt; pjsua_call_setting_default(call_opt); pjsua_call_make_call(0, pj_str(sip:5678192.168.1.101), call_opt, NULL, NULL, NULL); printf(已拨打...\n); } } // 清理资源 pjsua_destroy(); return 0; }✅ 这段代码能做什么在192.168.1.100:5060监听 SIP 请求收到来电自动接听输入c可向sip:5678192.168.1.101发起呼叫使用标准输入交互适合测试验证。 注意这里的 IP 地址要换成你真实的局域网 IP。两台机器各跑一个实例改一下账号 ID 和目标地址就可以互相打了让声音真正传起来音频配置不能少现在信令通了但你还听不到声音 —— 因为音频设备还没打开。默认情况下pjsua 会尝试使用系统的默认录音和播放设备。但在某些平台尤其是 Linux 的 ALSA可能需要手动指定。如何查看可用音频设备可以用这个小技巧int dev_count pjsua_get_snd_dev_count(); printf(发现 %d 个音频设备\n, dev_count); for (int i 0; i dev_count; i) { pjmedia_aud_dev_info info; pjsua_enum_aud_devices(i, info); printf([%d] %s\n, i, info.name); }然后选择合适的输入输出设备pjsua_set_snd_dev(0, 0); // 输入设备索引, 输出设备索引启用回声消除AEC告别“嗡嗡”声如果没有 AEC扬声器的声音会被麦克风重新拾取形成反馈环路导致刺耳的啸叫或低频嗡鸣。pjsip 内建了回声消除模块只需一行配置即可开启pjsua_media_config med_cfg; pjsua_media_config_default(med_cfg); med_cfg.ec_tail_len 200; // 回声延迟最长 200ms pjsua_media_modify_config(med_cfg);这个参数很关键- 太小 → 消不干净- 太大 → 占 CPU增加延迟。建议从100~200ms开始试根据实际环境调整。局域网能通外网打不了别忘了 NAT 穿透你在家里开发得好好的一上线就“单通”、“无法注册”大概率是 NAT 搞的鬼。大多数设备都在路由器后面公网 IP 并不直接暴露。这时候就需要STUN/TURN/ICE来帮忙打通路径。STUN告诉我我在公网上的真实地址STUN 服务器的作用很简单你问它“我从外面看长什么样” 它告诉你“你是x.x.x.x:54321”。pjsip 中启用 STUN 极其简单pjsua_transport_config tcfg; pjsua_transport_config_default(tcfg); tcfg.port 5060; tcfg.stun_host pj_str(stun.l.google.com:19302); // Google 免费 STUN pjsua_transport_create(PJSIP_TRANSPORT_UDP, tcfg, NULL);一旦启用所有 SIP 和 RTP 的地址都会替换成公网映射地址大幅提升穿透成功率。ICE多个备选路线自动选最优ICE 更进一步它会收集多种候选地址本地 IP、NAT 映射、TURN 中继然后挨个测试连通性选出最佳路径。启用 ICE 也很方便pjsua_var.media_cfg.ice_cfg.enable_ice PJ_TRUE;不过要注意如果要用 TURN 中继即媒体走服务器转发你需要自己部署或租用 TURN 服务如 Coturn。实战中常见的坑我都替你踩过了刚上手 pjsip总会遇到一些奇怪问题。下面是几个高频“翻车现场”及应对方案问题表现解决方法只能听见对方自己说不了话单通检查防火墙是否放行 RTP 端口通常 4000–5000启用 STUN双方都说不了话媒体不通检查 SDP 协商结果是否一致确认编解码器匹配来电无提示INVITE 没收到查看 SIP 是否绑定正确端口抓包看是否有 UDP 到达声音断续、卡顿抖动严重调大 Jitter Buffermed_cfg.jb_max 200单位 ms日志全是乱码或看不懂信息太多设置log_cfg.console_level 3只看关键消息 推荐调试手段用 Wireshark 抓 SIP 和 RTP 包看信令交换是否完整RTP 时间戳是否连续。更进一步这些设计经验值得收藏当你能把两个终端打通之后就可以考虑更贴近生产环境的设计了。✅ 日志分级管理开发阶段开到 level 4 或 5能看到完整的 SIP 消息头上线后降到 23避免日志爆炸。✅ 编解码器优先级调整默认 PCMUG.711u优先但如果带宽紧张可以把 OPUS 或 G.729 提前// 示例提升 OPUS 优先级 pjsua_codec_set_priority(pj_str(opus/48000/2), 255);✅ 异常恢复机制监听on_call_media_state和on_call_state_changed在网络中断后尝试重连或重拨。✅ 移动端优化启用 VAD静音检测降低功耗处理来电时申请音频焦点后台运行时切换到低带宽编码模式。✅ 安全加固重要信令走 TLSPJSIP_TRANSPORT_TLS媒体走 SRTP设置srtp_use PJMEDIA_SRTP_MANDATORY避免明文密码存储使用摘要认证结语你的第一个 VoIP 应用已经诞生看到这里你应该已经有了一个能拨打电话的 pjsip 程序也许还不够完美但它已经具备了 VoIP 的所有核心能力SIP 信令控制SDP 媒体协商RTP 音频传输NAT 穿透支持回声消除与抖动缓冲下一步你可以尝试加入视频通话pjsip 也支持 H.264实现即时消息MESSAGE 方法接入 WebRTC 客户端通过 B2BUA 模式打造自己的软交换调度系统pjsip 的魅力就在于它既是一个工具也是一个教科书式的通信架构范例。每读一段代码你都在深入理解实时通信的本质。如果你也想摆脱“调 SDK”的被动局面不妨从今天开始亲手敲下属于你自己的第一行 VoIP 代码。欢迎在评论区分享你的实现体验你是在树莓派上跑的吗遇到了哪些奇葩问题我们一起解决

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询