安卓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);@Overridepublic void ntsOnNotifyBroadcastCommand(String fromUserName, String fromUserNameAtDomain, String sn, String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic 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);}@Overridepublic void ntsOnAudioBroadcast(String commandFromUserName, String commandFromUserNameAtDomain, String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic void run() {stopAudioPlayer();destoryRTPReceiver();if (gb28181_agent_ != null ) {String local_ip_addr = IPAddrUtils.getIpAddress(context_);boolean is_tcp = true; // 默认用TCPrtp_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);}@Overridepublic void ntsOnInviteAudioBroadcastException(String sourceID, String targetID, String errorInfo) {handler_.postDelayed(new Runnable() {@Overridepublic 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);}@Overridepublic void ntsOnInviteAudioBroadcastTimeout(String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic 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;@Overridepublic 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;@Overridepublic 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_;}@Overridepublic 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;}@Overridepublic 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_) ) {// 启动定时器,长时间收不到音频数据,则停止播放,发送BYElast_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;}}@Overridepublic void ntsOnInviteAudioBroadcastResponse(String sourceID, String targetID, int statusCode, PlaySessionDescription sessionDescription) {handler_.postDelayed(new Runnable() {@Overridepublic 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);}@Overridepublic void ntsOnByeAudioBroadcast(String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic 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);}@Overridepublic void ntsOnTerminateAudioBroadcast(String sourceID, String targetID) {handler_.postDelayed(new Runnable() {@Overridepublic 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,   github

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

  1. Android平台GB28181设备接入端如何支持跨网段语音对讲

    技术背景 如果你是音视频开发者亦或寻求这块技术方案的公司,在探讨这个问题之前,你可能网上看了太多关于语音广播和语音对讲相关的资料,大多文章认为语音对讲和语音广播无本质区别,实现思路也大同小异. 今天我 ...

  2. Android 四大组件 —— 广播(广播机制解析)

    在网络通信中,一个IP网络范围中最大的IP 地址是被保留作为广播地址来使用的.比如某个网络的IP 范围是192.168.0.XXX,子网掩码是255.255.255.0,那么这个网络的广播地址就是19 ...

  3. Android学习笔记——广播机制

    Android广播机制 为了便于进行系统级别的消息通知,Android引入了一套广播消息机制. Android中的广播机制十分灵活,每个程序都可以对自己感兴趣的广播进行注册.程序只会接收自己所关心的广 ...

  4. Android平台GB28181设备接入端语音广播支持PS格式

    技术背景 对接Android平台GB28181设备接入端语音广播的时候,我们有遇到过INVITE SDP需要PCMA格式的audio,对方同时回了PS和PCMA两种,然后,发数据的时候,直接发了PS的 ...

  5. GB28181 安卓移动设备位置上报实现(订阅和通知实现)

    GB28181中事件订阅和通知机制是基于RFC3265 中的SIP扩展方法SUBSCRIBE和NOTIFY实现的.代码实现之前,先了解下相关协议. 这里先简单说明下RFC3265: 1.SUBSCRI ...

  6. 安卓设备接入GB28181(Android GB28181)

    最近对安卓现有代码进行了扩展,支持了GB28181, GB28181协议实现分两块,一块是信令部分,一块是流媒体数据传输.代码分两部分: 信令接口: public interface GBSIPAge ...

  7. android分享助手下载地址,语音导出分享助手手机版|语音导出分享助手安卓版下载 v2.1 - 跑跑车安卓网...

    语音导出分享助手是一款语音导出类的软件,这款软件可为需要的用户提供优质的语音服务,满足你的日常需求,快来下载吧! 软件介绍 还在为手机中语音不能分享而烦恼?还在为昔日误删好友而后悔获取不到两人往日的语 ...

  8. 安卓Intent的Action中的常值变量:窗口action常量(android.intent.action.+xxx),广播action常量(android.intent.action.+xxx)

    全栈工程师开发手册 (作者:栾鹏) 安卓教程全解 安卓Intent的Action中的常值变量:窗口action常量,广播action常量 窗口action名称常量,"android.inte ...

  9. 国标GB28181设备终端(国标摄像机、国标单兵设备)实现方案流程概述

    国标GB/T 28181协议的逐步普及,解决了海康.大华.宇视等各大厂家设备协议统一的问题,尤其是在主动注册到平台这一块的协议上,非常好地解决了所有有线.无线.4G.5G设备的统一接入协议的问题,GB ...

最新文章

  1. 澳洲计算机学,2020年澳洲计算机科学专业工作好找吗
  2. 为什么不建议用try catch处理异常?
  3. wxwidgets mysql_wxWidgets导入Excel文件详细教程
  4. python matplotlib plt 画图 将刻度 替换为文字/字符以及画断断续续的分段函数
  5. 老子学不动系列:Vue 3.0 新特性预览
  6. 二分查找 —— 有序数组不小于(不大于)某数的第一个(最后一个)元素
  7. 注册 aspnet_regiis
  8. iconv-----linux gbk 转 UTF-8
  9. 对我有利就契约,不利就废纸
  10. 命令调出本地链接_大牛进化路上之Linux基础命令,看看你了解多少?
  11. Allegro导入Altium Designer的pcb文件
  12. 在python中无论类的名字是什么构造方法的名字都是_超星尔雅大学生职业素养期末答案...
  13. 《微电子概论》2.1 理论基础
  14. 简明C语言教程(七)scanf 用法
  15. Web地图服务、WMS 请求方式、网络地图服务(WMS)的三大操作
  16. 阿里云服务器apt install 出错怎么办?出现Package gdb is not available, but is referred to by another package怎么办
  17. ET框架学习——消息系统之二
  18. 极简步骤试玩Ant Design Pro myapp demo
  19. 测试用例-微信发红包
  20. 生成式对抗网络(GAN)原理推导与网络构建思路

热门文章

  1. 阿里IOT云平台(二)---10分钟物联网设备接入阿里云IoT平台
  2. 微信老外产品经理:《中国移动应用设计趋势》
  3. 钉钉考勤接口调用与OA系统数据对接(多线程版)
  4. 深度学习笔记(四十一)循环神经网络及正反向传播
  5. JVM和DVM的区别
  6. python图像处理:核磁共振图像(3D)的缩放
  7. java跳转kotlin页面_Kotlin:return与跳转
  8. mysql按月份分组查询_mysql如何按月份分组查询
  9. CTFshow-萌新
  10. php6基因突变,基因突变中那些“披着狼皮的羊” 很多“致命性”基因突变正在被证实无害...