Tio Boot DocsTio Boot Docs
Home
  • java-db
  • api-table
  • mysql
  • postgresql
  • oceanbase
  • Enjoy
  • Tio Boot Admin
  • ai_agent
  • translator
  • knowlege_base
  • ai-search
  • 案例
Abount
  • Github
  • Gitee
Home
  • java-db
  • api-table
  • mysql
  • postgresql
  • oceanbase
  • Enjoy
  • Tio Boot Admin
  • ai_agent
  • translator
  • knowlege_base
  • ai-search
  • 案例
Abount
  • Github
  • Gitee
  • 01_tio-boot 简介

    • tio-boot:新一代高性能 Java Web 开发框架
    • tio-boot 入门示例
    • Tio-Boot 配置 : 现代化的配置方案
    • tio-boot 整合 Logback
    • tio-boot 整合 hotswap-classloader 实现热加载
    • 自行编译 tio-boot
    • 最新版本
    • 开发规范
  • 02_部署

    • 使用 Maven Profile 实现分环境打包 tio-boot 项目
    • Maven 项目配置详解:依赖与 Profiles 配置
    • tio-boot 打包成 FatJar
    • 使用 GraalVM 构建 tio-boot Native 程序
    • 使用 Docker 部署 tio-boot
    • 部署到 Fly.io
    • 部署到 AWS Lambda
    • 到阿里云云函数
    • 使用 Deploy 工具部署
    • 使用Systemctl启动项目
    • 使用 Jenkins 部署 Tio-Boot 项目
    • 使用 Nginx 反向代理 Tio-Boot
    • 使用 Supervisor 管理 Java 应用
    • 已过时
    • 胖包与瘦包的打包与部署
  • 03_配置

    • 配置参数
    • 服务器监听器
    • 内置缓存系统 AbsCache
    • 使用 Redis 作为内部 Cache
    • 静态文件处理器
    • 基于域名的静态资源隔离
    • DecodeExceptionHandler
    • 开启虚拟线程(Virtual Thread)
    • 框架级错误通知
  • 04_原理

    • 生命周期
    • 请求处理流程
    • 重要的类
  • 05_json

    • Json
    • 接受 JSON 和响应 JSON
    • 响应实体类
  • 06_web

    • 概述
    • 接收请求参数
    • 接收日期参数
    • 接收数组参数
    • 返回字符串
    • 返回文本数据
    • 返回网页
    • 请求和响应字节
    • 文件上传
    • 文件下载
    • 返回视频文件并支持断点续传
    • http Session
    • Cookie
    • HttpRequest
    • HttpResponse
    • Resps
    • RespBodyVo
    • Controller拦截器
    • 请求拦截器
    • LoggingInterceptor
    • 全局异常处理器
    • 异步处理
    • 动态 返回 CSS 实现
    • 返回图片
    • 跨域
    • 添加 Controller
    • Transfer-Encoding: chunked 实时音频播放
    • Server-Sent Events (SSE)
    • handler入门
    • 返回 multipart
    • 待定
    • 自定义 Handler 转发请求
    • 使用 HttpForwardHandler 转发所有请求
    • 常用工具类
    • HTTP Basic 认证
    • Http响应加密
    • 使用零拷贝发送大文件
    • 分片上传
    • 接口访问统计
    • 接口请求和响应数据记录
    • WebJars
    • JProtobuf
    • 测速
    • Gzip Bomb:使用压缩炸弹防御恶意爬虫
  • 07_validate

    • 数据紧校验规范
    • 参数校验
  • 08_websocket

    • 使用 tio-boot 搭建 WebSocket 服务
    • WebSocket 聊天室项目示例
  • 09_java-db

    • java‑db
    • 操作数据库入门示例
    • SQL 模板 (SqlTemplates)
    • 数据源配置与使用
    • ActiveRecord
    • Db 工具类
    • 批量操作
    • Model
    • Model生成器
    • 注解
    • 异常处理
    • 数据库事务处理
    • Cache 缓存
    • Dialect 多数据库支持
    • 表关联操作
    • 复合主键
    • Oracle 支持
    • Enjoy SQL 模板
    • 整合 Enjoy 模板最佳实践
    • 多数据源支持
    • 独立使用 ActiveRecord
    • 调用存储过程
    • java-db 整合 Guava 的 Striped 锁优化
    • 生成 SQL
    • 通过实体类操作数据库
    • java-db 读写分离
    • Spring Boot 整合 Java-DB
    • like 查询
    • 常用操作示例
    • Druid 监控集成指南
    • SQL 统计
  • 10_api-table

    • ApiTable 概述
    • 使用 ApiTable 连接 SQLite
    • 使用 ApiTable 连接 Mysql
    • 使用 ApiTable 连接 Postgres
    • 使用 ApiTable 连接 TDEngine
    • 使用 api-table 连接 oracle
    • 使用 api-table 连接 mysql and tdengine 多数据源
    • EasyExcel 导出
    • EasyExcel 导入
    • 预留
    • 预留
    • ApiTable 实现增删改查
    • 数组类型
    • 单独使用 ApiTable
    • TQL(Table SQL)前端输入规范
  • 11_aop

    • JFinal-aop
    • Aop 工具类
    • 配置
    • 配置
    • 独立使用 JFinal Aop
    • @AImport
    • 自定义注解拦截器
    • 原理解析
  • 12_cache

    • Caffine
    • Jedis-redis
    • hutool RedisDS
    • Redisson
    • Caffeine and redis
    • CacheUtils 工具类
    • 使用 CacheUtils 整合 caffeine 和 redis 实现的两级缓存
    • 使用 java-db 整合 ehcache
    • 使用 java-db 整合 redis
    • Java DB Redis 相关 Api
    • redis 使用示例
  • 13_认证和权限

    • FixedTokenInterceptor
    • TokenManager
    • 数据表
    • 匿名登录
    • 注册和登录
    • 个人中心
    • 重置密码
    • Google 登录
    • 短信登录
    • 移动端微信登录
    • 移动端重置密码
    • 微信登录
    • 移动端微信登录
    • 权限校验注解
    • Sa-Token
    • sa-token 登录注册
    • StpUtil.isLogin() 源码解析
  • 14_i18n

    • i18n
  • 15_enjoy

    • tio-boot 整合 Enjoy 模版引擎文档
    • Tio-Boot 整合 Java-DB 与 Enjoy 模板引擎示例
    • 引擎配置
    • 表达式
    • 指令
    • 注释
    • 原样输出
    • Shared Method 扩展
    • Shared Object 扩展
    • Extension Method 扩展
    • Spring boot 整合
    • 独立使用 Enjoy
    • tio-boot enjoy 自定义指令 localeDate
    • PromptEngine
    • Enjoy 入门示例-擎渲染大模型请求体
    • Tio Boot + Enjoy:分页与 SEO 实战指南
    • Tio Boot + Enjoy:分页与 SEO 实战指南
    • Tio Boot + Enjoy:分页与 SEO 实战指南
  • 16_定时任务

    • Quartz 定时任务集成指南
    • 分布式定时任务 xxl-jb
    • cron4j 使用指南
  • 17_tests

    • TioBootTest 类
  • 18_tio

    • TioBootServer
    • 独立端口启动 TCP 服务器
    • 内置 TCP 处理器
    • 独立启动 UDPServer
    • 使用内置 UDPServer
    • t-io 消息处理流程
    • tio-运行原理详解
    • TioConfig
    • ChannelContext
    • Tio 工具类
    • 业务数据绑定
    • 业务数据解绑
    • 发送数据
    • 关闭连接
    • Packet
    • 监控: 心跳
    • 监控: 客户端的流量数据
    • 监控: 单条 TCP 连接的流量数据
    • 监控: 端口的流量数据
    • 单条通道统计: ChannelStat
    • 所有通道统计: GroupStat
    • 资源共享
    • 成员排序
    • SSL
    • DecodeRunnable
    • 使用 AsynchronousSocketChannel 响应数据
    • 拉黑 IP
    • 深入解析 Tio 源码:构建高性能 Java 网络应用
  • 19_aio

    • ByteBuffer
    • AIO HTTP 服务器
    • 自定义和线程池和池化 ByteBuffer
    • AioHttpServer 应用示例 IP 属地查询
    • 手写 AIO Http 服务器
  • 20_netty

    • Netty TCP Server
    • Netty Web Socket Server
    • 使用 protoc 生成 Java 包文件
    • Netty WebSocket Server 二进制数据传输
    • Netty 组件详解
  • 21_netty-boot

    • Netty-Boot
    • 原理解析
    • 整合 Hot Reload
    • 整合 数据库
    • 整合 Redis
    • 整合 Elasticsearch
    • 整合 Dubbo
    • Listener
    • 文件上传
    • 拦截器
    • Spring Boot 整合 Netty-Boot
    • SSL 配置指南
    • ChannelInitializer
    • Reserve
  • 22_MQ

    • Mica-mqtt
    • EMQX
    • Disruptor
  • 23_tio-utils

    • tio-utils
    • HttpUtils
    • Notification
    • Email
    • JSON
    • File
    • Base64
    • 上传和下载
    • Http
    • Telegram
    • RsaUtils
    • EnvUtils 配置工具
    • 系统监控
    • 线程
    • 虚拟线程
    • 毫秒并发 ID (MCID) 生成方案
  • 24_tio-http-server

    • 使用 Tio-Http-Server 搭建简单的 HTTP 服务
    • tio-boot 添加 HttpRequestHandler
    • 在 Android 上使用 tio-boot 运行 HTTP 服务
    • tio-http-server-native
    • handler 常用操作
  • 25_tio-websocket

    • WebSocket 服务器
    • WebSocket Client
    • TCP数据转发
  • 26_tio-im

    • 通讯协议文档
    • ChatPacket.proto 文档
    • java protobuf
    • 数据表设计
    • 创建工程
    • 登录
    • 历史消息
    • 发消息
  • 27_mybatis

    • Tio-Boot 整合 MyBatis
    • 使用配置类方式整合 MyBatis
    • 整合数据源
    • 使用 mybatis-plus 整合 tdengine
    • 整合 mybatis-plus
  • 28_mongodb

    • tio-boot 使用 mongo-java-driver 操作 mongodb
  • 29_elastic-search

    • Elasticsearch
    • JavaDB 整合 ElasticSearch
    • Elastic 工具类使用指南
    • Elastic-search 注意事项
    • ES 课程示例文档
  • 30_magic-script

    • tio-boot 与 magic-script 集成指南
  • 31_groovy

    • tio-boot 整合 Groovy
  • 32_firebase

    • 整合 google firebase
    • Firebase Storage
    • Firebase Authentication
    • 使用 Firebase Admin SDK 进行匿名用户管理与自定义状态标记
    • 导出用户
    • 注册回调
    • 登录注册
  • 33_文件存储

    • 文件上传数据表
    • 本地存储
    • 存储文件到 亚马逊 S3
    • 存储文件到 腾讯 COS
    • 存储文件到 阿里云 OSS
  • 34_spider

    • jsoup
    • 爬取 z-lib.io 数据
    • 整合 WebMagic
    • WebMagic 示例:爬取学校课程数据
    • Playwright
    • Flexmark (Markdown 处理器)
    • tio-boot 整合 Playwright
    • 缓存网页数据
  • 36_integration_thirty_party

    • 整合 okhttp
    • 整合 GrpahQL
    • 集成 Mailjet
    • 整合 ip2region
    • 整合 GeoLite 离线库
    • 整合 Lark 机器人指南
    • 集成 Lark Mail 实现邮件发送
    • Thymeleaf
    • Swagger
    • Clerk 验证
  • 37_dubbo

    • 概述
    • dubbo 2.6.0
    • dubbo 2.6.0 调用过程
    • dubbo 3.2.0
  • 38_spring

    • Spring Boot Web 整合 Tio Boot
    • spring-boot-starter-webflux 整合 tio-boot
    • tio-boot 整合 spring-boot-starter
    • Tio Boot 整合 Spring Boot Starter db
    • Tio Boot 整合 Spring Boot Starter Data Redis 指南
  • 39_spring-cloud

    • tio-boot spring-cloud
  • 40_quarkus

    • Quarkus(无 HTTP)整合 tio-boot(有 HTTP)
    • tio-boot + Quarkus + Hibernate ORM Panache
  • 41_postgresql

    • PostgreSQL 安装
    • PostgreSQL 主键自增
    • PostgreSQL 日期类型
    • Postgresql 金融类型
    • PostgreSQL 数组类型
    • 索引
    • PostgreSQL 查询优化
    • 获取字段类型
    • PostgreSQL 全文检索
    • PostgreSQL 向量
    • PostgreSQL 优化向量查询
    • PostgreSQL 其他
  • 42_mysql

    • 使用 Docker 运行 MySQL
    • 常见问题
  • 43_oceanbase

    • 快速体验 OceanBase 社区版
    • 快速上手 OceanBase 数据库单机部署与管理
    • 诊断集群性能
    • 优化 SQL 性能指南
    • 待定
  • 49_jooq

    • 使用配置类方式整合 jOOQ
    • tio-boot + jOOQ 事务管理
    • 批量操作与性能优化
    • 代码生成(可选)与类型安全升级
    • JSONB、Upsert、窗口函数实战
    • 整合agroal
  • 50_media

    • JAVE 提取视频中的声音
    • Jave 提取视频中的图片
    • 待定
  • 51_asr

    • Whisper-JNI
  • 54_native-media

    • java-native-media
    • JNI 入门示例
    • mp3 拆分
    • mp4 转 mp3
    • 使用 libmp3lame 实现高质量 MP3 编码
    • Linux 编译
    • macOS 编译
    • 从 JAR 包中加载本地库文件
    • 支持的音频和视频格式
    • 任意格式转为 mp3
    • 通用格式转换
    • 通用格式拆分
    • 视频合并
    • VideoToHLS
    • split_video_to_hls 支持其他语言
    • 持久化 HLS 会话
    • 获取视频长度
    • 保存视频的最后一帧
    • 添加水印
    • linux版本
  • 55_cv

    • 使用 Java 运行 YOLOv8 ONNX 模型进行目标检测
    • tio-boot整合yolo
    • ONNX Runtime 推理说明
  • 58_telegram4j

    • 数据库设计
    • 基于 HTTP 协议开发 Telegram 翻译机器人
    • 基于 MTProto 协议开发 Telegram 翻译机器人
    • 过滤旧消息
    • 保存机器人消息
    • 定时推送
    • 增加命令菜单
    • 使用 telegram-Client
    • 使用自定义 StoreLayout
    • 延迟测试
    • Reactor 错误处理
    • Telegram4J 常见错误处理指南
  • 59_telegram-bots

    • TelegramBots 入门指南
    • 使用工具库 telegram-bot-base 开发翻译机器人
  • 60_LLM

    • 简介
    • 流式生成
    • 图片多模态输入
    • 协议自动转换 Google Gemini示例
    • 请求记录
    • 限流和错误处理
    • 整合Gemini realtime模型
    • Voice Agent 前端接入接口文档
    • 整合千问realtime模型
    • 增强检索(RAG)
    • 搜索+AI
    • AI 问答
    • 连接代码执行器
  • 61_ai_agent

    • 数据库设计
    • 示例问题管理
    • 会话管理
    • 历史记录
    • Perplexity API
    • 意图识别
    • 智能问答
    • 文件上传与解析文档
    • 翻译
    • 名人搜索功能实现
    • Ai studio gemini youbue 问答使用说明
    • 自建 YouTube 字幕问答系统
    • 自建 获取 youtube 字幕服务
    • 使用 OpenAI ASR 实现语音识别接口(Java 后端示例)
    • 定向搜索
    • 16
    • 17
    • 18
    • 在 tio-boot 应用中整合 ai-agent
    • 16
  • 63_knowlege_base

    • 数据库设计
    • 用户登录实现
    • 模型管理
    • 知识库管理
    • 文档拆分
    • 片段向量
    • 命中测试
    • 文档管理
    • 片段管理
    • 问题管理
    • 应用管理
    • 向量检索
    • 推理问答
    • 问答模块
    • 统计分析
    • 用户管理
    • api 管理
    • 存储文件到 S3
    • 文档解析优化
    • 片段汇总
    • 段落分块与检索
    • 多文档解析
    • 对话日志
    • 检索性能优化
    • Milvus
    • 文档解析方案和费用对比
    • 离线运行向量模型
  • 64_ai-search

    • ai-search 项目简介
    • ai-search 数据库文档
    • ai-search SearxNG 搜索引擎
    • ai-search Jina Reader API
    • ai-search Jina Search API
    • ai-search 搜索、重排与读取内容
    • ai-search PDF 文件处理
    • ai-search 推理问答
    • Google Custom Search JSON API
    • ai-search 意图识别
    • ai-search 问题重写
    • ai-search 系统 API 接口 WebSocket 版本
    • ai-search 搜索代码实现 WebSocket 版本
    • ai-search 生成建议问
    • ai-search 生成问题标题
    • ai-search 历史记录
    • Discover API
    • 翻译
    • Tavily Search API 文档
    • 对接 Tavily Search
    • 火山引擎 DeepSeek
    • 对接 火山引擎 DeepSeek
    • ai-search 搜索代码实现 SSE 版本
    • jar 包部署
    • Docker 部署
    • 爬取一个静态网站的所有数据
    • 网页数据预处理
    • 网页数据检索与问答流程整合
  • 65_ai-coding

    • Cline 提示词
    • Cline 提示词-中文版本
  • 66_java-uni-ai-server

    • 语音合成系统
    • Fish.audio TTS 接口说明文档与 Java 客户端封装
    • 整合 fishaudio 到 java-uni-ai-server 项目
    • 待定
  • 67_java-llm-proxy

    • 使用tio-boot搭建多模型LLM代理服务
  • 68_java-kit-server

    • Java 执行 python 代码
    • 通过大模型执行 Python 代码
    • 执行 Python (Manim) 代码
    • 待定
    • 待定
    • 待定
    • 视频下载增加水印说明文档
  • 69_ai-brower

    • AI Browser:基于用户指令的浏览器自动化系统
    • 提示词
    • dom构建- buildDomTree.js
    • dom构建- 将网页可点击元素提取与可视化
    • 提取网内容
    • 启动浏览器
    • 操作浏览器指令
  • 70_tio-boot-admin

    • 入门指南
    • 初始化数据
    • token 存储
    • 与前端集成
    • 文件上传
    • 网络请求
    • 多图片管理
    • 单图片管理(只读模式)
    • 布尔值管理
    • 字段联动
    • Word 管理
    • PDF 管理
    • 文章管理
    • 富文本编辑器
  • 73_tio-mail-wing

    • tio-mail-wing简介
    • 任务1:实现POP3系统
    • 使用 getmail 验证 tio-mail-wing POP3 服务
    • 任务2:实现 SMTP 服务
    • 数据库初始化文档
    • 用户管理
    • 邮件管理
    • 任务3:实现 SMTP 服务 数据库版本
    • 任务4:实现 POP3 服务(数据库版本)
    • IMAP 协议
    • 拉取多封邮件
    • 任务5:实现 IMAP 服务(数据库版本)
    • IMAP实现讲解
    • IMAP 手动测试脚本
    • IMAP 认证机制
    • 主动推送
  • 74_tio-mcp-server

    • 实现 MCP Server 开发指南
  • 75_tio-sip

    • SIP Server 第一版原理说明
    • SIP Server 第一版实战
    • 一、Windows 平台测试
    • SIP Server 第二版实战
    • SIP Server 第三版实战
    • 性能优化
    • 基于 MediaProcessor 对接 Realtime 模型说明
    • 对接大语言模型
    • 支持 G722 宽带语音
    • G722编码和解码
    • 会话级采样率转换
    • /zh/75_tio-sip/12.html
    • 增加 9196 回声测试分机
    • 语音系统链路说明
    • 一、Gemini Realtime 的打断机制
  • 76_manim

    • Teach me anything - 基于大语言的知识点讲解视频生成系统
    • Manim 开发环境搭建
    • 生成场景提示词
    • 生成代码
    • 完整脚本示例
    • TTS服务端
    • 废弃
    • 废弃
    • 废弃
    • 使用 SSE 流式传输生成进度的实现文档
    • 整合全流程完整文档
    • HLS 动态推流技术文档
    • manim 分场景生成代码
    • 分场景运行代码及流式播放支持
    • 分场景业务端完整实现流程
    • Maiim布局管理器
    • 仅仅生成场景代码
    • 使用 modal 运行 manim 代码
    • Python 使用 Modal GPU 加速渲染
    • Modal 平台 GPU 环境下运行 Manim
    • Modal Manim OpenGL 安装与使用
    • 优化 GPU 加速
    • 生成视频封面流程
    • Java 调用 manim 命令 执行代码 生成封面
    • Manim 图像生成服务客户端文档
    • manim render help
    • 显示 中文公式
    • ManimGL(manimgl)
    • Manim 实战入门:用代码创造数学动画
    • 欢迎
  • 80_性能测试

    • 压力测试 - tio-http-serer
    • 压力测试 - tio-boot
    • 压力测试 - tio-boot-native
    • 压力测试 - netty-boot
    • 性能测试对比
    • TechEmpower FrameworkBenchmarks
    • 压力测试 - tio-boot 12 C 32G
    • HTTP/1.1 Pipelining 性能测试报告
    • tio-boot vs Quarkus 性能对比测试报告
  • 81_tio-boot

    • 简介
    • Swagger 整合到 Tio-Boot 中的指南
    • 待定
    • 待定
    • 高性能网络编程中的 ByteBuffer 分配与回收策略
    • TioBootServerHandler 源码解析
  • 99_案例

    • 封装 IP 查询服务
    • tio-boot 案例 - 全局异常捕获与企业微信群通知
    • tio-boot 案例 - 文件上传和下载
    • tio-boot 案例 - 整合 ant design pro 增删改查
    • tio-boot 案例 - 流失响应
    • tio-boot 案例 - 增强检索
    • tio-boot 案例 - 整合 function call
    • tio-boot 案例 - 定时任务 监控 PostgreSQL、Redis 和 Elasticsearch
    • Tio-Boot 案例:使用 SQLite 整合到登录注册系统
    • tio-boot 案例 - 执行 shell 命令

增加 9196 回声测试分机

一、背景

当前项目基于 tio-core 自研了一套轻量级 SIP Server,用于承接语音呼叫接入,并为后续语音机器人、ASR、TTS、Realtime LLM 对话等能力提供底层通话链路。

在前面的几个阶段中,系统已经逐步完成了以下能力:

  • SIP TCP / UDP 监听
  • INVITE / ACK / BYE 基本流程处理
  • SDP Offer / Answer 协商
  • RTP 端口动态分配
  • G.711 / G.722 编解码
  • MediaProcessor 媒体处理抽象
  • RealtimeMediaProcessor 与实时模型桥接
  • 会话级 codec / resampler 资源管理

到目前为止,系统已经具备两类能力:

1. 基础语音链路能力

即:

  • SIP 建链
  • SDP 协商
  • RTP 音频收发
  • 编解码
  • 音频帧级处理

2. 智能语音能力

即:

  • 将 RTP 音频转换为模型输入格式
  • 发送给 Realtime 模型
  • 接收模型输出
  • 转换回当前会话格式并回发

也就是说,系统已经不再只是一个“能接电话”的 SIP Server,而是一个具备实时语音处理和 AI 对话能力的媒体平台。


二、现阶段问题

虽然系统已经具备了 Realtime 模型接入能力,但在联调、排障和基础验证阶段,还缺少一个非常重要的能力:

不经过模型、直接验证电话链路本身是否正常的测试入口。

在实际开发和运维过程中,经常会遇到以下场景:

1. 需要快速验证 RTP 音频链路是否正常

例如需要确认:

  • SIP 建链是否正常
  • SDP 协商是否正确
  • RTP 端口是否分配成功
  • 本端是否收到了对端音频
  • codec 编解码是否工作正常
  • RTP 回发链路是否正确

这类问题如果直接走 Realtime 模型链路,会引入很多额外变量:

  • 模型连接状态
  • 模型响应延迟
  • Realtime Session 是否建立成功
  • 模型输入输出格式是否匹配
  • 模型侧是否有静音或生成延迟

这样一来,即使用户听不到声音,也很难第一时间判断问题究竟出在哪一层。

2. 需要一个最简单、最确定的功能分机

在电话系统中,一个非常常见的调试能力就是:

  • 拨打某个测试分机
  • 系统直接把收到的音频原样返回
  • 用户立刻就能听到自己的回声

这种“回声测试”功能的价值非常高,因为它可以用最小成本证明:

  • SIP 信令是通的
  • RTP 链路是通的
  • 编解码是通的
  • 媒体处理链路是通的

也就是说,它可以把问题范围迅速缩小到“模型层之外”或者“模型层之内”。


三、目标

本次改造的目标,是在现有 SIP Server 中增加一个固定测试分机:

9196

当用户拨打该号码时,系统不进入 RealtimeMediaProcessor,而是直接进入最简单的音频回声处理流程。

整体目标包括三个方面。

1. 拨打 9196 时进入回声测试

当 SIP INVITE 的被叫号码为 9196 时:

  • 系统仍然正常完成 SIP / SDP 协商
  • 正常分配 RTP 端口
  • 正常建立通话
  • 但媒体处理器不再使用 RealtimeMediaProcessor
  • 而是使用 EchoMediaProcessor

这样,用户在通话中听到的就是自己的回声。

2. 其他号码继续走现有 Realtime 流程

本次改造不是替换原有能力,而是增加一个专用测试入口。

也就是说:

  • 拨打 9196 → 回声测试
  • 拨打其他号码 → 继续走 RealtimeMediaProcessor

这样可以保证:

  • 原有实时语音机器人链路不受影响
  • 新增功能只作为独立测试入口存在

3. 保持现有媒体架构不变

本次改造不改变以下核心设计:

  • RTP 层继续负责 codec decode / encode
  • MediaProcessor 继续作为媒体处理抽象
  • EchoMediaProcessor 继续负责最简单的“输入即输出”
  • RealtimeMediaProcessor 继续负责模型桥接

也就是说,本次功能本质上只是:

在 SIP 建链阶段,根据被叫号码选择不同的 MediaProcessor。


四、设计原则

为了避免功能写散、职责混乱,本次设计遵循以下原则。

1. 按被叫号码选择媒体处理器

“是否进入回声测试”是一个呼叫入口级决策,它应该在 SIP 建链阶段就确定,而不应该等到 RTP 处理阶段再临时判断。

原因很简单:

  • SIP INVITE 阶段已经拿到了完整的被叫信息
  • RTP 层只负责收发媒体,不应该承担业务路由职责
  • RealtimeMediaProcessor 也不应该混入“特殊号码分支逻辑”

因此,这个决策最合理的位置就是:

  • SipUdpServerHandler.handleInvite()

2. 回声测试不应依赖 Realtime 组件

拨打 9196 的目标是验证基础语音链路,而不是验证模型链路。 因此,进入回声测试后应尽量避免:

  • 创建 SipRealtimeSession
  • 连接 Realtime 模型
  • 走模型输入输出流程

这样才能让 9196 成为真正“最小、最纯净”的测试路径。

3. EchoMediaProcessor 继续保持最简单实现

回声测试本身不需要复杂逻辑,它只需要:

  • 收到 AudioFrame
  • 原样返回 AudioFrame

也就是:

public class EchoMediaProcessor implements MediaProcessor {

  @Override
  public AudioFrame process(AudioFrame input, CallSession session) {
    return input;
  }
}

这个实现非常简单,但在系统联调阶段价值极高。


五、改造方案

本次改造采用的方案是:

在 SIP 建链阶段,根据被叫号码动态选择 MediaProcessor。

整体上分为三个步骤。

1. 增加固定测试分机号

在 SipUdpServerHandler 中定义一个固定号码:

private static final String ECHO_TEST_EXTENSION = "9196";

这个号码用于标识“回声测试入口”。

2. 在 SipUdpServerHandler 中同时持有两个处理器

原本 SipUdpServerHandler 通常只持有一个统一的 mediaProcessor,用于所有呼叫。 本次改造后,改为:

  • 一个默认处理器:通常是 RealtimeMediaProcessor
  • 一个固定的回声处理器:EchoMediaProcessor

例如:

private final MediaProcessor defaultMediaProcessor;
private final MediaProcessor echoMediaProcessor = new EchoMediaProcessor();

这样在收到 INVITE 时,就可以根据被叫号码决定当前会话使用哪一个处理器。

3. 在 handleInvite() 中动态选择处理器

在创建 CallSession 并分配 RTP 服务前,先判断当前呼叫是否拨打到 9196。

如果是,则选择:

echoMediaProcessor

否则选择:

defaultMediaProcessor

随后调用:

rtpServerManager.allocateAndStart(session, selectedMediaProcessor);

这样一来,媒体处理路径就从建链开始被确定下来。


六、关键实现

1. EchoMediaProcessor

回声处理器本身无需改动,仍然保持最简单实现:

package com.litongjava.sip.rtp.media;

import com.litongjava.sip.model.CallSession;

public class EchoMediaProcessor implements MediaProcessor {

  @Override
  public AudioFrame process(AudioFrame input, CallSession session) {
    return input;
  }
}

它的职责非常清晰:

  • 不做模型调用
  • 不做额外音频变换
  • 只返回输入音频本身

2. 在 SipUdpServerHandler 中增加处理器选择逻辑

本次改造的核心在 SipUdpServerHandler。

关键思路包括:

增加默认处理器与回声处理器

private final MediaProcessor defaultMediaProcessor;
private final MediaProcessor echoMediaProcessor = new EchoMediaProcessor();

根据被叫号码选择处理器

private MediaProcessor chooseMediaProcessor(SipRequest req) {
  String calledNumber = resolveCalledNumber(req);
  if (ECHO_TEST_EXTENSION.equals(calledNumber)) {
    return echoMediaProcessor;
  }
  return defaultMediaProcessor;
}

在 handleInvite() 中使用选中的处理器

MediaProcessor selectedMediaProcessor = chooseMediaProcessor(req);
rtpServerManager.allocateAndStart(session, selectedMediaProcessor);

3. 从 SIP 头中提取被叫号码

为了判断是否拨打到 9196,需要从 SIP To 头中提取 user 部分。 例如:

To: <sip:9196@192.168.1.10>
To: sip:9196@192.168.1.10
To: "test" <sip:9196@192.168.1.10>;tag=abc

因此增加一个解析方法:

private String extractUserFromSipHeader(String headerValue) {
  if (headerValue == null) {
    return null;
  }

  String value = headerValue.trim();

  int sipIdx = value.toLowerCase().indexOf("sip:");
  if (sipIdx < 0) {
    return null;
  }

  String sub = value.substring(sipIdx + 4);
  int atIdx = sub.indexOf('@');
  if (atIdx < 0) {
    int semiIdx = sub.indexOf(';');
    int endIdx = semiIdx >= 0 ? semiIdx : sub.length();
    String user = sub.substring(0, endIdx).trim();
    return user.isEmpty() ? null : user;
  }

  String user = sub.substring(0, atIdx).trim();
  return user.isEmpty() ? null : user;
}

然后通过:

private String resolveCalledNumber(SipRequest req) {
  return extractUserFromSipHeader(req.getHeader("To"));
}

完成被叫号码提取。


七、完整行为说明

本次改造完成后,系统在收到 INVITE 时的行为如下。

情况一:拨打 9196

如果被叫号码是:

9196

那么系统流程为:

  1. 正常解析 SIP INVITE
  2. 正常进行 SDP 协商
  3. 正常创建 CallSession
  4. 正常分配 RTP 端口
  5. 在选择媒体处理器时命中 EchoMediaProcessor
  6. RTP 收到音频后,解码成 PCM
  7. 交给 EchoMediaProcessor
  8. EchoMediaProcessor 原样返回输入音频
  9. RTP 再按当前 codec 编码并发回

最终效果就是:

用户在电话中听到自己的回声

这条链路可以很好地验证:

  • SIP 信令
  • SDP 协商
  • RTP 端口分配
  • 编解码
  • 音频帧处理
  • RTP 回发

是否全部正常。

情况二:拨打其他号码

如果被叫号码不是 9196,则系统行为保持不变:

  1. SIP 建链
  2. SDP 协商
  3. 创建 CallSession
  4. 分配 RTP 端口
  5. 选择默认处理器 RealtimeMediaProcessor
  6. 进入现有 Realtime 模型链路

也就是说,本次功能不会影响原有 AI 语音能力。


八、测试结果

经过实际测试,当前功能已经验证通过:

  • 拨打 9196 可正常进入回声测试
  • 用户可以听到自己的回声
  • 其他号码仍然继续走 RealtimeMediaProcessor
  • SIP / SDP / RTP 主链路未受影响

这说明本次方案已经达到预期目标。


九、设计收益

增加 9196 回声测试分机之后,系统获得了几个非常实际的收益。

1. 大幅提升联调效率

当电话链路有问题时,可以先拨打 9196 做最小验证。 如果 9196 正常,而 Realtime 链路不正常,就说明问题更多集中在模型桥接层。

2. 建立了最小闭环测试入口

9196 提供了一个不依赖模型、不依赖外部业务逻辑的最小通话闭环,便于:

  • 新环境部署验证
  • codec 调试
  • RTP 排障
  • 终端兼容性测试

3. 媒体架构更加灵活

这次改造证明了现有 MediaProcessor 抽象是有效的。 系统已经能够根据呼叫入口动态切换不同媒体处理器,这为后续继续扩展提供了很好的基础。

例如未来还可以继续增加:

  • 测试分机
  • 播报分机
  • 录音分机
  • 语音质检分机
  • 指定机器人技能入口

十、后续可扩展方向

虽然当前版本已经能正常工作,但未来还可以继续做一些增强。

1. 将 9196 改为可配置项

当前实现中 9196 是写死在代码中的:

private static final String ECHO_TEST_EXTENSION = "9196";

后续可以改成配置项,例如从环境变量读取,方便不同环境灵活调整。

2. 支持更多测试分机

未来可以按同样方式扩展更多特殊号码,例如:

  • 9196:回声测试
  • 9197:播放固定音频
  • 9198:TTS 测试
  • 9199:Realtime 模型测试

3. TCP Handler 同步支持

如果系统同时支持 SIP TCP 和 SIP UDP,那么同样的号码分流逻辑也应该补到对应的 TCP Handler 中,保证两种传输方式行为一致。


十一、总结

本次改造的核心目标,是为当前 SIP Server 增加一个固定测试分机:

9196

当用户拨打该号码时,系统不再进入 Realtime 模型链路,而是直接进入最简单的 EchoMediaProcessor,把收到的音频原样回发,从而形成回声测试闭环。

这个功能看似简单,但在实际系统中非常有价值。它提供了一个:

  • 最小
  • 稳定
  • 可预期
  • 易排障

的电话链路测试入口,可以显著提升系统联调和故障定位效率。

从架构角度看,这次改造也再次验证了当前设计的合理性:

  • SIP 层负责建链和路由
  • RTP 层负责编解码和媒体收发
  • MediaProcessor 负责音频内容处理
  • 不同业务场景通过选择不同的 MediaProcessor 实现差异化行为

可以把这一篇的核心价值概括成一句话:

9196 回声测试分机并不是一个额外的 demo 功能,而是当前 SIP 媒体平台中非常重要的最小链路验证入口。

Edit this page
Last Updated: 3/11/26, 5:29 AM
Contributors: litongjava
Prev
/zh/75_tio-sip/12.html
Next
语音系统链路说明