# 腾讯云 Web 直播 SDK 踩坑记录
> 说明:本文基于一个真实项目的接入过程整理而成,文中的域名、推流地址、鉴权参数、业务名、配置接口地址均已做脱敏处理,代码片段也做了适度抽象,避免泄漏隐私信息。
## 一、背景
最近做了一个基于浏览器的视频直播推流页面,核心目标很简单:
1. 在 Web 端完成摄像头采集。
2. 通过腾讯云 Web 直播 SDK 完成实时推流。
3. 兼容桌面浏览器和 iPhone。
# 腾讯云 Web 直播 SDK 接入实战复盘
> 说明:本文基于一个真实项目的接入过程整理而成,文中的域名、推流地址、鉴权参数、业务名、配置接口地址均已做脱敏处理,代码片段也做了适度抽象,避免泄漏隐私信息。
## 一、背景
最近做了一个基于浏览器的视频直播推流页面,核心目标很简单:
1. 在 Web 端完成摄像头采集。
2. 通过腾讯云 Web 直播 SDK 完成实时推流。
3. 兼容桌面浏览器和 iPhone。
前端技术栈比较简单:
- React
- Vite
- 腾讯云 Web 直播 SDK
这次接入看起来是“把 SDK 接起来”,但真正花时间的不是 `startPush()` 这一句,而是浏览器权限、设备枚举和 iPhone 摄像头行为。
## 二、接入思路
### 1. SDK 引入
项目里采用的是直接通过 CDN 引入腾讯云 Web 推流 SDK,这种方式前期验证很快:
```html
<script src="https://video.sdk.qcloudecdn.com/web/TXLivePusher-2.1.1.min.js"></script>
```
在 TypeScript 里补一个全局声明:
```ts
declare global {
interface Window {
TXLivePusher: any;
}
}
```
这样就可以直接通过 `window.TXLivePusher` 创建实例。
### 2. 推流启动流程
我最后稳定下来的启动流程是:
1. 调用 `checkSupport()` 检查当前浏览器是否支持 WebRTC 推流。
2. 主动调用一次 `getUserMedia` 申请权限。
3. 用临时推流器做设备枚举。
4. 默认优先选后置摄像头。
5. 创建正式推流器并绑定渲染容器。
6. 启动摄像头。
7. 调用 `startPush()` 开始推流。
核心代码可以抽象成这样:
```ts
const support = await window.TXLivePusher.checkSupport();
if (!support.isWebRTCSupported) {
throw new Error('当前浏览器不支持 WebRTC');
}
await navigator.mediaDevices.getUserMedia({
video: true,
audio: false
});
const pusher = new window.TXLivePusher();
pusher.setRenderView('videoContainer');
pusher.videoView.muted = true;
pusher.setVideoQuality('480p');
pusher.setProperty('setVideoFPS', 25);
await pusher.startCamera();
await pusher.startPush('<push-url>');
```
这里有两个细节非常关键。
第一个是:权限申请必须前置。
如果不先申请权限,部分浏览器尤其是 iOS Safari 下拿到的设备列表不完整,很难正确识别前后摄像头。
第二个是:每次启动前先清理旧的预览容器。
如果渲染容器残留上一次的 video/canvas 节点,会导致新一轮推流出现黑屏、残帧或者尺寸异常。
## 三、这次接入里踩过的坑
### 坑 1:iPhone 上后置摄像头黑屏
这是最典型、也最耗时间的问题。
一开始我的实现方式是:
1. 先 `startCamera()`
2. 再 `switchCamera(targetCameraId)`
3. 然后 `startPush()`
在桌面浏览器上问题不大,但在 iPhone 尤其是多摄机型上,这个流程经常表现成:
- 黑屏
- 只出第一帧
- 切换后推流不稳定
根因在于 iOS 的多镜头切换链路没有想象中稳定。
“先打开默认镜头,再切后置镜头”这件事,并不总是可靠。
最后更稳的方案是:
- iOS 上不要“先开再切”
- 直接按朝向启动摄像头
也就是:
```ts
await pusher.startCamera(useRearCamera ? 'environment' : 'user');
```
这个调整之后,iPhone 上的后置启动稳定性明显提升。
### 坑 2:设备列表在 iOS 上不完整
如果页面一加载就直接枚举设备,拿到的摄像头信息有时会不全,尤其是设备 label 不可靠。
解决方式是:
1. 先触发一次 `getUserMedia`
2. 再做设备枚举
```ts
await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
const tempPusher = new window.TXLivePusher();
await enumerateDevices(tempPusher);
```
这是一个非常实用的顺序优化。
### 坑 3:推流地址不应该长期写死在前端
前期联调时,把完整推流地址直接写在前端里确实很省事,但这只是临时方案。
问题主要有三个:
- 地址里可能带有鉴权参数
- 参数过期后需要重新更新前端
- 不利于按用户、设备、会话动态下发授权
更合理的做法是:
- 前端请求业务后端
- 后端动态返回临时可用的推流地址
- 前端只负责消费,不负责持有长期有效的敏感信息
### 坑 4:不同平台不要强行共用一套摄像头启动策略
桌面端浏览器、Android 浏览器和 iPhone Safari 在摄像头行为上并不一致。
如果一套逻辑想强行覆盖所有平台,最后通常会变成:
- 桌面端正常
- Android 基本正常
- iPhone 问题特别多
这次接入之后,我的结论非常明确:
- 桌面端可以按设备 ID 处理
- iPhone 应该优先按朝向处理
- 多摄设备要尽量避免复杂切换链路
## 四、如果再做一遍,我会更早做的事情
如果让我重新来一次,我会更早做下面这些事:
- 更早把推流地址下沉到后端,避免前端直接持有可用推流 URL
- 更早针对 iPhone 做单独启动策略,不和桌面端走完全相同的流程
- 更早把“权限申请 -> 设备枚举 -> 启动摄像头”固定成标准顺序
这些事情不一定影响你做出第一个 Demo,但会直接影响后面的稳定性。
## 五、总结
腾讯云 Web 直播 SDK 的基础接入并不复杂,真正难的是浏览器权限、设备枚举和移动端摄像头这几个边界问题。
这次接入给我的几个结论很明确:
- 权限申请顺序非常重要。
- iPhone 上的摄像头处理必须单独设计,不要照搬桌面端逻辑。
- 后置镜头问题大多不是推流地址问题,而是摄像头启动和切换时序问题。
- 推流地址的授权能力应该放在后端,而不是长期暴露在前端。
如果只是做 Demo,接通推流很快。
但如果目标是做稳定可用的 Web 推流页面,真正值得花时间的,往往就是这些和 SDK 直接相关、但文档里不会替你兜底的细节。
---
如果你正在接入腾讯云 Web 推流 SDK,建议优先排查下面四件事:
1. 权限申请时机是否正确。
2. iPhone 上是否还在走“先开再切镜头”。
3. 是否在未授权的情况下就开始枚举设备。
4. 推流地址是否已经从前端下沉到后端动态下发。
这四件事处理好了,接入难度会下降很多。
前端技术栈比较简单:
- React
- Vite
- 腾讯云 Web 直播 SDK
这次接入看起来是“把 SDK 接起来”,但真正花时间的不是 `startPush()` 这一句,而是浏览器权限、设备枚举和 iPhone 摄像头行为。
## 二、接入思路
### 1. SDK 引入
项目里采用的是直接通过 CDN 引入腾讯云 Web 推流 SDK,这种方式前期验证很快:
```html
<script src="https://video.sdk.qcloudecdn.com/web/TXLivePusher-2.1.1.min.js"></script>
```
在 TypeScript 里补一个全局声明:
```ts
declare global {
interface Window {
TXLivePusher: any;
}
}
```
这样就可以直接通过 `window.TXLivePusher` 创建实例。
### 2. 推流启动流程
我最后稳定下来的启动流程是:
1. 调用 `checkSupport()` 检查当前浏览器是否支持 WebRTC 推流。
2. 主动调用一次 `getUserMedia` 申请权限。
3. 用临时推流器做设备枚举。
4. 默认优先选后置摄像头。
5. 创建正式推流器并绑定渲染容器。
6. 启动摄像头。
7. 调用 `startPush()` 开始推流。
核心代码可以抽象成这样:
```ts
const support = await window.TXLivePusher.checkSupport();
if (!support.isWebRTCSupported) {
throw new Error('当前浏览器不支持 WebRTC');
}
await navigator.mediaDevices.getUserMedia({
video: true,
audio: false
});
const pusher = new window.TXLivePusher();
pusher.setRenderView('videoContainer');
pusher.videoView.muted = true;
pusher.setVideoQuality('480p');
pusher.setProperty('setVideoFPS', 25);
await pusher.startCamera();
await pusher.startPush('<push-url>');
```
这里有两个细节非常关键。
第一个是:权限申请必须前置。
如果不先申请权限,部分浏览器尤其是 iOS Safari 下拿到的设备列表不完整,很难正确识别前后摄像头。
第二个是:每次启动前先清理旧的预览容器。
如果渲染容器残留上一次的 video/canvas 节点,会导致新一轮推流出现黑屏、残帧或者尺寸异常。
## 三、这次接入里踩过的坑
### 坑 1:iPhone 上后置摄像头黑屏
这是最典型、也最耗时间的问题。
一开始我的实现方式是:
1. 先 `startCamera()`
2. 再 `switchCamera(targetCameraId)`
3. 然后 `startPush()`
在桌面浏览器上问题不大,但在 iPhone 尤其是多摄机型上,这个流程经常表现成:
- 黑屏
- 只出第一帧
- 切换后推流不稳定
根因在于 iOS 的多镜头切换链路没有想象中稳定。
“先打开默认镜头,再切后置镜头”这件事,并不总是可靠。
最后更稳的方案是:
- iOS 上不要“先开再切”
- 直接按朝向启动摄像头
也就是:
```ts
await pusher.startCamera(useRearCamera ? 'environment' : 'user');
```
这个调整之后,iPhone 上的后置启动稳定性明显提升。
### 坑 2:设备列表在 iOS 上不完整
如果页面一加载就直接枚举设备,拿到的摄像头信息有时会不全,尤其是设备 label 不可靠。
解决方式是:
1. 先触发一次 `getUserMedia`
2. 再做设备枚举
```ts
await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
const tempPusher = new window.TXLivePusher();
await enumerateDevices(tempPusher);
```
这是一个非常实用的顺序优化。
### 坑 3:推流地址不应该长期写死在前端
前期联调时,把完整推流地址直接写在前端里确实很省事,但这只是临时方案。
问题主要有三个:
- 地址里可能带有鉴权参数
- 参数过期后需要重新更新前端
- 不利于按用户、设备、会话动态下发授权
更合理的做法是:
- 前端请求业务后端
- 后端动态返回临时可用的推流地址
- 前端只负责消费,不负责持有长期有效的敏感信息
### 坑 4:不同平台不要强行共用一套摄像头启动策略
桌面端浏览器、Android 浏览器和 iPhone Safari 在摄像头行为上并不一致。
如果一套逻辑想强行覆盖所有平台,最后通常会变成:
- 桌面端正常
- Android 基本正常
- iPhone 问题特别多
这次接入之后,我的结论非常明确:
- 桌面端可以按设备 ID 处理
- iPhone 应该优先按朝向处理
- 多摄设备要尽量避免复杂切换链路
## 四、如果再做一遍,我会更早做的事情
如果让我重新来一次,我会更早做下面这些事:
- 更早把推流地址下沉到后端,避免前端直接持有可用推流 URL
- 更早针对 iPhone 做单独启动策略,不和桌面端走完全相同的流程
- 更早把“权限申请 -> 设备枚举 -> 启动摄像头”固定成标准顺序
这些事情不一定影响你做出第一个 Demo,但会直接影响后面的稳定性。
## 五、总结
腾讯云 Web 直播 SDK 的基础接入并不复杂,真正难的是浏览器权限、设备枚举和移动端摄像头这几个边界问题。
这次接入给我的几个结论很明确:
- 权限申请顺序非常重要。
- iPhone 上的摄像头处理必须单独设计,不要照搬桌面端逻辑。
- 后置镜头问题大多不是推流地址问题,而是摄像头启动和切换时序问题。
- 推流地址的授权能力应该放在后端,而不是长期暴露在前端。
如果只是做 Demo,接通推流很快。
但如果目标是做稳定可用的 Web 推流页面,真正值得花时间的,往往就是这些和 SDK 直接相关、但文档里不会替你兜底的细节。
---
如果你正在接入腾讯云 Web 推流 SDK,建议优先排查下面四件事:
1. 权限申请时机是否正确。
2. iPhone 上是否还在走“先开再切镜头”。
3. 是否在未授权的情况下就开始枚举设备。
4. 推流地址是否已经从前端下沉到后端动态下发。
这四件事处理好了,接入难度会下降很多。