安卓设备接入GB28181(Android GB28181)

9 篇文章 2 订阅
8 篇文章 0 订阅

      当前用安卓设备做执法记录仪的方案非常多, 在安卓系统上实现GB/T 28181-2016,GB/T 28181-2022很有必要,GB28181协议实现主要分两部分,一部分是信令, 信令主要包括SIP Register,SIP Message,SIP Invite,SIP NOTIFY,SIP SUBSCRIBE 等方法的请求和响应处理,还有就是MANSCDP的解析和生成; 另外一部分就是媒体数据的编码,视频主要是把摄像头图像编码成H.264或者H.265, 音频主要是把麦克风采集的音频编码成G.711, 然后把编码后的音视频数据打包成PS包, 再把PS包打包到RTP包中, 然后发送RTP包。我的实现代码分两部分:

     信令接口代码:

/*
 * Copyright (C) 1130758427@qq.com. All rights reserved.
*/

package com.gb.ntsignalling;

public interface GBSIPAgent {
    void addListener(GBSIPAgentListener listener);

    void addPlayListener(GBSIPAgentPlayListener playListener);

    void addTalkListener(GBSIPAgentTalkListener talkListener);

    void addAudioBroadcastListener(GBSIPAgentAudioBroadcastListener audioBroadcastListener);

    void addDeviceControlListener(GBSIPAgentDeviceControlListener deviceControlListener);

    void addQueryCommandListener(GBSIPAgentQueryCommandListener queryCommandListener);

    /*
     * 设置SIP本地链接地址
     * @param address 本地IP地址, 如192.168.0.111
     */
    void setLocalAddress(String address);

    /*
     * 设置SIP Server配置参数
     * @param address SIP服务器地址, 如 192.168.0.101
     * @param port SIP服务器端口, 如 15060
     * @param id SIP服务器ID, 如 34020000002000000001
     * @param domain SIP域, 如 3402000000
     */
    void setServerParameter(String address, int port, String id, String domain);

    /*
     * 设置GB28181 SIP User配置参数
     * @param userName SIP用户名, 如 34020000001110000045
     * @param password 密码, 如 123456
     */
    void setUserInfo(String userName, String password);

    /*
     * 设置GB28181 SIP User配置参数
     * @param userName SIP用户名, 如 34020000001110000045
     * @param authenticationUserName SIP认证用户名, 可能和userName相同
     * @param password 密码, 如 123456
     */
    void setUserInfo(String userName, String authenticationUserName, String password);

    /*
     * 设置SIP请求头中的UserAgent
     * @param userAgent用户代理
     */
    void setUserAgent(String userAgent);

    /*
     * 设置SIP传输协议
     * @param transport_protocol, 设置SIP信令传输协议: UDP, TCP, 默认是UDP
     */
    void setTransportProtocol(String transportProtocol);

    /*
     * 设置GB28181配置参数
     * @param regExpired 注册有效期, 单位: 秒, 如 3600
     * @param heartBeatInterval 心跳间隔, 单位: 秒, 默认60
     * @param heartBeatCount 心跳超时次数, 默认3次
     */
    void config(int regExpired, int heartBeatInterval, int heartBeatCount);

    void clearDevices();

    /*
     *增加设备
     */
    boolean addDevice(Device device);

    /*
     *更新设备位置信息
     */
    boolean updateDevicePosition(String deviceId, DevicePosition position);


    boolean createSipStack();

    /*
    * 绑定本地端口
    * @param port本地SIP端口, 如 15070
    */
    boolean bindLocalPort(int port);

    boolean initialize();

    /*
    *启动
     */
    boolean start();

    boolean isRunning();

    /*
    *响应Invite play 200 OK
     */
    boolean respondPlayInviteOK(String deviceId, MediaSessionDescription localVideoDescription);

    /*
    *响应Invite play 其他状态码
     */
    boolean respondPlayInvite(int statusCode, String deviceId);

    /*
    *终止Play会话
     */
    void terminatePlay(String deviceId, boolean isSendBYE);

    /*
    *终止所有Play会话
     */
    void terminateAllPlays(boolean isSendBYE);


    /*
     *响应Invite Talk 200 OK
     */
    boolean respondTalkInviteOK(String deviceId, String addressType, String localAddress,
                                MediaSessionDescription mainLocalAudioDescription, MediaSessionDescription subLocalAudioDescription);

    /*
     *响应Invite Talk 其他状态码
     */
    boolean respondTalkInvite(int statusCode, String deviceId);


    /*
     *终止Talk会话
     */
    void terminateTalk(String deviceId, boolean isSendBYE);

    /*
     *终止所有Talk会话
     */
    void terminateAllTalks(boolean isSendBYE);


    /*
     *语音广播应答
     */
    void respondBroadcastCommand(String fromUserName, String fromUserNameAtDomain, String sn, String sourceID, String targetID, boolean result);

    /*
    *语音广播接收者发送Invite消息, rtp ssrc暂时由sdk生成
    *@param addressType: ipv4:"IP4", ipv6:"IP6", 其他不支持, 填充SDP用
    *@param localAddress: 本地IP地址, 填充SDP用
    *@param localPort: 本地端口, 填充SDP用
    *@param mediaTransportProtocol: 媒体传输协议, rtp over udp:"RTP/AVP", rtp over tcp:"TCP/RTP/AVP". 其他不支持, 填充SDP用
     */
    boolean inviteAudioBroadcast(String commandFromUserName, String commandFromUserNameAtDomain, String sourceID, String targetID,
                                 String addressType, String localAddress, int localPort, String mediaTransportProtocol);

    /*
    *取消音频广播, 这个需要在invite收到临时响应之后[101-199],最终响应之前才能成功, 如果UAS已经发送过最终响应, UAS收到cancel不做处理, 具体参考RFC3261
     */
    boolean cancelAudioBroadcast(String sourceID, String targetID);

    /*
    *终止语音广播会话, 发送BYE消息
     */
    boolean byeAudioBroadcast(String sourceID, String targetID);

    /*
    预置位查询应答
     */
    boolean respondDevicePresetQueryCommand(String fromUserName, String fromUserNameAtDomain, String sn, String deviceId, java.util.List<PresetItem> presetList);

    /*
     *停止
     */
    void stop();

    void unInitialize();

    void unBindLocalPort();

    void releaseSipStack();
}

   信令Listener代码:

/*
* Copyright (C) 1130758427@qq.com. All rights reserved.
*/


package com.gb.ntsignalling;


public interface GBSIPAgentListener
{
    /*注册成功
    * @param dateString: 服务器日期,用来校准设备端时间,用户自行决定是否校准设备时间
    */
    void ntsRegisterOK(String dateString);

    /*
    *注册超时
    */
    void ntsRegisterTimeout();

    /*
    *注册网络传输曾异常
    */
    void ntsRegisterTransportError(String errorInfo);

    /*
    *心跳达到异常次数
    */
    void ntsOnHeartBeatException(int exceptionCount, String lastExceptionInfo);

    /*
     * 设备位置请求, 这个主要用在移动设备位置订阅上
     * @param interval 请求间隔, 单位是毫秒
     */
    void ntsOnDevicePositionRequest(String deviceId, int interval);

}


public interface GBSIPAgentPlayListener {

    /*
     *收到s=Play的实时视音频点播
     */
    void ntsOnInvitePlay(String deviceId, SessionDescription sessionDescription);

    /*
     *发送play invite response 异常
     */
    void ntsOnPlayInviteResponseException(String deviceId, int statusCode, String errorInfo);

    /*
     * 收到CANCEL play INVITE请求
     */
    void ntsOnCancelPlay(String deviceId);

    /*
     * 收到Ack
     */
    void ntsOnAckPlay(String deviceId);

    /*
     * 收到Bye
     */
    void ntsOnByePlay(String deviceId);

    /*
     * 不是在收到BYE Message情况下, 终止Play
     */
    void ntsOnTerminatePlay(String deviceId);

    /*
     * Play会话对应的对话终止, 一般不会出发这个回调,目前只有在响应了200K, 但在64*T1时间后还没收到ACK,才可能会出发
    收到这个, 请做相关清理处理
    */
    void ntsOnPlayDialogTerminated(String deviceId);
}

public interface GBSIPAgentTalkListener {
    /*
     *收到s=Talk 语音对讲
     */
    void ntsOnInviteTalk(String deviceId, SessionDescription sessionDescription);

    /*
     *发送talk invite response 异常
     */
    void ntsOnTalkInviteResponseException(String deviceId, int statusCode, String errorInfo);

    /*
     * 收到CANCEL Talk INVITE请求
     */
    void ntsOnCancelTalk(String deviceId);

    /*
     * 收到Ack
     */
    void ntsOnAckTalk(String deviceId);

    /*
     * 收到Bye
     */
    void ntsOnByeTalk(String deviceId);

    /*
     * 不是在收到BYE Message情况下, 终止Talk
     */
    void ntsOnTerminateTalk(String deviceId);

    /*
     * Talk会话对应的对话终止, 一般不会出发这个回调,目前只有在响应了200K, 但在64*T1时间后还没收到ACK,才可能会出发
    收到这个, 请做相关清理处理
    */
    void ntsOnTalkDialogTerminated(String deviceId);
}


public interface GBSIPAgentQueryCommandListener {

    /*
     * 设备预置位查询
     */
    void ntsOnDevicePresetQueryCommand(String fromUserName, String fromUserNameAtDomain, String sn, String deviceId);
}


public interface GBSIPAgentDeviceControlListener {

    /*
     * 收到远程启动控制命令
     */
    void ntsOnDeviceControlTeleBootCommand(String deviceId, String teleBootValue);

    /*
    * 云台控制
     */
    void ntsOnDeviceControlPTZCmd(String deviceId, String typeValue);
}


public interface GBSIPAgentAudioBroadcastListener {

    /*
     *收到语音广播通知
     */
    void ntsOnNotifyBroadcastCommand(String fromUserName, String fromUserNameAtDomain, String sn, String sourceID, String targetID);

    /*
     *需要准备接受语音广播的SDP内容
     */
    void ntsOnAudioBroadcast(String commandFromUserName, String commandFromUserNameAtDomain, String sourceID, String targetID);


    /*
     *音频广播, 发送Invite请求异常
     */
    void ntsOnInviteAudioBroadcastException(String sourceID, String targetID, String errorInfo);


    /*
     *音频广播, 等待Invite响应超时
     */
    void ntsOnInviteAudioBroadcastTimeout(String sourceID, String targetID);


    /*
     *音频广播, 收到Invite消息最终响应
     */
    void ntsOnInviteAudioBroadcastResponse(String sourceID, String targetID, int statusCode, SessionDescription sessionDescription);


    /*
     * 音频广播, 收到BYE Message
     */
    void ntsOnByeAudioBroadcast(String sourceID, String targetID);


    /*
     * 不是在收到BYE Message情况下, 终止音频广播
     */
    void ntsOnTerminateAudioBroadcast(String sourceID, String targetID);
}

    流媒体传输接口(只是和GB2818相关的部分接口, 其他接口未展示):

public class SmartPublisherJniV2 {

     /**
	 * Open publisher(启动推送实例)
	 *
	 * @param ctx: get by this.getApplicationContext()
	 * 
	 * @param audio_opt:
	 * if 0: 不推送音频
	 * if 1: 推送编码前音频(PCM)
	 * if 2: 推送编码后音频(aac/pcma/pcmu/speex).
	 * 
	 * @param video_opt:
	 * if 0: 不推送视频
	 * if 1: 推送编码前视频(YUV420SP/YUV420P/RGBA/ARGB)
	 * if 2: 推送编码后视频(H.264)
	 *
	 * @param width: capture width; height: capture height.
	 *
	 * <pre>This function must be called firstly.</pre>
	 *
	 * @return the handle of publisher instance
	 */
    public native long SmartPublisherOpen(Object ctx, int audio_opt, int video_opt,  int width, int height);


    /*+++++++++++++++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);


	/*+++++++++++++++RTP Sender相关接口+++++++++++++++*/


	/*+++++++++++++++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相关接口---------------*/

   
   /**
     * 关闭推送实例,结束时必须调用close接口释放资源
	 *
	 * @return {0} if successful
	 */
    public native int SmartPublisherClose(long handle);
}
 


    下面是相关调用代码:

public class GB28181Demo extends Activity, implements Callback, PreviewCallback, GBSIPAgentListener
{
  /*** GB28181 相关参数,可以修改相关参数后测试 ***/

    GBSIPAgent     gb28181_agent_             = null;
    private int    gb28181_sip_local_port_    = 12070;
    private String gb28181_sip_server_id_     = "34020000002000000001";
    private String gb28181_sip_server_domain_ = "3402000000";
    private String gb28181_sip_server_addr_   = "192.168.0.104";
    private int    gb28181_sip_server_port_   = 15060;

    private String gb28181_sip_user_agent_filed_  = "NT GB2818 User Agent V1.0";
    private String gb28181_sip_username_   = "31011500991320000069";
    private String gb28181_sip_password_   = "12345678";

    private int gb28181_reg_expired_           = 3600; // 注册有效期时间最小3600秒
    private int gb28181_heartbeat_interval_    = 20; // 心跳间隔GB28181默认是60, 目前调整到20秒
    private int gb28181_heartbeat_count_       = 3; // 心跳间隔3次失败,表示和服务器断开了
    private int gb28181_sip_trans_protocol_    = 0; // 0表示信令用UDP传输, 1表示信令用TCP传输

    private long gb28181_rtp_sender_handle_ = 0;
    private int  gb28181_rtp_payload_type_  = 96;

    /*** GB28181 相关参数,可以修改相关参数后测试 ***/


    @Override
    public void onCreate(Bundle savedInstanceState) {
     /*其他初始化代码**/

      libPublisher = new SmartPublisherJniV2();

      if ( initGB28181Agent() ) {
          gb28181_agent_.start();
      }
    }

    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;
    }
   
    @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 :""));
    }

    @Override
    public 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() {
            @Override
            public 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);
    }


    @Override
    public void ntsOnInvitePlay(String deviceId, InvitePlaySessionDescription session_des) {
        handler.postDelayed(new Runnable() {
            @Override
            public 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, 1024*1024);
                libPublisher.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);
    }


    @Override
    public void ntsOnCancelPlay(String deviceId) {
        // 这里取消Play会话
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "ntsOnCancelPlay, deviceId=" + device_id_);

                destoryRTPSender();
            }

            private String device_id_;

            public Runnable set(String device_id) {
                this.device_id_ = device_id;
                return this;
            }

        }.set(deviceId),0);
    }


    @Override
    public void ntsOnAckPlay(String deviceId) {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG,"ntsOnACKPlay, device_id:" +device_id_);

                InitAndSetConfig();
      
                libPublisher.SetGB28181RTPSender(publisherHandle, gb28181_rtp_sender_handle_, gb28181_rtp_payload_type_);
                int startRet = libPublisher.StartGB28181MediaStream(publisherHandle);
                if (startRet != 0) {
                  if (publisherHandle != 0) {
                     libPublisher.SmartPublisherClose(publisherHandle);
                     publisherHandle = 0;
                   }

                   destoryRTPSender();
                   return;
                }


                isGB28181StreamRunning = true;
            }

            private String device_id_;

            public Runnable set(String device_id) {
                this.device_id_ = device_id;
                return this;
            }

        }.set(deviceId),0);
    }

    @Override
    public void ntsOnPlayInviteResponseException(String deviceId, int statusCode, String errorInfo) {
        // 这里要释放掉响应的资源
        Log.i(TAG, "ntsOnPlayInviteResponseException, deviceId=" + deviceId + " statusCode=" +statusCode
        + " errorInfo:" + errorInfo);

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "ntsOnPlayInviteResponseException, deviceId=" + device_id_);

                destoryRTPSender();
            }

            private String device_id_;

            public Runnable set(String device_id) {
                this.device_id_ = device_id;
                return this;
            }

        }.set(deviceId),0);
    }

    @Override
    public void ntsOnByePlay(String deviceId)
    {
        handler.postDelayed(new Runnable() {
            @Override
            public 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);
    }

    @Override
    public void ntsOnPlayDialogTerminated(String deviceId) {
        /*
        Play会话对应的对话终止, 一般不会出发这个回调,目前只有在响应了200K, 但在64*T1时间后还没收到ACK,才可能会出发
        收到这个请做相关清理处理
        */
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "ntsOnPlayDialogTerminated, 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);
    }


   //停止GB28181 媒体流
    private void stopGB28181Stream() {
        if(!isGB28181StreamRunning)
            return;


        if (libPublisher != null) {
            libPublisher.StopGB28181MediaStream(publisherHandle);
        }


        if (publisherHandle != 0) {
           if (libPublisher != null) {
            libPublisher.SmartPublisherClose(publisherHandle);
            publisherHandle = 0;
           }
        }

        isGB28181StreamRunning = false;
    }

 private void destoryRTPSender() {
        if (gb28181_rtp_sender_handle_ != 0) {
            libPublisher.DestoryRTPSender(gb28181_rtp_sender_handle_);
            gb28181_rtp_sender_handle_ = 0;
        }
   }


   @Override
    protected void onDestroy() {
        Log.i(TAG, "activity destory!");

        if (gb28181_agent_ != null ) {
            if (gb28181_agent_.isRunning()) {
                gb28181_agent_.terminateAllPlays(false);
                gb28181_agent_.stop();
            }
            gb28181_agent_ = null;
        }

        stopGB28181Stream();
        destoryRTPSender();

        if (publisherHandle != 0) {
          if (libPublisher != null) {
            libPublisher.SmartPublisherClose(publisherHandle);
             publisherHandle = 0;
            }
         }

      super.onDestroy();
 }

}

     音视频采集编码相关功能已经稳定运行多年了,GB28181接入用C++实现H264, H265打包成PS流,然后拆成RTP包发送即可,RTP传输同时支持UDP和TCP(这个根据Invite sdp来确定)。配合28181服务器测试,延时非常低,达到了预期的效果. 

   当前实现接口也支持多个设备(或者说是多个通道), 可以很方便的实现多个现有rtsp摄像头到GB28181的转换,另外考虑到安卓移动端的特性,也增加了对设备经纬度位置信息的上报. 更多问题可以联系qq: 1130758427

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值