@tencentcloud/sdk-mcp 1.7.7 → 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/CHANGELOG.md +13 -0
- package/README.md +7 -9
- package/index.js +8 -8
- package/knowledge/chunker.js +1 -0
- package/knowledge/doc-url-resolver.js +16 -9
- package/knowledge/embedding/build-vectors.js +92 -0
- package/knowledge/embedding/embed-model.js +41 -0
- package/knowledge/embedding/vector-augment.js +126 -0
- package/knowledge/embedding/vector-index.js +70 -0
- package/knowledge/frontmatter-meta.js +23 -0
- package/knowledge/path-meta.js +56 -0
- package/knowledge/search/exact-lookup.js +145 -16
- package/knowledge/search/filter-pool.js +77 -33
- package/knowledge/search/rank-profile.js +25 -0
- package/knowledge/search/requires-framework.js +4 -1
- package/knowledge/search/search-core.js +74 -13
- package/knowledge/search/search-knowledge.js +24 -34
- package/knowledge/search/search-pass.js +495 -169
- package/knowledge/search/url-row-scorer.js +24 -6
- package/package.json +3 -1
- package/resource/index/manifest.json +1 -1
- package/resource/index/vectors/index.json +4 -0
- package/resource/integration/callkit/preset/android/integration.md +0 -2
- package/resource/integration/callkit/preset/ios/integration.md +0 -2
- package/resource/integration/chat/preset/react/integration.md +9 -5
- package/resource/integration/chat/preset/uni-app/integration.md +4 -0
- package/resource/integration/chat/preset/vue/integration.md +10 -6
- 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/integration/roomkit/preset/vue/integration.md +154 -208
- 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 +2 -3
- package/resource/knowledge/callkit/preset/miniprogram/uniapp-integration.md +0 -2
- package/resource/knowledge/chat/preset/ios-uikit/integration.md +0 -16
- package/resource/knowledge/chat/preset/react/h5/integration.md +16 -5
- package/resource/knowledge/chat/preset/vue/features/conversation-list.md +6 -3
- package/resource/knowledge/chat/preset/vue/h5/integration.md +7 -4
- 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/android/honor.md +16 -1
- package/resource/knowledge/push/config/android/huawei.md +20 -4
- package/resource/knowledge/push/config/android/meizu.md +19 -5
- package/resource/knowledge/push/config/android/vivo.md +20 -1
- package/resource/knowledge/push/config/donut.md +0 -2
- package/resource/knowledge/push/config/harmonyos.md +21 -5
- 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 +1 -4
- 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/roomkit/preset/uniapp-app/integration.md +18 -14
- package/resource/knowledge/rtcengine/web/how_to_run_web_sdk_demo.md +0 -2
- package/resource/knowledge/rtcengine/web/plugin/23-advanced-support-detection.md +30 -0
- package/resource/knowledge/rtcengine/web/plugin/24-advanced-network-quality.md +0 -2
- package/resource/knowledge/rtcengine/web/plugin/31-advanced-plugins-overview.md +1 -1
- package/resource/knowledge/rtcengine/web/plugin/35-advanced-ai-denoiser.md +1 -1
- package/resource/knowledge/rtcengine/web/plugin/36-advanced-virtual-background.md +4 -0
- package/resource/knowledge/trtc/android/TRTCCloud.md +94 -85
- package/resource/knowledge/trtc/android/TRTCCloudDef.md +48 -46
- package/resource/knowledge/trtc/android/TRTCCloudListener.md +48 -48
- package/resource/knowledge/trtc/android/TXAudioEffectManager.md +18 -18
- package/resource/knowledge/trtc/android/TXDeviceManager.md +4 -4
- package/resource/knowledge/trtc/android/TXLiteAVCode.md +1 -0
- package/resource/knowledge/trtc/c++/ITRTCCloud.md +90 -90
- package/resource/knowledge/trtc/c++/ITXAudioEffectManager.md +18 -18
- package/resource/knowledge/trtc/c++/ITXDeviceManager.md +9 -9
- package/resource/knowledge/trtc/c++/TRTCCloudCallback.md +47 -47
- package/resource/knowledge/trtc/c++/TRTCTypeDef.md +47 -45
- package/resource/knowledge/trtc/c++/TXLiteAVCode.md +1 -0
- package/resource/knowledge/trtc/ios/TRTCCloud.md +93 -93
- package/resource/knowledge/trtc/ios/TRTCCloudDelegate.md +50 -50
- package/resource/knowledge/trtc/ios/TXAudioEffectManager.md +8 -8
- package/resource/knowledge/trtc/ios/TXDeviceManager.md +9 -9
- package/resource/knowledge/trtc/ios/TXLiteAVCode.md +1 -0
- package/resource/knowledge/trtc/ios/TXLiveSDKTypeDef.md +48 -46
- package/server-config.js +8 -9
- package/server.js +1 -1
- package/tools/common/finalize_answer.js +1 -1
- package/tools/common/present_framework_choice.js +1 -1
- package/tools/common/search_trtc_knowledge.js +22 -3
- package/tools/definitions/search_trtc_knowledge_def.js +3 -2
- package/utils/preflight-route.js +19 -2
- package/utils/report-cls-client.js +1 -1
- package/utils/report-es-client.js +1 -1
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
---
|
|
2
|
+
product: iot
|
|
3
|
+
framework:
|
|
4
|
+
- '*'
|
|
5
|
+
types:
|
|
6
|
+
- feature
|
|
7
|
+
retrievable_scope: always
|
|
8
|
+
feature_domain: device
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 产品概述
|
|
12
|
+
|
|
13
|
+
云存服务是腾讯云物联网开发平台(IoT Explorer)面向智能视频设备的一站式云端存储解决方案,为智能摄像机(IPC)、可视门铃门锁、智慧车载等音视频设备提供安全、可靠、高可用的云端录像存储能力,解决传统本地 SD/TF 卡存储**易损坏丢失、容量受限、远程访问困难**的痛点。
|
|
14
|
+
|
|
15
|
+
设备端集成设备端 SDK 推流,应用端集成 SDK 回放组件,配合云 API 完成套餐购买与生命周期管理,即可快速构建「设备推流 → 云端存储 → 终端回放」的完整业务闭环。本服务还可与 [智能视觉服务](https://cloud.tencent.com/document/product/1081/131558) 组合,为 C 端用户提供 AI 云存储增值服务。
|
|
16
|
+
|
|
17
|
+
### 云存套餐体系
|
|
18
|
+
|
|
19
|
+
云存套餐分为**视频云存套餐**(可上传视频及图片)以及**图片云存套餐** (仅支持上传图片);视频云存套餐进一步分为全时云存、事件云存、低功耗事件云存。开通套餐请移步至 [云存开通服务](https://cloud.tencent.com/document/product/1081/135239) 页面。
|
|
20
|
+
|
|
21
|
+
> **注意:**
|
|
22
|
+
> 一个设备只能同时生效一个视频云存套餐,新购套餐将覆盖原有套餐。
|
|
23
|
+
>
|
|
24
|
+
|
|
25
|
+
## 设备端接入
|
|
26
|
+
|
|
27
|
+
### 前提条件
|
|
28
|
+
|
|
29
|
+
在接入云存储之前,请先完成以下工作(已完成的可跳过):
|
|
30
|
+
1. 完成 [登录与注册](https://cloud.tencent.com/document/product/1081/135023) 文档中的 tc_iot_login 登录功能。
|
|
31
|
+
|
|
32
|
+
2. 通过云 API(CreateStorageService)为设备开通云存储服务并购买套餐:
|
|
33
|
+
|
|
34
|
+
- **单通道设备**:直接购买即可,无需指定通道号,默认使用通道 ID 为0。
|
|
35
|
+
|
|
36
|
+
- **多通道设备**:按实际通道号分别购买对应通道的云存储套餐。
|
|
37
|
+
|
|
38
|
+
3. 设备已具备采集并编码音视频帧的能力。
|
|
39
|
+
|
|
40
|
+
> **注意:**
|
|
41
|
+
>
|
|
42
|
+
> **通道号一致性原则**:创建音视频通道、推帧、调用云存储 API 时传入的 `channel_id`,须与已开通套餐的通道号保持一致。后续各步骤中涉及的 `channel_id` 参数均遵循此原则。
|
|
43
|
+
>
|
|
44
|
+
|
|
45
|
+
### 接入流程
|
|
46
|
+
|
|
47
|
+
云存储接入以「初始化 → 持续推帧 → 按套餐触发录制/抓拍」为主线。数据处理、上传、云端上报等均由 SDK 自动完成,业务侧主要负责:**注册回调、持续推帧、按需触发事件录制/抓拍**。
|
|
48
|
+
|
|
49
|
+
#### 步骤 1:初始化云存储并注册回调
|
|
50
|
+
|
|
51
|
+
调用 `tc_iot_cloud_storage_init`,传入回调集合 `tc_iot_cloud_storage_callback_t`。初始化的结果通过 `on_init_result` 回调返回。
|
|
52
|
+
|
|
53
|
+
`tc_iot_cloud_storage_callback_t` 回调说明:
|
|
54
|
+
|
|
55
|
+
|回调|说明|
|
|
56
|
+
|---------|---------|
|
|
57
|
+
|`on_init_result`|**必填**,初始化结果(含套餐查询结果)。`error_code == TC_IOT_ERR_SUCCESS` 表示成功。|
|
|
58
|
+
|`on_event_result`|可选,事件处理结果,返回事件上报结果 `event_report_result` 与图片上传结果 `picture_upload_result`。|
|
|
59
|
+
|`on_plan_type_changed`|可选,云端云存储套餐类型发生变化时回调,业务可据此调整录制策略和控制推流。|
|
|
60
|
+
|
|
61
|
+
``` c
|
|
62
|
+
static void on_cs_init_result(tc_iot_error_e error_code, const char *error_message) {
|
|
63
|
+
if (error_code == TC_IOT_ERR_SUCCESS) {
|
|
64
|
+
printf("cloud storage init success\n");
|
|
65
|
+
} else {
|
|
66
|
+
printf("cloud storage init failed: %d, %s\n", error_code,
|
|
67
|
+
error_message ? error_message : "");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static void on_cs_event_result(uint8_t channel_id,
|
|
72
|
+
const tc_iot_cloud_storage_event_result_t *result) {
|
|
73
|
+
printf("event result|ch:%u|event_id:%u|report:%d|pic:%d\n", channel_id,
|
|
74
|
+
result->event_id, result->event_report_result, result->picture_upload_result);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static void on_cs_plan_type_changed(uint8_t channel_id,
|
|
78
|
+
tc_iot_cloud_storage_plan_type_t plan_type) {
|
|
79
|
+
printf("plan type changed|ch:%u|plan:%d\n", channel_id, plan_type);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
void cloud_storage_init_sample(void) {
|
|
83
|
+
tc_iot_cloud_storage_callback_t cb = {0};
|
|
84
|
+
cb.on_init_result = on_cs_init_result;
|
|
85
|
+
cb.on_event_result = on_cs_event_result;
|
|
86
|
+
cb.on_plan_type_changed = on_cs_plan_type_changed;
|
|
87
|
+
|
|
88
|
+
tc_iot_error_e err = tc_iot_cloud_storage_init(&cb);
|
|
89
|
+
if (err != TC_IOT_ERR_SUCCESS) {
|
|
90
|
+
printf("init call failed: %d\n", err);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### 步骤 2:查询云存储套餐类型
|
|
96
|
+
|
|
97
|
+
`tc_iot_cloud_storage_get_plan_type` 返回指定 `channel_id` 对应的视频套餐类型。业务侧根据实际需要查询已开通套餐的通道号,不同套餐类型决定了可调用的录制接口范围:
|
|
98
|
+
|
|
99
|
+
|枚举值|说明|
|
|
100
|
+
|---------|---------|
|
|
101
|
+
|`TC_IOT_CLOUD_STORAGE_PLAN_TYPE_UNKNOWN`|未知(未初始化 / 未获取到套餐)。|
|
|
102
|
+
|`TC_IOT_CLOUD_STORAGE_PLAN_TYPE_NONE`|无套餐。|
|
|
103
|
+
|`TC_IOT_CLOUD_STORAGE_PLAN_TYPE_FULL_TIME`|全时录制套餐。支持全时录制、事件录制、事件抓拍(见 步骤 5、步骤 6、步骤 7)。|
|
|
104
|
+
|`TC_IOT_CLOUD_STORAGE_PLAN_TYPE_EVENT`|事件录制套餐。支持事件录制、事件抓拍(见 步骤 6、步骤 7)。|
|
|
105
|
+
|`TC_IOT_CLOUD_STORAGE_PLAN_TYPE_IMAGE`|图片套餐。仅支持事件抓拍(见 步骤 7)。|
|
|
106
|
+
|
|
107
|
+
> **说明:**
|
|
108
|
+
> 需在 `on_init_result` 回调通知云存初始化成功后调用此接口。
|
|
109
|
+
>
|
|
110
|
+
|
|
111
|
+
``` c
|
|
112
|
+
tc_iot_cloud_storage_plan_type_t plan =
|
|
113
|
+
tc_iot_cloud_storage_get_plan_type(/*channel_id*/ 0);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### 步骤 3:创建 / 复用音视频通道
|
|
117
|
+
|
|
118
|
+
云存储录制的帧来自音视频通道(AV Channel)——设备端采集编码后的音视频帧统一推送到此通道,云存储与实时监控/通话共享同一路帧数据。只需推送一次,即可同时用于实时监控与云存储录制,无需为云存储单独喂帧。
|
|
119
|
+
|
|
120
|
+
`tc_iot_create_video_channel` 参数说明:
|
|
121
|
+
|
|
122
|
+
|参数|说明|
|
|
123
|
+
|---------|---------|
|
|
124
|
+
|channel_id|通道号,对应设备的一路摄像头。|
|
|
125
|
+
|quality|视频清晰度,取值参考 tc_iot_video_quality_e。|
|
|
126
|
+
|
|
127
|
+
通道用 `tc_iot_av.h` 的接口创建:
|
|
128
|
+
``` c
|
|
129
|
+
// 视频通道:每路摄像头一个 channel_id,各自独立创建
|
|
130
|
+
tc_iot_av_channel_t *video_channel =
|
|
131
|
+
tc_iot_create_video_channel(/*channel_id*/ 0, TC_IOT_VIDEO_QUALITY_HD);
|
|
132
|
+
|
|
133
|
+
// 音频通道:麦克风唯一,全进程只创建一次,多路共享
|
|
134
|
+
tc_iot_av_channel_t *audio_channel = tc_iot_create_audio_channel();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> **说明:**
|
|
138
|
+
> **音视频通道是设备端上行帧的统一入口,云存储与实时监控 / 通话共用同一路通道**。
|
|
139
|
+
>
|
|
140
|
+
> - 若设备已接入实时监控 / 通话,av channel 已经创建、帧也已经在推,则云存储直接复用即可,无需再次创建 av channel、也无需再起一路推流。只要保证对应 `channel_id` 上持续有帧,云存储便能在调用对应的接口后自动从 av channel 中获取数据完成录制。
|
|
141
|
+
> - 只有当某路通道尚未被实时监控 / 通话创建(例如纯云存储、无人观看的场景)时,才由业务侧按上面的方式创建并推帧。
|
|
142
|
+
> 一句话概括:一路摄像头只创建一次通道、只推一次流,实时监控与云存储各取所需,切勿为云存储重复建通道 / 重复推流。
|
|
143
|
+
>
|
|
144
|
+
> 创建得到的 `video_channel` / `audio_channel` 句柄用于 步骤 4 的推帧,并在退出时(步骤 8)销毁。
|
|
145
|
+
>
|
|
146
|
+
|
|
147
|
+
#### 步骤 4:向音视频通道推送编码帧
|
|
148
|
+
|
|
149
|
+
云存储录制依赖音视频通道中的编码帧。业务侧需持续把编码帧推入对应 channel_id:
|
|
150
|
+
|
|
151
|
+
`tc_iot_push_video_frame` / `tc_iot_push_audio_frame` 的第一个参数为步骤 3 创建的通道句柄,第二个参数为待推送的编码帧。
|
|
152
|
+
|
|
153
|
+
`tc_iot_video_frame` 字段说明:
|
|
154
|
+
|
|
155
|
+
|字段|说明|
|
|
156
|
+
|---------|---------|
|
|
157
|
+
|codec|视频编码格式,取值 TC_IOT_VIDEO_CODEC_H264 / TC_IOT_VIDEO_CODEC_H265 / TC_IOT_VIDEO_CODEC_MJPEG。|
|
|
158
|
+
|type|帧类型,TC_IOT_VIDEO_FRAME_TYPE_IDR(关键帧)或 TC_IOT_VIDEO_FRAME_TYPE_P(P 帧)。|
|
|
159
|
+
|rotation|画面旋转角度,取值 TC_IOT_VIDEO_ROTATION_0 / 90 / 180 / 270。|
|
|
160
|
+
|width|视频宽度(像素)。|
|
|
161
|
+
|height|视频高度(像素)。|
|
|
162
|
+
|data|编码后视频帧数据指针。|
|
|
163
|
+
|data_size|数据字节数。|
|
|
164
|
+
|pts_ms|帧显示时间戳(毫秒)。|
|
|
165
|
+
|
|
166
|
+
`tc_iot_audio_frame` 字段说明:
|
|
167
|
+
|
|
168
|
+
|字段|说明|
|
|
169
|
+
|---------|---------|
|
|
170
|
+
|codec|音频编码格式,取值 TC_IOT_AUDIO_CODEC_PCM / AAC / OPUS / G722。|
|
|
171
|
+
|sample_rate|采样率,取值 TC_IOT_AUDIO_SAMPLE_RATE_8000 / 16000 / 32000 / 48000。|
|
|
172
|
+
|channels|声道数,TC_IOT_AUDIO_CHANNEL_MONO(单声道)或 TC_IOT_AUDIO_CHANNEL_STEREO(立体声)。|
|
|
173
|
+
|frame_duration_ms|单帧时长(毫秒)。|
|
|
174
|
+
|data|编码后音频帧数据指针。|
|
|
175
|
+
|data_size|数据字节数。|
|
|
176
|
+
|pts_ms|帧时间戳(毫秒)。|
|
|
177
|
+
|
|
178
|
+
> **说明:**
|
|
179
|
+
> 云存音频格式支持 PCM 和 AAC。
|
|
180
|
+
>
|
|
181
|
+
|
|
182
|
+
``` c
|
|
183
|
+
// 视频帧
|
|
184
|
+
tc_iot_video_frame vframe = {0};
|
|
185
|
+
vframe.codec = TC_IOT_VIDEO_CODEC_H264;
|
|
186
|
+
vframe.type = is_idr ? TC_IOT_VIDEO_FRAME_TYPE_IDR : TC_IOT_VIDEO_FRAME_TYPE_P;
|
|
187
|
+
vframe.width = 1920;
|
|
188
|
+
vframe.height = 1080;
|
|
189
|
+
vframe.data = encoded_data;
|
|
190
|
+
vframe.data_size = encoded_size;
|
|
191
|
+
vframe.pts_ms = current_time_ms();
|
|
192
|
+
tc_iot_push_video_frame(video_channel, &vframe);
|
|
193
|
+
|
|
194
|
+
// 音频帧
|
|
195
|
+
tc_iot_audio_frame aframe = {0};
|
|
196
|
+
aframe.codec = TC_IOT_AUDIO_CODEC_AAC;
|
|
197
|
+
aframe.sample_rate = TC_IOT_AUDIO_SAMPLE_RATE_16000;
|
|
198
|
+
aframe.channels = TC_IOT_AUDIO_CHANNEL_MONO;
|
|
199
|
+
aframe.data = audio_data;
|
|
200
|
+
aframe.data_size = audio_size;
|
|
201
|
+
aframe.pts_ms = current_time_ms();
|
|
202
|
+
tc_iot_push_audio_frame(audio_channel, &aframe);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
> **注意:**
|
|
206
|
+
> 视频流必须包含 IDR 帧。云存储起录时会从最近的 IDR 帧开始,若缺少 IDR 帧会导致无法起录或录制内容不可正常播放。
|
|
207
|
+
>
|
|
208
|
+
|
|
209
|
+
#### 步骤 5:全时录制
|
|
210
|
+
|
|
211
|
+
对于全时录制套餐,调用以下接口开启/停止指定 channel 的持续录制。开启后,SDK 会自动录制并上传,业务侧只需保证持续推帧:
|
|
212
|
+
``` c
|
|
213
|
+
tc_iot_cloud_storage_start_continuous_recording(/*channel_id*/ 0);
|
|
214
|
+
// ... 录制期间 SDK 自动录制上传 ...
|
|
215
|
+
tc_iot_cloud_storage_stop_continuous_recording(/*channel_id*/ 0);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
> **说明:**
|
|
219
|
+
> `channel_id` 合法范围为 `[0, 4]`,用于支持多路摄像头设备,需与创建通道时的通道号、开通套餐的通道号保持一致。
|
|
220
|
+
>
|
|
221
|
+
> **适用套餐**:`FULL_TIME`(全时录制套餐)
|
|
222
|
+
>
|
|
223
|
+
|
|
224
|
+
#### 步骤 6:事件录制
|
|
225
|
+
|
|
226
|
+
发生告警、移动侦测等事件时,触发事件录制。可携带事件封面图与预录时长(从事件发生前若干秒开始录制):
|
|
227
|
+
|
|
228
|
+
`tc_iot_cloud_storage_event_params_t` 字段说明:
|
|
229
|
+
|
|
230
|
+
|字段|说明|
|
|
231
|
+
|---------|---------|
|
|
232
|
+
|`event_id`|**必填**。事件 ID,业务侧生成,用于关联开始/停止与结果回调。|
|
|
233
|
+
|`picture_data`|事件封面/抓拍图数据指针,`on_event_result` 回调返回前需保持有效。|
|
|
234
|
+
|`picture_size`|图片字节数(与 `picture_data` 配合使用)。|
|
|
235
|
+
|`pre_record_seconds`|预录时长(秒),从事件发生前若干秒起录。**最大值5秒。**|
|
|
236
|
+
|`extra_info`|业务自定义附加信息(JSON 格式)。|
|
|
237
|
+
|
|
238
|
+
> **说明:**
|
|
239
|
+
> `channel_id` 合法范围为 `[0, 4]`,用于支持多路摄像头设备,需与创建 av 通道时的通道号、开通套餐的通道号保持一致。
|
|
240
|
+
>
|
|
241
|
+
> **适用套餐**:`FULL_TIME`(全时录制套餐)、`EVENT`(事件录制套餐)。
|
|
242
|
+
>
|
|
243
|
+
|
|
244
|
+
``` c
|
|
245
|
+
tc_iot_cloud_storage_event_params_t params = {0};
|
|
246
|
+
params.event_id = generate_event_id();
|
|
247
|
+
params.picture_data = jpeg_data; // 事件封面图(可选)
|
|
248
|
+
params.picture_size = jpeg_size;
|
|
249
|
+
params.pre_record_seconds = 5; // 预录 5 秒
|
|
250
|
+
params.extra_info = "{\"type\":\"motion\"}";
|
|
251
|
+
|
|
252
|
+
tc_iot_cloud_storage_start_event_recording(/*channel_id*/ 0, ¶ms);
|
|
253
|
+
// ... 事件持续期间 SDK 自动录制上传 ...
|
|
254
|
+
tc_iot_cloud_storage_stop_event_recording(/*channel_id*/ 0, params.event_id);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
#### 步骤 7:事件抓拍
|
|
258
|
+
|
|
259
|
+
对于图片套餐,仅需上报一张事件抓拍图,无需录制视频,图片上传与事件消息上报结果通过 `on_event_result` 回调返回。
|
|
260
|
+
``` c
|
|
261
|
+
tc_iot_cloud_storage_event_params_t params = {0};
|
|
262
|
+
params.event_id = generate_event_id();
|
|
263
|
+
params.picture_data = jpeg_data;
|
|
264
|
+
params.picture_size = jpeg_size;
|
|
265
|
+
params.extra_info = "{\"type\":\"snapshot\"}";
|
|
266
|
+
|
|
267
|
+
tc_iot_cloud_storage_report_event_snapshot(/*channel_id*/ 0, ¶ms);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
> **说明:**
|
|
271
|
+
> `channel_id` 合法范围为 `[0, 4]`,用于支持多路摄像头设备,需与创建 av 通道时的通道号、开通套餐的通道号保持一致。
|
|
272
|
+
>
|
|
273
|
+
> **适用套餐**:`FULL_TIME`(全时录制套餐)、`EVENT`(事件录制套餐)、`IMAGE`(图片套餐)。
|
|
274
|
+
>
|
|
275
|
+
|
|
276
|
+
#### 步骤 8:反初始化
|
|
277
|
+
|
|
278
|
+
设备不再使用云存储时释放资源:
|
|
279
|
+
``` c
|
|
280
|
+
// 1. 反初始化云存储
|
|
281
|
+
tc_iot_cloud_storage_deinit();
|
|
282
|
+
|
|
283
|
+
// 2. 销毁步骤 3 中创建的音视频通道
|
|
284
|
+
// 注意:若通道由实时监控 / 通话复用,则应在其结束回调中统一销毁,此处勿重复销毁
|
|
285
|
+
tc_iot_destroy_video_channel(video_channel);
|
|
286
|
+
tc_iot_destroy_audio_channel(audio_channel);
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 完整示例代码
|
|
290
|
+
``` c
|
|
291
|
+
#include <pthread.h>
|
|
292
|
+
#include <signal.h>
|
|
293
|
+
#include <stdbool.h>
|
|
294
|
+
#include <stdio.h>
|
|
295
|
+
#include <stdlib.h>
|
|
296
|
+
#include <string.h>
|
|
297
|
+
#include <sys/time.h>
|
|
298
|
+
#include <unistd.h>
|
|
299
|
+
|
|
300
|
+
#include "tc_iot.h"
|
|
301
|
+
#include "tc_iot_av.h"
|
|
302
|
+
#include "tc_iot_cloud_storage.h"
|
|
303
|
+
#include "tc_iot_def.h"
|
|
304
|
+
|
|
305
|
+
static volatile int s_login_done = 0;
|
|
306
|
+
static tc_iot_error_e s_login_rc = TC_IOT_ERR_SUCCESS;
|
|
307
|
+
static volatile int s_cloud_storage_init_done = 0;
|
|
308
|
+
static tc_iot_error_e s_cloud_storage_init_rc = TC_IOT_ERR_SUCCESS;
|
|
309
|
+
static volatile int s_event_result_done = 0;
|
|
310
|
+
|
|
311
|
+
static volatile bool g_pushing = false;
|
|
312
|
+
static pthread_t g_video_thread, g_audio_thread;
|
|
313
|
+
static tc_iot_av_channel_t *g_video_channel = NULL;
|
|
314
|
+
static tc_iot_av_channel_t *g_audio_channel = NULL;
|
|
315
|
+
static volatile int g_running = 1;
|
|
316
|
+
|
|
317
|
+
static uint8_t s_pic_data[128] = {0xFF, 0xD8, 0x00, 0x00, 0xFF, 0xD9};
|
|
318
|
+
|
|
319
|
+
/* 最小 H264 假帧(AnnexB):真实 SPS+PPS 过 avcC 校验,伪 IDR/P slice 仅过 SDK
|
|
320
|
+
* 校验, 录制文件不可解码;数组末尾多留几字节 0 吸收打包器 NAL 长度偏差。 */
|
|
321
|
+
static uint8_t s_h264_idr_frame[48] = {
|
|
322
|
+
0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xC0, 0x0A, 0xDA, 0x0A, 0x36,
|
|
323
|
+
0xC0, 0x44, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00,
|
|
324
|
+
0x50, 0x3C, 0x48, 0x9A, 0x80, 0x00, 0x00, 0x00, 0x01, 0x68, 0xCE,
|
|
325
|
+
0x01, 0x97, 0x20, 0x00, 0x00, 0x01, 0x65, 0x00,
|
|
326
|
+
};
|
|
327
|
+
static uint8_t s_h264_p_frame[12] = {
|
|
328
|
+
0x00, 0x00, 0x01, 0x41, 0x00,
|
|
329
|
+
};
|
|
330
|
+
#define S_H264_IDR_FRAME_SIZE 41
|
|
331
|
+
#define S_H264_P_FRAME_SIZE 5
|
|
332
|
+
|
|
333
|
+
static tc_iot_cloud_storage_plan_type_t s_plan_type =
|
|
334
|
+
TC_IOT_CLOUD_STORAGE_PLAN_TYPE_UNKNOWN;
|
|
335
|
+
|
|
336
|
+
static void *video_push_thread_func(void *arg);
|
|
337
|
+
static void *audio_push_thread_func(void *arg);
|
|
338
|
+
|
|
339
|
+
static uint64_t current_time_ms(void) {
|
|
340
|
+
struct timeval tv;
|
|
341
|
+
gettimeofday(&tv, NULL);
|
|
342
|
+
return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
static void on_login(tc_iot_error_e error_code, const char *error_message) {
|
|
346
|
+
s_login_rc = error_code;
|
|
347
|
+
s_login_done = 1;
|
|
348
|
+
if (error_code != TC_IOT_ERR_SUCCESS) {
|
|
349
|
+
printf("[demo] login failed: %d, msg=%s\n", error_code,
|
|
350
|
+
error_message ? error_message : "");
|
|
351
|
+
} else {
|
|
352
|
+
printf("[demo] login success\n");
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
static void on_cloud_storage_init_result(tc_iot_error_e error_code,
|
|
357
|
+
const char *error_message) {
|
|
358
|
+
s_cloud_storage_init_rc = error_code;
|
|
359
|
+
s_cloud_storage_init_done = 1;
|
|
360
|
+
if (error_code != TC_IOT_ERR_SUCCESS) {
|
|
361
|
+
printf("[demo] cloud storage init failed: %d, msg=%s\n", error_code,
|
|
362
|
+
error_message ? error_message : "");
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
printf("[demo] cloud storage init success\n");
|
|
366
|
+
|
|
367
|
+
/* 查询套餐类型 */
|
|
368
|
+
s_plan_type = tc_iot_cloud_storage_get_plan_type(0);
|
|
369
|
+
printf("[demo] plan type: %d\n", s_plan_type);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
static void on_cloud_storage_event_result(
|
|
373
|
+
uint8_t channel_id,
|
|
374
|
+
const tc_iot_cloud_storage_event_result_t *event_result) {
|
|
375
|
+
printf("[demo] event result: ch=%d, ev_id=%u, report=%d, pic=%d\n",
|
|
376
|
+
channel_id, event_result->event_id, event_result->event_report_result,
|
|
377
|
+
event_result->picture_upload_result);
|
|
378
|
+
s_event_result_done = 1;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
static void on_plan_type_changed(uint8_t channel_id,
|
|
382
|
+
tc_iot_cloud_storage_plan_type_t plan_type) {
|
|
383
|
+
printf("[demo] plan type changed: ch=%d, plan=%d\n", channel_id, plan_type);
|
|
384
|
+
s_plan_type = plan_type;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* 推流线程 */
|
|
388
|
+
static void *video_push_thread_func(void *arg) {
|
|
389
|
+
(void)arg;
|
|
390
|
+
uint32_t frame_count = 0;
|
|
391
|
+
|
|
392
|
+
while (g_pushing) {
|
|
393
|
+
if (g_video_channel) {
|
|
394
|
+
/* 模拟编码器 GOP=50 帧(2s):周期推 IDR,保证云存按 10s 切片对齐 */
|
|
395
|
+
bool is_idr = (frame_count % 50 == 0);
|
|
396
|
+
tc_iot_video_frame vframe;
|
|
397
|
+
memset(&vframe, 0, sizeof(vframe));
|
|
398
|
+
vframe.codec = TC_IOT_VIDEO_CODEC_H264;
|
|
399
|
+
vframe.type =
|
|
400
|
+
is_idr ? TC_IOT_VIDEO_FRAME_TYPE_IDR : TC_IOT_VIDEO_FRAME_TYPE_P;
|
|
401
|
+
vframe.rotation = TC_IOT_VIDEO_ROTATION_0;
|
|
402
|
+
vframe.width = 160;
|
|
403
|
+
vframe.height = 96;
|
|
404
|
+
vframe.data = is_idr ? s_h264_idr_frame : s_h264_p_frame;
|
|
405
|
+
vframe.data_size = is_idr ? S_H264_IDR_FRAME_SIZE : S_H264_P_FRAME_SIZE;
|
|
406
|
+
vframe.pts_ms = current_time_ms();
|
|
407
|
+
|
|
408
|
+
tc_iot_push_video_frame(g_video_channel, &vframe);
|
|
409
|
+
frame_count++;
|
|
410
|
+
}
|
|
411
|
+
usleep(40 * 1000);
|
|
412
|
+
}
|
|
413
|
+
return NULL;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
static void *audio_push_thread_func(void *arg) {
|
|
417
|
+
(void)arg;
|
|
418
|
+
static uint8_t dummy_audio[640] = {0};
|
|
419
|
+
|
|
420
|
+
while (g_pushing) {
|
|
421
|
+
if (g_audio_channel) {
|
|
422
|
+
tc_iot_audio_frame aframe;
|
|
423
|
+
memset(&aframe, 0, sizeof(aframe));
|
|
424
|
+
aframe.codec = TC_IOT_AUDIO_CODEC_PCM;
|
|
425
|
+
aframe.sample_rate = TC_IOT_AUDIO_SAMPLE_RATE_16000;
|
|
426
|
+
aframe.channels = TC_IOT_AUDIO_CHANNEL_MONO;
|
|
427
|
+
aframe.frame_duration_ms = 20;
|
|
428
|
+
aframe.data = dummy_audio;
|
|
429
|
+
aframe.data_size = sizeof(dummy_audio);
|
|
430
|
+
aframe.pts_ms = current_time_ms();
|
|
431
|
+
|
|
432
|
+
tc_iot_push_audio_frame(g_audio_channel, &aframe);
|
|
433
|
+
}
|
|
434
|
+
usleep(20 * 1000);
|
|
435
|
+
}
|
|
436
|
+
return NULL;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
static int start_pushing(void) {
|
|
440
|
+
if (g_pushing)
|
|
441
|
+
return 0;
|
|
442
|
+
|
|
443
|
+
g_video_channel = tc_iot_create_video_channel(0, TC_IOT_VIDEO_QUALITY_HD);
|
|
444
|
+
g_audio_channel = tc_iot_create_audio_channel();
|
|
445
|
+
if (!g_video_channel || !g_audio_channel) {
|
|
446
|
+
printf("[demo] create AV channels failed\n");
|
|
447
|
+
return -1;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
g_pushing = true;
|
|
451
|
+
pthread_create(&g_video_thread, NULL, video_push_thread_func, NULL);
|
|
452
|
+
pthread_create(&g_audio_thread, NULL, audio_push_thread_func, NULL);
|
|
453
|
+
return 0;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
static void stop_pushing(void) {
|
|
457
|
+
if (!g_pushing)
|
|
458
|
+
return;
|
|
459
|
+
|
|
460
|
+
g_pushing = false;
|
|
461
|
+
pthread_join(g_video_thread, NULL);
|
|
462
|
+
pthread_join(g_audio_thread, NULL);
|
|
463
|
+
|
|
464
|
+
if (g_video_channel) {
|
|
465
|
+
tc_iot_destroy_video_channel(g_video_channel);
|
|
466
|
+
g_video_channel = NULL;
|
|
467
|
+
}
|
|
468
|
+
if (g_audio_channel) {
|
|
469
|
+
tc_iot_destroy_audio_channel(g_audio_channel);
|
|
470
|
+
g_audio_channel = NULL;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
static void signal_handler(int sig) {
|
|
475
|
+
printf("\n[demo] signal %d, shutting down...\n", sig);
|
|
476
|
+
g_running = 0;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
int main(int argc, char **argv) {
|
|
480
|
+
signal(SIGINT, signal_handler);
|
|
481
|
+
signal(SIGTERM, signal_handler);
|
|
482
|
+
|
|
483
|
+
if (argc < 7) {
|
|
484
|
+
printf("Usage: %s -p <product_id> -d <device_id> -s <device_secret>\n",
|
|
485
|
+
argv[0]);
|
|
486
|
+
return 0;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const char *product_id = NULL, *device_id = NULL, *device_secret = NULL;
|
|
490
|
+
for (int i = 1; i < argc; i++) {
|
|
491
|
+
if (strcmp(argv[i], "-p") == 0 && i + 1 < argc)
|
|
492
|
+
product_id = argv[++i];
|
|
493
|
+
else if (strcmp(argv[i], "-d") == 0 && i + 1 < argc)
|
|
494
|
+
device_id = argv[++i];
|
|
495
|
+
else if (strcmp(argv[i], "-s") == 0 && i + 1 < argc)
|
|
496
|
+
device_secret = argv[++i];
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (!product_id || !device_id || !device_secret) {
|
|
500
|
+
printf("device info error\n");
|
|
501
|
+
return 1;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/* 步骤1: SDK初始化 */
|
|
505
|
+
tc_iot_config_s config;
|
|
506
|
+
memset(&config, 0, sizeof(config));
|
|
507
|
+
config.storage_path = "./";
|
|
508
|
+
config.log_level = TC_IOT_LOG_LEVEL_INFO;
|
|
509
|
+
config.region = "ap-guangzhou";
|
|
510
|
+
|
|
511
|
+
tc_iot_error_e rc = tc_iot_init(&config);
|
|
512
|
+
if (rc != TC_IOT_ERR_SUCCESS) {
|
|
513
|
+
printf("[ERROR] tc_iot_init failed: %d\n", rc);
|
|
514
|
+
return 1;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/* 步骤2: 登录 */
|
|
518
|
+
tc_iot_device_info_s device_info;
|
|
519
|
+
memset(&device_info, 0, sizeof(device_info));
|
|
520
|
+
device_info.product_id = product_id;
|
|
521
|
+
device_info.device_id = device_id;
|
|
522
|
+
device_info.device_secret = device_secret;
|
|
523
|
+
|
|
524
|
+
rc = tc_iot_login(&device_info, on_login);
|
|
525
|
+
if (rc != TC_IOT_ERR_SUCCESS) {
|
|
526
|
+
printf("[ERROR] tc_iot_login failed: %d\n", rc);
|
|
527
|
+
tc_iot_deinit();
|
|
528
|
+
return 1;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
int waited_ms = 0;
|
|
532
|
+
while (!s_login_done && waited_ms < 10000) {
|
|
533
|
+
usleep(100 * 1000);
|
|
534
|
+
waited_ms += 100;
|
|
535
|
+
}
|
|
536
|
+
if (!s_login_done || s_login_rc != TC_IOT_ERR_SUCCESS) {
|
|
537
|
+
printf("[demo] login failed or timeout\n");
|
|
538
|
+
tc_iot_deinit();
|
|
539
|
+
return 1;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/* 步骤3: 云存初始化 */
|
|
543
|
+
tc_iot_cloud_storage_callback_t cs_callback;
|
|
544
|
+
memset(&cs_callback, 0, sizeof(cs_callback));
|
|
545
|
+
cs_callback.on_init_result = on_cloud_storage_init_result;
|
|
546
|
+
cs_callback.on_event_result = on_cloud_storage_event_result;
|
|
547
|
+
cs_callback.on_plan_type_changed = on_plan_type_changed;
|
|
548
|
+
|
|
549
|
+
rc = tc_iot_cloud_storage_init(&cs_callback);
|
|
550
|
+
if (rc != TC_IOT_ERR_SUCCESS) {
|
|
551
|
+
printf("[ERROR] tc_iot_cloud_storage_init failed: %d\n", rc);
|
|
552
|
+
tc_iot_logout();
|
|
553
|
+
tc_iot_deinit();
|
|
554
|
+
return 1;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
waited_ms = 0;
|
|
558
|
+
while (!s_cloud_storage_init_done && waited_ms < 10000) {
|
|
559
|
+
usleep(100 * 1000);
|
|
560
|
+
waited_ms += 100;
|
|
561
|
+
}
|
|
562
|
+
if (!s_cloud_storage_init_done ||
|
|
563
|
+
s_cloud_storage_init_rc != TC_IOT_ERR_SUCCESS) {
|
|
564
|
+
printf("[demo] cloud storage init failed or timeout\n");
|
|
565
|
+
tc_iot_cloud_storage_deinit();
|
|
566
|
+
tc_iot_logout();
|
|
567
|
+
tc_iot_deinit();
|
|
568
|
+
return 1;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/* 步骤4: FULL_TIME/EVENT 需要推流 */
|
|
572
|
+
if (s_plan_type == TC_IOT_CLOUD_STORAGE_PLAN_TYPE_FULL_TIME ||
|
|
573
|
+
s_plan_type == TC_IOT_CLOUD_STORAGE_PLAN_TYPE_EVENT) {
|
|
574
|
+
if (start_pushing() != 0) {
|
|
575
|
+
printf("[demo] start pushing failed, exit.\n");
|
|
576
|
+
stop_pushing();
|
|
577
|
+
tc_iot_cloud_storage_deinit();
|
|
578
|
+
tc_iot_logout();
|
|
579
|
+
tc_iot_deinit();
|
|
580
|
+
return 1;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/* 步骤5: 按套餐类型调用对应接口 */
|
|
585
|
+
if (s_plan_type == TC_IOT_CLOUD_STORAGE_PLAN_TYPE_FULL_TIME) {
|
|
586
|
+
printf("[demo] Plan: FULL_TIME\n");
|
|
587
|
+
|
|
588
|
+
rc = tc_iot_cloud_storage_start_continuous_recording(0);
|
|
589
|
+
if (rc == TC_IOT_ERR_SUCCESS) {
|
|
590
|
+
printf("[demo] recording 30s...\n");
|
|
591
|
+
int elapsed = 0;
|
|
592
|
+
while (g_running && elapsed < 30) {
|
|
593
|
+
sleep(1);
|
|
594
|
+
elapsed++;
|
|
595
|
+
}
|
|
596
|
+
tc_iot_cloud_storage_stop_continuous_recording(0);
|
|
597
|
+
printf("[demo] recording stopped.\n");
|
|
598
|
+
} else {
|
|
599
|
+
printf("[ERROR] start_continuous_recording failed: %d\n", rc);
|
|
600
|
+
}
|
|
601
|
+
stop_pushing();
|
|
602
|
+
|
|
603
|
+
} else if (s_plan_type == TC_IOT_CLOUD_STORAGE_PLAN_TYPE_EVENT) {
|
|
604
|
+
printf("[demo] Plan: EVENT\n");
|
|
605
|
+
|
|
606
|
+
uint32_t event_id = (uint32_t)(current_time_ms() / 1000);
|
|
607
|
+
|
|
608
|
+
tc_iot_cloud_storage_event_params_t event_params;
|
|
609
|
+
memset(&event_params, 0, sizeof(event_params));
|
|
610
|
+
event_params.event_id = event_id;
|
|
611
|
+
event_params.picture_data = s_pic_data;
|
|
612
|
+
event_params.picture_size = sizeof(s_pic_data);
|
|
613
|
+
event_params.pre_record_seconds = 5;
|
|
614
|
+
event_params.extra_info = "motion_detected";
|
|
615
|
+
|
|
616
|
+
rc = tc_iot_cloud_storage_start_event_recording(0, &event_params);
|
|
617
|
+
if (rc == TC_IOT_ERR_SUCCESS) {
|
|
618
|
+
printf("[demo] event recording 15s (id=%u)...\n", event_id);
|
|
619
|
+
int elapsed = 0;
|
|
620
|
+
while (g_running && elapsed < 15) {
|
|
621
|
+
sleep(1);
|
|
622
|
+
elapsed++;
|
|
623
|
+
}
|
|
624
|
+
tc_iot_cloud_storage_stop_event_recording(0, event_id);
|
|
625
|
+
|
|
626
|
+
s_event_result_done = 0;
|
|
627
|
+
waited_ms = 0;
|
|
628
|
+
while (!s_event_result_done && waited_ms < 10000) {
|
|
629
|
+
usleep(100 * 1000);
|
|
630
|
+
waited_ms += 100;
|
|
631
|
+
}
|
|
632
|
+
printf("[demo] event recording done.\n");
|
|
633
|
+
} else {
|
|
634
|
+
printf("[ERROR] start_event_recording failed: %d\n", rc);
|
|
635
|
+
}
|
|
636
|
+
stop_pushing();
|
|
637
|
+
|
|
638
|
+
} else if (s_plan_type == TC_IOT_CLOUD_STORAGE_PLAN_TYPE_IMAGE) {
|
|
639
|
+
printf("[demo] Plan: IMAGE\n");
|
|
640
|
+
|
|
641
|
+
uint32_t event_id = (uint32_t)(current_time_ms() / 1000);
|
|
642
|
+
|
|
643
|
+
tc_iot_cloud_storage_event_params_t snap_params;
|
|
644
|
+
memset(&snap_params, 0, sizeof(snap_params));
|
|
645
|
+
snap_params.event_id = event_id;
|
|
646
|
+
snap_params.picture_data = s_pic_data;
|
|
647
|
+
snap_params.picture_size = sizeof(s_pic_data);
|
|
648
|
+
snap_params.extra_info = "doorbell_pressed";
|
|
649
|
+
|
|
650
|
+
rc = tc_iot_cloud_storage_report_event_snapshot(0, &snap_params);
|
|
651
|
+
if (rc == TC_IOT_ERR_SUCCESS) {
|
|
652
|
+
s_event_result_done = 0;
|
|
653
|
+
waited_ms = 0;
|
|
654
|
+
while (!s_event_result_done && waited_ms < 10000) {
|
|
655
|
+
usleep(100 * 1000);
|
|
656
|
+
waited_ms += 100;
|
|
657
|
+
}
|
|
658
|
+
printf("[demo] snapshot done (id=%u)\n", event_id);
|
|
659
|
+
} else {
|
|
660
|
+
printf("[ERROR] report_event_snapshot failed: %d\n", rc);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
} else {
|
|
664
|
+
printf("[demo] Plan: NONE/UNKNOWN, no valid plan.\n");
|
|
665
|
+
sleep(60);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
stop_pushing();
|
|
669
|
+
tc_iot_cloud_storage_deinit();
|
|
670
|
+
tc_iot_logout();
|
|
671
|
+
tc_iot_deinit();
|
|
672
|
+
printf("[demo] done.\n");
|
|
673
|
+
return 0;
|
|
674
|
+
}
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
**编译与运行**:将上述代码保存为 `main.c`,在 SDK 目录下执行编译并运行(传入设备三元组):
|
|
678
|
+
``` bash
|
|
679
|
+
cmake -B build
|
|
680
|
+
cmake --build build -j
|
|
681
|
+
./cloud_storage_demo -p YOUR_PRODUCT_ID -d YOUR_DEVICE_ID -s 'YOUR_DEVICE_SECRET'
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
观察日志输出 `cloud storage init success` 及对应套餐类型的录制/事件日志,即代表云存储接入成功。
|
|
685
|
+
|
|
686
|
+
### 常见问题
|
|
687
|
+
|
|
688
|
+
|问题|排查方向|
|
|
689
|
+
|---------|---------|
|
|
690
|
+
|`on_init_result` 回调初始化失败。|检查设备是否已登录成功;检查网络连接是否正常。|
|
|
691
|
+
|录制后 App 无法回看或播放失败。|确认已持续调用 `tc_iot_push_video_frame` 推帧,且视频流包含 IDR 帧;确认套餐类型与调用的接口匹配。|
|
|
692
|
+
|调用录制接口无响应或报错。|确认当前套餐类型支持该接口(如 `NONE` 套餐不支持任何录制);确认传入的 `channel_id` 已开通对应套餐。|
|
|
693
|
+
|事件图片上传失败。|确认 `picture_data` 在 `on_event_result` 回调前保持有效;确认套餐已开通对应能力。|
|
|
694
|
+
|事件结果回调未触发。|确认事件录制已正确调用对应的 stop 接口;确认 `event_id` 未重复使用。|
|
|
695
|
+
|多路设备录制混乱。|确认各通道的 `channel_id` 与推帧的通道一一对应,且不超过合法范围 `[0, 4]`。|
|
|
696
|
+
|