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

9.4 KiB
Raw Blame History

无人机实时视频接口对接说明

概述

本模块实现了无人机实时视频流的获取功能,采用清洁架构设计,支持多种镜头类型切换(广角、变焦、红外),并兼容火山引擎和声网两种RTC SDK。

API 接口

接口地址

POST http://1.95.137.212:59015/iot/UAV/changeLens

请求参数

{
  "sn": "1581F8HGX253U00A063U",           // 无人机设备序列号(必填)
  "lensType": "",                         // 镜头类型:wide(广角)、zoom(变焦)、ir(红外),可为空
  "cameraIndex": "176-0-0",               // 摄像头编号(必填)
  "qualityType": "adaptive",              // 清晰度:adaptive(自适应)、low、medium、high(默认adaptive)
  "videoExpire": 720000000                // Token有效期(毫秒,默认720000000)
}

返回数据

{
  "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

已注册以下单例:

sl.registerLazySingleton<GetUavVideoStreamUseCase>(
  () => GetUavVideoStreamUseCase(sl()),
);
sl.registerFactory<DroneStationBloc>(
  () => DroneStationBloc(sl(), sl(), sl(), sl()),
);

使用方式

方式一:直接使用示例页面

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. 导入必要的类

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

late DroneStationBloc _bloc;

@override
void initState() {
  super.initState();
  _bloc = sl<DroneStationBloc>();
  // 加载视频流
  _loadVideoStream(UavLensType.wide);
}

@override
void dispose() {
  _bloc.close();
  super.dispose();
}

3. 加载视频流

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. 监听状态变化

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. 切换镜头类型

// 切换到广角镜头
_loadVideoStream(UavLensType.wide);

// 切换到变焦镜头
_loadVideoStream(UavLensType.zoom);

// 切换到红外镜头
_loadVideoStream(UavLensType.ir);

RTC 集成

获取到视频流后,需要根据 urlType 选择对应的 RTC SDK:

火山引擎 (volc)

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)

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 - 注册依赖