大牛直播SDK(SmartMediaKit)鸿蒙NEXT GB28181设备接入指南

16 阅读19分钟

一、背景说明

随着 HarmonyOS NEXT 在行业终端、移动执法、应急指挥、车载视频、无人机巡检、智慧园区和工业现场等场景中的落地,越来越多鸿蒙设备开始承担“前端视频设备”的角色。它们不仅需要完成摄像头采集、音频采集和本地预览,还需要接入现有视频监管平台、行业调度平台或安防联网平台。

在国内安防和行业视频系统中,GB/T 28181 是非常常见的视频联网协议。传统接入对象通常是 IPC、NVR、执法记录仪、车载终端、边缘网关等设备。对于鸿蒙 NEXT 应用来说,如果希望被国标平台统一纳管,就不能只做一个普通的 RTMP 推流端,而是需要具备平台注册、心跳保活、设备目录、平台点播、语音广播、位置上报、设备控制等完整的国标设备接入能力。

大牛直播SDK(SmartMediaKit)鸿蒙 NEXT GB28181 设备接入模块,正是面向这一类场景设计。开发者可以在鸿蒙 NEXT 应用中,通过 ArkTS 层封装接口完成 GB28181 平台接入,而无需直接处理复杂的 SIP 状态机、平台鉴权、国标会话维护和底层媒体传输细节。

本文档从工程集成角度出发,说明如何在鸿蒙 NEXT 项目中集成大牛直播SDK的 GB28181 设备接入能力,并给出推荐的接入步骤、参数配置、事件处理、视频点播、语音广播、位置上报和异常恢复流程。


二、方案定位

大牛直播SDK(SmartMediaKit)鸿蒙 NEXT GB28181 模块主要面向“设备端接入平台”的场景。

也就是说,鸿蒙 NEXT 应用可以作为一个标准 GB28181 前端设备,注册到国标视频平台,并接受平台侧调度。

典型链路如下:

鸿蒙 NEXT 设备
    ↓
GB28181 平台注册
    ↓
心跳保活与设备在线维护
    ↓
平台发起实时视频点播
    ↓
设备启动摄像头/屏幕采集与编码
    ↓
通过国标媒体链路上传音视频
    ↓
平台接收实时视频并完成业务调度

与普通 RTMP 推流不同,GB28181 不是“填一个 URL 后主动推流”这么简单。GB28181 更像是一套设备联网体系:设备先被平台注册和纳管,平台可以查看设备在线状态,可以按需点播实时视频,也可以下发语音广播、位置订阅、PTZ 控制、远程重启、录像查询等命令。

因此,鸿蒙 NEXT GB28181 接入不应被理解为单一推流功能,而应被理解为“鸿蒙终端进入国标视频平台体系”的完整设备接入能力。


三、核心能力

大牛直播SDK鸿蒙 NEXT GB28181 设备接入模块主要覆盖以下能力:

能力说明
平台注册设备作为国标前端注册到 GB28181 平台
Digest 认证支持平台侧账号密码鉴权
心跳保活通过 Keepalive 维持设备在线状态
平台点播支持平台发起实时视频点播
实时视频上传与 SmartPublisher 媒体模块协同完成采集、编码和国标媒体发送
语音广播支持平台向设备下发语音广播,设备侧实时播放
位置上报支持 MobilePosition 位置订阅与上报
设备控制支持 PTZ 控制、远程重启等设备控制事件
预置位查询支持平台查询预置位,可按业务扩展
录像信息查询支持平台录像查询,可返回空列表或对接真实录像记录
生命周期管理支持启动、停止、释放、异常恢复
TCP/UDP支持 SIP 信令 TCP/UDP 配置,媒体链路按平台协商处理
模块协同可与 RTMP 推流、轻量级 RTSP 服务、本地录像、截图等能力组合使用

四、典型应用场景


五、推荐工程结构

鸿蒙 NEXT GB28181 接入建议采用清晰的分层方式,不建议把 SIP 信令、媒体采集、页面交互、定位、语音广播全部混在同一个页面文件里。

推荐结构如下:

entry/src/main/
├── ets/
│   ├── pages/
│   │   └── SmartPublisherPage.ets
│   │       业务页面、参数配置、按钮操作、日志展示
│   │
│   ├── gb28181/
│   │   ├── Gb28181SipAgent.ets
│   │   │   GB28181 信令封装,负责注册、心跳、点播、广播、控制等事件
│   │   ├── Gb28181SipAgentNative.ets
│   │   │   Native 能力封装层
│   │   └── GbLocationProvider.ets
│   │       位置获取、缓存和位置上报辅助模块
│   │
│   └── media/
│       ├── SmartPublisherWrapper.ets
│       │   推送封装层,负责摄像头、麦克风、编码和媒体链路管理
│       ├── PublisherSnapshotHelper.ets
│       │   快照辅助模块
│       ├── RecordFileHelper.ets
│       │   本地录像文件辅助模块
│       └── GbAudioBroadcastPlayer.ets
│           语音广播接收与播放辅助模块
│
├── cpp/
│   └── types/
│       ├── libGb28181SipAgent/
│       │   └── index.d.ts
│       ├── libSmartPublisher/
│       │   └── index.d.ts
│       └── libSmartPlayer/
│           └── index.d.ts
│
└── resources/rawfile/
    ├── libGb28181SipAgent.so
    ├── libSmartPublisher.so
    └── libSmartPlayer.so

整体分层建议如下:

语音广播和位置上报可以作为独立辅助模块挂接到 GB28181 Agent 事件中:

这种分层方式有几个好处:

  1. 页面层只负责交互、参数配置和状态展示;
  2. 信令层只处理 GB28181 平台事件;
  3. 媒体层只处理采集、编码和发送;
  4. 位置和语音广播单独封装,后续维护更清晰;
  5. 便于后续扩展 RTMP 推流、RTSP 服务、本地录像、快照等能力。

六、集成步骤总览

实际项目中,建议按照以下顺序接入,不要一开始就把所有能力同时打开。

这样可以快速定位问题。如果注册都未成功,就不要直接排查媒体链路;如果点播事件没有收到,也不要先怀疑编码器。


七、工程依赖配置

7.1 添加 SDK 文件

将 SDK 交付包中的相关文件放入工程对应目录。实际文件名和目录结构以 SDK 交付包为准,以下为推荐组织方式:

entry/src/main/cpp/types/
├── libGb28181SipAgent/
│   └── index.d.ts
├── libSmartPublisher/
│   └── index.d.ts
└── libSmartPlayer/
    └── index.d.ts

Native 库文件放入工程可加载位置:

entry/src/main/resources/rawfile/
├── libGb28181SipAgent.so
├── libSmartPublisher.so
└── libSmartPlayer.so

ArkTS 封装层建议放在:

entry/src/main/ets/gb28181/
├── Gb28181SipAgent.ets
├── Gb28181SipAgentNative.ets
└── GbLocationProvider.ets

entry/src/main/ets/media/
├── SmartPublisherWrapper.ets
├── GbAudioBroadcastPlayer.ets
├── PublisherSnapshotHelper.ets
└── RecordFileHelper.ets

7.2 配置 oh-package.json5

oh-package.json5 中声明依赖:

{
  "dependencies": {
    "libGb28181SipAgent.so": "file:./src/main/cpp/types/libGb28181SipAgent",
    "libSmartPublisher.so": "file:./src/main/cpp/types/libSmartPublisher",
    "libSmartPlayer.so": "file:./src/main/cpp/types/libSmartPlayer"
  }
}

说明:

  • libGb28181SipAgent.so:GB28181 信令接入模块;
  • libSmartPublisher.so:媒体采集、编码、推送、录像等能力;
  • libSmartPlayer.so:语音广播接收和播放等能力;
  • index.d.ts:提供 ArkTS 类型提示,便于开发阶段调用和检查。

八、权限配置

entry/src/main/module.json5 中声明必要权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      {
        "name": "ohos.permission.CAMERA"
      },
      {
        "name": "ohos.permission.MICROPHONE"
      },
      {
        "name": "ohos.permission.APPROXIMATELY_LOCATION",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.LOCATION",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ],
    "backgroundModes": ["dataTransfer"]
  }
}

权限说明:

权限是否必选说明
INTERNET必选SIP 信令和媒体链路均需要网络访问
CAMERA使用摄像头时必选平台点播实时视频时需要采集画面
MICROPHONE使用音频时必选推流含音频或语音广播相关能力需要
LOCATION使用位置上报时必选MobilePosition 上报需要
APPROXIMATELY_LOCATION可选按实际定位精度需求配置
backgroundModes可选需要后台保持链路时配置

注意:

  1. 相机、麦克风、位置权限不仅要在配置文件中声明,还需要在运行时向用户申请;
  2. 如果项目只做无音频视频上报,可以不启用麦克风采集;
  3. 如果项目不需要 MobilePosition,可以暂不申请位置权限;
  4. 若应用需要长时间运行,需结合鸿蒙后台机制合理处理后台保活策略。

九、初始化 GB28181 Agent

9.1 引入模块

示例:

import {
  Gb28181SipAgent,
  Gb28181SipAgentConfig,
  Gb28181AgentListener,
  Gb28181PlayListener,
  Gb28181AudioBroadcastListener,
  Gb28181DeviceControlListener,
  Gb28181SipEvent
} from '../gb28181/Gb28181SipAgent'

9.2 创建 Agent 实例

建议在页面或独立业务管理类中维护 Agent 实例:

private gbSipAgent: Gb28181SipAgent = new Gb28181SipAgent()
private isGB28181Running: boolean = false
private gb28181StatusText: string = '未启动'
private currentConfig?: Gb28181SipAgentConfig

建议把 GB28181 状态独立维护,不要和 RTMP 推流、RTSP 服务、本地录像状态完全混用。GB28181 是平台调度型链路,它的状态通常包括:

未启动
启动中
注册中
已注册
点播中
语音广播中
心跳异常
重连中
已停止

9.3 配置 License 上下文

在首次启动前,建议完成 License 校验上下文配置:

aboutToAppear(): void {
  Gb28181SipAgent.configureLicenseVerifyContext(getContext(this))
  this.setupGB28181Listeners()
}

说明:

  • 该步骤建议放在页面初始化或业务管理类初始化阶段;
  • 建议在调用 start() 之前完成;
  • 如果项目中还使用 SmartPublisher 或 SmartPlayer,也应保证对应模块的授权校验流程正常。

十、配置 GB28181 参数

启动 GB28181 Agent 前,需要构造平台参数。

示例:

private buildGB28181Config(): Gb28181SipAgentConfig {
  return {
    serverAddress: '192.168.1.100',
    serverPort: 5060,

    serverId: '34020000002000000001',
    serverDomain: '3402000000',

    localAddress: '',
    localPort: 5060,

    username: '34020000001320000001',
    password: '12345678',
    deviceId: '34020000001320000001',

    deviceName: 'HarmonyOS Camera',
    manufacturer: 'Daniulive',
    model: 'SmartPublisherOhos',

    transport: 'UDP',

    expires: 3600,
    heartbeatInterval: 20,
    heartbeatCount: 3,

    owner: 'Owner',
    civilCode: '340200',
    deviceAddress: 'HarmonyOS NEXT Device',
    parental: 0,
    safetyWay: 0,
    registerWay: 1,
    secrecy: 0,
    statusOnline: 1
  }
}

主要参数说明:

参数说明
serverAddressGB28181 平台 SIP 服务 IP 或域名
serverPort平台 SIP 端口,通常为 5060
serverId平台 SIP 服务器 ID,通常为 20 位国标编码
serverDomainSIP 域,通常取平台 ID 前 10 位
localAddress本机绑定 IP,多网卡环境建议指定
localPort本地 SIP 端口,默认可用 5060
username设备注册用户名,通常为设备国标 ID
password平台侧配置的设备注册密码
deviceId设备或通道 ID,用于平台目录展示和点播
deviceName平台设备树中显示的名称
manufacturer厂商名称
model设备型号
transportSIP 信令传输方式,可选 UDP 或 TCP
expires注册有效期,建议 3600 秒
heartbeatInterval心跳间隔,建议 20 秒左右
heartbeatCount连续心跳失败阈值,超过后触发异常恢复

参数配置建议:

  1. serverIdserverDomainusernamedeviceId 必须与平台侧添加的设备信息一致;
  2. serverDomain 不一定总是 serverId 前 10 位,最终以平台要求为准;
  3. 多网卡、VPN、热点、蜂窝网络等场景,建议显式指定 localAddress
  4. password 不建议硬编码到正式版本中,可通过安全配置或服务端下发;
  5. SIP 信令协议和媒体传输协议不是一回事,transport 只代表 SIP 信令传输方式,媒体链路按平台点播协商结果处理;
  6. heartbeatInterval 不建议设置过大,部分平台的在线超时阈值较短。

十一、启动与停止 GB28181

11.1 启动

private async startGB28181(): Promise<void> {
  if (this.isGB28181Running) {
    this.pushLog('[GB28181] 已启动,无需重复启动')
    return
  }

  this.setupGB28181Listeners()

  const config = this.buildGB28181Config()
  this.currentConfig = config

  const ok = await this.gbSipAgent.start(config)

  this.isGB28181Running = ok
  this.gb28181StatusText = ok ? '注册中' : '启动失败'

  this.pushLog(ok ? '[GB28181] 已启动,等待平台注册' : '[GB28181] 启动失败')
}

说明:

  • start() 成功仅代表 Agent 启动成功,并不等于已经注册成功;
  • 注册结果应通过 onRegisterOKonRegisterTimeoutonRegisterRejected 等回调判断;
  • 不建议短时间内频繁 start/stop;
  • 如果启动失败,应输出 getLastError() 或业务日志,便于定位配置或端口问题。

11.2 停止

private async stopGB28181(): Promise<void> {
  this.pushLog('[GB28181] 准备停止')

  await this.stopGB28181Media('manual stop')
  this.audioBroadcastPlayer?.stop()

  this.gbSipAgent.terminateAllPlays(true)
  this.gbSipAgent.terminateAllAudioBroadcasts(true)
  this.gbSipAgent.stop()

  this.isGB28181Running = false
  this.gb28181StatusText = '未启动'

  this.pushLog('[GB28181] 已停止')
}

停止时建议遵循以下顺序:

停止媒体链路
    ↓
停止语音广播
    ↓
终止平台点播会话
    ↓
终止语音广播会话
    ↓
停止 GB28181 Agent
    ↓
更新页面状态

11.3 页面销毁释放

aboutToDisappear(): void {
  this.gbSipAgent.release()
  this.audioBroadcastPlayer?.release()
  this.publisher?.release()

  this.pushLog('[GB28181] 页面退出,资源已释放')
}

stop()release() 的区别:

方法适用场景说明
stop()临时停止、异常重连、用户手动停止停止当前链路,保留对象,后续可再次启动
release()页面销毁、应用退出释放对象和监听器,不建议继续复用

十二、注册与心跳监听

GB28181 注册和心跳是基础链路。只有设备稳定在线,平台点播、语音广播、位置订阅和设备控制才有意义。

示例:

private setupGB28181AgentListener(): void {
  const agentListener = new Gb28181AgentListener()

  agentListener.onRegisterOK = (event: Gb28181SipEvent): void => {
    this.gb28181StatusText = '已注册'
    this.pushLog('[GB28181] 注册成功')
  }

  agentListener.onRegisterRejected = (event: Gb28181SipEvent): void => {
    this.gb28181StatusText = '注册被拒绝'
    this.pushLog(`[GB28181] 注册被拒绝: ${event.statusCode}, ${event.message ?? ''}`)
  }

  agentListener.onRegisterTimeout = (event: Gb28181SipEvent): void => {
    this.gb28181StatusText = '注册超时'
    this.pushLog('[GB28181] 注册超时,请检查平台地址、端口、设备 ID 和网络连通性')
  }

  agentListener.onRegisterTransportError = (event: Gb28181SipEvent): void => {
    this.gb28181StatusText = '传输异常'
    this.pushLog('[GB28181] 注册传输异常,请检查网络、防火墙或端口占用')
  }

  agentListener.onHeartbeatWarning = (event: Gb28181SipEvent): void => {
    this.pushLog(`[GB28181] 心跳异常预警,失败次数: ${event.statusCode}`)
  }

  agentListener.onHeartbeatException = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 心跳异常,准备重启链路')
    await this.restartGB28181()
  }

  agentListener.onMobilePositionRequest = (event: Gb28181SipEvent): void => {
    this.reportLastKnownLocation()
  }

  this.gbSipAgent.setAgentListener(agentListener)
}

十三、平台点播处理

平台点播是 GB28181 设备接入的核心流程。

整体流程可以理解为:

平台发起点播
    ↓
设备收到点播事件
    ↓
业务层准备媒体链路
    ↓
平台确认会话
    ↓
设备开始发送视频流
    ↓
平台停止点播
    ↓
设备释放媒体资源

推荐通过 Listener 方式处理点播事件:

private setupGB28181PlayListener(): void {
  const playListener = new Gb28181PlayListener()

  playListener.onInvitePlay = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 收到平台点播请求')
    await this.prepareGB28181Media(event)
  }

  playListener.onAckPlay = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 平台确认点播,启动媒体发送')
    await this.startGB28181Media(event)
  }

  playListener.onByePlay = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 平台停止点播')
    await this.stopGB28181Media('bye')
  }

  playListener.onCancelPlay = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 平台取消点播')
    await this.stopGB28181Media('cancel')
  }

  playListener.onTerminatePlay = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 点播会话终止')
    await this.stopGB28181Media('terminate')
  }

  playListener.onPlayDialogTerminated = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 点播会话超时,释放媒体资源')
    await this.stopGB28181Media('dialog terminated')
  }

  this.gbSipAgent.setPlayListener(playListener)
}

十四、媒体链路与 SmartPublisher 协同

GB28181 点播最终需要摄像头采集、音频采集、编码和媒体发送。大牛直播SDK在鸿蒙 NEXT 端通过 SmartPublisher 统一处理媒体能力。

建议业务层封装三个方法:

private async prepareGB28181Media(event: Gb28181SipEvent): Promise<void> {
  this.pushLog('[GB28181] 准备媒体链路')

  const ok = await this.publisher.prepareGB28181Media({
    videoWidth: this.publishWidth,
    videoHeight: this.publishHeight,
    fps: this.publishFps,
    bitrateKbps: this.publishBitrateKbps,
    audioEnabled: this.audioEnabled,
    videoCodec: 'H264',
    audioCodec: 'PCMA'
  }, event)

  if (!ok) {
    this.pushLog('[GB28181] 媒体链路准备失败')
    return
  }

  this.pushLog('[GB28181] 媒体链路准备完成')
}

启动媒体发送:

private async startGB28181Media(event: Gb28181SipEvent): Promise<void> {
  const ok = await this.publisher.startGB28181Media(event)

  if (!ok) {
    this.pushLog('[GB28181] 媒体发送启动失败')
    await this.stopGB28181Media('start failed')
    return
  }

  this.gb28181StatusText = '点播中'
  this.pushLog('[GB28181] 媒体发送已启动')
}

停止媒体链路:

private async stopGB28181Media(reason: string): Promise<void> {
  await this.publisher.stopGB28181Media()

  this.gb28181StatusText = this.isGB28181Running ? '已注册' : '未启动'
  this.pushLog(`[GB28181] 媒体链路已停止: ${reason}`)
}

推荐媒体参数:

参数建议值说明
视频编码H.264兼容性最好,适合大多数国标平台
视频分辨率720P / 1080P根据平台能力和网络带宽选择
帧率20~25 fps监控和行业场景通常足够
码率800~3000 kbps根据分辨率和网络情况调整
GOP1~2 秒兼顾首屏和带宽
音频编码PCMA / AAC国标平台通常更偏好 G.711 A-law
音频采样率8000 / 16000 / 48000以平台兼容性为准
传输方式按平台协商UDP/TCP 根据平台点播参数处理

对外文档中不建议展示过多底层调用。开发者更关心的是:如何把平台点播事件和 SmartPublisher 的采集编码能力打通,以及如何在停止、异常、页面退出时安全释放资源。


十五、语音广播接入

GB28181 语音广播适用于平台向前端设备下发语音指令,例如应急指挥、移动执法、车载调度、巡检提醒等场景。

整体流程可以理解为:

平台发起语音广播
    ↓
设备收到广播通知
    ↓
业务层决定是否接受
    ↓
建立音频接收链路
    ↓
播放平台下发的音频
    ↓
广播结束后释放资源

示例:

private setupGB28181AudioBroadcastListener(): void {
  const audioListener = new Gb28181AudioBroadcastListener()

  audioListener.onAudioBroadcastNotify = (event: Gb28181SipEvent): void => {
    this.pushLog('[GB28181] 收到语音广播通知')

    // 可根据业务状态决定是否接受
    this.gbSipAgent.respondBroadcastCommand(event.sourceId, event.targetId, true)
  }

  audioListener.onAudioBroadcast = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 准备接收语音广播')
    await this.audioBroadcastPlayer.prepare(event)
  }

  audioListener.onAudioBroadcastResponse = async (event: Gb28181SipEvent): Promise<void> => {
    if (event.statusCode === 200) {
      this.pushLog('[GB28181] 语音广播链路建立,开始播放')
      await this.audioBroadcastPlayer.start(event)
      this.gb28181StatusText = '语音广播中'
    } else {
      this.pushLog(`[GB28181] 语音广播被平台拒绝: ${event.statusCode}`)
      this.audioBroadcastPlayer.stop()
    }
  }

  audioListener.onByeAudioBroadcast = (event: Gb28181SipEvent): void => {
    this.pushLog('[GB28181] 语音广播结束')
    this.audioBroadcastPlayer.stop()
    this.gb28181StatusText = this.isGB28181Running ? '已注册' : '未启动'
  }

  audioListener.onAudioBroadcastInviteTimeout = (event: Gb28181SipEvent): void => {
    this.pushLog('[GB28181] 语音广播建立超时')
    this.audioBroadcastPlayer.stop()
  }

  this.gbSipAgent.setAudioBroadcastListener(audioListener)
}

十六、位置上报 MobilePosition

移动终端、车载设备、无人机、巡检设备接入 GB28181 平台时,平台通常不仅关心视频画面,也关心设备位置。

建议把定位能力独立封装,不要直接写在 GB28181 事件回调中。

示例:

private async initLocationProvider(): Promise<void> {
  const granted = await this.locationProvider.requestLocationPermission(getContext(this))

  if (granted) {
    this.locationProvider.startListening()
    this.pushLog('[GB28181] 定位模块已启动')
  } else {
    this.pushLog('[GB28181] 未获取定位权限,位置上报不可用')
  }
}

响应平台位置请求:

private reportLastKnownLocation(): void {
  const location = this.locationProvider.getLastLocation()

  if (!location) {
    this.pushLog('[GB28181] 当前暂无可上报位置')
    return
  }

  const ok = this.gbSipAgent.updateDevicePosition({
    longitude: location.longitude,
    latitude: location.latitude,
    altitude: location.altitude ?? 0,
    speed: location.speed ?? 0,
    direction: location.direction ?? 0,
    time: new Date().toISOString()
  })

  this.pushLog(ok ? '[GB28181] 位置上报成功' : '[GB28181] 位置上报失败')
}

十七、设备控制事件

GB28181 平台可能下发设备控制命令,例如 PTZ 控制、远程重启等。

对于普通鸿蒙手机或平板,部分控制命令可以只做日志记录或业务提示;对于机器人、云台、巡检设备、无人机或车载终端,则可以映射到实际硬件控制。

示例:

private setupGB28181DeviceControlListener(): void {
  const controlListener = new Gb28181DeviceControlListener()

  controlListener.onDeviceControlPtz = (event: Gb28181SipEvent): void => {
    this.pushLog(`[GB28181] 收到 PTZ 控制命令: ${event.ptzCmdValue ?? ''}`)

    // 可根据实际设备能力映射到云台、摄像头、机器人或无人机控制
    this.handlePtzCommand(event.ptzCmdValue)
  }

  controlListener.onDeviceControlTeleBoot = async (event: Gb28181SipEvent): Promise<void> => {
    this.pushLog('[GB28181] 收到远程重启指令,准备重启业务链路')

    // 建议理解为“重启 GB28181 业务链路”,不建议直接重启系统设备
    await this.restartGB28181()
  }

  this.gbSipAgent.setDeviceControlListener(controlListener)
}

十八、预置位查询与录像查询

GB28181 平台可能发起预置位查询或录像信息查询。

18.1 预置位查询

如果设备不支持预置位,可以返回空列表;如果支持云台预置位,可以返回真实预置位数据。

private setupPresetQueryListener(): void {
  const presetListener = new Gb28181PresetQueryListener()

  presetListener.onPresetQuery = (event: Gb28181SipEvent): void => {
    this.pushLog('[GB28181] 收到预置位查询')

    // 不支持预置位时,可返回空结果
    this.gbSipAgent.respondPresetQuery(
      event.fromUserName,
      event.fromUserNameAtDomain,
      event.sn,
      event.deviceId
    )
  }

  this.gbSipAgent.setPresetQueryListener(presetListener)
}

18.2 录像信息查询

如果设备侧没有本地录像能力,可以返回空列表;如果已经对接本地录像管理模块,可按时间范围检索并返回对应记录。

private setupRecordInfoListener(): void {
  const recordListener = new Gb28181RecordInfoListener()

  recordListener.onRecordInfoQuery = (event: Gb28181SipEvent): void => {
    this.pushLog(`[GB28181] 收到录像查询: ${event.startTime} - ${event.endTime}`)

    // 可根据业务情况返回空列表或真实录像记录
    this.gbSipAgent.respondRecordInfoQuery(
      event.fromUserName,
      event.fromUserNameAtDomain,
      event.toUserName,
      event.sn,
      event.deviceId
    )
  }

  this.gbSipAgent.setRecordInfoListener(recordListener)
}

十九、设备配置与远程升级

部分 GB28181 平台可能下发设备配置或升级命令。

对于鸿蒙 NEXT 设备端,建议按业务安全策略处理:

指令建议处理
基础参数配置可记录日志,必要时映射到业务配置
OSD 配置如项目支持水印/文字叠加,可映射处理
编码参数配置可根据项目策略决定是否允许平台修改
远程升级默认只记录日志,正式启用前需建立完整安全校验机制

二十、完整接入示例

以下示例展示一个较完整的业务组织方式,仅体现上层集成流程,不展开底层协议和媒体实现细节。

@Entry
@Component
struct Gb28181DemoPage {
  private gbSipAgent: Gb28181SipAgent = new Gb28181SipAgent()
  private publisher: SmartPublisherWrapper = new SmartPublisherWrapper()
  private audioBroadcastPlayer: GbAudioBroadcastPlayer = new GbAudioBroadcastPlayer()
  private locationProvider: GbLocationProvider = new GbLocationProvider()

  private isGB28181Running: boolean = false
  private currentConfig?: Gb28181SipAgentConfig

  @State gb28181StatusText: string = '未启动'

  aboutToAppear(): void {
    Gb28181SipAgent.configureLicenseVerifyContext(getContext(this))
    this.setupGB28181Listeners()
    this.initLocationProvider()
  }

  aboutToDisappear(): void {
    this.publisher.release()
    this.audioBroadcastPlayer.release()
    this.locationProvider.stopListening()
    this.gbSipAgent.release()
  }

  private setupGB28181Listeners(): void {
    this.setupGB28181AgentListener()
    this.setupGB28181PlayListener()
    this.setupGB28181AudioBroadcastListener()
    this.setupGB28181DeviceControlListener()
  }

  private async startGB28181(): Promise<void> {
    if (this.isGB28181Running) {
      this.pushLog('[GB28181] 已启动')
      return
    }

    const config = this.buildGB28181Config()
    this.currentConfig = config

    const ok = await this.gbSipAgent.start(config)
    this.isGB28181Running = ok
    this.gb28181StatusText = ok ? '注册中' : '启动失败'

    this.pushLog(ok ? '[GB28181] 启动成功,等待注册' : '[GB28181] 启动失败')
  }

  private async stopGB28181(): Promise<void> {
    await this.stopGB28181Media('manual stop')
    this.audioBroadcastPlayer.stop()

    this.gbSipAgent.terminateAllPlays(true)
    this.gbSipAgent.terminateAllAudioBroadcasts(true)
    this.gbSipAgent.stop()

    this.isGB28181Running = false
    this.gb28181StatusText = '未启动'

    this.pushLog('[GB28181] 已停止')
  }

  private buildGB28181Config(): Gb28181SipAgentConfig {
    return {
      serverAddress: '192.168.1.100',
      serverPort: 5060,
      serverId: '34020000002000000001',
      serverDomain: '3402000000',

      localAddress: '',
      localPort: 5060,

      username: '34020000001320000001',
      password: '12345678',
      deviceId: '34020000001320000001',

      deviceName: 'HarmonyOS Camera',
      manufacturer: 'Daniulive',
      model: 'SmartPublisherOhos',

      transport: 'UDP',
      expires: 3600,
      heartbeatInterval: 20,
      heartbeatCount: 3
    }
  }

  private pushLog(msg: string): void {
    console.info(msg)
  }
}

二十一、与 RTMP 推流、RTSP 服务、本地录像协同

大牛直播SDK鸿蒙 NEXT 方案并不只支持 GB28181。实际项目中,可以根据业务需要组合多种能力:

能力定位
GB28181 设备接入面向国标平台纳管和调度
RTMP 推流面向直播平台或业务服务器主动推流
轻量级 RTSP 服务设备本地提供 RTSP 拉流能力
本地录像设备侧保存音视频文件
快照保存当前视频画面
语音广播平台向设备下发语音调度
位置上报平台侧掌握移动设备位置

典型组合方式:

GB28181 接入监管平台
RTMP 推流到业务直播系统
轻量级 RTSP 服务供局域网客户端拉流
本地录像用于留痕
快照用于事件取证
位置上报用于调度
语音广播用于现场指挥

这也是大牛直播SDK(SmartMediaKit)的核心价值:它不是单点协议能力,而是一套面向实时视频系统的模块化能力。开发者可以按项目需要组合,而不是为每个协议重新搭一套采集、编码、传输和播放链路。


二十二、联调建议

GB28181 平台差异较多,不同平台在设备编码、SIP 域、目录结构、点播参数、传输方式、心跳超时、音频编码等方面可能存在差异。建议按以下顺序联调。

23.1 平台侧准备

确认平台侧已添加设备:

项目检查点
设备 ID与 App 中 username/deviceId 一致
注册密码与 App 中 password 一致
SIP 域与 App 中 serverDomain 一致
平台 ID与 App 中 serverId 一致
设备类型按平台要求选择 IPC/移动设备/执法仪等
传输协议UDP 或 TCP,与 App 配置一致
端口策略平台和设备之间 SIP/RTP 端口可达

23.2 设备侧检查

项目检查点
网络设备能访问平台 IP 和端口
权限相机、麦克风、位置权限已授权
本地 IP多网卡场景下 localAddress 正确
本地端口localPort 未被占用
LicenseSDK 授权校验通过
日志Demo 日志能看到注册、心跳、点播事件

23.3 验证顺序


二十三、总结

大牛直播SDK(SmartMediaKit)鸿蒙 NEXT GB28181 设备接入模块,解决的是鸿蒙 NEXT 终端如何作为标准国标前端设备接入视频平台的问题。

从工程集成角度看,开发者不需要直接关注 SIP 状态机、底层会话维护、媒体包发送和复杂协议细节,而是可以通过 ArkTS 层封装完成以下工作:

配置平台参数
注册事件监听
启动 GB28181 Agent
响应平台注册和心跳
处理平台点播事件
启动 SmartPublisher 媒体链路
处理语音广播、位置上报和设备控制
统一停止、释放和异常恢复

对于行业客户而言,这种方式的价值在于:

  1. 能让鸿蒙 NEXT 设备快速进入现有 GB28181 视频平台体系;
  2. 能复用大牛直播SDK长期积累的低延迟音视频能力;
  3. 能将信令、媒体、位置、语音广播、录像、截图等能力模块化组合;
  4. 能减少开发者对底层协议细节的重复投入;
  5. 能更好适配移动执法、应急指挥、车载视频、无人机巡检、智慧园区和工业现场等复杂业务场景。

建议实际项目按“先注册、再点播、再媒体、再扩展能力”的顺序逐步集成和验证。这样不仅排查效率更高,也更容易形成稳定、可维护、可交付的鸿蒙 NEXT 国标设备接入方案。


📎 CSDN官方博客:音视频牛哥-CSDN博客