go2rtc 接入 Wyze 摄像头:基于原生 P2P 与 DTLS 协议的流媒体集成指南
【免费下载链接】go2rtcUltimate camera streaming application项目地址: https://gitcode.com/GitHub_Trending/go/go2rtc
导读
本文以 go2rtc 仓库中 internal/wyze/README.md 为骨架,系统讲解如何在 go2rtc 中接入 Wyze 摄像头:无需 Wyze App 与官方 SDK,仅凭 Wyze 账号与 P2P 协议即可实现本地直连拉流,并支持 H.264/H.265 视频、AAC/G.711/PCM/Opus 音频、双向对讲(Intercom)以及 HD/SD 分辨率切换。文章将覆盖账号配置、WebUI 添加流程、wyze://流地址格式、配置参数详解与设备兼容性矩阵,并结合 internal/wyze/wyze.go 与 pkg/wyze 下的源码实现,深入解析其云端鉴权、DTLS 加密连接、TUTK 信令与码流探测等底层原理,让读者既能在 WebUI 上快速上手,也能理解整条链路的运转机制。
功能特性总览
该 source(go2rtc 中把"流来源"抽象为 source)允许直接以原生 P2P 方式从 Wyze 摄像头拉流,全程不依赖 Wyze App 或官方 SDK。核心特性如下:
- 视频编码:支持 H.264 与 H.265;
- 音频编码:支持 AAC、G.711(PCMU/PCMA)、PCM 与 Opus;
- 双向对讲:支持向摄像头扬声器回传音频(Intercom);
- 分辨率切换:支持 HD/SD 两档分辨率,甚至更多档位;
- 本地直连:流媒体全程走局域网 P2P 直连,仅账号加载阶段需要访问公网。
前提条件与重要限制
在开始之前,请先确认以下四点(均来自 README 的 "Important" 说明):
- 必须拥有 Wyze 账号:需要通过 WebUI 登录一次以拉取账号下的摄像头列表;
- 固件必须支持 DTLS:只有启用了 DTLS 的固件才能被支持,协议层直接要求
dtls=true; - 公网仅用于加载设备列表:从账号加载摄像头之后,所有流媒体传输都是本地 P2P,不再需要互联网;
- 连接仅限本地:P2P 连接是直接指向摄像头局域网 IP 的直连,并非云端中转。
从源码看,这些限制与实现严格一致:pkg/wyze/client.go 的Dial函数在dtls参数不为"true"时直接返回wyze: only DTLS cameras are supported,即非 DTLS 摄像头根本无法建立连接。
快速上手:WebUI 添加 Wyze 摄像头
第一步:获取 API Key
前往 Wyze 开发者门户申请你的 API Key(获取 API ID 与 API Key 两个凭证),这一步需要 Wyze 账号本身。WebUI 的添加页面(www/add.html)也内置了该说明链接。
第二步:WebUI > Add > Wyze 登录
在 go2rtc WebUI 的 Add 页面点击 Wyze 按钮,会展开一个登录表单(www/add.html),需要填写四个字段:
- API ID:开发者门户申请到的 API ID;
- API Key:开发者门户申请到的 API Key;
- email:Wyze 账号邮箱;
- password:Wyze 账号密码。
提交后,前端通过POST api/wyze调用后端接口完成登录(www/add.html),后端处理逻辑位于 internal/wyze/wyze.go 的apiAuth:先调用 Wyze 云端Login,成功后把账号凭证通过app.PatchConfig写入wyze.<email>配置节,随后立即拉取摄像头列表返回给前端表格。
第三步:选择摄像头生成流地址
登录成功后,页面会展示账号下的摄像头列表(名称、型号、MAC、IP 以及自动生成的wyze://流 URL)。你也可以在"已保存账号"下拉框中切换账号,通过GET api/wyze?id=<email>重新加载设备列表(www/add.html),后端对应 apiDeviceList。
后端在返回设备列表时会调用buildStreamURL(internal/wyze/wyze.go)为每台摄像头拼接流地址:以摄像头局域网 IP 为主机,附带uid(P2P ID)、enr(DTLS 加密密钥)、mac、model等参数,并在设备支持 DTLS(cam.DTLS == 1)时自动追加dtls=true。
配置示例与账号说明
账号配置(wyze 配置节)
在 go2rtc 配置文件中,wyze节按邮箱组织账号:
wyze: user@email.com: api_id: "your-api-id" api_key: "your-api-key" password: "yourpassword" # or MD5 triple-hash with "md5:" prefix对应源码中的结构体 AccountConfig:
| YAML 字段 | 说明 |
|---|---|
api_id | Wyze 开发者门户申请的 API ID |
api_key | Wyze 开发者门户申请的 API Key |
password | Wyze 账号密码;也支持md5:前缀传入"三重 MD5 哈希"后的值 |
密码的两种写法对应 pkg/wyze/cloud.go 的hashPassword实现:若密码以md5:前缀开头,则直接截取前缀后的十六进制串使用;否则对明文连续做 3 次 MD5 哈希。也就是说,md5:后应填写"对明文密码做 3 次 MD5"得到的值,避免在配置文件中出现明文。
从 Init 可以看到,该配置节在启动时通过app.LoadConfig加载,并注册了wyze流协议处理器:任何wyze://开头的流地址都会交给wyze.NewProducer创建流。getCloud(internal/wyze/wyze.go)则按邮箱取出账号配置,并要求api_key与api_id均非空,否则报错。
流配置(streams 配置节)
streams: wyze_cam: wyze://192.168.1.123?uid=WYZEUID1234567890AB&enr=xxx&mac=AABBCCDDEEFF&model=HL_CAM4&dtls=truewyze:// 流地址格式详解
在 WebUI 添加摄像头时,流 URL 会自动生成。其完整格式为:
wyze://[IP]?uid=[P2P_ID]&enr=[ENR]&mac=[MAC]&model=[MODEL]&subtype=[hd|sd]&dtls=true各参数含义如下表:
| 参数 | 说明 |
|---|---|
IP | 摄像头局域网 IP 地址 |
uid | P2P 标识符(20 字符) |
enr | DTLS 使用的加密密钥 |
mac | 设备 MAC 地址 |
model | 摄像头型号(如HL_CAM4) |
dtls | 是否启用 DTLS 加密(默认true) |
subtype | 摄像头分辨率:hd或sd(默认hd) |
在 pkg/wyze/client.go 的Dial中,uid、enr、mac、model分别用于建立连接与鉴权:enr与mac共同派生出 DTLS 认证密钥(CalculateAuthKey,见 pkg/tutk/dtls/auth.go),uid是 IOTC 会话标识,model则决定分辨率档位与门铃类设备的信令格式。另外,verbose=true参数可开启调试输出(源码在Dial中解析),排查问题时可临时追加。
分辨率切换
通过subtype参数可以切换摄像头的分辨率:
streams: wyze_hd: wyze://...&subtype=hd wyze_sd: wyze://...&subtype=sd虽然 README 只描述了hd/sd两档,但 pkg/wyze/client.go 与 pkg/wyze/producer.go 展示了更细的分档实现,实际支持 5 种档位:
| 值 | 含义 |
|---|---|
0 /hd(默认) | 自动高清:按型号取最佳档位(1080P / 2K / Floodlight) |
1 /sd | SD / 360P |
| 2 | 720P |
| 3 | 2K(仅 2K 型号生效,否则回退 HD) |
| 4 | Floodlight 专用档位 |
SetResolution(pkg/wyze/client.go)在内部把档位映射为frameSize与bitrate两元组:HD 与 2K 使用最大码率BitrateMax(0xF0),SD 使用BitrateSD(0x3C)。部分门铃/特定型号(WYZEDB3、WVOD1、HL_WCO2、WYZEC1)走 K10052 指令格式,其余型号走 K10056 指令格式。hd档位最终落到哪个 frame size,取决于hdFrameSize()/is2K()/isFloodlight()对model的判断(例如HL_CAM3P、HL_PANP、HL_CAM4、HL_DB2、HL_CFL2视为 2K 设备)。
双向对讲(Intercom)
双向对讲在 README 中被描述为"自动支持":当有消费者向该流发送音频时,音频会被传输到摄像头扬声器。
从源码看,这一"自动"建立在探测阶段的能力发现上。pkg/wyze/producer.go 的probe在检测到音频编码且client.SupportsIntercom()为真时,会额外追加一路DirectionSendonly的音频 Media(使用与下行相同的编码参数),并调用SetBackchannelCodec记录回传编码。hasIntercom由 pkg/wyze/client.go 的c.conn.HasTwoWayStreaming()在 K 鉴权完成后确定。
真正的对讲链路在 pkg/wyze/backchannel.go 的AddTrack中:启用对讲后,通过 K10010 指令打开MediaTypeReturnAudio(3)通道并等待AVServStart,随后把消费者发来的 RTP 音频转换为摄像头期望的编码(AAC 会转封装为 ADTS),并维护一个从 0 开始、按帧时长(微秒)递增的时间戳,通过AVSendAudioData发送到摄像头扬声器。
兼容性矩阵
README 给出了官方设备兼容性列表,其中Gwell 协议(标注*)的设备目前尚未支持:
| 名称 | 型号 | 固件 | 协议 | 加密 | 编码 |
|---|---|---|---|---|---|
| Wyze Cam v4 | HL_CAM4 | 4.52.9.4188 | TUTK | TransCode | h264, aac |
| 4.52.9.5332 | TUTK | HMAC-SHA1 | h264, aac | ||
| Wyze Cam v3 Pro | TUTK | ||||
| Wyze Cam v3 | WYZE_CAKP2JFUS | 4.36.14.3497 | TUTK | TransCode | h264, pcm |
| Wyze Cam v2 | WYZEC1-JZ | 4.9.9.3006 | TUTK | TransCode | h264, pcmu |
| Wyze Cam v1 | TUTK | ||||
| Wyze Cam Pan v4 | Gwell* | ||||
| Wyze Cam Pan v3 | TUTK | ||||
| Wyze Cam Pan v2 | TUTK | ||||
| Wyze Cam Pan v1 | TUTK | ||||
| Wyze Cam OG | Gwell* | ||||
| Wyze Cam OG Telephoto | Gwell* | ||||
| Wyze Cam OG (2025) | Gwell* | ||||
| Wyze Cam Outdoor v2 | TUTK | ||||
| Wyze Cam Outdoor v1 | TUTK | ||||
| Wyze Cam Floodlight Pro | ? | ||||
| Wyze Cam Floodlight v2 | TUTK | ||||
| Wyze Cam Floodlight | TUTK | ||||
| Wyze Video Doorbell v2 | HL_DB2 | 4.51.3.4992 | TUTK | TransCode | h264, pcm |
| Wyze Video Doorbell v1 | TUTK | ||||
| Wyze Video Doorbell Pro | ? | ||||
| Wyze Battery Video Doorbell | ? | ||||
| Wyze Duo Cam Doorbell | ? | ||||
| Wyze Battery Cam Pro | ? | ||||
| Wyze Solar Cam Pan | ? | ||||
| Wyze Duo Cam Pan | ? | ||||
| Wyze Window Cam | ? | ||||
| Wyze Bulb Cam | ? |
Gwell 协议尚未支持(README 原注:
_* Gwell based protocols are not yet supported._)。
这一点在源码中同样有体现:云端设备列表解析(pkg/wyze/cloud.go)会跳过ProductType != "Camera"以及DeviceParams.IP == ""(注释明确写着 "skip cameras without IP (gwell protocol)")的设备,即 Gwell 协议摄像头不会被列入可添加列表。
底层工作原理:从云端鉴权到本地 P2P 拉流
为了让读者对"为什么能不经 App/SDK 直接拉流"有完整认知,这里结合源码梳理整条链路的四个阶段。
1. 云端账号鉴权与设备发现
pkg/wyze/cloud.go 的Login使用API Key/Key ID作为请求头,把邮箱与三重 MD5 后的密码 POST 到 Wyze 认证服务(auth-prod.api.wyze.com/api/user/login)。若返回MFAOptions非空则抛出AuthError(NeedsMFA),前端会收到 401 与 MFA 提示;成功则保存access_token。
随后GetCameraList(pkg/wyze/cloud.go)携带 access_token、phone_id 等字段调用api.wyzecam.com/app/v2/home_page/get_object_list,从响应中提取每台设备的 MAC、ENR、P2P ID、IP、型号、固件版本与 DTLS 能力等字段,构成 Camera 结构——这正是wyze://URL 中各参数的来源。
2. DTLS 加密连接与 K 系列指令鉴权
与摄像头的本地连接使用 IOTC + DTLS。pkg/wyze/client.go 的connect通过dtls.DialDTLS(host, port, uid, authKey, enr, verbose)建立加密通道,其中authKey由enr + 大写MAC的 SHA-256 哈希再经 Base64 变换而来(pkg/tutk/dtls/auth.go),DTLS PSK 则派生自 ENR(DerivePSK,注意 TUTK 会把包含0x00的 PSK 截断)。
连接建立后依次执行两类登录:
- AV Login(
AVClientStart):完成 IOTC 层的 AV 会话登录(pkg/wyze/client.go); - K 指令鉴权(
doKAuth,pkg/wyze/client.go):通过 K10000→K10001 获取挑战值,再以 K10002→K10003 提交基于 ENR 与状态码生成的挑战响应完成鉴权,并从 K10003 响应中解析出音频能力(hasAudio)与双向流能力(hasIntercom)。
3. 码流探测与编解码协商
鉴权完成后,pkg/wyze/producer.go 的probe开始读取设备上报的码流,识别视频编码(H.264 取 SPS、H.265 取 VPS 生成 codec 描述)与音频编码(PCMU/PCMA/AAC/Opus/PCM/MP3/MJPEG 等),据此构建 go2rtc 的core.Media列表。若支持对讲,则额外附加一路 sendonly 音频 Media。SetResolution的分辨率指令也在探测前下发(pkg/wyze/producer.go)。
4. 流传输与编码转换
Producer.Start 持续从 DTLS 连接读取 TUTK 数据帧,按pkt.Codec映射为 go2rtc 的 RTP 包:H.264/H.265 走 Annex-B → AVCC 转换,AAC 去掉 ADTS 头后按 RTP 封装,G.711/PCM/Opus 等直接透传。之后按接收者的编码名称分发到各消费者(WebRTC/RTSP/HLS/MP4 等 go2rtc 出口),实现"一次拉流、多协议转发"。
常见问题排查
- 报错
only DTLS cameras are supported:摄像头固件不支持 DTLS,无法通过本 source 接入,可先确认固件版本是否满足 README 兼容性列表; - 登录返回 MFA 相关错误:账号开启了双重验证,云端会返回
AuthError(pkg/wyze/cloud.go),需要在满足 MFA 流程后再进行配置; - 列表缺少某台摄像头:检查是否为 Gwell 协议设备(Pan v4、OG 系列等),这类设备目前会被云端列表接口直接跳过(pkg/wyze/cloud.go);
- 需要排查连接细节:可在
wyze://URL 中追加verbose=true开启客户端调试日志,观察 DTLS 连接、AV Login、K 鉴权与码流探测各阶段输出。
延伸阅读
- source 入口与配置解析:internal/wyze/wyze.go
- 云端 API 客户端(登录、设备列表、P2P 信息):pkg/wyze/cloud.go
- P2P 客户端(DTLS 拨号、K 鉴权、分辨率指令):pkg/wyze/client.go
- 流生产者与编码转换:pkg/wyze/producer.go
- 对讲回传链路:pkg/wyze/backchannel.go
- 底层 TUTK 协议与 DTLS 实现:pkg/tutk、pkg/tutk/dtls/auth.go
- WebUI 添加页面: www/add.html
【免费下载链接】go2rtcUltimate camera streaming application项目地址: https://gitcode.com/GitHub_Trending/go/go2rtc
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考