《网络摄像机实战⑤:手机端 flutter集成声网Agora RTM打造远程控制设备功能》

45 阅读3分钟

背景

  • 摄像机设备需要支持远程控制(如分辨率、音量、网络配置等),并能够将设备状态(网络信息、运行状态、事件告警)实时上报给用户。这类能力本质上依赖于消息的发布/订阅机制。
  • 传统方案通常使用 MQTT,但需要自建 MQTT 服务器,并在全球范围部署节点,运维成本和接入复杂度较高。相比之下,声网 RTM 具备与 MQTT 类似的实时消息能力,同时提供全球节点覆盖和完善的 SDK,使用户在使用时更加轻量、简洁、无感化运维。

《网络摄像机实战》系列文章,请读者前往阅读 👀

《网络摄像机实战①:Flutter 集成声网 Agora 打造实时音视频对讲》

《网络摄像机实战②:Flutter集成声网Agora图片抓拍与录像功能》

《网络摄像机实战③:设备端集成声网Agora打造实时音视频对讲功能》

《网络摄像机实战④:设备端集成声网Agora 打造远程控制设备或者异常报警推送功能》

《网络摄像机实战⑤:手机端 flutter集成声网Agora RTM打造远程控制设备功能》

《网络摄像机实战⑥:手机端 flutter集成亚马逊 AWS Kinesis Video Streams 音视频界面和控制》

《网络摄像机实战⑦:嵌入式端AWS KVS IoT SDK 库编译与测试全流程-君正/瑞芯微/全志(超详细指南)》

《网络摄像机实战⑧:嵌入式端接入 AWS KVS Producer 的设计要点与注意事项》


声网RTM介绍

实时消息(Real-Time Messaging,RTM)为开发者提供一整套低延时、高并发、可扩展、高可靠的实时消息及状态同步解决方案。RTM 负责管理应用程序实时通信层所需的基础设施。为方便用户开发与创新,RTM 在保障 99.95% 的 SLA 正常运行时间的同时,提供丰富的 App 及开放的第三方 API 扩展。

在这里插入图片描述

RTM的核心概念:

用户: 是指应用的实际使用者。 设备: 是指实际接入 RTM 网络的终端,包括但不限于手机、电脑、智能手表等 IoT 设备。 客户端: 是指运行在设备上的 RTM 对象实例。

实例化 RtmClient 并且登录 rtm 服务器

  late RtmClient rtmClient;
   Future<void> agoraRtmInit() async
  {
    Get.log("agoraRtmInit userID: ${GlobalInformation().getCurrentDeviceUser().user.id}");
    // final record = await RTM(appId, channelName.value);
    // final record = await RTM(appId, GlobalInformation().getCurrentDeviceUser().user.id);
    var userId = randomDigits(9);
    Get.log("rtm userId : ${userId}");

    final record = await RTM(appId, userId);
    loginStatus = record.$1;
    Get.log("loginStatus ${loginStatus.reason}-${loginStatus.errorCode}");
    if (loginStatus.error == false) {
      Get.log("create rtm success");
      rtmClient = record.$2;
      rtmClient.addListener(
        linkState: (event) {
          Get.log('[linkState] ${event.toJson()}');
        },
        // 订阅主题的消息处理。
        message: (event) {
          Get.log('[message] event: ${event.toJson()}');
          Get.log('event.message:${utf8.decode(event.message!)}');
        },
        presence: (event) {
          Get.log('[presence] event: ${event.toJson()}');
        },
        topic: (event) {
          Get.log('[topic] event: ${event.toJson()}');
        },
        lock: (event) {
          Get.log('[lock] event: ${event.toJson()}');
        },
        storage: (event) {
          Get.log('[storage] event: ${event.toJson()}');
        },
        token: (channelName) {
          Get.log('[token] channelName: $channelName');
        },
      );
      await rtmClient.setParameters('{"rtm.log_filter":2063}');

      await agoraRtmLogin();

      // 后续逻辑
    } else {
      Get.log("create rtm  failed ${loginStatus.reason}");
    }

  }
   

登录成功之后,订阅通道的消息

Future<void> agoraRtmSubscribe() async
 {
   Get.log("agoraRtmSubscribe ${channelName.value}");
   try {
     final record = await rtmClient.subscribe(
       channelName.value,
       withMessage: true,
       withPresence: true,
       withMetadata: true,
       withLock: true,
     );
     Get.log(' errorCode: ${record.$1.errorCode}, reason: ${record.$1.reason}');
   } catch (e) {
     Get.log('something went wrong: $e');
   }
 }

发送电机控制指令到设备

Future<int> setMotorControlInformation()
  async {
    MotorControlInformationEntity motorInformationEntity = MotorControlInformationEntity();
    motorInformationEntity.motorControlInformation = motorControlInformation.value;

    Map<String, dynamic> requestJson = {};
    requestJson[MQTT_COMMAND_HANDLE_METHOD] = SET_MOTORCONTROL_INFORMATION_COMMAND ;
    requestJson[MQTT_COMMAND_HANDLE_PARAMS]=motorInformationEntity.toJson();
    Get.log(json.encode('$requestJson'));
    rtmClient.publish(channelName.value, json.encode(requestJson));
    // await MqttService().mqttPublishMessage("v1/devices/" +  GlobalInformation().getCurrentDeviceUser().id + "/rpc/request/01", json.encode(requestJson));
    DeviceInformation().setMotorControlInformation(motorControlInformation.value);

    // 保存到缓存
ApplicationCacheModule().ApplicationCacheHandleFunction(SAVE_CACHE_DEVICE_MOTOR_CONTROL_INFORMATION, motorControlInformation.value.toJson());

    motorControlInformation.refresh();

    return 0;
  }

回调函数处理设备的状态信息或者报警

 // 订阅主题的消息处理。
        message: (event) {
          Get.log('[message] event: ${event.toJson()}');
          Get.log('event.message:${utf8.decode(event.message!)}');
          handleMessage(message)
        },

退出 rtm

  await rtmClient.logout();

App截图

在这里插入图片描述

友情提示🔔

🙏 感谢你的阅读! 如果这篇文章对你有所启发,欢迎关注我 ⭐,欢迎点击 “打赏支持作者” 支持一下我,你的支持是我持续创作的最大动力! 我会持续分享更多关于 智能摄像头 📷、机器人项目、 🤖音视频 RTC 🎧、App 开发 📱、嵌入式开发 🔧 等方向的实战经验,让你更快落地、更少踩坑。 欢迎浏览我其他文章 📚,或许能解决你当前的难题。 如果你正好在做相关项目产品,也欢迎随时私信我,一起技术交流、一起搞事情! 🤝💬📞 联系微信/电话:13826173658