安卓GB28181设备语音广播和语音对讲(Android GB28181 语音广播和语音对讲)实现

15 篇文章 1 订阅
8 篇文章 0 订阅

     安卓GB28181语音广播和语音对讲是一个非常重要的功能,很多场景都需要。语音对讲需要安卓有接收语音广播的功能。安卓还需要采集音频,并和视频一起打包到PS传给服务器,采集音频传服务器实现较容易。关键还是语音广播功能实现,语音广播的GB28181流程如下:

    1. SIP服务器发MESSAGE语音广播命令到安卓端:

 <?xml version="1.0" encoding="GB2312"?>
   <Notify>
      <CmdType>Broadcast</CmdType>
      <SN>679389313</SN>
      <SourceID>31010600002000000001</SourceID>
      <TargetID>31010600001380000001</TargetID>
   </Notify>

    2. 安卓端发MESSAGE消息应答语音广播命令:

 <?xml version="1.0" encoding="GB2312"?>
 <Response>
 <CmdType>Broadcast</CmdType>
 <SN>679389313</SN>
 <DeviceID>31010600001380000001</DeviceID>
 <Result>OK</Result>
 </Response>

    3.安卓收到MESSAGE响应200OK后,发送INVITE消息,SDP:

    v=0
    o=31010600002000000001 0 0 IN IP4 192.168.0.100
    s=Play
    c=IN IP4 192.168.0.100
    t=0 0
    m=audio 25000 TCP/RTP/AVP 8
    a=setup:active
    a=connection:new
    a=recvonly
    a=rtpmap:8 PCMA/8000
    y=0200005724
    f=v/a/1/8/1 

  4.安卓端收到INVITE 200OK响应,SDP:

    v=0
    o=31010600002000000001 0 0 IN IP4 192.168.0.105
    s=Play
    c=IN IP4 192.168.0.105
    t=0 0
    m=audio 40062 TCP/RTP/AVP 8
    a=sendonly
    a=rtpmap:8 PCMA/8000
    a=setup:passive
    a=connection:new
    y=0200005724
    f=v/a/1/8/1

   安卓回复ACK后, 开始读取RTP包,解析RTP包,对音频数据解码,输出到安卓播放设备即可, 流程不是太复杂,但实现细节挺繁琐的,下面是我实现的接口和demo代码:

   语音广播信令Listener

package com.gb28181.ntsignalling;

public interface GBSIPAgentListener
{
    /*
    *收到语音广播通知
     */
    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, PlaySessionDescription sessionDescription);

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

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

  语音广播的信令接口:

package com.gb28181.ntsignalling;

public interface GBSIPAgent {

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

    /*
    *语音广播接收者发送Invite消息
    *@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);

    /*
    *取消音频广播,具体参考RFC3261
     */
    boolean cancelAudioBroadcast(String sourceID, String targetID);

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

   RTP音频包接收和解码输出接口:

package com.daniulive.smartplayer;

public class SmartPlayerJniV2 {
/**
	 * Initialize Player(启动播放实例)
	 *
	 * @param ctx: get by this.getApplicationContext()
	 *
	 * <pre>This function must be called firstly.</pre>
	 *
	 * @return player handle if successful, if return 0, which means init failed. 
	 */

	public native long SmartPlayerOpen(Object ctx);

	/**
	 * Set External Audio Output(设置回调PCM数据)
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param external_audio_output:  External Audio Output
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerSetExternalAudioOutput(long handle, Object external_audio_output);

	/**
	 * Set Audio Data Callback(设置回调编码后音频数据)
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param audio_data_callback: Audio Data Callback.
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerSetAudioDataCallback(long handle, Object audio_data_callback);


	/**
	 * Set buffer(设置缓冲时间,单位:毫秒)
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param buffer:
	 *
	 * <pre> NOTE: Unit is millisecond, range is 0-5000 ms </pre>
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerSetBuffer(long handle, int buffer);

	/**
	 * Set mute or not(设置实时静音)
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param is_mute: if with 1:mute, if with 0: does not mute
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerSetMute(long handle, int is_mute);

	/**
	 * 设置播放音量
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param volume: 范围是[0, 100], 0是静音,100是最大音量, 默认是100
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerSetAudioVolume(long handle, int volume);


	/**
	 * 清除所有 rtp receivers
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerClearRtpReceivers(long handle);


	/**
	 * 增加 rtp receiver
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param rtp_receiver_handle: return value from CreateRTPReceiver()
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerAddRtpReceiver(long handle, long rtp_receiver_handle);


	/**
	 * 设置需要播放或录像的RTMP/RTSP url
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param uri: rtsp/rtmp playback/recorder uri
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerSetUrl(long handle, String uri);


	/**
	 * Start playback stream(开始播放)
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerStartPlay(long handle);

	/**
	 * Stop playback stream(停止播放)
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerStopPlay(long handle);


	/**
	 * Start pull stream(开始拉流,用于数据转发,只拉流不播放)
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerStartPullStream(long handle);

	/**
	 * Stop pull stream(停止拉流)
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerStopPullStream(long handle);

	/**
	 * 关闭播放实例,结束时必须调用close接口释放资源
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * <pre> NOTE: it could not use player handle after call this function. </pre> 
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerClose(long handle);


	/*++++++++++++++++++RTP Receiver++++++++++++++++++++++*/

	/*
	 * 创建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++++++++++++++++++++++*/

}

    具体的Demo调用代码如下(这里只给出和音频广播相关代码):

public class AndroidGB28181Demo implements GBSIPAgentListener {
    private String gb_source_id_ = null;
    private String gb_target_id_ = null;

    private long player_handle_ = 0;
    private long rtp_receiver_handle_ = 0;
    private AtomicLong last_receive_audio_data_time_ = new AtomicLong(0);
  
    @Override
    public void ntsOnNotifyBroadcastCommand(String fromUserName, String fromUserNameAtDomain, String sn, String sourceID, String targetID) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (gb28181_agent_ != null ) {
                    gb28181_agent_.respondBroadcastCommand(from_user_name_, from_user_name_at_domain_,sn_,source_id_, target_id_, true);
                }
            }

            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() {
            @Override
            public void run() {
                stopAudioPlayer();
                destoryRTPReceiver();

                if (gb28181_agent_ != null ) {
                    String local_ip_addr = IPAddrUtils.getIpAddress(context_);

                    boolean is_tcp = true; // 默认用TCP
                    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();
                            }

                        } else {
                            destoryRTPReceiver();
                        }
                    }
                }
            }

            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() {
            @Override
            public void run() {
                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 ntsOnInviteAudioBroadcastTimeout(String sourceID, String targetID) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                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);
    }

    class PlayerExternalPCMOutput implements NTExternalAudioOutput {
        private int buffer_size_ = 0;
        private ByteBuffer pcm_buffer_ = null;

        @Override
        public ByteBuffer getPcmByteBuffer(int size)  {
            if(size < 1)
                return null;

            if(buffer_size_ != size) {
                buffer_size_ = size;
                pcm_buffer_ = ByteBuffer.allocateDirect(buffer_size_);
            }

            return pcm_buffer_;
        }

        public void onGetPcmFrame(int ret, int sampleRate, int channel, int sampleSize, int is_low_latency) {

            if (null == pcm_buffer_)
                return;

            pcm_buffer_.rewind();

            if (ret == 0 && isGB28181StreamRunning && publisherHandle != 0 )
                // 传给发送端做音频相关处理
                libPublisher.SmartPublisherOnFarEndPCMData(publisherHandle, pcm_buffer_, sampleRate, channel, sampleSize, is_low_latency);
        }
    }

    class PlayerAudioDataOutput implements NTAudioDataCallback {
        private int buffer_size_ = 0;
        private int param_info_size_ = 0;

        private ByteBuffer buffer_ = null;
        private ByteBuffer parameter_info_ = null;

        @Override
        public ByteBuffer getAudioByteBuffer(int size) {
            if( size < 1 ) return null;

            if (size <= buffer_size_ && buffer_ != null )
                return buffer_;

            buffer_size_ = align(size + 256, 16);
            buffer_ = ByteBuffer.allocateDirect(buffer_size_);
            return buffer_;
        }

        @Override
        public ByteBuffer getAudioParameterInfo(int size) {
            if(size < 1) return null;

            if ( size <= param_info_size_ &&  parameter_info_ != null )
                return  parameter_info_;

            param_info_size_ = align(size + 32, 16);
            parameter_info_ = ByteBuffer.allocateDirect(param_info_size_);

            return parameter_info_;
        }

        public void onAudioDataCallback(int ret, int audio_codec_id, int sample_size, int is_key_frame, long timestamp, int sample_rate, int channel, int parameter_info_size, long reserve)  {
            last_receive_audio_data_time_.set(SystemClock.elapsedRealtime());
        }
    }

    class AudioPlayerDataTimer implements Runnable {
        public static final int THRESHOLD_MS = 60*1000; 
        public static final int INTERVAL_MS = 10*1000; 

        public AudioPlayerDataTimer(long handle) {
            handle_ = handle;
        }

        @Override
        public void run() {
            if (0 == handle_)
                return;

            if (handle_ != player_handle_)
                return;
  
            long last_update_time = last_receive_audio_data_time_.get();
            long cur_time = SystemClock.elapsedRealtime();

            if ( (last_update_time + this.THRESHOLD_MS) >  cur_time) {
                // 继续定时器
                handler_.postDelayed(new AudioPlayerDataTimer(this.handle_), this.INTERVAL_MS);

            }
            else {
                if (gb_source_id_!= null && gb_target_id_ != null) {
                    if (gb28181_agent_ != null)
                        gb28181_agent_.byeAudioBroadcast(gb_source_id_, gb_target_id_);
                }

                gb_source_id_= null;
                gb_target_id_ = null;

                stopAudioPlayer();
                destoryRTPReceiver();
            }
        }

        private long handle_;
    }

    private boolean startAudioPlay() {
        if (player_handle_ != 0 )
            return false;

        player_handle_ = lib_player_.SmartPlayerOpen(context_);
        if (player_handle_ == 0)
            return false;

        // lib_player_.SetSmartPlayerEventCallbackV2(player_handle_,new EventHandePlayerV2());

        lib_player_.SmartPlayerSetBuffer(player_handle_, 0);

        lib_player_.SmartPlayerSetReportDownloadSpeed(player_handle_, 1, 10);

        lib_player_.SmartPlayerClearRtpReceivers(player_handle_);
        lib_player_.SmartPlayerAddRtpReceiver(player_handle_, rtp_receiver_handle_);

        lib_player_.SmartPlayerSetSurface(player_handle_, null);
        // lib_player_.SmartPlayerSetRenderScaleMode(player_handle_, 1);

        lib_player_.SmartPlayerSetAudioOutputType(player_handle_, 1);

        lib_player_.SmartPlayerSetMute(player_handle_, 0);

        lib_player_.SmartPlayerSetAudioVolume(player_handle_, 100);

        lib_player_.SmartPlayerSetExternalAudioOutput(player_handle_, new PlayerExternalPCMOutput());

        lib_player_.SmartPlayerSetUrl(player_handle_, "rtp://xxxxxxxxxxxxxxxxxxx");

        if (0 != lib_player_.SmartPlayerStartPlay(player_handle_)) {
            lib_player_.SmartPlayerClose(player_handle_);
            player_handle_ = 0;

            Log.e(TAG,  "start audio paly failed");
            return false;
        }

        lib_player_.SmartPlayerSetAudioDataCallback(player_handle_, new PlayerAudioDataOutput());

        if (0 ==lib_player_.SmartPlayerStartPullStream(player_handle_) ) {
            // 启动定时器,长时间收不到音频数据,则停止播放,发送BYE
            last_receive_audio_data_time_.set(SystemClock.elapsedRealtime());
            handler_.postDelayed(new AudioPlayerDataTimer(player_handle_), AudioPlayerDataTimer.INTERVAL_MS);
        }

        return true;
    }

    private void stopAudioPlayer() {
        if (player_handle_ != 0 ) {
            lib_player_.SmartPlayerStopPullStream(player_handle_);
            lib_player_.SmartPlayerStopPlay(player_handle_);
            lib_player_.SmartPlayerClose(player_handle_);
            player_handle_ = 0;
        }
    }

    private void destoryRTPReceiver() {
        if (rtp_receiver_handle_ != 0) {
            lib_player_.UnInitRTPReceiver(rtp_receiver_handle_);
            lib_player_.DestoryRTPReceiverSession(rtp_receiver_handle_);
            lib_player_.DestoryRTPReceiver(rtp_receiver_handle_);
            rtp_receiver_handle_ = 0;
        }
    }

    @Override
    public void ntsOnInviteAudioBroadcastResponse(String sourceID, String targetID, int statusCode, PlaySessionDescription sessionDescription) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                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());

                            int clock_rate = audio_attr.getClockRate();
                            lib_player_.SetRTPReceiverPayloadType(rtp_receiver_handle_, audio_attr.getPayloadType(),  audio_attr.getEncodingName(), 2, clock_rate);

                            // 如果是PCMA, 会默认填采样率8000, 通道1, 其他音频编码需要手动填入
                            // lib_player_.SetRTPReceiverAudioSamplingRate(rtp_receiver_handle_, 8000);
                            // lib_player_.SetRTPReceiverAudioChannels(rtp_receiver_handle_, 1);

                            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_source_id_ = source_id_;
                                gb_target_id_ = target_id_;
                             
                            }
                        }

                    } 

                    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() {
            @Override
            public void run() {
                gb_source_id_ = null;
                gb_target_id_ = null;
    
                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() {
            @Override
            public void run() {
                gb_source_id_ = null;
                gb_target_id_ = null;

                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);
    }
}

     测试下来音频效果不错,从文档描述到代码实现,需要不少精力,更多问题可以联系qq: 1130758427

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值