• Android平台GB28181设备接入侧如何实现SIP校时


    规范解读

    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交互:

    1. class ButtonGB28181AgentListener implements View.OnClickListener {
    2. public void onClick(View v) {
    3. record_executor_.cancel_tasks();
    4. stopRecordDownloads(true);
    5. stopAudioPlayer();
    6. destoryRTPReceiver();
    7. gb_broadcast_source_id_ = null;
    8. gb_broadcast_target_id_ = null;
    9. btnGB28181AudioBroadcast.setText("GB28181语音广播");
    10. btnGB28181AudioBroadcast.setEnabled(false);
    11. stopGB28181Stream();
    12. destoryRTPSender();
    13. if (null == gb28181_agent_ ) {
    14. if( !initGB28181Agent() )
    15. return;
    16. }
    17. if (gb28181_agent_.isRunning()) {
    18. gb28181_agent_.terminateAllAudioBroadcasts(true);
    19. gb28181_agent_.terminateAllPlays(true);// 目前测试下来,发送BYE之后,有些服务器会立即发送INVITE,是否发送BYE根据实际情况看
    20. gb28181_agent_.stop();
    21. btnGB28181Agent.setText("启动GB28181");
    22. }
    23. else {
    24. record_executor_.cancel_tasks();
    25. initRecordDownloads(null);
    26. if ( gb28181_agent_.start() ) {
    27. btnGB28181Agent.setText("停止GB28181");
    28. }
    29. }
    30. }
    31. }

    其中,initGb28181Agent()实现如下:

    1. /*
    2. * MainActivity.java
    3. * initGB28181Agent
    4. * Author: daniusdk.com
    5. */
    6. private boolean initGB28181Agent() {
    7. if ( gb28181_agent_ != null )
    8. return true;
    9. getLocation(context_);
    10. String local_ip_addr = IPAddrUtils.getIpAddress(context_);
    11. Log.i(TAG, "initGB28181Agent local ip addr: " + local_ip_addr);
    12. if ( local_ip_addr == null || local_ip_addr.isEmpty() ) {
    13. Log.e(TAG, "initGB28181Agent local ip is empty");
    14. return false;
    15. }
    16. gb28181_agent_ = GBSIPAgentFactory.getInstance().create();
    17. if ( gb28181_agent_ == null ) {
    18. Log.e(TAG, "initGB28181Agent create agent failed");
    19. return false;
    20. }
    21. gb28181_agent_.addListener(this);
    22. gb28181_agent_.addPlayListener(this);
    23. gb28181_agent_.addAudioBroadcastListener(this);
    24. gb28181_agent_.addDeviceControlListener(this);
    25. gb28181_agent_.addQueryCommandListener(this);
    26. gb28181_agent_.addQueryRecordInfoListener(this);
    27. // 必填信息
    28. gb28181_agent_.setLocalAddress(local_ip_addr);
    29. gb28181_agent_.setServerParameter(gb28181_sip_server_addr_, gb28181_sip_server_port_, gb28181_sip_server_id_, gb28181_sip_domain_);
    30. gb28181_agent_.setUserInfo(gb28181_sip_username_, gb28181_sip_password_);
    31. //gb28181_agent_.setUserInfo(gb28181_sip_username_, gb28181_sip_username_, gb28181_sip_password_);
    32. // 可选参数
    33. gb28181_agent_.setUserAgent(gb28181_sip_user_agent_filed_);
    34. gb28181_agent_.setTransportProtocol(gb28181_sip_trans_protocol_==0?"UDP":"TCP");
    35. // GB28181配置
    36. gb28181_agent_.config(gb28181_reg_expired_, gb28181_heartbeat_interval_, gb28181_heartbeat_count_);
    37. com.gb.ntsignalling.Device gb_device = new com.gb.ntsignalling.Device("34020000001380000001", "安卓测试设备", Build.MANUFACTURER, Build.MODEL,
    38. "宇宙","火星1","火星", true);
    39. if (mLongitude != null && mLatitude != null) {
    40. com.gb.ntsignalling.DevicePosition device_pos = new com.gb.ntsignalling.DevicePosition();
    41. device_pos.setTime(mLocationTime);
    42. device_pos.setLongitude(mLongitude);
    43. device_pos.setLatitude(mLatitude);
    44. gb_device.setPosition(device_pos);
    45. gb_device.setSupportMobilePosition(true); // 设置支持移动位置上报
    46. }
    47. gb28181_agent_.addDevice(gb_device);
    48. if (!gb28181_agent_.createSipStack()) {
    49. gb28181_agent_ = null;
    50. Log.e(TAG, "initGB28181Agent gb28181_agent_.createSipStack failed.");
    51. return false;
    52. }
    53. boolean is_bind_local_port_ok = false;
    54. // 最多尝试5000个端口
    55. int try_end_port = gb28181_sip_local_port_base_ + 5000;
    56. try_end_port = try_end_port > 65536 ?65536: try_end_port;
    57. for (int i = gb28181_sip_local_port_base_; i < try_end_port; ++i) {
    58. if (gb28181_agent_.bindLocalPort(i)) {
    59. is_bind_local_port_ok = true;
    60. break;
    61. }
    62. }
    63. if (!is_bind_local_port_ok) {
    64. gb28181_agent_.releaseSipStack();
    65. gb28181_agent_ = null;
    66. Log.e(TAG, "initGB28181Agent gb28181_agent_.bindLocalPort failed.");
    67. return false;
    68. }
    69. if (!gb28181_agent_.initialize()) {
    70. gb28181_agent_.unBindLocalPort();
    71. gb28181_agent_.releaseSipStack();
    72. gb28181_agent_ = null;
    73. Log.e(TAG, "initGB28181Agent gb28181_agent_.initialize failed.");
    74. return false;
    75. }
    76. return true;
    77. }

    注册成功的话,返回校时信息:

    1. @Override
    2. public void ntsRegisterOK(String dateString) {
    3. Log.i(TAG, "ntsRegisterOK Date: " + (dateString!= null? dateString : ""));
    4. }
    5. @Override
    6. public void ntsRegisterTimeout() {
    7. Log.e(TAG, "ntsRegisterTimeout");
    8. }
    9. @Override
    10. public void ntsRegisterTransportError(String errorInfo) {
    11. Log.e(TAG, "ntsRegisterTransportError error:" + (errorInfo != null?errorInfo :""));
    12. }

    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国标设备接入端校时协议规范和相关实现。

  • 相关阅读:
    JSP科研处管理信息系统免费源代码+LW
    概率DP—练习
    10.1 调试事件读取寄存器
    仿游戏热血江湖游戏类22(物品方法)
    【C++】STL容器适配器——queue类的使用指南(含代码使用)(18)
    计算机组成与体系结构入门(二)
    昇思25天学习打卡营第15天|ResNet50迁移学习
    动态规划-构建乘积数组
    线程第一次启动和异常的注册(UEF的一个特性)
    第四章 文件管理 九、文件系统的层次结构
  • 原文地址:https://blog.csdn.net/renhui1112/article/details/133708222