Files
feature-tenant/docs/UAV_VIDEO_INTEGRATION_GUIDE.md
2026-08-07 08:49:29 +08:00

324 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 无人机实时视频接口对接说明
## 概述
本模块实现了无人机实时视频流的获取功能,采用清洁架构设计,支持多种镜头类型切换(广角、变焦、红外),并兼容火山引擎和声网两种RTC SDK。
## API 接口
### 接口地址
```
POST http://1.95.137.212:59015/iot/UAV/changeLens
```
### 请求参数
```json
{
"sn": "1581F8HGX253U00A063U", // 无人机设备序列号(必填)
"lensType": "", // 镜头类型:wide(广角)、zoom(变焦)、ir(红外),可为空
"cameraIndex": "176-0-0", // 摄像头编号(必填)
"qualityType": "adaptive", // 清晰度:adaptive(自适应)、low、medium、high(默认adaptive)
"videoExpire": 720000000 // Token有效期(毫秒,默认720000000)
}
```
### 返回数据
```json
{
"msg": "操作成功",
"code": 200,
"data": {
"sn": "1581F8HGX253U00A063U",
"camera_index": "176-0-0",
"url": "app_id=xxx&expire_time=xxx&room_id=xxx&token=xxx&user_id=xxx",
"expire_ts": 1781155234,
"url_type": "volc" // volc(火山引擎) 或 agora(声网)
}
}
```
## 架构设计
### 目录结构
```
lib/features/v2/device_list/
├── domain/
│ ├── entities/
│ │ └── uav_video_stream_entity.dart # 实体类
│ ├── repositories/
│ │ ── drone_station_repository.dart # 仓库接口
│ └── usecases/
│ └── get_uav_video_stream_usecase.dart # 用例
├── data/
│ ├── datasources/
│ │ ├── drone_station_datasource.dart # 数据源接口
│ │ └── drone_station_datasource_impl.dart # 数据源实现
│ └── repositories/
│ └── drone_station_repository_impl.dart # 仓库实现
── presentation/
├── bloc/
│ ├── drone_station_bloc.dart # BLoC状态管理
│ ├── drone_station_event.dart # 事件定义
│ └── drone_station_state.dart # 状态定义
└── pages/
── uav_live_video_page.dart # 示例页面
```
### 核心组件
#### 1. 实体类 (Entity)
**文件**: `domain/entities/uav_video_stream_entity.dart`
定义了枚举类型和实体类:
- `UavLensType`: 镜头类型枚举(wide、zoom、ir)
- `VideoQualityType`: 视频质量枚举(adaptive、low、medium、high)
- `UavVideoStreamEntity`: 视频流实体,包含解析RTC参数的方法
#### 2. 数据源 (DataSource)
**文件**: `data/datasources/drone_station_datasource_impl.dart`
实现了API调用逻辑:
- 发送POST请求到 `/iot/UAV/changeLens`
- 处理响应并转换为实体对象
- 包含详细的日志输出用于调试
#### 3. 仓库 (Repository)
**文件**: `data/repositories/drone_station_repository_impl.dart`
使用 `fpdart` 的 `Either` 类型处理错误:
- 成功时返回 `Right(UavVideoStreamEntity)`
- 失败时返回 `Left(Failure)`
#### 4. 用例 (UseCase)
**文件**: `domain/usecases/get_uav_video_stream_usecase.dart`
封装业务逻辑,供BLoC调用。
#### 5. BLoC 状态管理
**文件**: `presentation/bloc/drone_station_bloc.dart`
新增事件和状态:
- **事件**: `UavVideoStreamLoad` - 加载视频流
- **状态**:
- `UavVideoStreamLoading` - 加载中
- `UavVideoStreamLoaded` - 加载成功
- `UavVideoStreamError` - 加载失败
#### 6. 依赖注入
**文件**: `core/di/injection.dart`
已注册以下单例:
```dart
sl.registerLazySingleton<GetUavVideoStreamUseCase>(
() => GetUavVideoStreamUseCase(sl()),
);
sl.registerFactory<DroneStationBloc>(
() => DroneStationBloc(sl(), sl(), sl(), sl()),
);
```
## 使用方式
### 方式一:直接使用示例页面
```dart
import 'package:maibu_satabot_v2/features/v2/device_list/presentation/pages/uav_live_video_page.dart';
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UavLiveVideoPage(
droneSn: '1581F8HGX253U00A063U',
cameraIndex: '176-0-0',
),
),
);
```
### 方式二:在现有页面中使用
#### 1. 导入必要的类
```dart
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../core/di/injection.dart';
import '../../domain/entities/uav_video_stream_entity.dart';
import '../bloc/drone_station_bloc.dart';
import '../bloc/drone_station_event.dart';
import '../bloc/drone_station_state.dart';
```
#### 2. 初始化 BLoC
```dart
late DroneStationBloc _bloc;
@override
void initState() {
super.initState();
_bloc = sl<DroneStationBloc>();
// 加载视频流
_loadVideoStream(UavLensType.wide);
}
@override
void dispose() {
_bloc.close();
super.dispose();
}
```
#### 3. 加载视频流
```dart
void _loadVideoStream(UavLensType lensType) {
setState(() {
_isLoading = true;
_errorMessage = null;
});
_bloc.add(
UavVideoStreamLoad(
sn: widget.droneSn,
cameraIndex: widget.cameraIndex,
lensType: lensType,
qualityType: VideoQualityType.adaptive,
videoExpire: 720000000,
),
);
}
```
#### 4. 监听状态变化
```dart
BlocConsumer<DroneStationBloc, DroneStationState>(
listener: (context, state) {
if (state is UavVideoStreamLoaded) {
final videoStream = state.videoStream;
debugPrint('URL Type: ${videoStream.urlType}');
debugPrint('AppId: ${videoStream.appId}');
debugPrint('RoomId: ${videoStream.roomId}');
debugPrint('UserId: ${videoStream.userId}');
// TODO: 根据 urlType 初始化对应的 RTC 引擎
if (videoStream.urlType.toLowerCase() == 'volc') {
// 使用火山引擎 RTC SDK
} else if (videoStream.urlType.toLowerCase() == 'agora') {
// 使用声网 RTC SDK
}
} else if (state is UavVideoStreamError) {
setState(() {
_errorMessage = state.message;
});
}
},
builder: (context, state) {
// 根据状态渲染UI
if (state is UavVideoStreamLoading) {
return const CircularProgressIndicator();
}
if (state is UavVideoStreamLoaded) {
// 显示视频画面
return Container();
}
if (state is UavVideoStreamError) {
return Text('错误: ${state.message}');
}
return Container();
},
)
```
#### 5. 切换镜头类型
```dart
// 切换到广角镜头
_loadVideoStream(UavLensType.wide);
// 切换到变焦镜头
_loadVideoStream(UavLensType.zoom);
// 切换到红外镜头
_loadVideoStream(UavLensType.ir);
```
## RTC 集成
获取到视频流后,需要根据 `urlType` 选择对应的 RTC SDK:
### 火山引擎 (volc)
```dart
final appId = videoStream.appId;
final roomId = videoStream.roomId;
final token = videoStream.token;
final userId = videoStream.userId;
// 使用 volc_engine_rtc SDK
final engine = await RTCEngine.createRTCEngine(
RTCVideoContext(appId: appId, eventHandler: handler),
);
final room = await engine.createRTCRoom(roomId);
await room.joinRoom(token: token, userId: userId);
```
### 声网 (agora)
```dart
final appId = videoStream.appId;
final channelId = videoStream.roomId;
final token = videoStream.token;
final uid = int.tryParse(videoStream.userId) ?? 0;
// 使用 agora_rtc_engine SDK
final engine = createAgoraRtcEngine();
await engine.initialize(RtcEngineContext(appId: appId));
await engine.joinChannel(
token: token,
channelId: channelId,
uid: uid,
options: ChannelMediaOptions(...),
);
```
## 注意事项
1. **可扩展性**: 本模块采用清洁架构设计,所有业务逻辑与UI分离,便于在其他页面复用。
2. **错误处理**: 使用 `Either<Failure, T>` 模式统一处理错误,确保异常不会直接抛出。
3. **日志记录**: 数据源层包含详细的日志输出,方便调试和问题排查。
4. **默认值**:
- `lensType` 可为空,后端会根据实际情况选择默认镜头
- `qualityType` 默认为 `adaptive`(自适应)
- `videoExpire` 默认为 `720000000` 毫秒
5. **Token 有效期**: `videoExpire` 参数单位为毫秒,建议设置较长的有效期以避免频繁刷新。
6. **多镜头支持**: 通过 `UavLensType` 枚举可以轻松扩展更多镜头类型。
## 后续工作
1. [ ] 集成 RTC SDK 显示实际视频画面
2. [ ] 添加视频录制功能
3. [ ] 添加截图功能
4. [ ] 优化视频加载超时处理
5. [ ] 添加视频质量切换功能
6. [ ] 支持多路视频同时观看
## 相关文件清单
### 新增文件
- `lib/features/v2/device_list/domain/entities/uav_video_stream_entity.dart`
- `lib/features/v2/device_list/domain/usecases/get_uav_video_stream_usecase.dart`
- `lib/features/v2/device_list/presentation/pages/uav_live_video_page.dart`
### 修改文件
- `lib/core/consts/http_api_consts.dart` - 添加 API 常量
- `lib/features/v2/device_list/data/datasources/drone_station_datasource.dart` - 添加接口方法
- `lib/features/v2/device_list/data/datasources/drone_station_datasource_impl.dart` - 实现接口
- `lib/features/v2/device_list/data/repositories/drone_station_repository_impl.dart` - 实现仓库
- `lib/features/v2/device_list/domain/repositories/drone_station_repository.dart` - 添加仓库接口
- `lib/features/v2/device_list/presentation/bloc/drone_station_event.dart` - 添加事件
- `lib/features/v2/device_list/presentation/bloc/drone_station_state.dart` - 添加状态
- `lib/features/v2/device_list/presentation/bloc/drone_station_bloc.dart` - 添加事件处理
- `lib/core/di/injection.dart` - 注册依赖