安卓端GB28181设备接入模块如何实现实时位置订阅(MobilePosition)

技术背景

实时位置(MobilePosition)订阅和上报,对GB28281设备接入终端尤其重要,如移动单兵设备、执法记录仪、智能安全帽、车载终端等,Android国标接入设备通过获取到实时经纬度信息,按照一定的间隔上报到国标服务平台,国标服务平台通过如电子地图,实时动态显示前端设备的定位信息,从而实现前端接入设备的可视可控管理。比如4G/5G执法仪,智能安全帽,智能警用头盔,单兵等。

我们先看看GB/T28181-2016针对MobilePosition描述:

ini 复制代码
<elementname="TargetID"type="tg:deviceIDType"/>移动设备位置数据通知
<! -- 命令类型:移动设备位置数据通知(必选)-->
<elementname="CmdType"fixed="MobilePosition"/>
<! -- 命令序列号(必选)-->
<elementname="SN" type="integer"minInclusivevalue= "1"/>
<! -- 产生通知时间(必选)--> 
<elementname="Time" type="dateTime"/> 
<! --经度(必选)--> <elementname="Longitude"type="double"/> 
<! -- 纬度(必选)--> <elementname="Latitude"type="double"/> 
<! --速度,单位:km/h(可选)--> 
<elementname="Speed"type="double"/> 
<!--方向,取值为当前摄像头方向与正北方的顺时针夹角,取值范围0°~360°,单位:(°)(可选)-->
<elementname="Direction"type="double"/>
<! --海拔高度,单位:m(可选)-->
<elementname="Altitude"type="tg:deviceIDType"/>
  1. 配置设备支持位置订阅:在GB28181设备中需要配置支持位置订阅功能。可以通过设备管理平台或者设备自身的管理界面进行配置。

  2. 获取SIP服务器地址和端口:在位置订阅的过程中,需要知道SIP服务器的地址和端口信息。

  3. 发送订阅请求:使用SIP协议发送一个位置订阅请求。在SIP消息中定义请求的订阅参数,如订阅的设备ID、订阅类型、订阅的时间间隔等。

  4. 响应订阅请求:SIP服务器收到位置订阅请求后,会返回一个订阅成功的响应消息。

  5. 接收位置更新消息:当设备位置发生变化时,设备会向SIP服务器发送位置更新消息。SIP服务器会将该消息传递给订阅者。

  6. 处理位置更新消息:订阅者收到位置更新消息后,可以根据需要进行相应的处理,如在地图上实时显示设备位置、记录设备行踪等。

技术实现

本文以大牛直播SDK的Andorid平台GB28181设备对接模块为例,Android国标接入端DevicePosition基本结构如下:

typescript 复制代码
/*
 * DevicePosition.java
 *
 * Author: https://daniusdk.com
 *
 */
public class DevicePosition {
    private String mTime; // 产生位置信息的时间,格式如:2022-03-16T10:37:21, yyyy-MM-dd'T'HH:mm:ss
    private String mLongitude; // 经度
    private String mLatitude; //纬度
    private String mSpeed; // 速度,单位:km/h
    private String mDirection; // 方向,取值为当前摄像头方向与正北方的顺时针夹角,取值范围0°~360°,单位:(°)
    private String mAltitude; // 海拔高度,单位:m
 
    public String getTime() {
        return mTime;
    }
 
    public void setTime(String time) {
        this.mTime = time;
    }
 
    public String getLongitude() {
        return mLongitude;
    }
 
    public void setLongitude(double longitude) {
        this.mLongitude = String.valueOf(longitude);
    }
 
    public void setLongitude(String longitude) { this.mLongitude =longitude; }
 
    public String getLatitude() {
        return mLatitude;
    }
 
    public void setLatitude(double latitude) {
        this.mLatitude = String.valueOf(latitude);
    }
 
    public void setLatitude(String latitude) { this.mLatitude = latitude;}
 
    public String getSpeed() {
        return mSpeed;
    }
 
    public void setSpeed(double speed) {
        this.mSpeed = String.valueOf(speed);
    }
 
    public String getDirection() {
        return mDirection;
    }
 
    public void setDirection(double direction) {
        this.mDirection = String.valueOf(direction);
    }
 
    public String getAltitude() {
        return mAltitude;
    }
 
    public void setAltitude(double altitude) {
        this.mAltitude = String.valueOf(altitude);
    }
}

当有SUBSCRIBE request请求位置更新,把请求回到上层:

arduino 复制代码
/*
 * 设备位置请求, 这个主要用在移动设备位置订阅上
 * @param interval 请求间隔, 单位是毫秒
 */
void ntsOnDevicePositionRequest(String deviceId, int interval);

对外提供个更新设备位置信息的接口:

arduino 复制代码
/*
 *更新设备位置信息 
 */
boolean updateDevicePosition(String deviceId, DevicePosition position)

上层具体处理ntsOnDevicePositionRequest:

typescript 复制代码
@Override
 public void ntsOnDevicePositionRequest(String deviceId, int interval) {
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            getLocation(myContext);

            Log.i(TAG, "ntsOnDevicePositionRequest, deviceId:" + this.device_id_ + ", Longitude:" + mLongitude + ", Latitude:" + mLatitude + ", Time:" + mLocationTime);

            if (mLongitude != null && mLatitude != null) {
                com.gb28181.ntsignalling.DevicePosition device_pos = new com.gb28181.ntsignalling.DevicePosition();

                device_pos.setTime(mLocationTime);
                device_pos.setLongitude(mLongitude);
                device_pos.setLatitude(mLatitude);

                if (gb28181_agent_ != null ) {
                    gb28181_agent_.updateDevicePosition(device_id_, device_pos);
                }
            }
        }

        private String device_id_;
        private int interval_;

        public Runnable set(String device_id, int interval) {
            this.device_id_ = device_id;
            this.interval_ = interval;
            return this;
        }

    }.set(deviceId, interval),0);
}

如何添加设备:

java 复制代码
private void addTestDevice() {
com.gb28181.ntsignalling.Device gb_device = new com.gb28181.ntsignalling.Device("34020000001380000037", "某安卓设备", Build.MANUFACTURER, Build.MODEL,
                    "宇宙","火星1","火星", true);
        
     if (mLongitude != null && mLatitude != null) {
          com.gb28181.ntsignalling.DevicePosition device_pos = new com.gb28181.ntsignalling.DevicePosition();

          device_pos.setTime(mLocationTime);
          device_pos.setLongitude(mLongitude);
          device_pos.setLatitude(mLatitude);
          gb_device.setPosition(device_pos);

          gb_device.setSupportMobilePosition(true); // 设置支持移动位置上报
      }

      gb28181_agent_.addDevice(gb_device);
}
相关推荐
the3clipse6 小时前
H.265运动补偿优化:Merge模式与AMVP技术详解——如何更高效地利用时间冗余
视频编码·h.265·运动补偿·帧间预测·amvp·merge模式·运动矢量预测
the3clipse2 天前
H.265:为什么我们需要新一代视频编码标准?——从H.264到HEVC的技术演进解析
视频编码·h.265·hevc·h.264·视频压缩·流媒体技术·带宽优化
the3clipse3 天前
H.265/HEVC、HEIF、HEIC 关系详解:为什么 HEIC 比 JPEG 更省空间?一文讲清容器、编码与文件后缀
视频编码·h.265·hevc·图片压缩·jpeg·heif·图像容器
the3clipse5 天前
视频编码技术如何赋能游戏性能优化:从硬件隔离到AI驱动的带宽革命
游戏·性能优化·音视频·视频编码·硬件加速·ai编码·自适应编码
the3clipse6 天前
AI 视界双雄会:DLSS 5 与“小黄鸭”(LSFG)在游戏与视频领域的跨界博弈与前景展望
视频编码·神经渲染·dlss5·lsfg·losslessscaling·帧生成技术·ai画质增强
花椒技术7 天前
2.46 秒生成 5 秒视频:拆解 H3 Max 的模型、推理栈与硬件协同
算法·音视频开发·视频编码
代码小学僧13 天前
从 0 到 1,记录我的第一个出海 SaaS 独立开发项目
前端·rpc·音视频开发
贾伟康14 天前
【HarmonyOS 7新能力|041】弱网直播优化工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·音视频开发·直播
用户380341658829716 天前
Broadcast Extension 里的 Live Activity:一次跨进程妥协
ios·音视频开发
用户380341658829717 天前
macOS 录屏:ScreenCaptureKit 与 iOS 的分野,共用引擎的抽象层该切在哪
ios·音视频开发