尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

go2rtc 中的 SRTP 模块:支撑 HomeKit 摄像头安全媒体传输的 UDP 加密通道

go2rtc 中的 SRTP 模块:支撑 HomeKit 摄像头安全媒体传输的 UDP 加密通道 go2rtc 中的 SRTP 模块支撑 HomeKit 摄像头安全媒体传输的 UDP 加密通道【免费下载链接】go2rtcUltimate camera streaming application项目地址: https://gitcode.com/GitHub_Trending/go/go2rtcgo2rtc 的 SRTPSecure Real-time Transport Protocol模块是一个专门为 Apple HomeKit 摄像头协议服务的底层支持组件负责在 go2rtc 与 HomeKit 设备之间建立基于 UDP 的加密 RTP/RTCP 媒体通道。读完本文你将掌握该模块的配置方式默认监听:8443、它与 HomeKit 客户端/服务器两种模式的协作机制以及 SRTP 会话如何完成密钥协商、RTP/RTCP 单端口复用与加解密处理。模块定位HomeKit 的专属支撑模块在 go2rtc 的源码树中internal/srtp/README.md 开宗明义地指出This is a support module for the HomeKit module.也就是说SRTP 模块并不独立提供对外能力它是 internal/homekit/README.md 所描述的 Apple HomeKit 协议客户端 服务器双模式正常运行的前提。HomeKit 摄像头使用 SRTP 作为其媒体传输的安全层因此 go2rtc 必须内置一个 SRTP 端点endpoint来接收和发送加密封装的音视频 RTP 包。值得注意的是该文档同时给出了一条来自作者的架构提示This module can be removed and its functionality transferred to the homekit module.此模块可被移除其功能可合并进 homekit 模块。这说明当前 SRTP 是作为独立模块抽取出来的未来存在并入 HomeKit 模块的可能性。从 internal/debug/stack.go 可以看到其初始化入口被登记为internal/srtp.Init属于 go2rtc 模块化启动体系中的一员。配置说明一行配置即可启用SRTP 模块的配置极为精简完整配置如下来自 internal/srtp/README.mdsrtp: listen: :8443 # enabled by default其中srtp.listenSRTP 服务器UDP 端点的监听地址与端口格式为 Go 标准的host:port。:8443表示监听所有网络接口的 8443 端口该值为默认值即此项即使不写也会生效。若将listen置空srtp.listen: 则该模块将不启动HomeKit 模块会因此无法工作详见下文 HomeKit 协作部分。源码层面internal/srtp/srtp.go 完整展示了配置的加载与默认值逻辑func Init() { var cfg struct { Mod struct { Listen string yaml:listen } yaml:srtp } // default config cfg.Mod.Listen :8443 // load config from YAML app.LoadConfig(cfg) if cfg.Mod.Listen { return } // create SRTP server (endpoint) for receiving video from HomeKit cameras Server srtp.NewServer(cfg.Mod.Listen) }可以确认的事实有两点代码中先写死默认值:8443再通过app.LoadConfig覆盖因此“默认启用”的说法与实现一致配置通过 YAML 的srtp顶层键读取listen为空字符串时Init()提前返回Server保持nil。启动后go2rtc 全局包变量internal/srtp.Server指向创建的*srtp.Server实例供 HomeKit 模块引用。监听端口可通过配置修改例如内网环境中常用的 8554 等端口若被占用可自由调整为其他未占用 UDP 端口。源码解剖Server 与 Session 两层结构SRTP 模块的实现位于 pkg/srtp/server.go 与 pkg/srtp/session.go分为「服务器Server」与「会话Session」两个核心抽象。Server按 SSRC 分发 RTP/RTCP 包的 UDP 端点Server结构体包含监听地址、底层net.PacketConnUDP 连接、以及以uint32为键的sessions映射表type Server struct { address string conn net.PacketConn sessions map[uint32]*Session mu sync.Mutex }其关键行为包括按需创建 UDP 监听AddSession在注册第一个会话时才通过net.ListenPacket(udp, s.address)真正建立监听并启动handle()读取协程当最后一个会话被DelSession移除后连接被关闭代码注释还引用了 issue #734 防止空指针问题。RTP/RTCP 单端口复用RFC 5761handle()对每个 UDP 包根据第二个字节packet type进行分流取值99、110或其高位带0x80标记的变体视为 RTP 数据包从第 8 字节读取 SSRC转交对应会话的ReadRTP取值200~207视为 RTCP 控制包从第 4 字节读取 SSRC转交对应会话的ReadRTCP。这正是 RFC 5761「在单一端口上复用 RTP 数据包与控制包」的实现注释中也明确引用了该 RFC意味着 HomeKit 的媒体与控制流可以共用一个 UDP 端口。按 SSRC 寻址会话会话以对端声明的 SSRC 为键注册到sessions映射收到包时用同样的 SSRC 查表分发。Port()方法返回实际监听端口供上层构造 SDP 应答时使用当conn尚未建立时它会回退解析配置字符串中的端口号。Session封装 SRTP 加解密与端点信息Session代表一次端到端的 SRTP 会话包含Local与Remote两个Endpoint分别描述本端与对端的地址、端口、主密钥MasterKey、主盐MasterSalt与 SSRCtype Endpoint struct { Addr string Port uint16 MasterKey []byte MasterSalt []byte SSRC uint32 ... }Endpoint.init()调用srtp.CreateContext(MasterKey, MasterSalt, profile(MasterKey))建立加解密上下文。值得注意的细节是profile()函数当密钥长度为 16 字节时选用ProtectionProfileAes128CmHmacSha1_80AES-128 计数器模式加密 HMAC-SHA1 80 位认证而 32 字节的 AES-256 分支在源码中处于注释状态——从源码结构看当前实现仅支持 AES-128-CM/HMAC-SHA1-80 这一 HomeKit 标配的 SRTP 保护配置。会话的关键数据通路WriteRTP将上游传入的 RTP 包重写为以本地 SSRC、指定PayloadType封装的包调用EncryptRTP加密后经共享 UDP 连接conn.WriteTo发往对端地址同时按RTCPInterval周期性地发送携带包计数、字节计数的 SRSender Report。WriteRTCP对 RTCP 报文执行EncryptRTCP后发送S RTCP 的加密保护。ReadRTP用Remote端点的上下文DecryptRTP解密还原出rtp.Packet后触发OnReadRTP回调。ReadRTCP解密 RTCP 头部仅对 Sender ReportSR类型作出响应——向对端回送一个 Receiver ReportRR完成基本的 RTCP 反馈。会话对象同时维护Recv/Send两个累计收发字节计数器供 go2rtc 的流量统计使用。与 HomeKit 模块的协作两条完整调用链SRTP 服务器被 HomeKit 模块在两种场景下使用分别对应 internal/homekit/homekit.go 与 internal/homekit/server.go 中的逻辑。场景一HomeKit 客户端拉流 HomeKit 摄像头当 go2rtc 配置了homekit://...形式的流源时streamHandler会先检查 SRTP 服务器是否可用func streamHandler(rawURL string) (core.Producer, error) { if srtp.Server nil { return nil, errors.New(homekit: cant work without SRTP server) } ... client, err : homekit.Dial(rawURL, srtp.Server)若 SRTP 服务器为 nil例如srtp.listen被置空HomeKit 流将直接报错“cant work without SRTP server”。这是配置srtp.listen时必须注意的硬性依赖。客户端侧pkg/homekit/producer.go 的Client.Start()会为视频与音频各创建一个srtp.Sessionc.videoSession srtp.Session{Local: c.srtpEndpoint()} c.audioSession srtp.Session{Local: c.srtpEndpoint()} ... c.srtp.AddSession(c.videoSession) c.srtp.AddSession(c.audioSession)其中srtpEndpoint()生成本端端点地址为本地 IP、端口取srtp.Server.Port()MasterKey 为 16 字节随机串、MasterSalt 为 14 字节随机串、SSRC 为随机uint32。随后通过 HAP 协议与 HomeKit 摄像头完成 Setup Endpoints 协商把上述端点信息通过 SDP 应答发给摄像头摄像头随后向该 UDP 端口推送加密 RTP 流go2rtc 侧由Server.handle()按 SSRC 分发到对应 SessionReadRTP解密后经OnReadRTP回调写入内部视频/音频轨道。场景二HomeKit 服务器向 Apple Home 推流在 HomeKit 服务器模式下把任意 H264 摄像头导出到 Apple Homeinternal/homekit/server.go 的SetCharacteristic处理SetupEndpoints特性时创建homekit.NewConsumer(conn, srtp2.Server)consumer : homekit.NewConsumer(conn, srtp2.Server) consumer.SetOffer(offer) s.consumer consumer消费者pkg/homekit/consumer.go从 Apple 设备的 offer 中提取对端地址、端口、MasterKey/MasterSalt并生成本端端点构成应答GetAnswer随后在SetConfig阶段把对端 SSRC、PayloadType、RTCP 间隔写入两个 Session 并注册到 SRTP 服务器。当 go2rtc 内部流开始推送数据时AddTrack为每个轨道创建发送器H264 数据经h264.RTPPay打包MTU 1378、必要时RepairAVCC修复OPUS 数据经opus.RepackToHAP重打包最终统一走session.WriteRTP加密发送给 Apple 设备。两种模式的端到端数据流HomeKit 摄像头 ──HAP(SDP协商)──► go2rtc ──HAP(代理)──► Apple Home │ ▲ │ ▲ │ │ 加密RTP/RTCP │ │ 加密RTP/RTCP ▼ │ ▼ │ SRTP Server (UDP :8443) SRTP Server (UDP :8443) └─ Session.ReadRTP/ReadRTCP └─ Session.WriteRTP/WriteRTCP作为客户端SRTP 服务器是「接收端」解密摄像头发来的媒体包作为服务器SRTP 服务器是「发送端」加密向 Apple 设备推送媒体包。两端共用同一个 UDP 监听端口靠 SSRC 区分会话靠 RFC 5761 区分 RTP 与 RTCP。安全机制与实现要点小结加密配置固定使用ProtectionProfileAes128CmHmacSha1_8016 字节主密钥 14 字节主盐这是 HomeKit 规范规定的 SRTP 保护配置密钥来源本端密钥由core.RandString随机生成对端密钥来自 HAP 协议 Setup Endpoints 协商结果端口复用RTP 数据与 RTCP 控制在同一 UDP 端口上通过包头类型字段区分遵循 RFC 5761RTCP 交互发送端周期性发送 SR接收端收到 SR 后回送 RR维持链路健康生命周期会话随流创建、随流销毁所有会话结束时 UDP 监听自动关闭避免端口长期占用。注意事项与配置建议不要轻易关闭 SRTP 模块srtp.listen置空会导致 HomeKit 流源报错、HomeKit 服务器无法建立媒体会话。除非你的部署完全不用 HomeKit 功能否则保持默认配置即可端口冲突8443 为默认 UDP 端口若与其他服务冲突改为任意空闲 UDP 端口即可无需修改 HomeKit 侧配置——端口号会通过 SDP 协商告知对端防火墙/容器映射由于 HomeKit 设备客户端场景需要主动向该 UDP 端口发包若 go2rtc 运行在容器或 NAT 之后需要保证该 UDP 端口可达配合 HomeKit 使用完整的 HomeKit 配置示例客户端拉流、服务器导出、透明代理三种用法可参考 internal/homekit/README.mdSRTP 模块无需额外声明默认即参与其中。结语SRTP 模块虽小却是 go2rtc 打通 Apple HomeKit 生态的关键一环它用约百行核心代码实现了 RFC 5761 单端口复用、AES-128 SRTP 加解密、RTCP 心跳与按 SSRC 的会话分发让 HomeKit 摄像头可以在不暴露明文媒体流的情况下安全地接入 go2rtc并进一步复用 RTSP、WebRTC、MSE、MP4 等输出能力。理解 internal/srtp/srtp.go 的配置加载与 pkg/srtp/server.go、pkg/srtp/session.go 的会话模型是排查 HomeKit 音视频不通问题的第一步也是深入 go2rtc 媒体管道的最佳切入点之一。【免费下载链接】go2rtcUltimate camera streaming application项目地址: https://gitcode.com/GitHub_Trending/go/go2rtc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表