安卓端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);
}
相关推荐
dvlinker21 小时前
【音视频开发】使用支持硬件加速的D3D11绘图遇到的绘图失败与绘图崩溃问题的记录与总结
音视频开发·c/c++·视频播放·d3d11·d3d11绘图模式
aqi004 天前
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
ffmpeg·音视频·直播·流媒体
音视频牛哥6 天前
Android平台GB28181实时回传流程和技术实现
音视频开发·视频编码·直播
音视频牛哥8 天前
RTMP、RTSP直播播放器的低延迟设计探讨
音视频开发·视频编码·直播
音视频牛哥12 天前
电脑共享同屏的几种方法分享
音视频开发·视频编码·直播
aqi0014 天前
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
android·ffmpeg·音视频·直播·流媒体
aqi0015 天前
FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
android·ffmpeg·音视频·直播·流媒体
加油吧x青年16 天前
Web端开启直播技术方案分享
前端·webrtc·直播
aqi001 个月前
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
android·ffmpeg·音视频·直播·流媒体