国网B接口语音对讲和广播技术探究及与GB28181差别

news2024/11/24 12:23:48

接口描述

在谈国网B接口的语音广播和语音对讲的时候,大家会觉得,国网B接口是不是和GB28181大同小异?实际上确实信令有差别,但是因为要GB28181设备接入测的对接,再次做国网B接口就简单多了。

语音对讲和广播包括信令接口和媒体流接口,采用与“调阅实时视频”流程相同的机制,不同之处
在于用户发出的请求消息的 SDP 仅携带音频描述信息。
语音所采用的编解码算法为 ITU-T G.711A
语音对讲和广播,被调阅的平台无需进行音频分发行为。

接口流程

语音对讲和广播的接口流程如下:

主要功能流程如下:
a) F1:平台用户,对前端系统指定的前端系统摄像机发起实时音频的调阅请求,发送 INVITE 消
息,携带 SDP 内容,通过平台转发到前端系统。
b) F2:按照 SIP 要求,如前端系统在 0.5 s 内未处理该请求,则先发送 1xx 临时响应给平台。
c) F3:前端系统接受了调阅请求的操作,则发送携带 SDP 的 200 OK 响应到平台。
d) F4:平台发送 ACK 给前端系统,确认会话建立。
e) 实时语音流开始传输,前端设备/用户根据相应的解码器解码并语音输出。
f) F5:用户结束会话,平台发送 BYE 消息到前端系统。
g) F6:前端系统发送确认,将媒体通道拆线,会话结束。

接口参数

SIP头字段如下:

SIP响应码返回码如下:

SIP参数定义:

 

 RTP 动态 Payload 定义如下:

 消息示例

INVITE sip:前端设备地址编码@前端系统所属平台域名或IP地址 SIP/2.0
From: <sip:用户地址编码@用户所属平台域名或IP地址>;tag=3101300
To: <sip:前端设备地址编码@前端系统所属平台域名或IP地址>
Contact: <sip:用户地址编码@用户所属平台域名或IP地址>
Call-ID: c47k42
Via: SIP/2.0/UDP 用户所属平台IP地址;branch=z9hG4bK
CSeq: 1 INVITE
Content-type: application/SDP
Content-Length: 消息体的长度
v=0
o=- 0 0 IN IP4 用户会话IP地址描述
s=-
c=IN IP4 用户媒体IP地址描述
m=audio 38564 RTP/AVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv

 语音会话请求响应如下:

SIP/2.0 200 OK
From: <sip: 用户地址编码@用户所属平台域名或IP地址>;tag=3101300
To: <sip: 前端设备地址编码@前端系统所属平台域名或IP地址>;tag=20b0660
Contact: <sip: 用户地址编码@用户所属平台域名或IP地址>
Call-ID: c47k42
Via: SIP/2.0/UDP 用户所属平台IP地址;branch=z9hG4bK
CSeq: 1 INVITE
Content-type: application/SDP
Content-Length: 消息体的长度
v=0
o=- 0 0 IN IP4 前端设备会话IP地址描述
s=-
c=IN IP4 前端设备媒体IP地址描述
m=audio 1000 RTP/AVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv

代码实现

    @Override
    public void ntsOnInviteTalk(String deviceId, SessionDescription sessionDescription) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                // 先振铃响应下
                gb28181_agent_.respondTalkInvite(180, device_id_);

                MediaSessionDescription audio_description = null;
                SDPRtpMapAttribute rtp_map_attribute = null;

                Vector<MediaSessionDescription> audio_des_list = session_description_.getAudioDescriptions();
                if (audio_des_list != null && !audio_des_list.isEmpty()) {
                    // 先尝试获取PCMA格式
                    for(MediaSessionDescription m : audio_des_list) {
                        if (m != null && m.isValidAddressType() && m.isHasAddress()) {
                            rtp_map_attribute = m.getRtpMapAttribute(SDPRtpMapAttribute.PCMA_ENCODING_NAME);
                            if (rtp_map_attribute != null) {
                                audio_description = m;
                                break;
                            }
                        }
                    }

                    // 如果没有PCMA格式,尝试获取PS格式
                    if (null == rtp_map_attribute) {
                        for(MediaSessionDescription m : audio_des_list) {
                            if (m != null && m.isValidAddressType() && m.isHasAddress()) {
                                rtp_map_attribute = m.getRtpMapAttribute(SDPRtpMapAttribute.PS_ENCODING_NAME);
                                if (rtp_map_attribute != null) {
                                    audio_description = m;
                                    break;
                                }
                            }
                        }
                    }
                }

                if (null == audio_description) {
                    gb28181_agent_.respondTalkInvite(488, device_id_);
                    Log.i(TAG, "ntsOnInviteTalk get audio description is null, response 488, device_id:" + device_id_);
                    return;
                }

                if (null == rtp_map_attribute ) {
                    gb28181_agent_.respondTalkInvite(488, device_id_);
                    Log.i(TAG, "ntsOnInviteTalk get rtp map attribute is null, response 488, device_id:" + device_id_);
                    return;
                }

                Log.i(TAG,"ntsOnInviteTalk, device_id:" +device_id_+", is_tcp:" + audio_description.isRTPOverTCP()
                        + " rtp_port:" + audio_description.getPort() + " ssrc:" + audio_description.getSSRC()
                        + " address_type:" + audio_description.getAddressType() + " address:" + audio_description.getAddress()
                        + " payload_type:" +   rtp_map_attribute.getPayloadType() + " encoding_name:" + rtp_map_attribute.getEncodingName());

                long rtp_sender_handle = libPublisher.CreateRTPSender(0);
                if (0 == rtp_sender_handle) {
                    gb28181_agent_.respondTalkInvite(488, device_id_);
                    Log.i(TAG, "ntsOnInviteTalk CreateRTPSender failed, response 488, device_id:" + device_id_);
                    return;
                }

                gb_talk_rtp_payload_type_  = rtp_map_attribute.getPayloadType();
                gb_talk_rtp_encoding_name_ = rtp_map_attribute.getEncodingName();

                Log.i(TAG, "gb_talk_rtp_payload_type: " + gb_talk_rtp_payload_type_ + " gb_talk_rtp_encoding_name: " + gb_talk_rtp_encoding_name_);

                gb_talk_rtp_encoding_name_ =  "PS";

                libPublisher.SetRTPSenderTransportProtocol(rtp_sender_handle, audio_description.isRTPOverUDP()?0:1);
                libPublisher.SetRTPSenderIPAddressType(rtp_sender_handle, audio_description.isIPv4()?0:1);
                //libPublisher.SetRTPSenderLocalPort(rtp_sender_handle, 0);
                libPublisher.SetRTPSenderLocalPort(rtp_sender_handle, audio_description.getPort());
                libPublisher.SetRTPSenderSSRC(rtp_sender_handle, audio_description.getSSRC());
                libPublisher.SetRTPSenderSocketSendBuffer(rtp_sender_handle, 256*1024); // 音频配置到256KB
                libPublisher.SetRTPSenderClockRate(rtp_sender_handle, rtp_map_attribute.getClockRate());
                libPublisher.SetRTPSenderDestination(rtp_sender_handle, audio_description.getAddress(), audio_description.getPort());

                gb_talk_is_receive_ = audio_description.isHasAttribute("sendrecv");

                Log.i(TAG, "gb_talk_is_receive: " + gb_talk_is_receive_);

                if (gb_talk_is_receive_) {
                    libPublisher.EnableRTPSenderReceive(rtp_sender_handle, 1);

                    // 收包SSRC, 暂时不设置, 因为部分平台ssrc不一致的
                    // libPublisher.SetRTPSenderReceiveSSRC(rtp_sender_handle, audio_description.getSSRC());

                    // 这个一定要设置
                    libPublisher.SetRTPSenderReceivePayloadType(rtp_sender_handle, gb_talk_rtp_payload_type_, gb_talk_rtp_encoding_name_, 2,  rtp_map_attribute.getClockRate());

                    // 目前发现某些平台 PS-PCMA 是8000, 不建议设置
                    if (gb_talk_rtp_encoding_name_.equals("PS")) {
                        libPublisher.SetRTPSenderReceivePSClockFrequency(rtp_sender_handle, 8000);
                     }

                    // 如果是PCMA编码, 采样率和通道可以先不设置
                    // libPublisher.SetRTPSenderReceiveAudioSamplingRate(rtp_sender_handle, 8000);
                    // libPublisher.SetRTPSenderReceiveAudioChannels(rtp_sender_handle, 1);
                }

                if (libPublisher.InitRTPSender(rtp_sender_handle) != 0 ) {
                    gb28181_agent_.respondTalkInvite(488, device_id_);
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    return;
                }

                int local_port = libPublisher.GetRTPSenderLocalPort(rtp_sender_handle);
                if (0==local_port) {
                    gb28181_agent_.respondTalkInvite(488, device_id_);
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    return;
                }

                Log.i(TAG,"ntsOnInviteTalk get local_port:" + local_port);

                String local_ip_addr = IPAddrUtils.getIpAddress(context_);

                MediaSessionDescription main_local_audio_des = new MediaSessionDescription(audio_description.getType());

                main_local_audio_des.addFormat(String.valueOf(rtp_map_attribute.getPayloadType()));
                main_local_audio_des.addRtpMapAttribute(rtp_map_attribute);

                main_local_audio_des.addAttribute(new SDPAttribute("sendonly"));
                if (audio_description.isRTPOverTCP()) {
                    // tcp主动链接服务端
                    main_local_audio_des.addAttribute(new SDPAttribute("setup", "active"));
                    main_local_audio_des.addAttribute(new SDPAttribute("connection", "new"));
                }

                main_local_audio_des.setPort(local_port);
                main_local_audio_des.setTransportProtocol(audio_description.getTransportProtocol());

                main_local_audio_des.setSSRC(audio_description.getSSRC());

                MediaSessionDescription sub_local_audio_des = null;
                if (gb_talk_is_receive_) {
                    sub_local_audio_des = new MediaSessionDescription(audio_description.getType());

                    sub_local_audio_des.addFormat(String.valueOf(rtp_map_attribute.getPayloadType()));
                    sub_local_audio_des.addRtpMapAttribute(rtp_map_attribute);

                    sub_local_audio_des.addAttribute(new SDPAttribute("recvonly"));
                    if (audio_description.isRTPOverTCP()) {
                        // tcp主动链接服务端
                        sub_local_audio_des.addAttribute(new SDPAttribute("setup", "active"));
                        sub_local_audio_des.addAttribute(new SDPAttribute("connection", "new"));
                    }

                    sub_local_audio_des.setPort(local_port);
                    sub_local_audio_des.setTransportProtocol(audio_description.getTransportProtocol());

                    sub_local_audio_des.setSSRC(audio_description.getSSRC());
                }

                if (!gb28181_agent_.respondTalkInviteOK(device_id_, audio_description.getAddressType(), local_ip_addr, main_local_audio_des, sub_local_audio_des) ) {
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    Log.e(TAG, "ntsOnInviteTalk call respondPlayInviteOK failed.");
                    return;
                }

                gb_talk_rtp_sender_handle_ = rtp_sender_handle;
            }

            private String device_id_;
            private SessionDescription session_description_;

            public Runnable set(String device_id, SessionDescription session_des) {
                this.device_id_ = device_id;
                this.session_description_ = session_des;
                return this;
            }
        }.set(deviceId, sessionDescription),0);
    }

总结

国网B接口的语音广播和语音对讲,和GB28181的还是有些差别,B接口的语音广播和语音对讲,不需要先发broadcast过来,不用设备接入端发invite请求,而是电网平台侧发invite,类似实时视频请求播放流程,感兴趣的开发者,可以根据规范仔细解读研究。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/424626.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小白学Pytorch系列--Torch.optim API Scheduler(4)

小白学Pytorch系列–Torch.optim API Scheduler(4) 方法注释lr_scheduler.LambdaLR将每个参数组的学习率设置为初始lr乘以给定函数。lr_scheduler.MultiplicativeLR将每个参数组的学习率乘以指定函数中给定的因子。lr_scheduler.StepLR每个步长周期衰减每个参数组的学习率。lr_…

RFID技术在智慧图书馆盘点系统中的优势

RFID射频识别及技术&#xff0c;作为一种新兴的非接触式的自动识别技术&#xff0c;其基本原理是电磁理论&#xff0c;因其操作便捷高效&#xff0c;无需人工干预&#xff0c;可在各种恶劣环境下&#xff0c;通过射频信号自动识别目标并获取相关数据&#xff0c;可识别高速运动…

LightGBM论文翻译

0.摘要 Gradient Boosting Decision Tree (GBDT)是一个非常流行的机器学习算法&#xff0c;却只有像XGBoost和pGBRT的一些实现。尽管许多工程上的优化方案已经在这些实现中应用了&#xff0c;但是当特征维度较高和数据量巨大的时候&#xff0c;仍然存在效率和可扩展性的问题。…

家庭智能插座一Homekit智能

传统的灯泡是通过手动打开和关闭开关来工作。有时&#xff0c;它们可以通过声控、触控、红外等方式进行控制&#xff0c;或者带有调光开关&#xff0c;让用户调暗或调亮灯光。 智能灯泡内置有芯片和通信模块&#xff0c;可与手机、家庭智能助手、或其他智能硬件进行通信&#x…

L2-031 深入虎穴

著名的王牌间谍 007 需要执行一次任务&#xff0c;获取敌方的机密情报。已知情报藏在一个地下迷宫里&#xff0c;迷宫只有一个入口&#xff0c;里面有很多条通路&#xff0c;每条路通向一扇门。每一扇门背后或者是一个房间&#xff0c;或者又有很多条路&#xff0c;同样是每条路…

电脑频繁出现0x0000000A蓝屏错误怎么重装系统?

电脑频繁出现0x0000000A蓝屏错误怎么重装系统&#xff1f;有的小伙伴使用电脑的时候&#xff0c;总是会出现蓝屏的问题&#xff0c;导致自己不得不进行系统的重装。遇到这个情况只能是使用U盘来进行系统的重装了。一起来看看以下的具体操作方法教学吧。 准备工作&#xff1a; 1…

ClickHouse实现大数据探索性分析

分析数据一般会从探索性分析开始&#xff0c;即尝试理解数据本身的概况。通常包括中位数、平均值或分布情况&#xff0c;Python Numpy/Pandas很容易实现&#xff0c;但如果数据量为Tb级&#xff0c;不能简单依赖RAM工具实现。ClickHouse提供的强大的工具来挖掘数据&#xff0c;…

7.基于概率距离快速削减法的风光场景生成与削减方法

matlab代码&#xff1a;基于概率距离快速削减法的风光场景生成与削减方法 参考代码资源&#xff1a;风、光、负荷场景生成&#xff1b;风电出力各场景及概率&#xff1b;光伏出力各场景及概率&#xff1b;负荷各场景及概率&#xff1b;场景的削减&#xff1b;样本概率初始化&a…

【大数据基础】基于 TMDB 数据集的电影数据分析

https://dblab.xmu.edu.cn/blog/2400/ 实验内容 环境搭建 pip3 install bottle数据预处理 本次项目使用的数据集来自知名数据网站 Kaggle 的 tmdb-movie-metadata 电影数据集&#xff0c;该数据集包含大约 5000 部电影的相关数据。本次实验使用数据集中有关电影的数据表 tm…

五一临近,赋能乡村振兴,低代码也有话讲!

中国作为农业生产大国&#xff0c;农业已成为近千年来中国主要的经济来源&#xff0c;农民人口基数庞大。因此&#xff0c;乡村振兴战略的提出对推进农业农村现代化具有重要意义&#xff0c;治理好乡村成为解决“三农”问题的必要举措。 随着时代的发展&#xff0c;人们反而更向…

【STC8A8K64D4开发板】——有源蜂鸣器鸣响控制

学习目的 掌握有源蜂鸣器驱动电路的设计&#xff1a;控制方式、限流电阻的计算和确定。了解有源蜂鸣器的特性以及和无源蜂鸣器的区别。 硬件电路设计 开发板上的蜂鸣器驱动电路如下图所示&#xff0c;使用的蜂鸣器是3V有源蜂鸣器&#xff0c;这里&#xff0c;我们有必要了解…

Vue学习——【第二弹】

前言 上一篇文章 Vue学习——【第一弹】 中我们学习了Vue的相关特点及语法&#xff0c;这篇文章接着通过浏览器中的Vue开发者工具扩展来进一步了解Vue的相关工作机制。 Vue的扩展 我们打开Vue的官方文档&#xff0c;点击导航栏中的生态系统&#xff0c;点击Devtools 接着我…

C/C++|物联网开发入门+项目实战|嵌入式C语言高级|简介及GCC参数|define|编译过程-学习笔记(7)

课程介绍 参考&#xff1a;麦子学院-嵌入式C语言高级 本套课程的定位 前导课程:掌握简单C语言的基本语法 计算机程序语言的学习思路? 基本程序设计思想&#xff0b;语言工具的特性 基本程序设计思想: 数据类型、运算符、条件分支、循环设计 面向对象的设计 C语言工具的特性…

数据库系统笔记CH5(初)

计组的知识 虚拟存储 IEEE754标准 5.1存储层级 二级存储器磁盘和固态硬盘 红色部分是磁道&#xff0c;蓝色部分是扇区&#xff0c;绿色指示部分是数据库中的一个块/页 块/页是我们用来存储介质的一个物理单元,数据写入磁盘以块位单位写入内存,一个块的大小一般是4KB或者8KB&…

项目管理中,这些思维误区一定要避开

项目需要在限定的时间要求完成的事情&#xff0c;可控的关键把握是&#xff1a;人、时、事。 但是&#xff0c;项目实施时间一般较长&#xff0c;总有很多项目实施结果不尽人意。那么&#xff0c;IT项目管理过程中&#xff0c;容易出现哪些思维误区呢&#xff1f; 1、忘记项…

react性能优化之shouldComponentUpdate的原理剖析

shouldComponentUpdate原理讲解shouldComponentUpdate是干什么的怎么使state更新而render函数不执行呢&#xff1f;使用shouldComponentUpdate完成性能优化当组件的state没有变化&#xff0c;props也没有变化&#xff0c;render函数可能执行吗&#xff1f;pureComponent的基本用…

北京小厂Java实习面经

目录1.数据库的三大范式2.事务四个特性3.知道多少种索引&#xff0c;分别讲讲4.主键索引和唯一索引的区别5.索引失效的场景6.数据库的日志知道哪些&#xff0c;分别讲讲7.redis的数据结构和应用场景8.缓存击穿是怎么产生的&#xff0c;解决方案9.redis中key的过期策略10.redis内…

达梦数据库支持GB18030-2022中文编码字符集证明方法

既然是证明就要做到有图有真相。 证明途径1&#xff1a;系统概览法 查看达梦数据库“管理工具”->“对象导航”->“管理服务器”-“系统概览”->“字符集编码”->”GB18030”. 看见”GB18030”字样就是证据之一。如果你没有看见这个字样&#xff0c;而是UTF8等其…

1. 大端法和小端法

int32_t num 0x01020304;一个int32_t是4个字节&#xff0c;在内存中的存储是高位字节在低地址&#xff0c;低位字节在高地址。 &#xff08;数字&#xff09;前者的高低是数字位数的高低&#xff0c;左边是高位数&#xff0c;右边是低位数&#xff1b; &#xff08;地址&…

git代码使用空格缩进

1、idea设置缩进符为空格 Java 代码 golang 代码 2、设置提交仓库时的空格处理&#xff0c;否则 golang 代码为了减少文件大小&#xff0c;可能会把空格缩进改为制表符。 设置当前仓库配置 git config core.whitespace "-trailing-space,space-before-tab" 设置当前…