如何快速实现Android平台前端设备接入能力

技术背景

SIP(会话初始化协议)是在 IP网络上进行多媒体通信的应用层控制协议,以几种RFC的形式提供,其中最重要的是包含核心协议规范的RFC3261。该协议用于创建,修改和终止与一个或多个参与者的会话。通过会话,我们了解了一组进行通信的发送方和接收方,以及在通信过程中这些发送方和接收方保持的状态。会话的示例可以包括Internet电话呼叫,多媒体分发,多媒体会议,分布式计算机游戏等。

SIP不是通信设备将需要的唯一协议,也不意味着是通用协议。SIP的目的仅仅是使通信成为可能,通信本身必须通过其他方式(可能还有其他协议)来实现。

与SIP一起最常使用的两种协议是RTP和SDP。 RTP协议用于承载实时多媒体数据(包括音频,视频和文本),该协议可以将数据编码和拆分为数据包,并通过Internet传输此类数据包。

另一个重要的协议是SDP,用于描述和编码会话参与者的功能。 然后,将这种描述用于协商会话的特征,以便所有设备都可以参与(例如,包括协商用于编码媒体的编解码器,以便所有参与者都可以对其进行解码,协商使用的传输协议 等等)。

GB/T28181-2011 《安全防范视频监控联网系统信息传输、交换、控制技术要求》是由公安部科技信息化局提出,由全国安全防范报警系统标准化技术委员会(SAC/TC100)归口,公安部一所等多家单位共同起草的一部国家标准。

该标准规定了城市监控报警联网系统中信息传输、交换、控制的互联结构、通信协议结构,传输、交换、控制的基本要求和安全性要求,以及控制、传输流程和协议接口等技术要求。该标准适用于安全防范监控报警联网系统的方案设计、系统检测、验收以及与之相关的设备研发、生产,其他信息系统可参考采用。
该标准于2012年6月1日正式发布实施,在全国范围内的平安城市项目建设中被普遍推广应用。GB/T28181-2011标准自发布以来,受到了各大视频监控厂商的积极响应。截止2012年底,有近百家视频监控企业通过公安部一所、公安部三所的认证,如深圳宙视达、浙江宇视、超视科技、东方网力、海康威视、高远时代、浙江大华、先进视讯、波粒科技、华为技术、中兴力维、中星电子、科达、天地伟业等。

相关接口

废话不多说,直接上设计接口,好多开发者网上看到的大多是非常简单的接口。极致简单,一直是我们追求的目标,但是更好的参数化配置和可扩展的设计,也是一个规范化产品的必经之路。

除了常规的音视频采集编码接口外,GB28181设备接入模块,主要分信令交互和媒体数据传输两个部分,以大牛直播SDK(官方)分别介绍下相关接口设计。

媒体数据传输相关

	/*+++++++++++++++RTP Sender相关接口+++++++++++++++*//** 创建RTP Sender实例** @param reserve:保留参数传0** @return RTP Sender 句柄,0表示失败*/public native long CreateRTPSender(int reserve);/***设置 RTP Sender传输协议** @param rtp_sender_handle, CreateRTPSender返回值* @param transport_protocol, 0:UDP, 1:TCP, 默认是UDP** @return {0} if successful*/public native int SetRTPSenderTransportProtocol(long rtp_sender_handle, int transport_protocol);/***设置 RTP Sender IP地址类型** @param rtp_sender_handle, CreateRTPSender返回值* @param ip_address_type, 0:IPV4, 1:IPV6, 默认是IPV4, 当前仅支持IPV4** @return {0} if successful*/public native int SetRTPSenderIPAddressType(long rtp_sender_handle, int ip_address_type);/***设置 RTP Sender RTP Socket本地端口** @param rtp_sender_handle, CreateRTPSender返回值* @param port, 必须是偶数,设置0的话SDK会自动分配, 默认值是0** @return {0} if successful*/public native int SetRTPSenderLocalPort(long rtp_sender_handle, int port);/***设置 RTP Sender SSRC** @param rtp_sender_handle, CreateRTPSender返回值* @param ssrc, 如果设置的话,这个字符串要能转换成uint32类型, 否则设置失败** @return {0} if successful*/public native int SetRTPSenderSSRC(long rtp_sender_handle, String ssrc);/***设置 RTP Sender RTP socket 发送Buffer大小** @param rtp_sender_handle, CreateRTPSender返回值* @param buffer_size, 必须大于0, 默认是512*1024, 当前仅对UDP socket有效, 根据视频码率考虑设置合适的值** @return {0} if successful*/public native int SetRTPSenderSocketSendBuffer(long rtp_sender_handle, int buffer_size);/***设置 RTP Sender RTP时间戳时钟频率** @param rtp_sender_handle, CreateRTPSender返回值* @param clock_rate, 必须大于0, 对于GB28181 PS规定是90kHz, 也就是90000** @return {0} if successful*/public native int SetRTPSenderClockRate(long rtp_sender_handle, int clock_rate);/***设置 RTP Sender 目的IP地址, 注意当前用在GB2818推送上,只设置一个地址,将来扩展如果用在其他地方,可能要设置多个目的地址,到时候接口可能会调整** @param rtp_sender_handle, CreateRTPSender返回值* @param address, IP地址* @param port, 端口** @return {0} if successful*/public native int SetRTPSenderDestination(long rtp_sender_handle, String address, int port);/***初始化RTP Sender, 初始化之前先调用上面的接口配置相关参数** @param rtp_sender_handle, CreateRTPSender返回值** @return {0} if successful*/public native int InitRTPSender(long rtp_sender_handle);/***获取RTP Sender RTP Socket本地端口** @param rtp_sender_handle, CreateRTPSender返回值** @return 失败返回0, 成功的话返回响应的端口, 请在InitRTPSender返回成功之后调用*/public native int GetRTPSenderLocalPort(long rtp_sender_handle);/*** UnInit RTP Sender** @param rtp_sender_handle, CreateRTPSender返回值** @return {0} if successful*/public native int UnInitRTPSender(long rtp_sender_handle);/*** 释放RTP Sender, 释放之后rtp_sender_handle就无效了,请不要再使用** @param rtp_sender_handle, CreateRTPSender返回值** @return {0} if successful*/public native int DestoryRTPSender(long rtp_sender_handle);

 信令相关操作

	/*+++++++++++++++GB28181相关接口+++++++++++++++*//*** 设置GB28181 RTP Sender** @param rtp_sender_handle, CreateRTPSender返回值* @param rtp_payload_type, 对于GB28181 PS, 协议定义是96, 具体以SDP为准** @return {0} if successful*/public native int SetGB28181RTPSender(long handle, long rtp_sender_handle, int rtp_payload_type);/*** 启动 GB28181 媒体流** @return {0} if successful*/public native int StartGB28181MediaStream(long handle);/*** 停止 GB28181 媒体流** @return {0} if successful*/public native int StopGB28181MediaStream(long handle);/*---------------GB28181相关接口---------------*/

 启动、停止GB28181

完成视频分辨率等参数配置后,点击“启动GB28181”,即可开始走信令交互流程,设备端主动发送Register,进入后续交互流程。

如需停止GB28181,点停止即可。

GB28181设备端主要实现了按需推送数据到平台端。

    class ButtonGB28181AgentListener implements OnClickListener {public void onClick(View v) {stopGB28181Stream();destoryRTPSender();if (null == gb28181_agent_ ) {if( !initGB28181Agent() )return;}if (gb28181_agent_.isRunning()) {gb28181_agent_.terminateAllPlays(true);// 目前测试下来,发送BYE之后,有些服务器会立即发送INVITE,是否发送BYE根据实际情况看gb28181_agent_.stop();btnGB28181Agent.setText("启动GB28181");}else {if ( gb28181_agent_.start() ) {btnGB28181Agent.setText("停止GB28181");}}}}

注册

当Andriod设备端第一次接入平台端时,设备端将持续向平台端发送 REGISTER消息,直到 Server端回复"200 OK"代表注册成功。

如果设备或系统注册不成功,宜延迟一定的随机时间后重新注册每隔一定时间客户端都会再次向服务器刷新注册,防止注册过期导致连接断开。

以基本注册为例:基本注册采用IETFRFC3261规定的基于数字摘要的挑战应答式安全技术进行注册。

注册流程描述如下:
a) 1:SIP代理向SIP服务器发送 Register请求;
b) 2:SIP服务器向 SIP代理发送响应401,并在响应的消息头 WWW_Authenticate字段中给出适合SIP代理的认证体制和参数;
c) 3:SIP代理重新向SIP服务器发送 Register请求,在请求的 Authorization字段给出信任书, 包含认证信息;
d) 4:SIP 服务器对请求进行验证,如果检查出 SIP 代理身份合法,SIP 代理发送成功响应 200OK,如果身份不合法则发送拒绝服务应答
相关注册反馈:
    @Overridepublic void ntsRegisterOK(String dateString) {Log.i(TAG, "ntsRegisterOK Date: " + (dateString!= null? dateString : ""));}@Overridepublic void ntsRegisterTimeout() {Log.e(TAG, "ntsRegisterTimeout");}@Overridepublic void ntsRegisterTransportError(String errorInfo) {Log.e(TAG, "ntsRegisterTransportError error:" + (errorInfo != null?errorInfo :""));}

信息查询(Catalog)

注册成功后,客户端与服务器之间信息查询操作,如目录查询、历史录像文件查看等,GB28181使用 SIP扩展协议规定的 Message方法实现。目前使用了两种类型的查询命令:Catalog 设备目录查询消息、RecordInfo 历史录像文件查询消息。
本文以Catalog设备目录查询消息为例:平台端向设备端发送Catalog请求,设备端回复200 OK后,发送设备信息,平台端回复200 OK,如遇多个设备信息,切记分次发送。
    private boolean initGB28181Agent(){if ( gb28181_agent_ != null )return  true;String local_ip_addr = IPAddrUtils.getIpAddress(myContext);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_.setLocalAddressInfo(local_ip_addr, gb28181_sip_local_port_);gb28181_agent_.setServerParameter(gb28181_sip_server_addr_, gb28181_sip_server_port_, gb28181_sip_server_id_, gb28181_sip_server_domain_);gb28181_agent_.setUserInfo(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.gb28181.ntsignalling.Device gb_device = new com.gb28181.ntsignalling.Device("34020000001380000001", "安卓测试设备", Build.MANUFACTURER, Build.MODEL,"宇宙","火星1","火星", true);getLocation(this);gb_device.setLongitude(mLongitude);gb_device.setLatitude(mLatitude);gb28181_agent_.addDevice(gb_device);if (!gb28181_agent_.initialize()) {gb28181_agent_ = null;Log.e(TAG, "initGB28181Agent gb28181_agent_.initialize failed.");return  false;}return true;}

心跳(KeepAlive)

KeepAlive以MESSAGE的形式传递,异常处理如下:
    @Overridepublic void ntsOnHeartBeatException(int exceptionCount,  String lastExceptionInfo) {Log.e(TAG, "ntsOnHeartBeatException heart beat timeout count reached, count:" + exceptionCount+", exception info:" + (lastExceptionInfo!=null?lastExceptionInfo:""));// 10毫秒后,停止信令, 然后重启handler.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "gb28281_heart_beart_timeout");stopGB28181Stream();destoryRTPSender();if (gb28181_agent_ != null) {Log.i(TAG, "gb28281_heart_beart_timeout sip stop");gb28181_agent_.stop();Log.i(TAG, "gb28281_heart_beart_timeout sip start");gb28181_agent_.start();}}},10);}

Invite处理

假定整个信令交互流程顺利,Android设备端完成Register、Catalog、KeepAlive消息处理后,平台端发过来Invite请求并携带SDP消息体。

Android设备端可获取到比如deviceid, tcp/udp传输模式、rtp端口,address类型等,并构建200 OK,携带相关的音视频信息。

    @Overridepublic void ntsOnInvitePlay(String deviceId, InvitePlaySessionDescription session_des) {handler.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG,"ntsInviteReceived, device_id:" +device_id_+", is_tcp:" + session_des_.isRTPOverTCP()+ " rtp_port:" + session_des_.getMediaPort() + " ssrc:" + session_des_.getSSRC()+ " address_type:" + session_des_.getAddressType() + " address:" + session_des_.getAddress());// 可以先给信令服务器发送临时振铃响应//sip_stack_android.respondPlayInvite(180, device_id_);long rtp_sender_handle = libPublisher.CreateRTPSender(0);if ( rtp_sender_handle == 0 ) {gb28181_agent_.respondPlayInvite(488, device_id_);Log.i(TAG, "ntsInviteReceived CreateRTPSender failed, response 488, device_id:" + device_id_);return;}gb28181_rtp_payload_type_ = session_des_.getPSRtpMapAttribute().getPayloadType();libPublisher.SetRTPSenderTransportProtocol(rtp_sender_handle, session_des_.isRTPOverUDP()?0:1);libPublisher.SetRTPSenderIPAddressType(rtp_sender_handle, session_des_.isIPv4()?0:1);libPublisher.SetRTPSenderLocalPort(rtp_sender_handle, 0);libPublisher.SetRTPSenderSSRC(rtp_sender_handle, session_des_.getSSRC());libPublisher.SetRTPSenderSocketSendBuffer(rtp_sender_handle, 2*1024*1024); // 设置到2MlibPublisher.SetRTPSenderClockRate(rtp_sender_handle, session_des_.getPSRtpMapAttribute().getClockRate());libPublisher.SetRTPSenderDestination(rtp_sender_handle, session_des_.getAddress(), session_des_.getMediaPort());if ( libPublisher.InitRTPSender(rtp_sender_handle) != 0 ) {gb28181_agent_.respondPlayInvite(488, device_id_);libPublisher.DestoryRTPSender(rtp_sender_handle);return;}int local_port = libPublisher.GetRTPSenderLocalPort(rtp_sender_handle);if (local_port == 0) {gb28181_agent_.respondPlayInvite(488, device_id_);libPublisher.DestoryRTPSender(rtp_sender_handle);return;}Log.i(TAG,"get local_port:" + local_port);String local_ip_addr = IPAddrUtils.getIpAddress(myContext);gb28181_agent_.respondPlayInviteOK(device_id_,local_ip_addr, local_port);gb28181_rtp_sender_handle_ = rtp_sender_handle;}private String device_id_;private InvitePlaySessionDescription session_des_;public Runnable set(String device_id, InvitePlaySessionDescription session_des) {this.device_id_ = device_id;this.session_des_ = session_des;return this;}}.set(deviceId, session_des),0);}

Ack确认

平台端发送Ack确认,设备端收到Ack后,开始发送音视频数据。

    @Overridepublic void ntsOnAckPlay(String deviceId) {handler.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG,"ntsOnACKPlay, device_id:" +device_id_);if (!isRecording && !isRTSPPublisherRunning && !isPushingRtsp && !isPushingRtmp) {InitAndSetConfig();}libPublisher.SetGB28181RTPSender(publisherHandle, gb28181_rtp_sender_handle_, gb28181_rtp_payload_type_);int startRet = libPublisher.StartGB28181MediaStream(publisherHandle);if (startRet != 0) {if (!isRecording && !isRTSPPublisherRunning && !isPushingRtmp && !isPushingRtsp) {if (publisherHandle != 0) {libPublisher.SmartPublisherClose(publisherHandle);publisherHandle = 0;}}destoryRTPSender();Log.e(TAG, "Failed to start GB28181 service..");return;}if (!isRecording && !isRTSPPublisherRunning && !isPushingRtsp && !isPushingRtmp) {if (pushType == 0 || pushType == 1) {CheckInitAudioRecorder();    //enable pure video publisher..}}isGB28181StreamRunning = true;}private String device_id_;public Runnable set(String device_id) {this.device_id_ = device_id;return this;}}.set(deviceId),0);}

BYE

如果客户端需要断开Invite会话,则会发送BYE,客户端返回200 OK。

    @Overridepublic void ntsOnByePlay(String deviceId){handler.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnByePlay, stop GB28181 media stream, deviceId=" + device_id_);stopGB28181Stream();destoryRTPSender();}private String device_id_;public Runnable set(String device_id) {this.device_id_ = device_id;return this;}}.set(deviceId),0);}

注销

客户端向服务器发送 Register命令消息,消息中的 Expire字段设置为0即是注销。
 

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

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

相关文章

如何解决Win11系统显示你的账户已被停用

现在Win11系统是现在非常火热的电脑操作系统,很多用户都想去升级体验,最近有使用Win11系统用户在咨询这样一个情况,就是电脑突然提示“你的账户已被停用,请向系统管理员咨询”,遇到这样的问题该如何解决呢?下面小编就…

Win11系统创建虚拟桌面的方法

现在Win11系统是非常火热的电脑操作系统,现在已经有越来越多的小伙伴在使用Win11系统,Win11系统集成了Windows10的许多便利的功能,例如虚拟桌面,但是有的朋友不知道在Windows11上怎么进行操作。接下来小编就来为大家简单的介绍一下…

Win10系统开机任务栏一直转圈怎么解决

Win10系统可说是最常用的系统之一,不过最近有不少使用Win10系统的小伙伴发现自己开机之后任务栏一直转圈,那么Win10系统开机任务栏一直转圈怎么解决呢?下面小编就带给大家带来了Win10系统开机任务栏一直转圈的解决方法。 Win10系统开机任务栏一直转圈怎…

Win10系统电脑不会一键还原系统怎么解决

在我们电脑遇到大问题之后,还原系统是最简单有效的办法,现在网络上有很多种系统还原系统的办法,有简单的也有复杂的,Win10系统电脑不会一键还原系统怎么解决呢,这个办法是我觉得最简单的办法之一,小伙伴们可…

Win10本地账户怎么更改为Microsoft账户

在使用电脑的时候,用户想要使用任何Microsoft服务,就需要创建一个Microsoft帐户。那有些用户一直使用的本地账户,这该怎么切换成Microsoft账户呢?其实方法很简单,小编这里就教教大家Win10本地账户更改为Microsoft账户的吧。 Win…

edge浏览器怎么恢复默认设置 edge恢复默认设置方法

edge浏览器也是我们最常用的浏览器之一了,但是edge浏览器还存在着一些小问题,比方说edge浏览器不能看视频等问题,那着个时候可以尝试恢复默认设置能让浏览器恢复正常。那edge浏览器怎么恢复默认设置?请看下面。 1、从win10的开始菜单中找到…

桔子浏览器电脑版如何登录 桔子浏览器PC版账号登录教程

桔子浏览器电脑版如何登陆?桔子浏览器支持账号登录功能,能够帮助用户收藏自动备份,不用担心丢失的情况,今天我们就来讲讲怎么登录账号。 桔子浏览器PC版账号登录教程 1、打开桔子浏览器点击【工具】-【登录桔子浏览器】 桔子浏览器电脑版…

Win11任务栏图标重叠怎么办 Win11任务栏图标重叠的解决方法

Win11操作系统也推出一段时间了,不少小伙都有下载体验,但有一些小伙伴在使用Win11系统的时候发现自己任务栏图标重叠在一起,那么碰到这种情况应该怎么办,下面就和小编一起来看看有什么解决方法。 Win11任务栏图标重叠怎么办&…

怎么隐藏Windows11开始菜单中的推荐面板

相信现在很多用户都在使用Win11操作系统,在“开始”菜单的下半部分包含了“推荐”面板。目前它用于突出显示最近使用的文件和最近安装的应用程序,但有些人担心Microsoft会使用它向用户发送其他推荐的垃圾邮件。如果你不喜欢它,这里是如何禁用…

Windows11安全中心打不开怎么办 Win11打不开安全中心解决方法

使用Win11系统的用户们最近遇到了一个问题,尽管之前升级Win11系统之后也遇到了各种问题,甚至很多用户在升级这一步就遇到了不少问题升级不了。现在在打开Win11系统的时候又遇到了问题,安全中心打不开了。这是怎么一回儿事呢? Windows11安全…

Win11任务栏如何设置在顶部

Windows 11的镜像已经在网上泄露,很多朋友都已经下载安装体验了一番,在使用的过程中大家都知道,Windows 11的一大改变在于任务栏,系统默认将任务栏置于中间,且相关图标都作了修改。那么Win11任务栏可以设置在顶部吗?接…

Win11怎么打开以前的word文档

很多用户在Win11系统出来之后都选择了升级Win11系统,但是Win11进行了大部分改革,所以很多用户都操作不来,对这个新系统也很陌生。就像我们Win10系统中留存下来的文档,在升级了Win11系统之后,以前的文档也打不开了&…

Win7旗舰版系统如何设置定时关机

Win7旗舰版系统用户每次下班都忘记关电脑,领导说了很多次就是记不住,如果电脑能设置定时关机就好啦,Win7旗舰版系统如何设置定时关机?快来跟着小编一 起学习一下Win7旗舰版系统设置定时关机教程吧。 Win7旗舰版系统如何设置定时关机 1、【…

Win7系统网页视频无法播放怎么办

Win7系统网页视频无法播放怎么办?最近有Win7系统用户反映,网页视频无法播放,用户反复试了几次,结果都一样,这让用户非常苦恼。那么Win7系统网页视频无法播放怎么办呢?下面就和小编一起来看看详细的解决方法吧! Win7系统网页视频…

win7纯净版系统锁定系统时间的设置方法

在使用电脑的过程中总是会遇到各式各样的问题,就有小伙伴咨询小编说想要锁定系统时间,想知道怎么操作。那么针对这个问题,小编就以win7纯净版为例,给大家讲讲锁定系统时间的办法win7纯净版系统锁定系统时间的设置方法吧。 win7纯…

Win7系统搜索功能无法使用的应对办法

Win7系统电脑里面包含有很多方便我们操作的便捷功能,比如电脑搜索功能,但最近有不少使用Win7系统用户反映电脑搜索功能不能使用,那么Win7搜索功能无法使用怎么解决呢?下面就和小编一起来看看Win7系统搜索功能无法使用的应对办法吧。 Win7系…

Win7旗舰版系统0x0000007f蓝屏怎么办

Win7旗舰版0x0000007f是一种蓝屏代码,出现此蓝屏代码的原因大部分是硬件问题,很多小伙伴遇到此类问题就束手无策,Win7旗舰版0x0000007f蓝屏怎么处理?针对此问题,下面小编在这分享一篇Win7旗舰版0x0000007f蓝屏的处理方法&#xf…

桔子浏览器电脑版收藏夹位置在哪里 收藏夹位置路径

桔子浏览器电脑版收藏夹位置在哪里?有很多用户将之前浏览的网页保存到了收藏夹里,不知道在哪里可以找到,下面通过这篇文章给大家讲解一下。 桔子浏览器电脑版收藏夹位置在哪里 收藏夹位置路径 桔子浏览器PC版收藏夹位置路径 在桔子浏览器页面上方有一…

Win11系统调节屏幕亮度的方法

目前Win11系统是一款非常火热的电脑操作系统,很多用户都想安装体验,电脑安装了Win11系统后发现屏幕太亮了,看久了眼睛很疲累,于是想要重新修改一下屏幕亮度,但是这个该如何操作呢?接下来小编就来为大家简单的介绍一下…

Win11系统资源管理器自动重启怎么办

Win11系统是目前非常受欢迎的电脑操作系统,很多用户都想升级体验,当我们在使用Win11系统的时候,经常会打开资源管理器来对文件夹进行操作等,不过有时候可能会遇到资源管理器自动重启的问题,这该如何解决呢?今天小编就…