帮你快速理解、总结文档立即下载

监控拉流

最近更新时间:2026-09-09 16:53:32
我的收藏
本文将介绍腾讯云物联网(IoT)应用端 SDK 的监控拉流能力(TXIoTMonitorSession):如何在 App 或小程序中拉取已绑定设备的实时音视频流并渲染播放,以及在此基础上进行清晰度切换、语音对讲、多通道观看、截图与录制、PTZ 云台控制等。监控拉流基于腾讯云实时音视频(TRTC)链路实现,相比传统 P2P 直连方案,在连通率、首帧速度、弱网表现与多端同看等方面具备明显优势(详情参见 方案优势)。

功能概述

监控拉流指应用端主动向已绑定的设备发起一次实时观看请求,设备按请求的通道与清晰度推送音视频流,应用端订阅并渲染,全过程由 TXIoTMonitorSession 统一管理。典型能力包括:实时画面播放、高清/流畅清晰度切换、远端音频控制、双向语音对讲、多通道同时观看、画面截图与本地录制、PTZ 云台控制。
监控拉流广泛应用于家庭安防、可视门铃、看护陪护、门店巡检等消费类音视频设备场景:


方案优势

TXIoTMonitorSession 底层复用腾讯云实时音视频(TRTC)的媒体网络与传输能力:设备与应用端分别就近接入 TRTC 媒体网络并在同一房间内完成推流与订阅,不依赖设备与手机之间的端到端直连。这一架构选择带来的差异如下。

与传统 P2P 方案对比



前提条件

在使用监控拉流能力前,请确保已完成以下准备工作:
已开通腾讯云物联网相关服务,并在控制台完成实例、应用和设备的准备工作。可参见 开通服务
已在客户端工程中集成 IoT 应用端 SDK 并完成登录。可参见 Android 集成与登录iOS 集成与登录
目标设备已绑定到当前登录账户名下,或已被分享给当前账户。可参见 设备绑定
目标设备为支持音视频推流的设备,且当前处于在线状态。
若需要使用语音对讲,已在工程中申请并获取麦克风权限。

使用建议

调用顺序:获取监控会话对象 → addListener 注册回调 → startRemoteView 绑定渲染视图 → startSession 开始拉流 → 收到 onSessionEstablished 后画面稳定播放 → 结束时 stopRemoteView + stopSession
先绑定视图再开始会话startRemoteView 可以在 startSession 之前调用,可省去一次通道协商,出图更快。
尽早注册监听:在 startSession 之前完成 addListener(iOS 为 addDelegate),避免错过 onSessionEstablished 等早期回调。
及时释放:不再需要监控时调用 stopSession 并移除监听,避免资源泄漏与重复回调。
统一错误处理:在 onError 中集中处理错误码,结合错误码给出用户可理解的提示。
警告:
监控会话对象为单例,同一时刻只存在一个监控会话。若已有会话正在运行中(已调用 startSession 且尚未 stopSession),再次调用 startSession 会被直接忽略,不会打断或切换已有会话。切换观看设备前必须先调用 stopSession

接入步骤

步骤 1:获取监控会话对象

登录成功后,通过 TXIoTEngine 实例调用 getMonitorSession() 获取监控会话对象。若返回 null(iOS 为 nil),通常是 SDK 尚未登录或登录已过期。
Android
iOS
TXIoTMonitorSession session = TXIoTEngine.getInstance(context).getMonitorSession();
if (session == null) {
// SDK 未登录或登录已过期,请先完成登录
return;
}
TXIoTMonitorSession *session = [[TXIoTEngine getInstance] getMonitorSession];
if (session == nil) {
// SDK 未登录或登录已过期,请先完成登录
return;
}

步骤 2:注册监听回调

监控会话的状态变化、首帧渲染、播放状态与错误均通过监听接口返回。请在 startSession 之前完成注册。
Android
iOS
TXIoTMonitorSessionListener monitorListener = new TXIoTMonitorSessionListener() {
@Override
public void onSessionEstablished() {
// 会话建立成功,所有已请求通道进入播放状态
}

@Override
public void onRenderFirstFrame(int channelId) {
// 指定通道首帧已渲染,此时可隐藏加载动画
}

@Override
public void onPlayStateChanged(int channelId, TXIoTPlayState state) {
// PLAYING / LOADING / STOPPED,用于驱动 loading 与占位图
}

@Override
public void onSessionReconnecting() {
// 链路中断,SDK 正在自动重连
}

@Override
public void onSessionRecovery() {
// 重连成功,画面恢复
}

@Override
public void onError(int channelId, TXIoTErrorCode errCode, String errMsg) {
// 统一处理错误码与用户提示
}

// 其他回调按需实现...
};

session.addListener(monitorListener);
@interface MonitorViewController () <TXIoTMonitorSessionDelegate>
@end

@implementation MonitorViewController

- (void)onSessionEstablished {
// 会话建立成功,所有已请求通道进入播放状态
}

- (void)onRenderFirstFrame:(NSInteger)channelId {
// 指定通道首帧已渲染,此时可隐藏加载动画
}

- (void)onPlayStateChanged:(NSInteger)channelId state:(TXIoTPlayState)state {
// Playing / Loading / Stopped,用于驱动 loading 与占位图
}

- (void)onSessionReconnecting {
// 链路中断,SDK 正在自动重连
}

- (void)onSessionRecovery {
// 重连成功,画面恢复
}

- (void)onError:(NSInteger)channelId
errorCode:(TXIoTErrorCode)errorCode
errorMessage:(NSString *)errorMessage {
// 统一处理错误码与用户提示
}

@end

// 注册代理
[session addDelegate:self];
// 退出时注销
// [session removeDelegate:self];

步骤 3:绑定渲染视图并开始拉流

先通过 startRemoteView 为目标通道绑定渲染视图并指定清晰度,再调用 startSession 与设备建立会话。
方法
说明
startRemoteView
channelId 通道绑定渲染视图并播放实时画面。channelId 表示设备的视频通道,每个通道对应设备的一个摄像头,需与设备端通道编号对齐,单通道设备使用 0streamType 为码流类型(HD 高清 / SD 流畅)。小程序端不传视图对象,需先用 setIoTPlayer 绑定 <iot-player> 组件。
startSession
与目标设备建立监控会话,deviceId 为目标设备标识(productId + deviceName)。
Android
iOS
// remoteView 为布局中的 TXCloudVideoView
TXCloudVideoView remoteView = findViewById(R.id.remote_view);

int channelId = 0; // 单通道设备使用 0
// 先绑定渲染视图,再开始会话,可减少一次通道协商
session.startRemoteView(channelId, TXIoTStreamType.HD, remoteView);

TXIoTDeviceId deviceId = new TXIoTDeviceId();
deviceId.productId = "已绑定到当前账户的 productId";
deviceId.deviceName = "已绑定到当前账户的 deviceName";

session.startSession(deviceId);
// remoteView 为布局中的 UIView
UIView *remoteView = self.remoteVideoView;

NSInteger channelId = 0; // 单通道设备使用 0
// 先绑定渲染视图,再开始会话,可减少一次通道协商
[session startRemoteView:channelId streamType:TXIoTStreamTypeHD view:remoteView];

TXIoTDeviceId *deviceId = [[TXIoTDeviceId alloc] init];
deviceId.productId = @"已绑定到当前账户的 productId";
deviceId.deviceName = @"已绑定到当前账户的 deviceName";

[session startSession:deviceId];
说明:
即使设备没有视频画面(例如纯语音对讲场景),小程序端仍需通过 setIoTPlayer 绑定 <iot-player> 组件,音频通过该组件播放。

步骤 4:停止拉流并释放资源

退出监控页面时,先停止通道播放,再停止会话并移除监听。
Android
iOS
小程序
session.stopRemoteView(0);
session.stopSession();
session.removeListener(monitorListener);
[session stopRemoteView:0];
[session stopSession];
[session removeDelegate:self];
// 一般在页面 onHide / onUnload 中调用
session.stopRemoteView(0);
session.stopSession();
session.removeListener(monitorListener);

常用能力

切换视频清晰度

观看过程中可动态切换通道画面的清晰度,无需重新建立会话。应用端切换后,SDK 会将清晰度要求同步给设备端,由设备推送对应清晰度的视频流。
注意:
不同清晰度可能对应不同的计费标准,请确保应用端实际使用的清晰度与用户购买的套餐一致,避免因清晰度与计费套餐不匹配引发计费争议。
Android
iOS
// 切换为流畅流
session.switchRemoteStream(0, TXIoTStreamType.SD);
// 切换为高清流
session.switchRemoteStream(0, TXIoTStreamType.HD);
// 切换为流畅流
[session switchRemoteStream:0 streamType:TXIoTStreamTypeSD];
// 切换为高清流
[session switchRemoteStream:0 streamType:TXIoTStreamTypeHD];

远端音频控制与语音对讲

muteRemoteAudio 控制单个通道的远端音频,muteAllRemoteAudio 控制所有通道。开启语音对讲时调用 startLocalAudio 采集并上行本地音频,结束时调用 stopLocalAudio;对讲期间可用 muteLocalAudio 临时停止上行。
Android
iOS
// 静音 0 号通道的远端声音
session.muteRemoteAudio(0, true);
// 静音全部通道
session.muteAllRemoteAudio(true);

// 开启语音对讲(需先获取麦克风权限)
session.startLocalAudio();
// 对讲过程中临时停止上行
session.muteLocalAudio(true);
// 结束对讲
session.stopLocalAudio();
// 静音 0 号通道的远端声音
[session muteRemoteAudio:0 mute:YES];
// 静音全部通道
[session muteAllRemoteAudio:YES];

// 开启语音对讲(需先获取麦克风权限)
[session startLocalAudio];
// 对讲过程中临时停止上行
[session muteLocalAudio:YES];
// 结束对讲
[session stopLocalAudio];

多通道同时拉流

枪球一体机、多目摄像机等设备包含多个视频通道。为每个通道分别调用 startRemoteView 绑定独立视图即可同时观看,SDK 会在一次会话内统一订阅这些通道。
说明:
建议在调用 startSession 之前为全部需要观看的通道都完成 startRemoteView;会话建立后新增通道会触发一次通道协商,画面出图相对更慢。所有已请求通道均进入播放状态后才会回调 onSessionEstablished
Android
iOS
// 同时观看 0、1 两个通道
session.startRemoteView(0, TXIoTStreamType.HD, remoteView0);
session.startRemoteView(1, TXIoTStreamType.HD, remoteView1);
session.startSession(deviceId);

// 仅关闭 1 号通道,0 号通道继续播放
session.stopRemoteView(1);
// 同时观看 0、1 两个通道
[session startRemoteView:0 streamType:TXIoTStreamTypeHD view:self.remoteView0];
[session startRemoteView:1 streamType:TXIoTStreamTypeHD view:self.remoteView1];
[session startSession:deviceId];

// 仅关闭 1 号通道,0 号通道继续播放
[session stopRemoteView:1];

截图与本地录制

takeSnapshot 对指定通道的当前画面截图,结果通过 onSnapshotComplete 返回。startLocalRecording 将指定通道的音视频录制到本地文件,录制过程通过 onLocalRecordBeginonLocalRecordingonLocalRecordComplete 回调通知。
注意:
TXIoTLocalRecordingParams.filePath 为必填项。若传入空字符串,SDK 会通过 onLocalRecordBegin 回调 ERR_INVALID_PARAMETER(iOS 为 TXIoTErrorCodeInvalidParameter)而不会开始录制。多通道设备的截图与录制均按 channelId 独立进行,如需同时录制多个通道,请对每个通道分别调用。
Android
iOS
// 截图,结果通过 onSnapshotComplete(channelId, bitmap, errCode) 返回
session.takeSnapshot(0);

// 本地录制
TXIoTLocalRecordingParams params = new TXIoTLocalRecordingParams();
params.filePath = getExternalFilesDir(null) + "/monitor_record.mp4";
session.startLocalRecording(0, params);

// 结束录制,完成后回调 onLocalRecordComplete
session.stopLocalRecording(0);
// 截图,结果通过 onSnapshotComplete:image:errorCode: 返回
[session takeSnapshot:0];

// 本地录制
TXIoTLocalRecordingParams *params = [[TXIoTLocalRecordingParams alloc] init];
params.filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"monitor_record.mp4"];
[session startLocalRecording:0 params:params];

// 结束录制,完成后回调 onLocalRecordComplete:errorCode:storagePath:
[session stopLocalRecording:0];

PTZ 云台控制

对支持云台的设备,通过 sendPTZCommand 下发转动与变焦指令,speed 为转动速度。手势拖动等高频场景下 SDK 会自动合并待发送指令并串行下发,业务层无需自行节流。松手时下发 STOP 停止转动。
Android
iOS
// 向左转动
session.sendPTZCommand(0, TXIoTPTZCommand.LEFT, 5);
// 松手停止
session.sendPTZCommand(0, TXIoTPTZCommand.STOP, 0);
// 画面放大
session.sendPTZCommand(0, TXIoTPTZCommand.ZOOM_IN, 5);
// 向左转动
[session sendPTZCommand:0 command:TXIoTPTZCommandLeft speed:5];
// 松手停止
[session sendPTZCommand:0 command:TXIoTPTZCommandStop speed:0];
// 画面放大
[session sendPTZCommand:0 command:TXIoTPTZCommandZoomIn speed:5];

状态与回调通知

监控会话通过监听接口(Android:TXIoTMonitorSessionListener,iOS:TXIoTMonitorSessionDelegate)回调状态与错误:
回调
触发时机
关键参数
onSessionEstablished
监控会话建立成功,所有已请求通道均进入播放状态。
无。
onSessionReconnecting
会话中断,SDK 正在自动重连。
无。
onSessionRecovery
会话重连成功,画面恢复。
无。
onRenderFirstFrame
指定通道首帧已渲染,可用于隐藏加载动画。
channelId
onPlayStateChanged
播放状态变化,用于驱动 loading 与占位图。
channelId, statePLAYING / LOADING / STOPPED
onSnapshotComplete
截图完成。
channelId 与截图结果(Android 为 Bitmap,iOS 为 TXImage,小程序为图片路径)
onLocalRecordBegin
本地录制开始,或因参数非法未能开始。
channelId, errCode, storagePath
onLocalRecording
录制进度更新。
channelId, durationMs, storagePath
onLocalRecordComplete
本地录制结束。
channelId, errCode, storagePath
onError
会话或某通道发生错误。
channelId, errCode, errMsg
注意:
会话中断时会先触发 onSessionReconnecting,SDK 自动尝试重连;重连成功触发 onSessionRecovery,无需业务层主动重建会话。若重连仍然失败,最终通过 onError 回调错误。

常见问题

调用 startSession 后一直没有画面,如何排查?

按以下顺序排查:
1. 确认监听在 startSession 之前注册,否则可能错过 onSessionEstablished 与早期的 onError
2. 检查是否收到 onError。若为 ERR_DEVICE_OFFLINE,说明设备已离线;若为 ERR_UNAUTHORIZED_OPERATION,说明当前账户没有该设备的权限,请先完成 设备绑定
3. 确认 startRemoteView 传入的 channelId 与设备端通道编号一致。通道编号不匹配时设备不会推送对应通道的流,onPlayStateChanged 会长期停留在 LOADING
4. 确认渲染视图已正确加载且尺寸不为0(小程序端确认 setIoTPlayer 传入的 component-id<iot-player> 一致)。
5. 若通道长时间处于 LOADING,SDK 会判定为加载超时并自动重试一次;仍失败则通过 onError 回调,此时应引导用户检查设备网络与在线状态。

监控过程中会被视频通话打断吗?

会。监控拉流的优先级低于视频通话。若设备正在被监控,此时对该设备发起视频通话,视频通话会抢占设备的推流能力:应用端会收到 onError 回调 ERR_DEVICE_SWITCH_TO_VOIP(iOS 为 TXIoTErrorCodeDeviceSwitchToVoIP),且当前监控会话会自动停止。业务层应在收到该错误后更新界面状态,不需要再调用 stopSession。视频通话相关能力参见 视频通话

网络抖动导致画面中断,需要业务层自己重连吗?

不需要。SDK 内置自动重连:链路中断后先回调 onSessionReconnecting,重连成功回调 onSessionRecovery。建议在 onSessionReconnecting 中显示重连提示,在 onSessionRecovery 中恢复正常界面。仅当 SDK 自动重连失败时才会通过 onError 回调错误,此时再由业务层决定是否引导用户手动重试。

可以同时监控多台设备吗?

不可以。监控会话对象为单例,同一时刻只存在一个监控会话。切换观看设备时,必须先调用 stopSession 停止当前会话,再对新设备调用 startSession;未先停止会话时,新的 startSession 调用会被直接忽略。

一台设备有多个摄像头,如何同时查看?

为每个通道分别调用 startRemoteView 并绑定独立的渲染视图,SDK 会在同一会话内订阅这些通道,参见 多通道同时拉流。建议在 startSession 之前完成全部通道的绑定。

截图与录制可以对多个通道同时进行吗?

可以。takeSnapshotstartLocalRecordingstopLocalRecording 均以 channelId 为维度独立生效,需要对多个通道同时操作时,对每个通道分别调用即可,各通道的回调通过参数中的 channelId 区分。

接口参考

监控拉流相关接口的完整定义参见:
安防摄像头场景下的云台控制、语音对讲、录制与截图的进阶用法,参见 云台控制语音对讲录制与截图