Kinesis Video Streams WebRTC Data Plane WebSocket API 深度解析
基于官方文档与 amazon-kinesis-video-streams-webrtc-sdk-c-main 源码(v1.7.0+)
1. 职责定位
| 维度 |
说明 |
| 所属平面 |
Data Plane WebSocket(信令数据面) |
| 主要用途 |
1. 建立 Master/Viewer 会话长连接 2. 实时交换 SDP Offer/Answer 3. 收发 ICE Candidate(Trickle) 4. 下发控制信令(Go Away、Reconnect Ice Server) |
| 协议 |
WebSocket over TLS(WSS) |
| 鉴权 |
预签名 URL(X-Amz-ChannelARN、X-Amz-ClientId 等 Query 参数) |
| 消息格式 |
JSON,UTF-8,每条消息 ≤ 10 KiB |
| 并发模型 |
每通道仅 1 个 Master + N 个 Viewer(默认 10,可调) |
2. 端到端交互时序
Client (SDK) WSS Endpoint KVS Signaling Service 1. 建立连接 GET /?X-Amz-ChannelARN=arn:aws:kinesisvideo:...&X-Amz-ClientId=web-123 101 Switching Protocols 2. 心跳/保活(可选) Ping Pong loop [every 30 s] 3. 业务消息 {"action":"SDP_OFFER","RecipientClientId":"master","MessagePayload":"..."} {"action":"STATUS_RESPONSE","CorrelationId":"...","Status":"200"} {"action":"SDP_ANSWER","SenderClientId":"master","MessagePayload":"..."} 4. 关闭 Close(1000) Client (SDK) WSS Endpoint KVS Signaling Service
3. 连接握手细节
3.1 端点拼装
- 模板定义(src/source/Signaling/LwsApiCalls.h:97-98)
c
复制代码
#define SIGNALING_ENDPOINT_MASTER_URL_WSS_TEMPLATE \
"%s?%s=%s" // baseWssUrl?X-Amz-ChannelARN=...
#define SIGNALING_ENDPOINT_VIEWER_URL_WSS_TEMPLATE \
"%s?%s=%s&%s=%s" // + &X-Amz-ClientId=...
- 代码拼装(src/source/Signaling/LwsApiCalls.c:1463-1469)
c
复制代码
if (role == VIEWER) {
SNPRINTF(url, ARRAY_SIZE(url),
SIGNALING_ENDPOINT_VIEWER_URL_WSS_TEMPLATE,
pSignalingClient->channelEndpointWss,
SIGNALING_CHANNEL_ARN_PARAM_NAME,
pSignalingClient->channelDescription.channelArn,
SIGNALING_CLIENT_ID_PARAM_NAME,
pSignalingClient->clientInfo.signalingClientInfo.clientId);
} else { // MASTER
SNPRINTF(url, ARRAY_SIZE(url),
SIGNALING_ENDPOINT_MASTER_URL_WSS_TEMPLATE,
pSignalingClient->channelEndpointWss,
SIGNALING_CHANNEL_ARN_PARAM_NAME,
pSignalingClient->channelDescription.channelArn);
}
3.2 TLS & 预签名
- 使用
HTTPS 证书链校验;根证书由系统 CA 提供。
- Query 参数已包含 SigV4 预签名,服务端校验时间戳、签名、过期(默认 15 min)。
- SDK 内部复用
createRequestInfo() 统一注入 AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_SESSION_TOKEN(若使用临时凭证)。
4. 消息格式
4.1 发送模板(src/source/Signaling/LwsApiCalls.h:115-129)
jsonc
复制代码
// 基础版
{
"action": "SDP_OFFER|SDP_ANSWER|ICE_CANDIDATE|...",
"RecipientClientId": "<peer id>",
"MessagePayload": "<Base64Encoded>"
}
// 带 CorrelationId(用于同步等待 STATUS_RESPONSE)
{
"action": "...",
"RecipientClientId": "...",
"MessagePayload": "...",
"CorrelationId": "<uuid>"
}
MessagePayload 长度 ≤ 10 KiB(UTF-8 编码后)。
- 若消息类型为
SDP_OFFER 且本地已获取 IceServerList,SDK 会追加 IceServerList 字段(供对端使用)。
4.2 接收格式
jsonc
复制代码
{
"action": "SDP_OFFER|SDP_ANSWER|ICE_CANDIDATE|GO_AWAY|RECONNECT_ICE_SERVER|STATUS_RESPONSE",
"SenderClientId": "<from>", // 仅接收时存在
"MessagePayload": "<Base64>",
"CorrelationId": "<uuid>", // 可选
"Status": "200|403|404|..." // 仅 STATUS_RESPONSE
}
5. 代码调用链路
5.1 连接建立
c
复制代码
// 状态机:SIGNALING_STATE_CONNECT
connectSignalingChannel()
└─ connectSignalingChannelLws() // src/source/Signaling/LwsApiCalls.c:1445
├─ lws_client_connect_via_info() // libwebsockets
└─ 等待 LWS_CALLBACK_CLIENT_ESTABLISHED
5.2 发送消息
c
复制代码
// 应用线程
signalingClientSendMessageSync()
└─ writeLwsData() // 原子写入缓冲区
└─ lws_callback_on_writable() // 唤醒 LWS 线程
// LWS 线程回调
lwsWssCallbackRoutine(LWS_CALLBACK_CLIENT_WRITEABLE)
└─ lws_write()
5.3 接收消息
c
复制代码
lwsWssCallbackRoutine(LWS_CALLBACK_CLIENT_RECEIVE)
├─ jsmn_parse() // 解析 JSON
├─ getMessageTypeFromString() // 转枚举
├─ receiveLwsMessageWrapper() // 异步投递工作线程
└─ 用户回调 messageReceivedFn
6. 状态机与错误处理
| 回调原因 |
SDK 动作 |
日志关键词 |
LWS_CALLBACK_CLIENT_ESTABLISHED |
设置 connected=TRUE,广播 connectedCvar |
Connection established |
LWS_CALLBACK_CLIENT_CONNECTION_ERROR |
设置 connected=FALSE,启动 reconnectHandler 线程 |
Client connection failed |
LWS_CALLBACK_CLIENT_CLOSED |
同上 |
WSS callback ... closed |
LWS_CALLBACK_WS_PEER_INITIATED_CLOSE |
记录关闭码 |
Peer initiated close with code |
- 重连线程指数退避:初始 100 ms → 最大 30 s;退避因子 1.5。
- 退避期间保持
WSS 协议级 Ping/Pong(默认 30 s 间隔)。
7. 关键日志与快速检索
bash
复制代码
# 连接
grep -n "Connection established\|Client connection failed" master.log
# 消息收发
grep -n "Sending data over web socket\|Received message type" master.log
# 关闭/重连
grep -n "WSS callback.*closed\|Reconnect attempt" master.log
8. 性能与限制
| 项目 |
默认值/上限 |
说明 |
| 单通道 Viewer 数 |
10 |
可在控制面提高配额 |
| 消息大小 |
10 KiB |
含 Base64 后的 JSON |
| 连接空闲超时 |
60 s |
服务端主动断开 |
| Ping/Pong 间隔 |
30 s |
保活,可配置 |
| 重连退避 |
100 ms → 30 s |
指数 1.5x |
9. 常见错误码与排错
| HTTP Status |
含义 |
排查要点 |
| 400 InvalidArgument |
参数非法 |
检查 ARN、ClientId 格式与长度 |
| 403 AccessDenied |
签名/权限失败 |
时钟偏差 < 5 min;IAM 策略是否允许 kinesisvideo:ConnectAsViewer/ConnectAsMaster |
| 404 ResourceNotFound |
通道不存在 |
ARN 区域与端点一致;通道是否被删除 |
| 400 ClientLimitExceeded |
超限 |
Viewer 数超配额;API 速率超限(默认 100 TPS) |
| 1000/1001 正常关闭 |
- |
无需处理;重连即可 |
10. 小结
- 职责:WebSocket 数据面仅负责会话级信令,不承载媒体与配置。
- 安全:TLS + 预签名 URL,短期凭证,独立限流。
- 可靠:指数退避重连、Ping/Pong 保活、消息 ACK(CorrelationId)。
- 易用:JSON 透明格式,与标准 WebRTC 信令对齐;SDK 封装发送/接收/重连细节。
掌握连接 URL 拼装、消息模板、回调处理与重连策略,即可快速定位信令层问题。