如何在Android平台GB28181接入终端实现语音广播和语音对讲

技术背景

在之前的blog,我们以Android平台国标接入终端为例,分别介绍了一些常规的功能,比如REGISTER、CATALOG、INVITE、Keepalive、SUBSCRIBE、NOTIFY等常规操作,今天主要介绍下语音广播和语音对讲这部分。

GB28181平台广播和对讲这块,重要性不言而喻,没有广播的接入终端,数据只是单向流入,加入后,指挥中心和终端之间的联系更紧密,实时双向沟通更方便,适用的行业范围也更广泛。

相关SPEC解读

关于语音广播和对讲,感兴趣的开发者可直接参阅GBT 28181-2016.pdf相关技术规范里面的9.12章节,以下是部分精选介绍:

命令交互流程

命令描述流程

a) 1:SIP服务器向语音流接收者发送语音广播通知消息,消息中通过 To头域标明作为目的地址 的语音流接收者ID,消息采用 Message方法携带。

举例说明:

MESSAGE sip:34020000001380000001@192.168.2.212:12070 SIP/2.0
Via: SIP/2.0/UDP 192.168.2.154:15060;rport;branch=z9hG4bK311226558
From: <sip:34020000002000000001@3402000000>;tag=280226558
To: <sip:34020000001380000001@192.168.2.212:12070>
Call-ID: 172226558
CSeq: 207 MESSAGE
Content-Type: Application/MANSCDP+xml
Max-Forwards: 70
Content-Length: 206<?xml version="1.0" encoding="GB2312"?>
<Notify><CmdType>Broadcast</CmdType><SN>461226558</SN><SourceID>34020000002000000001</SourceID><TargetID>34020000001380000001</TargetID>
</Notify>

b) 2:语音流接收者收到语音广播通知消息后,向SIP服务器发送200OK 响应。

SIP/2.0 200 OK
CSeq: 207 MESSAGE
Call-ID: 172226558
From: <sip:34020000002000000001@3402000000>;tag=280226558
To: <sip:34020000001380000001@192.168.2.212:12070>
Via: SIP/2.0/UDP 192.168.2.154:15060;rport=15060;branch=z9hG4bK311226558;received=192.168.2.154
Content-Length: 0

c) 3:语音流接收者向SIP服务器发送语音广播应答消息,消息中通过 To头域标明作为目的地 址的SIP服务器ID,消息采用 Message方法携带。

MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
Call-ID: 0fc1f2c83c28898a29e146d7ef581908@192.168.2.212
CSeq: 337044229 MESSAGE
From: <sip:34020000001380000001@3402000000>;tag=93882333
To: <sip:34020000002000000001@3402000000>
Via: SIP/2.0/UDP 192.168.2.212:12070;rport;branch=z9hG4bK-363733-79fd88c45667975e5ebaf18f84b91a8e
Max-Forwards: 70
User-Agent: NT GB28181 User Agent V1.2(daniusdk.com)
Content-Type: Application/MANSCDP+xml
Content-Length: 180<?xml version="1.0" encoding="GB2312"?>
<Response>
<CmdType>Broadcast</CmdType>
<SN>461226558</SN>
<DeviceID>34020000001380000001</DeviceID>
<Result>OK</Result>
</Response>

d) 4:SIP服务器收到语音广播应答消息后,向语音流接收者发送200OK 响应。

SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.2.212:12070;rport=12070;received=192.168.2.212;branch=z9hG4bK-363733-79fd88c45667975e5ebaf18f84b91a8e
From: <sip:34020000001380000001@3402000000>;tag=93882333
To: <sip:34020000002000000001@3402000000>;tag=355226593
CSeq: 337044229 MESSAGE
Call-ID: 0fc1f2c83c28898a29e146d7ef581908@192.168.2.212
Content-Length: 0

e) 5:语音流接收者向SIP服务器发送Invite消息,消息中通过 To头域标明作为目的地址的语音 流发送者ID,消息头域中携带Subject字段,表明请求的语音流发送者ID、发送方媒体流序列 号、语音流接收者ID、接收方媒体流序列号等参数,SDP消息体中s字段为“Play”代表实时点 播,m 字段中媒体参数标识为“audio”表示请求语音媒体流。

INVITE sip:34020000002000000001@3402000000 SIP/2.0
Call-ID: 2b4f0f0512aa1a49ffc645618d0e8bae@192.168.2.212
CSeq: 44264 INVITE
From: <sip:34020000001380000001@3402000000>;tag=32ecf22a
To: <sip:34020000002000000001@3402000000>
Via: SIP/2.0/UDP 192.168.2.212:12070;rport;branch=z9hG4bK-363733-15283c8a0ea0a1e9dbf295ce2359dbe7
Max-Forwards: 70
Contact: <sip:34020000001380000001@192.168.2.212:12070>
Subject: 34020000002000000001:0200006727,34020000001380000001:0
User-Agent: NT GB28181 User Agent V1.2(daniusdk.com)
Content-Type: APPLICATION/SDP
Content-Length: 221v=0
o=34020000002000000001 0 0 IN IP4 192.168.2.212
s=Play
c=IN IP4 192.168.2.212
t=0 0
m=audio 25002 TCP/RTP/AVP 8
a=setup:active
a=connection:new
a=recvonly
a=rtpmap:8 PCMA/8000
y=0200006727
f=v/a/1/8/1

f) 6:SIP服务器收到Invite请求后,通过三方呼叫控制建立媒体服务器和语音流发送者之间的媒体连接。向媒体服务器发送Invite消息,此消息不携带SDP消息体。

g) 7:媒体服务器收到SIP服务器的Invite请求后,回复200OK 响应,携带SDP消息体,消息体 中描述了媒体服务器接收媒体流的IP、端口、媒体格式等内容。

h) 8:SIP服务器收到媒体服务器返回的200OK 响应后,向语音流发送者发送Invite请求,消息 中通过 To头域标明作为目的地址的语音流发送者ID,消息头域中携带 Subject字段,表明请 求的语音流发送者ID、发送方媒体流序列号、语音流接收者ID、接收方媒体流序列号等参数, 请求中携带消息7中媒体服务器回复的200OK 响应消息体,s字段为“Play”代表实时点播, m 字段中媒体参数标识为“audio”表示请求语音媒体流,增加y字段描述SSRC值,f字段描述 媒体参数。

SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.2.212:12070;rport=12070;received=192.168.2.212;branch=z9hG4bK-363733-15283c8a0ea0a1e9dbf295ce2359dbe7
From: <sip:34020000001380000001@3402000000>;tag=32ecf22a
To: <sip:34020000002000000001@3402000000>;tag=954226632
CSeq: 44264 INVITE
Call-ID: 2b4f0f0512aa1a49ffc645618d0e8bae@192.168.2.212
Contact: <sip:34020000002000000001@192.168.2.154:15060>
Content-Length: 222
Content-Type: APPLICATION/SDPv=0
o=34020000002000000001 0 0 IN IP4 192.168.2.154
s=Play
c=IN IP4 192.168.2.154
t=0 0
m=audio 30005 TCP/RTP/AVP 8
a=sendonly
a=rtpmap:8 PCMA/8000
a=setup:passive
a=connection:new
y=0200006727
f=v/a/1/8/1

i) 9:语音流发送者收到SIP服务器的Invite请求后,回复200OK 响应,携带SDP消息体,消息 体中描述了媒体流发送者发送媒体流的IP、端口、媒体格式、SSRC 字段等内容,s字段为 “Play”代表实时点播,m 字段中媒体参数标识为“audio”表示请求语音媒体流。

j) 10:SIP服务器收到语音流发送者返回的200OK 响应后,向媒体服务器发送 ACK 请求,请求 中携带消息9中语音流发送者回复的200OK 响应消息体,完成与媒体服务器的Invite会话 建立过程。

k) 11:SIP服务器收到语音流发送者返回的200OK 响应后,向语音流发送者发送 ACK 请求,请 求中不携带消息体,完成与语音流发送者的Invite会话建立过程。

l) 12:完成三方呼叫控制后,SIP服务器通过 B2BUA 代理方式建立语音流接收者和媒体服务器 之间的媒体连接。在消息5中增加SSRC值,转发给媒体服务器。

m)13:媒体服务器收到Invite请求,回复200OK 响应,携带SDP消息体,消息体中描述了媒体服 务器发送媒体流的IP、端口、媒体格式、SSRC值等内容,s字段为“Play”代表实时点播,m 字段 中媒体参数标识为“audio”表示请求语音媒体流。

n) 14:SIP服务器将消息13转发给语音流接收者。

o) 15:语音流接收者收到200OK 响应后,回复 ACK 消息,完成与SIP服务器的Invite会话建立 过程。

p) 16:SIP服务器将消息15转发给媒体服务器,完成与媒体服务器的Invite会话建立过程。

q) 17:SIP服务器向语音流接收者发送 BYE消息,断开消息5、14、15建立的Invite会话。

r) 18:语音流接收者收到 BYE消息后回复200OK 响应,会话断开。

s) 19:SIP服务器向媒体服务器发送 BYE 消息,断开消息 12、13、16 建立的同媒体服务器的 Invite会话。

t) 20:媒体服务器收到 BYE消息后回复200OK 响应,会话断开。

u) 21:SIP服务器向媒体服务器发送 BYE消息,断开消息6、7、10建立的同媒体服务器的Invite 会话。

v) 22:媒体服务器收到 BYE消息后回复200OK 响应,会话断开。

w)23:SIP服务器向语音流发送者发送 BYE 消息,断开消息8、9、11建立的同语音流发送者的 Invite会话。

x) 24:语音流发送者收到 BYE消息后回复200OK 响应,会话断开。

注:语音广播通知消息除上述流程中通过SIP服务器发出外,也可由语音流发送者发出,消息中通过 To头域标明 作为目的地址的语音流接收者ID,经SIP服务器中转后发往语音流接收者;语音流接收者处理后发送应答消 息,消息中通过 To头域标明作为目的地址的语音流发送者ID,经SIP服务器中转后回复给语音流发送者。后续呼叫流程与上述流程相同。

语音对讲

语音对讲功能实现中心用户与前端用户之间的一对一语音对讲功能。 语音对讲功能由下述两个独立的流程组合实现:

a) 通过9.2的实时视音频点播功能,中心用户获得前端设备的实时视音频媒体流;

b) 通过9.12的语音广播功能,中心用户向前端对讲设备发送实时音频媒体流,语音流的封装格 式见 C.2.4音频流的 RTP封装定义。

C.2.4 音频流的 RTP封装

语音比特流宜采用标准的 RTP协议进行打包,这里只摘录G.711A律的:

在一个 RTP包中,音频载荷数据应为整数个音频编码帧,且时间长度在20ms~180ms之间。

音频载荷数据的 RTP封装参数如下:

a) G.711的主要参数 G.711A律语音编码 RTP包的负载类型(PayloadType)的参数规定如下(见IETFRFC3551— 2003中的表4): 1)负载类型(PT):8; 2) 编码名称(encodingname):PCMA; 3) 时钟频率(clockrate):8kHz; 4) 通道数:1; 5) SDP描述中“m”字段的“media”项:audio。

技术实现

语音广播接收这块,由于有之前的RTMP和RTSP播放器积累,直接在player端做相应扩展即可,当收到广播后,GB28181语音广播按钮使能。

相关接口设计如下:

/*++++++++++++++++++RTP Receiver++++++++++++++++++++++*///GitHub: https://github.com/daniulive/SmarterStreaming//WebSite: https://daniusdk.com/** 创建RTP Receiver** @param reserve:保留参数传0** @return RTP Receiver 句柄,0表示失败*/public native long CreateRTPReceiver(int reserve);/***设置 RTP Receiver传输协议** @param rtp_receiver_handle, CreateRTPReceiver* @param transport_protocol, 0:UDP, 1:TCP, 默认是UDP** @return {0} if successful*/public native int SetRTPReceiverTransportProtocol(long rtp_receiver_handle, int transport_protocol);/***设置 RTP Receiver IP地址类型** @param rtp_receiver_handle, CreateRTPReceiver* @param ip_address_type, 0:IPV4, 1:IPV6, 默认是IPV4** @return {0} if successful*/public native int SetRTPReceiverIPAddressType(long rtp_receiver_handle, int ip_address_type);/***设置 RTP Receiver RTP Socket本地端口** @param rtp_receiver_handle, CreateRTPReceiver* @param port, 必须是偶数,设置0的话SDK会自动分配, 默认值是0** @return {0} if successful*/public native int SetRTPReceiverLocalPort(long rtp_receiver_handle, int port);/***设置 RTP Receiver SSRC** @param rtp_receiver_handle, CreateRTPReceiver* @param ssrc, 如果设置的话,这个字符串要能转换成uint32类型, 否则设置失败** @return {0} if successful*/public native int SetRTPReceiverSSRC(long rtp_receiver_handle, String ssrc);/***创建 RTP Receiver 会话** @param rtp_receiver_handle, CreateRTPReceiver* @param reserve, 保留值,目前传0** @return {0} if successful*/public native int CreateRTPReceiverSession(long rtp_receiver_handle, int reserve);/***获取 RTP Receiver RTP Socket本地端口** @param rtp_receiver_handle, CreateRTPReceiver** @return 失败返回0, 成功的话返回响应的端口, 请在CreateRTPReceiverSession返回成功之后调用*/public native int GetRTPReceiverLocalPort(long rtp_receiver_handle);/***设置 RTP Receiver Payload 相关信息** @param rtp_receiver_handle, CreateRTPReceiver** @param payload_type, 请参考 RFC 3551** @param encoding_name, 编码名, 请参考 RFC 3551, 如果payload_type不是动态的, 可能传null就好** @param media_type, 媒体类型, 请参考 RFC 3551, 1 是视频, 2是音频** @param clock_rate, 请参考 RFC 3551** @return {0} if successful*/public native int SetRTPReceiverPayloadType(long rtp_receiver_handle, int payload_type, String encoding_name, int media_type, int clock_rate);/***设置 RTP Receiver 音频采样率** @param rtp_receiver_handle, CreateRTPReceiver* @param sampling_rate, 音频采样率** @return {0} if successful*/public native int SetRTPReceiverAudioSamplingRate(long rtp_receiver_handle, int sampling_rate);/***设置 RTP Receiver 音频通道数** @param rtp_receiver_handle, CreateRTPReceiver* @param channels, 音频通道数** @return {0} if successful*/public native int SetRTPReceiverAudioChannels(long rtp_receiver_handle, int channels);/***设置 RTP Receiver 远端地址** @param rtp_receiver_handle, CreateRTPReceiver* @param address, IP地址* @param port, 端口** @return {0} if successful*/public native int SetRTPReceiverRemoteAddress(long rtp_receiver_handle, String address, int port);/***初始化 RTP Receiver** @param rtp_receiver_handle, CreateRTPReceiver** @return {0} if successful*/public native int InitRTPReceiver(long rtp_receiver_handle);/***UnInit RTP Receiver** @param rtp_receiver_handle, CreateRTPReceiver** @return {0} if successful*/public native int UnInitRTPReceiver(long rtp_receiver_handle);/***Destory RTP Receiver Session** @param rtp_receiver_handle, CreateRTPReceiver** @return {0} if successful*/public native int DestoryRTPReceiverSession(long rtp_receiver_handle);/***Destory RTP Receiver** @param rtp_receiver_handle, CreateRTPReceiver** @return {0} if successful*/public native int DestoryRTPReceiver(long rtp_receiver_handle);/*++++++++++++++++++RTP Receiver++++++++++++++++++++++*/

相关调用代码:

class ButtonGB28181AudioBroadcastListener implements OnClickListener {public void onClick(View v) {if (gb_broadcast_source_id_ != null && gb_broadcast_target_id_ != null) {if (gb28181_agent_ != null ) {if (gb28181_agent_.byeAudioBroadcast(gb_broadcast_source_id_, gb_broadcast_target_id_) ) {gb_broadcast_source_id_ = null;gb_broadcast_target_id_ = null;btnGB28181AudioBroadcast.setText("GB28181语音广播");btnGB28181AudioBroadcast.setEnabled(false);}}}stopAudioPlayer();destoryRTPReceiver();}}
@Override
public void ntsOnNotifyBroadcastCommand(String fromUserName, String fromUserNameAtDomain, String sn, String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnNotifyBroadcastCommand, fromUserName:"+ from_user_name_ + ", fromUserNameAtDomain:"+ from_user_name_at_domain_+ ", SN:" + sn_ + ", sourceID:" + source_id_ + ", targetID:" + target_id_);if (gb28181_agent_ != null ) {gb28181_agent_.respondBroadcastCommand(from_user_name_, from_user_name_at_domain_,sn_,source_id_, target_id_, true);btnGB28181AudioBroadcast.setText("收到GB28181语音广播通知");}}private String from_user_name_;private String from_user_name_at_domain_;private String sn_;private String source_id_;private String target_id_;public Runnable set(String from_user_name, String from_user_name_at_domain, String sn, String source_id, String target_id) {this.from_user_name_ = from_user_name;this.from_user_name_at_domain_ = from_user_name_at_domain;this.sn_ = sn;this.source_id_ = source_id;this.target_id_ = target_id;return this;}}.set(fromUserName, fromUserNameAtDomain, sn, sourceID, targetID),0);
}@Override
public void ntsOnAudioBroadcast(String commandFromUserName, String commandFromUserNameAtDomain, String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnAudioBroadcastPlay, fromFromUserName:" + command_from_user_name_+ " FromUserNameAtDomain:" + command_from_user_name_at_domain_+ " sourceID:" + source_id_ + ", targetID:" + target_id_);stopAudioPlayer();destoryRTPReceiver();if (gb28181_agent_ != null ) {String local_ip_addr = IPAddrUtils.getIpAddress(context_);boolean is_tcp = true; // 考虑到跨网段, 默认用TCP传输rtp包rtp_receiver_handle_ = lib_player_.CreateRTPReceiver(0);if (rtp_receiver_handle_ != 0 ) {lib_player_.SetRTPReceiverTransportProtocol(rtp_receiver_handle_, is_tcp?1:0);lib_player_.SetRTPReceiverIPAddressType(rtp_receiver_handle_, 0);if (0 == lib_player_.CreateRTPReceiverSession(rtp_receiver_handle_, 0) ) {int local_port = lib_player_.GetRTPReceiverLocalPort(rtp_receiver_handle_);boolean ret = gb28181_agent_.inviteAudioBroadcast(command_from_user_name_,command_from_user_name_at_domain_,source_id_, target_id_, "IP4", local_ip_addr, local_port, is_tcp?"TCP/RTP/AVP":"RTP/AVP");if (!ret ) {destoryRTPReceiver();btnGB28181AudioBroadcast.setText("GB28181语音广播");}else {btnGB28181AudioBroadcast.setText("GB28181语音广播呼叫中");}} else {destoryRTPReceiver();btnGB28181AudioBroadcast.setText("GB28181语音广播");}}}}private String command_from_user_name_;private String command_from_user_name_at_domain_;private String source_id_;private String target_id_;public Runnable set(String command_from_user_name, String command_from_user_name_at_domain, String source_id, String target_id) {this.command_from_user_name_ = command_from_user_name;this.command_from_user_name_at_domain_ = command_from_user_name_at_domain;this.source_id_ = source_id;this.target_id_ = target_id;return this;}}.set(commandFromUserName, commandFromUserNameAtDomain, sourceID, targetID),0);
}@Override
public void ntsOnInviteAudioBroadcastException(String sourceID, String targetID, String errorInfo) {handler_.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnInviteAudioBroadcastException, sourceID:" + source_id_ + ", targetID:" + target_id_);destoryRTPReceiver();btnGB28181AudioBroadcast.setText("GB28181语音广播");}private String source_id_;private String target_id_;public Runnable set(String source_id, String target_id) {this.source_id_ = source_id;this.target_id_ = target_id;return this;}}.set(sourceID, targetID),0);
}@Override
public void ntsOnInviteAudioBroadcastTimeout(String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnInviteAudioBroadcastTimeout, sourceID:" + source_id_ + ", targetID:" + target_id_);destoryRTPReceiver();btnGB28181AudioBroadcast.setText("GB28181语音广播");}private String source_id_;private String target_id_;public Runnable set(String source_id, String target_id) {this.source_id_ = source_id;this.target_id_ = target_id;return this;}}.set(sourceID, targetID),0);
}
@Override
public void ntsOnInviteAudioBroadcastResponse(String sourceID, String targetID, int statusCode, PlaySessionDescription sessionDescription) {handler_.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnInviteAudioBroadcastResponse, statusCode:" + status_code_ +" sourceID:" + source_id_ + ", targetID:" + target_id_);boolean is_need_destory_rtp = true;if (gb28181_agent_ != null ) {boolean is_need_bye = 200==status_code_;if (200 == status_code_ && session_description_ != null && rtp_receiver_handle_ != 0 ) {MediaSessionDescription audio_des = session_description_.getAudioDescription();SDPRtpMapAttribute audio_attr = null;if (audio_des != null && audio_des.getRtpMapAttributes() != null && !audio_des.getRtpMapAttributes().isEmpty() )audio_attr = audio_des.getRtpMapAttributes().get(0);if ( audio_des != null && audio_attr != null ) {lib_player_.SetRTPReceiverSSRC(rtp_receiver_handle_, audio_des.getSSRC());lib_player_.SetRTPReceiverPayloadType(rtp_receiver_handle_, audio_attr.getPayloadType(),audio_attr.getEncodingName(), 2, audio_attr.getClockRate());lib_player_.SetRTPReceiverRemoteAddress(rtp_receiver_handle_, audio_des.getAddress(), audio_des.getPort());lib_player_.InitRTPReceiver(rtp_receiver_handle_);if (startAudioPlay()) {is_need_bye = false;is_need_destory_rtp = false;gb_broadcast_source_id_ = source_id_;gb_broadcast_target_id_ = target_id_;btnGB28181AudioBroadcast.setText("终止GB28181语音广播");btnGB28181AudioBroadcast.setEnabled(true);}}} else {btnGB28181AudioBroadcast.setText("GB28181语音广播");}if (is_need_bye)gb28181_agent_.byeAudioBroadcast(source_id_, target_id_);}if (is_need_destory_rtp)destoryRTPReceiver();}private String source_id_;private String target_id_;private int status_code_;private PlaySessionDescription session_description_;public Runnable set(String source_id, String target_id, int status_code, PlaySessionDescription session_description) {this.source_id_ = source_id;this.target_id_ = target_id;this.status_code_ = status_code;this.session_description_ = session_description;return this;}}.set(sourceID, targetID, statusCode, sessionDescription),0);
}@Override
public void ntsOnByeAudioBroadcast(String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnByeAudioBroadcast sourceID:" + source_id_ + " targetID:" + target_id_);gb_broadcast_source_id_ = null;gb_broadcast_target_id_ = null;btnGB28181AudioBroadcast.setText("GB28181语音广播");btnGB28181AudioBroadcast.setEnabled(false);stopAudioPlayer();destoryRTPReceiver();}private String source_id_;private String target_id_;public Runnable set(String source_id, String target_id) {this.source_id_ = source_id;this.target_id_ = target_id;return this;}}.set(sourceID, targetID),0);
}@Override
public void ntsOnTerminateAudioBroadcast(String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnTerminateAudioBroadcast sourceID:" + source_id_ + " targetID:" + target_id_);gb_broadcast_source_id_ = null;gb_broadcast_target_id_ = null;btnGB28181AudioBroadcast.setText("GB28181语音广播");btnGB28181AudioBroadcast.setEnabled(false);stopAudioPlayer();destoryRTPReceiver();}private String source_id_;private String target_id_;public Runnable set(String source_id, String target_id) {this.source_id_ = source_id;this.target_id_ = target_id;return this;}}.set(sourceID, targetID),0);
}

总结

至此、Android平台GB28181接入终端,如位置订阅、语音广播和语音对讲这块已经全面覆盖,加上之前的技术积累,看了下,已覆盖了以下部分:

  • ​[视频格式]H.264/H.265(Android H.265硬编码);
  • [音频格式]G.711 A律、AAC;
  • [音量调节]Android平台采集端支持实时音量调节;
  • [H.264硬编码]支持H.264特定机型硬编码;
  • [H.265硬编码]支持H.265特定机型硬编码;
  • [软硬编码参数配置]支持gop间隔、帧率、bit-rate设置;
  • [软编码参数配置]支持软编码profile、软编码速度、可变码率设置;
  • 支持纯视频、音视频PS打包传输;
  • 支持RTP OVER UDP和RTP OVER TCP被动模式;
  • 支持信令通道网络传输协议TCP/UDP设置;
  • 支持注册、注销,支持注册刷新及注册有效期设置;
  • 支持设备目录查询应答;
  • 支持心跳机制,支持心跳间隔、心跳检测次数设置;
  • 支持移动设备位置(MobilePosition)订阅和通知;
  • 支持国标GB/T28181—2016平台接入;
  • 支持语音广播及语音对讲;
  • [实时水印]支持动态文字水印、png水印;
  • [实时静音]支持实时静音/取消静音;
  • [实时快照]支持实时快照;
  • [降噪]支持环境音、手机干扰等引起的噪音降噪处理、自动增益、VAD检测。​

特别是语音广播和语音对讲这块,是GB28181终端接入模块的一个核心扩展功能,在智能门禁、工业与物联网、监控等行业,用途非常广泛,技术实现这块,不要忽略的技术点还有降噪和回音消除这块,由于之前我们有技术积累,可以直接复用,对新入手的开发者来说,也提出了新的挑战,感兴趣的开发者,可以酌情参考。

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

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

相关文章

Android GB28181设备接入端语音广播和语音对讲技术实现探究

上篇文章提到Android端GB28181接入端的语音广播和语音对讲的实现&#xff0c;从spec角度大概介绍了下流程和简单的接口设计&#xff0c;好多开发者私信我&#xff0c;希望展开说一下。其实这块难度不大&#xff0c;只是广播和对讲涉及到双向实现&#xff0c;如果之前没有相关的…

微信公众号页面模版怎么添加文章推荐功能

微信公众号中发布的文章可以添加推荐的文章&#xff0c;该怎么添加文章推荐功能呢?下面我们就来看看详细的教程。 微信公众号页面模版怎么添加文章推荐功能? 1、登录微信公众平台&#xff0c;选择“功能”——“页面模板”——“添加模板” 微信公众号页面模版怎么添加文章…

Android native层实现MediaCodec编码H264/HEVC

Android平台在上层实现mediacodec的编码&#xff0c;资料泛滥&#xff0c;已经不再是难事&#xff0c;今天给大家介绍下&#xff0c;如何在Android native层实现MediaCodec编码H264/HEVC&#xff0c;网上千篇一律的接口说明&#xff0c;这里不再赘述&#xff0c;本文主要介绍下…

edge浏览器运行不流畅怎么办 提高edge浏览器速度的方法

edge浏览器是win10系统的专用浏览器&#xff0c;它代替了慢吞吞的IE&#xff0c;很多人觉得edge浏览器运行速度快&#xff0c;但是有时候浏览某些网站的时候会不流畅&#xff0c;所以怎么提高edge浏览器的运行速度呢&#xff0c;小编就来教教大家。 1、打开Edge浏览器后&#…

GB/T 28181联网系统通信协议结构和技术实现

技术回顾 在本文开头&#xff0c;我们先一起回顾下GB/T28181联网系统通信协议结构&#xff1a; 联网系统在进行视音频传输及控制时应建立两个传输通道&#xff1a;会话通道和媒体流通道。 会话通道用于在设备之间建立会话并传输系统控制命令&#xff1b;媒体流通道用于传输视…

Android平台GB28181设备接入端对接编码前后音视频源类型浅析

前言 今天主要对Android平台GB28181设备接入模块支持的接入数据类型&#xff0c;做个简单的汇总&#xff1a; 编码前数据&#xff08;目前支持的有YV12/NV21/NV12/I420/RGB24/RGBA32/RGB565等数据类型&#xff09;&#xff0c;其中&#xff0c;Android平台前后摄像头数据&…

搜狗高速浏览器怎么设置页面字体 设置方法介绍

搜狗高速浏览器是由搜狗公司开发的一款浏览器应用&#xff0c;我们在使用电脑或者手机等设备时都是离不开浏览器应用的&#xff0c;并且在很多浏览器中有的功能都是可以根据用户的使用习惯和喜好来设置的&#xff0c;就比如页面字体&#xff0c;所以小编今天就来跟大家分享一下…

C++学习之-析构函数必须为虚函数吗?

今天讨论个比较有意思的话题&#xff1a;析构函数是不是必须要为虚函数&#xff1f; 先说答案&#xff1a; 析构函数可以是虚函数&#xff0c;也可以不是虚函数。 再说原因&#xff1a; 析构函数为虚函数的情况&#xff1a;继承 当父类指针释放子类对象时&#xff0c;如果…

如何实现RTMP或RTSP播放端回调YUV/RGB数据?

今天某乎收到个问题推荐&#xff0c;如何实现RTSP回调YUV数据&#xff0c;用于二次处理&#xff1f; 正好前些年我们做RTSP和RTMP直播播放的时候&#xff0c;实现过相关的需求&#xff0c;本文就以Android为例&#xff0c;大概说说具体实现吧。 先说回调yuv或rgb这块意义吧&a…

Win7系统打印机删除不掉的解决方法

在Win7系统下&#xff0c;如果想要把安装的打印机删除&#xff0c;通常会在设备和打印机里删除打印机图标&#xff0c;但是一些用户反馈&#xff0c;用户在删除了打印机之后&#xff0c;只要一刷新打印机又会重新出现&#xff0c;感觉是删除不了&#xff0c;那么Win7系统打印机…

GB/T28181-2016传输要求和Android平台设备接入技术实现

相关协议规范 GB/T28181-2016公共安全视频监控联网系统 信息传输、交换、控制技术要求相关的传输要求如下&#xff1a; 5.1 网络传输协议要求 联网系统网络层应支持IP协议,传输层应支持 TCP和 UDP协议。 5.2 媒体传输协议要求 视音频流在基于IP的网络上传输时应支持 RTP/R…

无法打开Win11系统小组件怎么办

Win11操作系统也推出一段时间了&#xff0c;不少小伙都有下载体验&#xff0c;Win11与之前的Win10比较起来改动非常大&#xff0c;小组件是Win11系统中全新添加的功能&#xff0c;他类似于Win10最新的加入的兴趣模块&#xff0c;但是有朋友遇到了小组件无法打开的情况这是怎么回…

GB28181控制、传输流程和协议接口之注册|注销和技术实现

注册和注销基本要求 SIP客户端、网关、SIP设备、联网系统等 SIP代理(SIP UA)使用IETFRFC3261中定义的方法 15 GB/T28181—2016Register进行注册和注销。 注册和注销时应进行认证&#xff0c;认证方式应支持数字摘要认证方式&#xff0c;高安全级别的宜支持数字证书的认证方式&…

Edge浏览器网页怎么收藏 Edge浏览器网页收藏图文教程

Edge浏览器是微软最新推出的网页浏览工具。而现在有很多Edge浏览器新用户可能对它不是很了解&#xff0c;在使用过程中会出现小问题。今天小编就为大家解答Edge浏览器网页怎么收藏&#xff0c;一起来看教程吧! Edge浏览器网页收藏图文教程 一、怎么收藏网页? 1、打开Edge浏…

GB28181状态信息报送解读及Android端国标设备接入技术实现

今天主要聊聊GB/T28181状态信息报送这块&#xff0c;先回顾下协议规范相关细节&#xff0c;然后再针对代码实现&#xff0c;做个简单的说明。 状态消息报送基本要求 当源设备(包括网关、SIP设备、SIP客户端或联网系统)发现工作异常时,应立即向本 SIP监控域 的SIP服务器发送状…

IE浏览器怎么设置兼容性 添加兼容站点方法

IE浏览器是我们工作和生活中应用最广泛的浏览器&#xff0c;其安全、便捷是它的特点之一。不过这个浏览器在浏览部分网页的时候&#xff0c;会出现图片不刷新的情况&#xff0c;今天小编就带来了解决方法&#xff0c;告诉大家IE浏览器怎么设置兼容性。 1、首先点击IE浏览器右上…

GB28181设备接入端如何实现校时?

在探讨这个问题之前&#xff0c;我们先看看GB/T28181-2016官方文档怎么说的&#xff0c;9.10.1章节校时基本要求提到&#xff1a; 联网内设备支持基于SIP方式或 NTP方式的网络校时功能&#xff0c;标准时间为北京时间。 SIP方式校时见本节具体描述&#xff1b;NTP(见IETFRFC2…

Win7运行窗口的打开方法

Win7系统中运行窗口可谓是最常用的功能之一&#xff0c;可以帮助我们快速执行程序&#xff0c;在系统有问题时经常运用其协助解决。有用户问到运行窗口在哪?如何打开?找不到怎么办?其实方法不难&#xff0c;下面小编就跟大家详细介绍一下Win7运行窗口的打开方法。 Win7运行…

如何在Unity下采集音视频实现轻量级RTSP服务(类似于IPC)

好多开发者在做虚拟仿真、VR教育等场景的时候&#xff0c;遇到个问题&#xff0c;想把头显里面的画面在内网环境下低延迟的同步出来&#xff0c;又不想单独部署流媒体服务器。为此&#xff0c;我们在Unity下&#xff0c;添加了轻量级RTSP服务模块&#xff0c;通过头显端启动个轻…

【Datawhale 大模型基础】第十一章 环境影响

第十一章 环境影响 This blog is based on datawhale files and a paper. The initial consideration revolves around the potential positive or negative direct impact on the environment. Other transformative technological advancements, like the metaverse, are li…