@tencentcloud/sdk-mcp 1.7.8 → 1.7.9-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/knowledge/chunker.js +1 -0
- package/knowledge/frontmatter-meta.js +23 -0
- package/knowledge/path-meta.js +56 -0
- package/knowledge/search/filter-pool.js +9 -1
- package/knowledge/search/rank-profile.js +25 -0
- package/knowledge/search/requires-framework.js +4 -1
- package/knowledge/search/search-core.js +56 -1
- package/knowledge/search/search-pass.js +126 -5
- package/package.json +1 -1
- package/resource/index/manifest.json +1 -1
- package/resource/index/vectors/index.json +2 -2
- package/resource/integration/callkit/preset/android/integration.md +0 -2
- package/resource/integration/callkit/preset/ios/integration.md +0 -2
- package/resource/integration/livekit/preset/live/android/prepare-integration.md +0 -4
- package/resource/integration/livekit/preset/live/ios/prepare-integration.md +0 -4
- package/resource/knowledge/callkit/best-practice/android/video-chat-dating.md +0 -2
- package/resource/knowledge/callkit/core-sdk/android/answer-call.md +0 -2
- package/resource/knowledge/callkit/core-sdk/android/make-call.md +0 -2
- package/resource/knowledge/callkit/core-sdk/flutter/answer-call.md +0 -4
- package/resource/knowledge/callkit/core-sdk/flutter/make-call.md +0 -2
- package/resource/knowledge/callkit/core-sdk/flutter/offline-push.md +0 -2
- package/resource/knowledge/callkit/core-sdk/ios/answer-call.md +0 -2
- package/resource/knowledge/callkit/core-sdk/ios/make-call.md +0 -4
- package/resource/knowledge/callkit/core-sdk/ios/offline-push.md +0 -2
- package/resource/knowledge/callkit/core-sdk/uni-app/answer-call.md +0 -2
- package/resource/knowledge/callkit/core-sdk/uni-app/make-call.md +0 -2
- package/resource/knowledge/callkit/faq/ios.md +0 -2
- package/resource/knowledge/callkit/faq/uniapp-app.md +0 -2
- package/resource/knowledge/callkit/preset/miniprogram/integration.md +0 -2
- package/resource/knowledge/callkit/preset/miniprogram/uniapp-integration.md +0 -2
- package/resource/knowledge/iot/app/activate-service.md +95 -0
- package/resource/knowledge/iot/app/demo/android.md +93 -0
- package/resource/knowledge/iot/app/demo/ios.md +87 -0
- package/resource/knowledge/iot/app/demo/miniprogram.md +79 -0
- package/resource/knowledge/iot/app/device-binding.md +378 -0
- package/resource/knowledge/iot/app/device-sharing.md +414 -0
- package/resource/knowledge/iot/app/family-management.md +762 -0
- package/resource/knowledge/iot/app/integration/android.md +328 -0
- package/resource/knowledge/iot/app/integration/harmonyos.md +326 -0
- package/resource/knowledge/iot/app/integration/ios.md +351 -0
- package/resource/knowledge/iot/app/integration/miniprogram.md +268 -0
- package/resource/knowledge/iot/app/monitor-playback.md +557 -0
- package/resource/knowledge/iot/app/remote-control.md +139 -0
- package/resource/knowledge/iot/app/video-call.md +559 -0
- package/resource/knowledge/iot/app/wechat-call/device-call-miniprogram.md +204 -0
- package/resource/knowledge/iot/app/wechat-call/miniprogram-call-device.md +193 -0
- package/resource/knowledge/iot/client-api/app/android/txiotcallsession.md +189 -0
- package/resource/knowledge/iot/client-api/app/android/txiotcloudstorage.md +77 -0
- package/resource/knowledge/iot/client-api/app/android/txiotdevicemanager.md +175 -0
- package/resource/knowledge/iot/client-api/app/android/txiotengine.md +172 -0
- package/resource/knowledge/iot/client-api/app/android/txiotenginedef.md +163 -0
- package/resource/knowledge/iot/client-api/app/android/txiotfamilymanager.md +146 -0
- package/resource/knowledge/iot/client-api/app/android/txiotmonitorsession.md +246 -0
- package/resource/knowledge/iot/client-api/app/harmonyos/txiotcallsession.md +191 -0
- package/resource/knowledge/iot/client-api/app/harmonyos/txiotcloudstorage.md +77 -0
- package/resource/knowledge/iot/client-api/app/harmonyos/txiotdevicemanager.md +183 -0
- package/resource/knowledge/iot/client-api/app/harmonyos/txiotengine.md +186 -0
- package/resource/knowledge/iot/client-api/app/harmonyos/txiotenginedef.md +164 -0
- package/resource/knowledge/iot/client-api/app/harmonyos/txiotfamilymanager.md +150 -0
- package/resource/knowledge/iot/client-api/app/harmonyos/txiotmonitorsession.md +252 -0
- package/resource/knowledge/iot/client-api/app/ios/txiotcallsession.md +199 -0
- package/resource/knowledge/iot/client-api/app/ios/txiotcloudstorage.md +76 -0
- package/resource/knowledge/iot/client-api/app/ios/txiotdevicemanager.md +173 -0
- package/resource/knowledge/iot/client-api/app/ios/txiotengine.md +173 -0
- package/resource/knowledge/iot/client-api/app/ios/txiotenginedef.md +171 -0
- package/resource/knowledge/iot/client-api/app/ios/txiotfamilymanager.md +146 -0
- package/resource/knowledge/iot/client-api/app/ios/txiotmonitorsession.md +250 -0
- package/resource/knowledge/iot/client-api/app/miniprogram/txiotcallsession.md +180 -0
- package/resource/knowledge/iot/client-api/app/miniprogram/txiotcloudstorage.md +76 -0
- package/resource/knowledge/iot/client-api/app/miniprogram/txiotdevicemanager.md +281 -0
- package/resource/knowledge/iot/client-api/app/miniprogram/txiotengine.md +183 -0
- package/resource/knowledge/iot/client-api/app/miniprogram/txiotenginedef.md +152 -0
- package/resource/knowledge/iot/client-api/app/miniprogram/txiotfamilymanager.md +179 -0
- package/resource/knowledge/iot/client-api/app/miniprogram/txiotmonitorsession.md +226 -0
- package/resource/knowledge/iot/client-api/device/android-smart-device.md +813 -0
- package/resource/knowledge/iot/client-api/device/linux-rtos-device.md +2027 -0
- package/resource/knowledge/iot/device/activate-service.md +167 -0
- package/resource/knowledge/iot/device/ai-voice-chat/advanced-features/custom-agent.md +171 -0
- package/resource/knowledge/iot/device/ai-voice-chat/advanced-features/smart-device-control.md +721 -0
- package/resource/knowledge/iot/device/ai-voice-chat/integration-guide/android-smart-device.md +247 -0
- package/resource/knowledge/iot/device/ai-voice-chat/integration-guide/linux-rtos-device.md +368 -0
- package/resource/knowledge/iot/device/ai-voice-chat/overview.md +84 -0
- package/resource/knowledge/iot/device/cloud-storage.md +696 -0
- package/resource/knowledge/iot/device/data-model.md +972 -0
- package/resource/knowledge/iot/device/demo/android-smart-device.md +97 -0
- package/resource/knowledge/iot/device/demo/linux-rtos-device.md +106 -0
- package/resource/knowledge/iot/device/device-ota-upgrade.md +237 -0
- package/resource/knowledge/iot/device/dynamic-registration/android-smart-device.md +275 -0
- package/resource/knowledge/iot/device/dynamic-registration/linux-rtos-device.md +297 -0
- package/resource/knowledge/iot/device/login-and-register/android-smart-device.md +131 -0
- package/resource/knowledge/iot/device/login-and-register/linux-rtos-device.md +291 -0
- package/resource/knowledge/iot/device/monitor-pushing/android-smart-device.md +237 -0
- package/resource/knowledge/iot/device/monitor-pushing/linux-rtos-device.md +493 -0
- package/resource/knowledge/iot/device/video-call/android-smart-device.md +299 -0
- package/resource/knowledge/iot/device/video-call/linux-rtos-device.md +465 -0
- package/resource/knowledge/iot/device/wechat-call/android-smart-device.md +534 -0
- package/resource/knowledge/iot/device/wechat-call/linux-rtos-device.md +681 -0
- package/resource/knowledge/iot/kids-watch/overview.md +28 -0
- package/resource/knowledge/iot/security-camera/activate-service.md +74 -0
- package/resource/knowledge/iot/security-camera/monitor-playback/app-integration.md +302 -0
- package/resource/knowledge/iot/security-camera/monitor-playback/device-integration/android.md +237 -0
- package/resource/knowledge/iot/security-camera/monitor-playback/device-integration/linux-rtos.md +493 -0
- package/resource/knowledge/iot/security-camera/overview.md +31 -0
- package/resource/knowledge/iot/security-camera/ptz-control.md +153 -0
- package/resource/knowledge/iot/security-camera/recording-and-snapshot.md +182 -0
- package/resource/knowledge/iot/security-camera/voice-intercom.md +174 -0
- package/resource/knowledge/iot/smart-vision/serviceoverview.md +114 -0
- package/resource/knowledge/iot/voice-recorder/app-demo.md +99 -0
- package/resource/knowledge/iot/voice-recorder/device-demo.md +189 -0
- package/resource/knowledge/iot/voice-recorder/overview.md +64 -0
- package/resource/knowledge/livekit/core-sdk/features/android/base-beauty.md +0 -2
- package/resource/knowledge/livekit/core-sdk/features/android/gift.md +0 -4
- package/resource/knowledge/livekit/core-sdk/features/android/live-list.md +0 -2
- package/resource/knowledge/livekit/core-sdk/features/flutter/audio-effect.md +0 -2
- package/resource/knowledge/livekit/core-sdk/features/flutter/base-beauty.md +0 -2
- package/resource/knowledge/livekit/core-sdk/features/flutter/gift.md +0 -4
- package/resource/knowledge/livekit/core-sdk/features/ios/base-beauty.md +0 -2
- package/resource/knowledge/livekit/core-sdk/features/ios/gift.md +0 -4
- package/resource/knowledge/livekit/core-sdk/features/ios/live-list.md +0 -2
- package/resource/knowledge/livekit/core-sdk/features/uni-app/base-beauty.md +0 -2
- package/resource/knowledge/livekit/core-sdk/features/uni-app/gift.md +0 -4
- package/resource/knowledge/livekit/core-sdk/live/android/co-guest-interaction.md +0 -4
- package/resource/knowledge/livekit/core-sdk/live/android/host-interaction.md +0 -10
- package/resource/knowledge/livekit/core-sdk/live/android/integration.md +0 -2
- package/resource/knowledge/livekit/core-sdk/live/flutter/co-guest-interaction.md +0 -2
- package/resource/knowledge/livekit/core-sdk/live/flutter/host-interaction.md +0 -10
- package/resource/knowledge/livekit/core-sdk/live/flutter/integration.md +0 -2
- package/resource/knowledge/livekit/core-sdk/live/ios/co-guest-interaction.md +0 -4
- package/resource/knowledge/livekit/core-sdk/live/ios/host-interaction.md +0 -10
- package/resource/knowledge/livekit/core-sdk/live/ios/integration.md +0 -2
- package/resource/knowledge/livekit/core-sdk/live/uni-app/co-guest-interaction.md +0 -4
- package/resource/knowledge/livekit/core-sdk/live/uni-app/host-interaction.md +0 -4
- package/resource/knowledge/livekit/core-sdk/live/uni-app/integration.md +0 -2
- package/resource/knowledge/livekit/core-sdk/voice/android/co-guest-interaction.md +0 -2
- package/resource/knowledge/livekit/core-sdk/voice/android/host-interaction.md +0 -4
- package/resource/knowledge/livekit/core-sdk/voice/android/integration.md +0 -4
- package/resource/knowledge/livekit/core-sdk/voice/flutter/integration.md +0 -2
- package/resource/knowledge/livekit/core-sdk/voice/ios/co-guest-interaction.md +0 -2
- package/resource/knowledge/livekit/core-sdk/voice/ios/host-interaction.md +0 -4
- package/resource/knowledge/livekit/core-sdk/voice/ios/integration.md +0 -4
- package/resource/knowledge/livekit/core-sdk/voice/uni-app/co-guest-interaction.md +0 -2
- package/resource/knowledge/livekit/core-sdk/voice/uni-app/integration.md +0 -2
- package/resource/knowledge/livekit/faq/error-code.md +0 -2
- package/resource/knowledge/push/config/donut.md +0 -2
- package/resource/knowledge/push/integration/android.md +0 -5
- package/resource/knowledge/push/integration/donut.md +0 -3
- package/resource/knowledge/push/integration/flutter.md +0 -3
- package/resource/knowledge/push/integration/harmonyos.md +0 -3
- package/resource/knowledge/push/integration/ios.md +0 -3
- package/resource/knowledge/push/integration/react-native.md +0 -5
- package/resource/knowledge/push/integration/uni-app.md +0 -3
- package/resource/knowledge/push/integration/unity.md +0 -3
- package/resource/knowledge/push/integration/unreal-engine.md +0 -3
- package/resource/knowledge/roomkit/core-sdk/android/call-user-to-room.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/android/room-participant-state.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/android/room-state.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/android/schedule-room.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/flutter/call-user-to-room.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/flutter/room-participant-state.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/flutter/room-state.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/flutter/schedule-room.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/ios/call-user-to-room.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/ios/room-participant-state.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/ios/room-state.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/ios/schedule-room.md +0 -2
- package/resource/knowledge/roomkit/core-sdk/vue/room-view.md +0 -3
- package/resource/knowledge/rtcengine/web/how_to_run_web_sdk_demo.md +0 -2
- package/resource/knowledge/rtcengine/web/plugin/24-advanced-network-quality.md +0 -2
- package/tools/common/finalize_answer.js +1 -1
- package/tools/common/search_trtc_knowledge.js +2 -2
- package/tools/definitions/search_trtc_knowledge_def.js +3 -2
- package/utils/preflight-route.js +11 -2
package/resource/knowledge/iot/security-camera/monitor-playback/device-integration/linux-rtos.md
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
---
|
|
2
|
+
product: iot
|
|
3
|
+
framework:
|
|
4
|
+
- linux
|
|
5
|
+
types:
|
|
6
|
+
- feature
|
|
7
|
+
retrievable_scope: always
|
|
8
|
+
feature_domain: security-camera
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
本文将介绍设备如何实现响应 APP 发起的**监控请求**、**推送音频帧与视频帧**、 **切换清晰度**,帮助您快速了解实时监控的功能。
|
|
12
|
+
|
|
13
|
+
## 前提条件
|
|
14
|
+
|
|
15
|
+
在开始之前,请您先完成 快速接入 文档中跑通 `tc_iot_login` 登录功能。如果您已经完成,可以跳过该操作。
|
|
16
|
+
|
|
17
|
+
## 接入步骤
|
|
18
|
+
|
|
19
|
+
### 步骤 1:注册监控事件回调
|
|
20
|
+
|
|
21
|
+
登录成功后,调用 `tc_iot_av_init` 注册 `tc_iot_av_observer_s`,实时监控相关的回调如下:
|
|
22
|
+
|
|
23
|
+
|回调|说明|
|
|
24
|
+
|---------|---------|
|
|
25
|
+
|`on_monitor_begin`|APP 发起监控查看请求时触发,携带 `channel_id`(本路监控的通道标识)与 `option`(媒体类型、清晰度等)。|
|
|
26
|
+
|`on_monitor_end`|对端结束监控查看时触发,携带 `channel_id`。|
|
|
27
|
+
|`on_monitor_switch`|APP 在监控查看期间切换清晰度时触发,携带 `channel_id` 与切换后的 `quality`(可选实现。|
|
|
28
|
+
|
|
29
|
+
``` c
|
|
30
|
+
#include "tc_iot_av.h"
|
|
31
|
+
|
|
32
|
+
static void on_monitor_begin(int channel_id, tc_iot_call_option_t option);
|
|
33
|
+
static void on_monitor_end(int channel_id);
|
|
34
|
+
static void on_monitor_switch(int channel_id, tc_iot_video_quality_e quality);
|
|
35
|
+
|
|
36
|
+
tc_iot_av_observer_s observer;
|
|
37
|
+
memset(&observer, 0, sizeof(observer));
|
|
38
|
+
observer.on_monitor_begin = on_monitor_begin;
|
|
39
|
+
observer.on_monitor_end = on_monitor_end;
|
|
40
|
+
observer.on_monitor_switch = on_monitor_switch;
|
|
41
|
+
|
|
42
|
+
tc_iot_error_e av_rc = tc_iot_av_init(&observer);
|
|
43
|
+
if (av_rc != TC_IOT_ERR_SUCCESS) {
|
|
44
|
+
printf("tc_iot_av_init failed: %d\n", av_rc);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 步骤 2:响应 on_monitor_begin,创建发送通道
|
|
49
|
+
|
|
50
|
+
根据 `option.media_content`,在 `on_monitor_begin` 回调中创建对应的发送通道:
|
|
51
|
+
|
|
52
|
+
|接口|说明|
|
|
53
|
+
|---------|---------|
|
|
54
|
+
|`tc_iot_create_video_channel(channel_id, quality)`|创建视频发送通道,`channel_id` 需与回调中的 `channel_id` 一致,`quality` 为视频清晰度。|
|
|
55
|
+
|`tc_iot_create_audio_channel()`|创建音频发送通道,无需传入 `channel_id`。|
|
|
56
|
+
|
|
57
|
+
> **注意:**
|
|
58
|
+
> 设备通常只有一路麦克风采集源,`tc_iot_create_audio_channel` 建议全局只创建一次;多路视频监控同时在线时,可共享同一路音频发送通道,无需重复创建。
|
|
59
|
+
>
|
|
60
|
+
|
|
61
|
+
``` c
|
|
62
|
+
static tc_iot_av_channel_t *g_video_channel = NULL;
|
|
63
|
+
static tc_iot_av_channel_t *g_audio_channel = NULL;
|
|
64
|
+
|
|
65
|
+
static void on_monitor_begin(int channel_id, tc_iot_call_option_t option) {
|
|
66
|
+
printf("[demo] on_monitor_begin channel_id=%d media=%d quality=%d\n",
|
|
67
|
+
channel_id, option.media_content, option.video_quality);
|
|
68
|
+
|
|
69
|
+
if (option.media_content == TC_IOT_MEDIA_CONTENT_VIDEO ||
|
|
70
|
+
option.media_content == TC_IOT_MEDIA_CONTENT_AUDIO_VIDEO) {
|
|
71
|
+
g_video_channel = tc_iot_create_video_channel(channel_id, option.video_quality);
|
|
72
|
+
if (!g_video_channel) {
|
|
73
|
+
printf("[demo] create video channel failed, channel_id=%d\n", channel_id);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if ((option.media_content == TC_IOT_MEDIA_CONTENT_AUDIO ||
|
|
78
|
+
option.media_content == TC_IOT_MEDIA_CONTENT_AUDIO_VIDEO) &&
|
|
79
|
+
!g_audio_channel) {
|
|
80
|
+
g_audio_channel = tc_iot_create_audio_channel();
|
|
81
|
+
if (!g_audio_channel) {
|
|
82
|
+
printf("[demo] create audio channel failed\n");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 启动本地采集(示意,详见步骤 3/4 推流示例)
|
|
87
|
+
// start_capture_and_push(...)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 步骤 3:推送视频帧
|
|
92
|
+
|
|
93
|
+
采集到一帧编码后的视频数据后,填充 `tc_iot_video_frame` 并调用 `tc_iot_push_video_frame` 推送到视频发送通道:
|
|
94
|
+
|
|
95
|
+
|字段|说明|
|
|
96
|
+
|---------|---------|
|
|
97
|
+
|`codec`|视频编码格式,`TC_IOT_VIDEO_CODEC_H264` 或 `TC_IOT_VIDEO_CODEC_H265`。|
|
|
98
|
+
|`type`|帧类型,关键帧 `TC_IOT_VIDEO_FRAME_TYPE_IDR` 或非关键帧 `TC_IOT_VIDEO_FRAME_TYPE_P`。|
|
|
99
|
+
|`rotation`|画面旋转角度,如 `TC_IOT_VIDEO_ROTATION_0`。|
|
|
100
|
+
|`width` / `height`|画面宽高(像素)。|
|
|
101
|
+
|`data` / `data_size`|编码后的视频裸流数据指针与长度。|
|
|
102
|
+
|`pts_ms`|帧时间戳(毫秒)。|
|
|
103
|
+
|
|
104
|
+
> **说明:**
|
|
105
|
+
> 建议推送第一个 **IDR 关键帧**之后才开始持续推流,以保证对端能正常解码;在 IDR 帧之前推送 P 帧,对端可能无法解码画面。
|
|
106
|
+
>
|
|
107
|
+
|
|
108
|
+
``` c
|
|
109
|
+
void push_video_frame_sample(tc_iot_av_channel_t *video_channel,
|
|
110
|
+
const uint8_t *encoded_data, size_t encoded_size,
|
|
111
|
+
bool is_key_frame) {
|
|
112
|
+
if (!video_channel) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
tc_iot_video_frame frame;
|
|
117
|
+
memset(&frame, 0, sizeof(frame));
|
|
118
|
+
frame.codec = TC_IOT_VIDEO_CODEC_H264;
|
|
119
|
+
frame.type = is_key_frame ? TC_IOT_VIDEO_FRAME_TYPE_IDR : TC_IOT_VIDEO_FRAME_TYPE_P;
|
|
120
|
+
frame.rotation = TC_IOT_VIDEO_ROTATION_0;
|
|
121
|
+
frame.width = 480;
|
|
122
|
+
frame.height = 320;
|
|
123
|
+
frame.data = (uint8_t *)encoded_data;
|
|
124
|
+
frame.data_size = encoded_size;
|
|
125
|
+
frame.pts_ms = current_time_ms(); // 由业务自行实现,返回当前毫秒时间戳
|
|
126
|
+
|
|
127
|
+
tc_iot_error_e err = tc_iot_push_video_frame(video_channel, &frame);
|
|
128
|
+
if (err != TC_IOT_ERR_SUCCESS) {
|
|
129
|
+
printf("[demo] push video frame failed: %d\n", err);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 步骤 4:推送音频帧
|
|
135
|
+
|
|
136
|
+
采集到一帧编码后的音频数据后,填充 `tc_iot_audio_frame` 并调用 `tc_iot_push_audio_frame` 推送到音频发送通道:
|
|
137
|
+
|
|
138
|
+
|字段|说明|
|
|
139
|
+
|---------|---------|
|
|
140
|
+
|`codec`|音频编码格式,支持 `TC_IOT_AUDIO_CODEC_PCM` / `AAC` / `OPUS` / `G722`。|
|
|
141
|
+
|`sample_rate`|采样率,如 `TC_IOT_AUDIO_SAMPLE_RATE_16000`。|
|
|
142
|
+
|`channels`|声道数,`TC_IOT_AUDIO_CHANNEL_MONO`(单声道)或 `TC_IOT_AUDIO_CHANNEL_STEREO`(双声道)。|
|
|
143
|
+
|`frame_duration_ms`|单帧时长(毫秒),如 20ms 一帧。|
|
|
144
|
+
|`data` / `data_size`|编码后的音频裸流数据指针与长度。|
|
|
145
|
+
|`pts_ms`|帧时间戳(毫秒)。|
|
|
146
|
+
|
|
147
|
+
``` c
|
|
148
|
+
void push_audio_frame_sample(tc_iot_av_channel_t *audio_channel,
|
|
149
|
+
const uint8_t *pcm_data, size_t pcm_size) {
|
|
150
|
+
if (!audio_channel) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
tc_iot_audio_frame frame;
|
|
155
|
+
memset(&frame, 0, sizeof(frame));
|
|
156
|
+
frame.codec = TC_IOT_AUDIO_CODEC_PCM;
|
|
157
|
+
frame.sample_rate = TC_IOT_AUDIO_SAMPLE_RATE_16000;
|
|
158
|
+
frame.channels = TC_IOT_AUDIO_CHANNEL_MONO;
|
|
159
|
+
frame.frame_duration_ms = 20;
|
|
160
|
+
frame.data = (uint8_t *)pcm_data;
|
|
161
|
+
frame.data_size = pcm_size;
|
|
162
|
+
frame.pts_ms = current_time_ms(); // 由业务自行实现,返回当前毫秒时间戳
|
|
163
|
+
|
|
164
|
+
tc_iot_error_e err = tc_iot_push_audio_frame(audio_channel, &frame);
|
|
165
|
+
if (err != TC_IOT_ERR_SUCCESS) {
|
|
166
|
+
printf("[demo] push audio frame failed: %d\n", err);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 步骤 5:响应 on_monitor_switch,切换视频清晰度(可选)
|
|
172
|
+
|
|
173
|
+
APP 端在监控查看期间切换清晰度时,设备端会通过 `on_monitor_switch` 回调收到通知,携带 `channel_id`(对应的监控通道)与 `quality`(切换后的清晰度)。`quality` 的可选取值(`tc_iot_video_quality_e`)如下:
|
|
174
|
+
|
|
175
|
+
|取值|说明|
|
|
176
|
+
|---------|---------|
|
|
177
|
+
|`TC_IOT_VIDEO_QUALITY_UNKNOWN`|未知/未设置。|
|
|
178
|
+
|`TC_IOT_VIDEO_QUALITY_LD`|流畅(低清晰度)。|
|
|
179
|
+
|`TC_IOT_VIDEO_QUALITY_SD`|标清。|
|
|
180
|
+
|`TC_IOT_VIDEO_QUALITY_HD`|高清。|
|
|
181
|
+
|`TC_IOT_VIDEO_QUALITY_FHD`|超清(全高清)。|
|
|
182
|
+
|
|
183
|
+
视频发送通道创建时已固定清晰度,无法直接修改,因此收到 `on_monitor_switch` 后需要**销毁旧通道、按新清晰度重新创建**,后续视频帧继续推送到新通道即可:
|
|
184
|
+
``` c
|
|
185
|
+
static void on_monitor_switch(int channel_id, tc_iot_video_quality_e quality) {
|
|
186
|
+
printf("[demo] on_monitor_switch channel_id=%d quality=%d\n", channel_id, quality);
|
|
187
|
+
|
|
188
|
+
if (g_video_channel) {
|
|
189
|
+
tc_iot_destroy_video_channel(g_video_channel);
|
|
190
|
+
g_video_channel = NULL;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
g_video_channel = tc_iot_create_video_channel(channel_id, quality);
|
|
194
|
+
if (!g_video_channel) {
|
|
195
|
+
printf("[demo] recreate video channel failed, channel_id=%d\n", channel_id);
|
|
196
|
+
}
|
|
197
|
+
// 后续采集到的视频帧继续调用 tc_iot_push_video_frame 推送到新的 g_video_channel
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
> **注意:**
|
|
202
|
+
> 重建通道期间会短暂中断视频推流,建议尽快完成切换,并在重建后尽快推送一个 IDR 关键帧,保证画面能快速恢复。
|
|
203
|
+
>
|
|
204
|
+
|
|
205
|
+
### 步骤 6:响应 on_monitor_end,销毁发送通道
|
|
206
|
+
|
|
207
|
+
对端结束监控查看时触发 `on_monitor_end`,此时应停止采集并销毁对应的发送通道:
|
|
208
|
+
``` c
|
|
209
|
+
static void on_monitor_end(int channel_id) {
|
|
210
|
+
printf("[demo] on_monitor_end channel_id=%d\n", channel_id);
|
|
211
|
+
|
|
212
|
+
// 停止本地采集(示意,详见业务实现)
|
|
213
|
+
// stop_capture(...)
|
|
214
|
+
|
|
215
|
+
if (g_video_channel) {
|
|
216
|
+
tc_iot_destroy_video_channel(g_video_channel);
|
|
217
|
+
g_video_channel = NULL;
|
|
218
|
+
}
|
|
219
|
+
if (g_audio_channel) {
|
|
220
|
+
tc_iot_destroy_audio_channel(g_audio_channel);
|
|
221
|
+
g_audio_channel = NULL;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
> **说明:**
|
|
227
|
+
> 单个设备可同时存在多路监控发送通道(对应不同的 `channel_id`),本文仅演示单路场景;多路并发时建议用数组或列表管理各 `channel_id` 对应的通道指针与采集资源。
|
|
228
|
+
>
|
|
229
|
+
|
|
230
|
+
## 完整示例代码
|
|
231
|
+
``` c
|
|
232
|
+
#include <stdio.h>
|
|
233
|
+
#include <stdlib.h>
|
|
234
|
+
#include <string.h>
|
|
235
|
+
#include <stdbool.h>
|
|
236
|
+
#include <unistd.h>
|
|
237
|
+
#include <pthread.h>
|
|
238
|
+
#include <sys/time.h>
|
|
239
|
+
#include "tc_iot.h"
|
|
240
|
+
#include "tc_iot_av.h"
|
|
241
|
+
|
|
242
|
+
static volatile int s_login_done = 0;
|
|
243
|
+
static tc_iot_error_e s_login_rc = TC_IOT_ERR_SUCCESS;
|
|
244
|
+
|
|
245
|
+
static tc_iot_av_channel_t *g_video_channel = NULL;
|
|
246
|
+
static tc_iot_av_channel_t *g_audio_channel = NULL;
|
|
247
|
+
static volatile bool g_pushing = false;
|
|
248
|
+
static pthread_t g_video_thread;
|
|
249
|
+
static pthread_t g_audio_thread;
|
|
250
|
+
|
|
251
|
+
static uint64_t current_time_ms(void) {
|
|
252
|
+
struct timeval tv;
|
|
253
|
+
gettimeofday(&tv, NULL);
|
|
254
|
+
return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 登录回调:与快速接入一致
|
|
258
|
+
static void on_login(tc_iot_error_e error_code, const char *error_message) {
|
|
259
|
+
s_login_rc = error_code;
|
|
260
|
+
s_login_done = 1;
|
|
261
|
+
if (error_code != TC_IOT_ERR_SUCCESS) {
|
|
262
|
+
printf("[demo] login failed: %d, msg=%s\n", error_code,
|
|
263
|
+
error_message ? error_message : "");
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// 模拟视频采集:独立线程定时生成占位视频帧(首帧标记为 IDR)并推送。
|
|
268
|
+
// 实际接入时替换为真实摄像头采集与 H264/H265 编码逻辑。
|
|
269
|
+
static void *video_push_thread_func(void *arg) {
|
|
270
|
+
static uint8_t dummy_video[64] = {0};
|
|
271
|
+
bool first_frame = true;
|
|
272
|
+
|
|
273
|
+
while (g_pushing) {
|
|
274
|
+
if (g_video_channel) {
|
|
275
|
+
tc_iot_video_frame vframe;
|
|
276
|
+
memset(&vframe, 0, sizeof(vframe));
|
|
277
|
+
vframe.codec = TC_IOT_VIDEO_CODEC_H264;
|
|
278
|
+
vframe.type = first_frame ? TC_IOT_VIDEO_FRAME_TYPE_IDR
|
|
279
|
+
: TC_IOT_VIDEO_FRAME_TYPE_P;
|
|
280
|
+
vframe.rotation = TC_IOT_VIDEO_ROTATION_0;
|
|
281
|
+
vframe.width = 480;
|
|
282
|
+
vframe.height = 320;
|
|
283
|
+
vframe.data = dummy_video;
|
|
284
|
+
vframe.data_size = sizeof(dummy_video);
|
|
285
|
+
vframe.pts_ms = current_time_ms();
|
|
286
|
+
tc_iot_push_video_frame(g_video_channel, &vframe);
|
|
287
|
+
first_frame = false;
|
|
288
|
+
}
|
|
289
|
+
usleep(40 * 1000); // 模拟 25fps
|
|
290
|
+
}
|
|
291
|
+
return NULL;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 模拟音频采集:独立线程定时生成占位音频帧并推送。
|
|
295
|
+
// 实际接入时替换为真实麦克风采集与 PCM/AAC 编码逻辑。
|
|
296
|
+
static void *audio_push_thread_func(void *arg) {
|
|
297
|
+
static uint8_t dummy_audio[320] = {0}; // 16kHz/mono/20ms 对应的 PCM 采样点数
|
|
298
|
+
|
|
299
|
+
while (g_pushing) {
|
|
300
|
+
if (g_audio_channel) {
|
|
301
|
+
tc_iot_audio_frame aframe;
|
|
302
|
+
memset(&aframe, 0, sizeof(aframe));
|
|
303
|
+
aframe.codec = TC_IOT_AUDIO_CODEC_PCM;
|
|
304
|
+
aframe.sample_rate = TC_IOT_AUDIO_SAMPLE_RATE_16000;
|
|
305
|
+
aframe.channels = TC_IOT_AUDIO_CHANNEL_MONO;
|
|
306
|
+
aframe.frame_duration_ms = 20;
|
|
307
|
+
aframe.data = dummy_audio;
|
|
308
|
+
aframe.data_size = sizeof(dummy_audio);
|
|
309
|
+
aframe.pts_ms = current_time_ms();
|
|
310
|
+
tc_iot_push_audio_frame(g_audio_channel, &aframe);
|
|
311
|
+
}
|
|
312
|
+
usleep(20 * 1000); // 20ms 一帧
|
|
313
|
+
}
|
|
314
|
+
return NULL;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
static void on_monitor_begin(int channel_id, tc_iot_call_option_t option) {
|
|
318
|
+
printf("[demo] on_monitor_begin channel_id=%d media=%d quality=%d\n",
|
|
319
|
+
channel_id, option.media_content, option.video_quality);
|
|
320
|
+
|
|
321
|
+
if (option.media_content == TC_IOT_MEDIA_CONTENT_VIDEO ||
|
|
322
|
+
option.media_content == TC_IOT_MEDIA_CONTENT_AUDIO_VIDEO) {
|
|
323
|
+
g_video_channel = tc_iot_create_video_channel(channel_id, option.video_quality);
|
|
324
|
+
}
|
|
325
|
+
if ((option.media_content == TC_IOT_MEDIA_CONTENT_AUDIO ||
|
|
326
|
+
option.media_content == TC_IOT_MEDIA_CONTENT_AUDIO_VIDEO) &&
|
|
327
|
+
!g_audio_channel) {
|
|
328
|
+
g_audio_channel = tc_iot_create_audio_channel();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (!g_pushing) {
|
|
332
|
+
g_pushing = true;
|
|
333
|
+
pthread_create(&g_video_thread, NULL, video_push_thread_func, NULL);
|
|
334
|
+
pthread_create(&g_audio_thread, NULL, audio_push_thread_func, NULL);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
static void on_monitor_end(int channel_id) {
|
|
339
|
+
printf("[demo] on_monitor_end channel_id=%d\n", channel_id);
|
|
340
|
+
|
|
341
|
+
if (g_pushing) {
|
|
342
|
+
g_pushing = false;
|
|
343
|
+
pthread_join(g_video_thread, NULL);
|
|
344
|
+
pthread_join(g_audio_thread, NULL);
|
|
345
|
+
}
|
|
346
|
+
if (g_video_channel) {
|
|
347
|
+
tc_iot_destroy_video_channel(g_video_channel);
|
|
348
|
+
g_video_channel = NULL;
|
|
349
|
+
}
|
|
350
|
+
if (g_audio_channel) {
|
|
351
|
+
tc_iot_destroy_audio_channel(g_audio_channel);
|
|
352
|
+
g_audio_channel = NULL;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// 切换清晰度(本文步骤 5 核心内容,可选实现)
|
|
357
|
+
static void on_monitor_switch(int channel_id, tc_iot_video_quality_e quality) {
|
|
358
|
+
printf("[demo] on_monitor_switch channel_id=%d quality=%d\n", channel_id, quality);
|
|
359
|
+
|
|
360
|
+
if (g_video_channel) {
|
|
361
|
+
tc_iot_destroy_video_channel(g_video_channel);
|
|
362
|
+
g_video_channel = NULL;
|
|
363
|
+
}
|
|
364
|
+
g_video_channel = tc_iot_create_video_channel(channel_id, quality);
|
|
365
|
+
if (!g_video_channel) {
|
|
366
|
+
printf("[demo] recreate video channel failed, channel_id=%d\n", channel_id);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
int main(int argc, char **argv) {
|
|
371
|
+
if (argc < 7) {
|
|
372
|
+
printf("Usage: %s -p <product_id> -d <device_id> -s <device_secret>\n", argv[0]);
|
|
373
|
+
return 0;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const char *product_id = NULL;
|
|
377
|
+
const char *device_id = NULL;
|
|
378
|
+
const char *device_secret = NULL;
|
|
379
|
+
for (int i = 1; i < argc; i++) {
|
|
380
|
+
if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
|
|
381
|
+
product_id = argv[++i];
|
|
382
|
+
} else if (strcmp(argv[i], "-d") == 0 && i + 1 < argc) {
|
|
383
|
+
device_id = argv[++i];
|
|
384
|
+
} else if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
|
|
385
|
+
device_secret = argv[++i];
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (!product_id || !device_id || !device_secret) {
|
|
389
|
+
printf("device info error\n");
|
|
390
|
+
return 1;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// 初始化与登录:与快速接入一致
|
|
394
|
+
tc_iot_config_s config;
|
|
395
|
+
memset(&config, 0, sizeof(config));
|
|
396
|
+
config.storage_path = "./";
|
|
397
|
+
config.log_level = TC_IOT_LOG_LEVEL_INFO;
|
|
398
|
+
|
|
399
|
+
tc_iot_error_e rc = tc_iot_init(&config);
|
|
400
|
+
if (rc != TC_IOT_ERR_SUCCESS) {
|
|
401
|
+
printf("tc_iot_init failed: %d\n", rc);
|
|
402
|
+
return 1;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
tc_iot_device_info_s device_info;
|
|
406
|
+
device_info.product_id = product_id;
|
|
407
|
+
device_info.device_id = device_id;
|
|
408
|
+
device_info.device_secret = device_secret;
|
|
409
|
+
|
|
410
|
+
rc = tc_iot_login(&device_info, on_login);
|
|
411
|
+
if (rc != TC_IOT_ERR_SUCCESS) {
|
|
412
|
+
printf("tc_iot_login call failed: %d\n", rc);
|
|
413
|
+
tc_iot_deinit();
|
|
414
|
+
return 1;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
int waited_ms = 0;
|
|
418
|
+
while (!s_login_done && waited_ms < 5000) {
|
|
419
|
+
usleep(100 * 1000);
|
|
420
|
+
waited_ms += 100;
|
|
421
|
+
}
|
|
422
|
+
if (!s_login_done || s_login_rc != TC_IOT_ERR_SUCCESS) {
|
|
423
|
+
printf("login timeout or failed\n");
|
|
424
|
+
tc_iot_deinit();
|
|
425
|
+
return 1;
|
|
426
|
+
}
|
|
427
|
+
printf("[demo] login success\n");
|
|
428
|
+
|
|
429
|
+
// 注册监控事件回调(本文核心内容)
|
|
430
|
+
tc_iot_av_observer_s observer;
|
|
431
|
+
memset(&observer, 0, sizeof(observer));
|
|
432
|
+
observer.on_monitor_begin = on_monitor_begin;
|
|
433
|
+
observer.on_monitor_end = on_monitor_end;
|
|
434
|
+
observer.on_monitor_switch = on_monitor_switch;
|
|
435
|
+
|
|
436
|
+
rc = tc_iot_av_init(&observer);
|
|
437
|
+
if (rc != TC_IOT_ERR_SUCCESS) {
|
|
438
|
+
printf("tc_iot_av_init failed: %d\n", rc);
|
|
439
|
+
tc_iot_deinit();
|
|
440
|
+
return 1;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
printf("[demo] ready, waiting for monitor request from app/cloud (60s)...\n");
|
|
444
|
+
sleep(60);
|
|
445
|
+
|
|
446
|
+
// 释放资源
|
|
447
|
+
if (g_pushing) {
|
|
448
|
+
g_pushing = false;
|
|
449
|
+
pthread_join(g_video_thread, NULL);
|
|
450
|
+
pthread_join(g_audio_thread, NULL);
|
|
451
|
+
}
|
|
452
|
+
if (g_video_channel) {
|
|
453
|
+
tc_iot_destroy_video_channel(g_video_channel);
|
|
454
|
+
}
|
|
455
|
+
if (g_audio_channel) {
|
|
456
|
+
tc_iot_destroy_audio_channel(g_audio_channel);
|
|
457
|
+
}
|
|
458
|
+
tc_iot_av_deinit();
|
|
459
|
+
tc_iot_logout();
|
|
460
|
+
tc_iot_deinit();
|
|
461
|
+
printf("[demo] main exit\n");
|
|
462
|
+
return 0;
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## 编译并运行
|
|
467
|
+
|
|
468
|
+
将上述代码覆盖到 快速接入 中已创建的项目 `main.c`,`CMakeLists.txt` 无需改动,重新编译并运行即可。
|
|
469
|
+
1. 重新编译。
|
|
470
|
+
|
|
471
|
+
``` bash
|
|
472
|
+
cmake --build build -j
|
|
473
|
+
```
|
|
474
|
+
2. 运行可执行文件,传入设备三元组。
|
|
475
|
+
|
|
476
|
+
``` bash
|
|
477
|
+
./build/iot_quickstart_demo -p YOUR_PRODUCT_ID -d YOUR_DEVICE_NAME -s 'YOUR_DEVICE_SECRET'
|
|
478
|
+
```
|
|
479
|
+
3. 通过 APP 控制台对该设备发起监控查看请求,观察设备端日志输出 `on_monitor_begin` 及后续推流日志,即代表监控推流链路验证成功。
|
|
480
|
+
|
|
481
|
+
## 常见问题
|
|
482
|
+
|
|
483
|
+
|现象|排查建议|
|
|
484
|
+
|---------|---------|
|
|
485
|
+
|发起监控查看后,设备端未收到 `on_monitor_begin`|确认设备已成功登录且 `tc_iot_av_init` 调用成功;确认 `on_monitor_begin` 回调已正确赋值(未被 `memset` 清零覆盖)。|
|
|
486
|
+
|APP 端看不到监控画面|确认已在 `on_monitor_begin` 中正确创建视频发送通道;确认推送的首帧为 IDR 关键帧;确认 `tc_iot_push_video_frame` 返回值为 `TC_IOT_ERR_SUCCESS`。|
|
|
487
|
+
|APP 端听不到声音|确认 `option.media_content` 包含音频(`TC_IOT_MEDIA_CONTENT_AUDIO` 或 `TC_IOT_MEDIA_CONTENT_AUDIO_VIDEO`);确认已创建音频发送通道且 `tc_iot_push_audio_frame` 调用成功。|
|
|
488
|
+
|多路监控同时在线时声音异常(重复/杂音)|检查是否为每路监控重复创建了音频发送通道;音频发送通道应全局只创建一路,多路视频共享推送。|
|
|
489
|
+
|`tc_iot_push_video_frame` / `tc_iot_push_audio_frame` 返回失败|确认传入的发送通道指针非空且尚未被销毁;确认 `on_monitor_end` 触发后已停止继续推流。|
|
|
490
|
+
|切换清晰度后,设备端未收到 `on_monitor_switch`|确认设备已成功登录且 `tc_iot_av_init` 调用成功;确认 `on_monitor_switch` 已正确赋值(未被 `memset` 清零覆盖);确认监控会话已建立(`on_monitor_begin` 已触发)。|
|
|
491
|
+
|收到 `on_monitor_switch` 回调但画面清晰度未变化|确认已先销毁旧的视频发送通道再按新 `quality` 创建;确认推送视频帧时使用的是重建后的新通道指针,而非旧指针。|
|
|
492
|
+
|切换清晰度时画面卡顿或短暂黑屏|通道重建期间存在短暂推流中断,属正常现象;建议重建后尽快推送一个 IDR 关键帧,保证画面能快速恢复。|
|
|
493
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
product: iot
|
|
3
|
+
framework:
|
|
4
|
+
- '*'
|
|
5
|
+
types:
|
|
6
|
+
- feature
|
|
7
|
+
retrievable_scope: always
|
|
8
|
+
feature_domain: security-camera
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 场景概述
|
|
12
|
+
|
|
13
|
+
腾讯云物联网智能安防服务基于腾讯实时音视频 TRTC,将腾讯二十余年在网络与音视频技术上的积累与物联网能力深度融合,面向家用监控、商铺看护、户外安防等智能视频类安防硬件,提供高可靠、低延时、高清、流畅的全天候实时监控与异常告警服务。
|
|
14
|
+
|
|
15
|
+
## 方案优势
|
|
16
|
+
|
|
17
|
+
底层复用腾讯云实时音视频(TRTC)的媒体网络与传输能力:设备与应用端分别就近接入 TRTC 媒体网络并在同一房间内完成推流与订阅,不依赖设备与手机之间的端到端直连。这一架构选择带来的差异如下。
|
|
18
|
+
|
|
19
|
+
### 基本功能
|
|
20
|
+
|
|
21
|
+
|功能|功能描述|
|
|
22
|
+
|---------|---------|
|
|
23
|
+
|实时监控|在 APP 或小程序等 C 端应用中,用户可实时观看 WiFi、蜂窝类 IPC、智能门铃门锁、宠物监控、机器人等设备的实时监控画面。|
|
|
24
|
+
|设备对讲|用户在移动端观看监控画面时,可通过设备对讲功能与设备进行实时语音对讲。|
|
|
25
|
+
|画质设置|用户在观看监控画面时,可对监控画面设置清晰度,如流畅、标清等模式。|
|
|
26
|
+
|云台控制|提供云台控制信令通道,如云台控制、电机控制等。满足开发者不同型号设备的个性化控制设备需求。|
|
|
27
|
+
|录制与截图|用户在查看监控时,可将实时监控录制为一个文件保存在手机上 ,也可将当前监控画面进行截图保存为一个图片文件。|
|
|
28
|
+
|
|
29
|
+
## 计费说明
|
|
30
|
+
|
|
31
|
+
实时监控服务需集成设备 SDK,需要用户先购买消费实例下的音视频设备激活码,计费方式可参考 音视频设备接入服务。
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
product: iot
|
|
3
|
+
framework:
|
|
4
|
+
- '*'
|
|
5
|
+
types:
|
|
6
|
+
- feature
|
|
7
|
+
retrievable_scope: always
|
|
8
|
+
feature_domain: security-camera
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
本文将介绍设备如何实现实时监控场景下**云台控制**功能。
|
|
12
|
+
|
|
13
|
+
## 应用端接入
|
|
14
|
+
|
|
15
|
+
对于支持云台(PTZ)的设备,应用端在查看监控期间可通过 sendPTZCommand 控制镜头方向、变焦与停止控制。指令下发后,设备端会收到 `on_ptz_command_received` 回调并驱动云台硬件(见下文 设备端接入)。指令类型见枚举类型 TXIoTPTZCommand,速度 `speed` 由设备能力决定(通常取值 1 ~ 10)。
|
|
16
|
+
|
|
17
|
+
> **注意:**
|
|
18
|
+
> 方向类操作通常为 “按住转动、松开停止”,按下时下发方向指令(如 `LEFT`),松开时必须下发 `STOP`,否则云台会持续转动无法停止。
|
|
19
|
+
>
|
|
20
|
+
|
|
21
|
+
### 接口说明
|
|
22
|
+
|
|
23
|
+
|方法|说明|
|
|
24
|
+
|---------|---------|
|
|
25
|
+
|sendPTZCommand|向 `channelId` 通道发送云台指令,`command` 为指令类型(TXIoTPTZCommand),`speed` 为速度。|
|
|
26
|
+
|
|
27
|
+
### 调用示例
|
|
28
|
+
|
|
29
|
+
【Android】
|
|
30
|
+
``` java
|
|
31
|
+
// 控制云台向左转动,速度 5
|
|
32
|
+
session.sendPTZCommand(0, // 通道 ID,如果仅有一个通道,则传 0
|
|
33
|
+
TXIoTMonitorSession.TXIoTPTZCommand.LEFT, // 云台指令,例如:向左转动
|
|
34
|
+
5); // 转动速度
|
|
35
|
+
|
|
36
|
+
// 松开时停止云台转动
|
|
37
|
+
session.sendPTZCommand(0,
|
|
38
|
+
TXIoTMonitorSession.TXIoTPTZCommand.STOP,
|
|
39
|
+
0);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
【iOS】
|
|
43
|
+
``` objectivec
|
|
44
|
+
// 控制云台向左转动,速度 5
|
|
45
|
+
[session sendPTZCommand:0 // 通道 ID,如果仅有一个通道,则传 0
|
|
46
|
+
command:TXIoTPTZCommandLeft // 云台指令,例如:向左转动
|
|
47
|
+
speed:5]; // 转动速度
|
|
48
|
+
|
|
49
|
+
// 松开时停止云台转动
|
|
50
|
+
[session sendPTZCommand:0
|
|
51
|
+
command:TXIoTPTZCommandStop
|
|
52
|
+
speed:0];
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
【小程序】
|
|
56
|
+
``` typescript
|
|
57
|
+
// 控制云台向左转动,速度 5
|
|
58
|
+
session.sendPTZCommand(
|
|
59
|
+
0, // 通道 ID,单通道设备传 0
|
|
60
|
+
TXIoTPTZCommand.LEFT, // 向左转动
|
|
61
|
+
5, // 转动速度
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// 松开时停止云台转动
|
|
65
|
+
session.sendPTZCommand(0, TXIoTPTZCommand.STOP, 0);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 设备端接入
|
|
69
|
+
|
|
70
|
+
### 接入步骤
|
|
71
|
+
|
|
72
|
+
#### 步骤 1:注册 on_ptz_command_received 回调
|
|
73
|
+
|
|
74
|
+
调用 `tc_iot_av_init` 注册 `tc_iot_av_observer_s` 时,为 `on_ptz_command_received` 赋值。APP 端在查看监控期间发起云台操作时,设备端会通过该回调收到通知,携带 `channel_id`(对应的监控通道)、`ptz_command`(云台指令)与 `speed`(转动速度):
|
|
75
|
+
``` c
|
|
76
|
+
#include "tc_iot_av.h"
|
|
77
|
+
|
|
78
|
+
static void on_ptz_command_received(int channel_id, ptz_command_e ptz_command, int speed);
|
|
79
|
+
|
|
80
|
+
tc_iot_av_observer_s observer;
|
|
81
|
+
memset(&observer, 0, sizeof(observer));
|
|
82
|
+
observer.on_ptz_command_received = on_ptz_command_received;
|
|
83
|
+
|
|
84
|
+
tc_iot_error_e av_rc = tc_iot_av_init(&observer);
|
|
85
|
+
if (av_rc != TC_IOT_ERR_SUCCESS) {
|
|
86
|
+
printf("tc_iot_av_init failed: %d\n", av_rc);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`ptz_command` 的可选取值(`ptz_command_e`)如下:
|
|
91
|
+
|
|
92
|
+
|取值|说明|
|
|
93
|
+
|---------|---------|
|
|
94
|
+
|`PTZ_CMD_UP`|向上转动。|
|
|
95
|
+
|`PTZ_CMD_DOWN`|向下转动。|
|
|
96
|
+
|`PTZ_CMD_LEFT`|向左转动。|
|
|
97
|
+
|`PTZ_CMD_RIGHT`|向右转动。|
|
|
98
|
+
|`PTZ_CMD_ZOOM_IN`|镜头放大(拉近)。|
|
|
99
|
+
|`PTZ_CMD_ZOOM_OUT`|镜头缩小(拉远)。|
|
|
100
|
+
|`PTZ_CMD_STOP`|停止转动。|
|
|
101
|
+
|
|
102
|
+
#### 步骤 2:响应回调,驱动云台硬件
|
|
103
|
+
|
|
104
|
+
在回调中根据 `ptz_command` 调用对应的云台硬件驱动接口完成转动,`speed` 用于控制转动速度。云台驱动接口由具体硬件平台提供,以下以自定义 `ptz_motor_move` / `ptz_motor_zoom` / `ptz_motor_stop` 函数表示,请替换为您设备实际的云台驱动接口:
|
|
105
|
+
``` c
|
|
106
|
+
// 以下函数由业务自行实现,对接具体硬件平台的云台驱动接口
|
|
107
|
+
extern void ptz_motor_move(int direction, int speed); // direction: 0=上 1=下 2=左 3=右
|
|
108
|
+
extern void ptz_motor_zoom(bool zoom_in, int speed);
|
|
109
|
+
extern void ptz_motor_stop(void);
|
|
110
|
+
|
|
111
|
+
static void on_ptz_command_received(int channel_id, ptz_command_e ptz_command, int speed) {
|
|
112
|
+
printf("[demo] on_ptz_command_received channel_id=%d cmd=%d speed=%d\n",
|
|
113
|
+
channel_id, ptz_command, speed);
|
|
114
|
+
|
|
115
|
+
switch (ptz_command) {
|
|
116
|
+
case PTZ_CMD_UP:
|
|
117
|
+
ptz_motor_move(0, speed);
|
|
118
|
+
break;
|
|
119
|
+
case PTZ_CMD_DOWN:
|
|
120
|
+
ptz_motor_move(1, speed);
|
|
121
|
+
break;
|
|
122
|
+
case PTZ_CMD_LEFT:
|
|
123
|
+
ptz_motor_move(2, speed);
|
|
124
|
+
break;
|
|
125
|
+
case PTZ_CMD_RIGHT:
|
|
126
|
+
ptz_motor_move(3, speed);
|
|
127
|
+
break;
|
|
128
|
+
case PTZ_CMD_ZOOM_IN:
|
|
129
|
+
ptz_motor_zoom(true, speed);
|
|
130
|
+
break;
|
|
131
|
+
case PTZ_CMD_ZOOM_OUT:
|
|
132
|
+
ptz_motor_zoom(false, speed);
|
|
133
|
+
break;
|
|
134
|
+
case PTZ_CMD_STOP:
|
|
135
|
+
ptz_motor_stop();
|
|
136
|
+
break;
|
|
137
|
+
default:
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
> **注意:**
|
|
144
|
+
> APP 端云台方向操作通常是"按住转动、松开发送 `PTZ_CMD_STOP`",请务必正确处理 `PTZ_CMD_STOP`,否则云台会持续转动无法停止。
|
|
145
|
+
>
|
|
146
|
+
|
|
147
|
+
### 常见问题
|
|
148
|
+
|
|
149
|
+
|现象|排查建议|
|
|
150
|
+
|---------|---------|
|
|
151
|
+
|发起云台操作后,设备端未收到 `on_ptz_command_received`。|确认设备已成功登录且 `tc_iot_av_init` 调用成功;确认 `on_ptz_command_received` 已正确赋值(未被 `memset` 清零覆盖);确认监控会话已建立(`on_monitor_begin` 已触发)。|
|
|
152
|
+
|收到回调但云台无转动。|确认已正确对接云台硬件驱动接口;确认 `switch` 分支覆盖了实际下发的 `ptz_command` 取值。|
|
|
153
|
+
|云台持续转动不停止。|检查是否正确处理了 `PTZ_CMD_STOP` 分支并调用了停止接口。|
|