GB/T28181-2016规范里面,9.10.1章节,关于校时基本要求:
联网内设备支持基于SIP方式或 NTP方式的网络校时功能,标准时间为北京时间。
SIP方式校时见本节具体描述;NTP(见IETFRFC2030)协议的网络统一校时服务,网络校时设备分为时钟源和客户端,支持客户/服务器的工作模式,时钟源应支持 TCP/IP、UDP及 NTP协议,将输入的或是自身产生的时间信号以标准的 NTP信息包格式输出。
系统运行时可根据配置使用具体校时方式。SIP校时在注册过程中完成。
具体流程如下:

在注册成功情况下,注册流程的最后一个 SIP应答消息200 OK中的 Date头-域中携带时间信息。
采用的格式为 XML标准格式:Date:yyyy-MM-dd'T'HH:mm:ss.SSS。
若SIP代理通过注册方式校时,其注册过期时间宜设置为小于SIP代理与 SIP服务器出现1s误差所经过的运行时间。
例如:SIP代理与SIP服务器校时后,SIP代理运行10h后设备时间与SIP服务器时间相差大于1s,则宜将注册过期时间设置为10h(36000s),以保证SIP代理与SIP服务器之间时 间误差小于1s。
以大牛直播SDK的Android平台GB28181设备接入模块为例:

点击页面“启动GB28181”按钮,启动GB28181服务,完成注册和catalog交互:
- class ButtonGB28181AgentListener implements View.OnClickListener {
- public void onClick(View v) {
- record_executor_.cancel_tasks();
-
- stopRecordDownloads(true);
-
- stopAudioPlayer();
- destoryRTPReceiver();
-
- gb_broadcast_source_id_ = null;
- gb_broadcast_target_id_ = null;
- btnGB28181AudioBroadcast.setText("GB28181语音广播");
- btnGB28181AudioBroadcast.setEnabled(false);
-
- stopGB28181Stream();
- destoryRTPSender();
-
- if (null == gb28181_agent_ ) {
- if( !initGB28181Agent() )
- return;
- }
-
- if (gb28181_agent_.isRunning()) {
- gb28181_agent_.terminateAllAudioBroadcasts(true);
- gb28181_agent_.terminateAllPlays(true);// 目前测试下来,发送BYE之后,有些服务器会立即发送INVITE,是否发送BYE根据实际情况看
- gb28181_agent_.stop();
- btnGB28181Agent.setText("启动GB28181");
- }
- else {
- record_executor_.cancel_tasks();
- initRecordDownloads(null);
- if ( gb28181_agent_.start() ) {
- btnGB28181Agent.setText("停止GB28181");
- }
- }
- }
- }
其中,initGb28181Agent()实现如下:
- /*
- * MainActivity.java
- * initGB28181Agent
- * Author: daniusdk.com
- */
- private boolean initGB28181Agent() {
- if ( gb28181_agent_ != null )
- return true;
-
- getLocation(context_);
-
- String local_ip_addr = IPAddrUtils.getIpAddress(context_);
- Log.i(TAG, "initGB28181Agent local ip addr: " + local_ip_addr);
-
- if ( local_ip_addr == null || local_ip_addr.isEmpty() ) {
- Log.e(TAG, "initGB28181Agent local ip is empty");
- return false;
- }
-
- gb28181_agent_ = GBSIPAgentFactory.getInstance().create();
- if ( gb28181_agent_ == null ) {
- Log.e(TAG, "initGB28181Agent create agent failed");
- return false;
- }
-
- gb28181_agent_.addListener(this);
- gb28181_agent_.addPlayListener(this);
- gb28181_agent_.addAudioBroadcastListener(this);
- gb28181_agent_.addDeviceControlListener(this);
- gb28181_agent_.addQueryCommandListener(this);
- gb28181_agent_.addQueryRecordInfoListener(this);
-
- // 必填信息
- gb28181_agent_.setLocalAddress(local_ip_addr);
- gb28181_agent_.setServerParameter(gb28181_sip_server_addr_, gb28181_sip_server_port_, gb28181_sip_server_id_, gb28181_sip_domain_);
- gb28181_agent_.setUserInfo(gb28181_sip_username_, gb28181_sip_password_);
- //gb28181_agent_.setUserInfo(gb28181_sip_username_, gb28181_sip_username_, gb28181_sip_password_);
-
- // 可选参数
- gb28181_agent_.setUserAgent(gb28181_sip_user_agent_filed_);
- gb28181_agent_.setTransportProtocol(gb28181_sip_trans_protocol_==0?"UDP":"TCP");
-
- // GB28181配置
- gb28181_agent_.config(gb28181_reg_expired_, gb28181_heartbeat_interval_, gb28181_heartbeat_count_);
-
- com.gb.ntsignalling.Device gb_device = new com.gb.ntsignalling.Device("34020000001380000001", "安卓测试设备", Build.MANUFACTURER, Build.MODEL,
- "宇宙","火星1","火星", true);
-
- if (mLongitude != null && mLatitude != null) {
- com.gb.ntsignalling.DevicePosition device_pos = new com.gb.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);
-
-
- if (!gb28181_agent_.createSipStack()) {
- gb28181_agent_ = null;
- Log.e(TAG, "initGB28181Agent gb28181_agent_.createSipStack failed.");
- return false;
- }
-
- boolean is_bind_local_port_ok = false;
-
- // 最多尝试5000个端口
- int try_end_port = gb28181_sip_local_port_base_ + 5000;
- try_end_port = try_end_port > 65536 ?65536: try_end_port;
-
- for (int i = gb28181_sip_local_port_base_; i < try_end_port; ++i) {
- if (gb28181_agent_.bindLocalPort(i)) {
- is_bind_local_port_ok = true;
- break;
- }
- }
-
- if (!is_bind_local_port_ok) {
- gb28181_agent_.releaseSipStack();
- gb28181_agent_ = null;
- Log.e(TAG, "initGB28181Agent gb28181_agent_.bindLocalPort failed.");
- return false;
- }
-
- if (!gb28181_agent_.initialize()) {
- gb28181_agent_.unBindLocalPort();
- gb28181_agent_.releaseSipStack();
- gb28181_agent_ = null;
- Log.e(TAG, "initGB28181Agent gb28181_agent_.initialize failed.");
- return false;
- }
-
- return true;
- }
注册成功的话,返回校时信息:
- @Override
- public void ntsRegisterOK(String dateString) {
- Log.i(TAG, "ntsRegisterOK Date: " + (dateString!= null? dateString : ""));
- }
-
- @Override
- public void ntsRegisterTimeout() {
- Log.e(TAG, "ntsRegisterTimeout");
- }
-
- @Override
- public void ntsRegisterTransportError(String errorInfo) {
- Log.e(TAG, "ntsRegisterTransportError error:" + (errorInfo != null?errorInfo :""));
- }
logcat示例日志如下:
2023-10-07 11:53:33.163 12889-13101/com.daniulive.smartpublisher I/NTGB28181: ntsRegisterOK Date: 2023-10-07T11:53:32.439
Android评估GB28181设备接入侧可以根据返回的时间,做响应的校时处理。以上就是GB28181国标设备接入端校时协议规范和相关实现。