///<summary> 创建 IceSocket /// IceSocket 是可靠的TCP传输 ///</summary> ///<param name="rtcConfiguration"> 服务器地址</param> ///<param name="rtcIceParameters"> 可选的来源标识</param> ///<param name="isCaller"> 是否为主叫</param> ///<param name="observer"> 事件侦听器</param> static public IceSocket Connect(string rtcConfiguration, string rtcIceParameters, bool isCaller, RTCSocketObserver observer) { if (observer == null) { throw new ArgumentNullException(); } int index = 1; while (index < OBSERVERS.Length && OBSERVERS[index] != null) { ++index; } if (index == OBSERVERS.Length) { throw new OverflowException(); } OBSERVERS[index] = observer; IntPtr iface = JSEP._CreateIceSocket(rtcConfiguration, rtcIceParameters, isCaller, (IntPtr)index, IceSocketCallback); if (iface == IntPtr.Zero) { OBSERVERS[index] = null; throw new ArgumentException(); } IceSocket self = new IceSocket(); SOCKETS.Add(iface, self); self.iface = iface; return(self); }
///<summary> 创建P2P通信实例 ///</summary> ///<param name="config"> 配置参数,JSON格式. 例如{'iceServers': [{'url': url}]}</param> ///<param name="zmfAudioPump"> 是否使用内置的'全局音频泵',可与外部音频流对接, @see JSEP_AUDIO_PUMP</param> ///<param name="isCaller"> 是否为主叫</param> ///<param name="observer"> 事件侦听器</param> ///<remarks> /// config 支持的配置参数 /// - STRUN 服务器地址 /// iceServers: [{ /// urls:'url' /// username:'' /// credential:'' /// }] /// - bundlePolicy:'balanced' /// - rtcpMuxPolicy:'require' | 'negotiate' /// - iceTransportPolicy:'all' /// - zmfAudioPump: false //全局设置,使用JSEP内置的音频流泵,可与外部音频流对接 /// /// constraints 支持的限制 /// - googIPv6: true /// - googDscp: true /// - DtlsSrtpKeyAgreement: true /// - RtpDataChannels: false /// - googSuspendBelowMinBitrate: true /// - googNumUnsignalledRecvStreams: 20 /// - googScreencastMinBitrate:int /// - googHighStartBitrate:int /// - googHighBitrate:true /// - googVeryHighBitrate:true /// - googCombinedAudioVideoBwe:true ///</remarks> public RTCPeerConnection(string config, bool zmfAudioPump, bool isCaller, RTCSessionObserver observer) { if (observer == null) { throw new ArgumentNullException(); } int index = 1; while (index < OBSERVERS.Length && OBSERVERS[index] != null) { ++index; } if (index == OBSERVERS.Length) { throw new OverflowException(); } OBSERVERS[index] = observer; iface = JSEP._CreatePeerConnection(config, zmfAudioPump, isCaller, (IntPtr)index, RTCSessionCallback); if (iface == IntPtr.Zero) { OBSERVERS[index] = null; throw new ArgumentException(); } }
///<summary> 创建 WebSocket 服务器并侦听客户的连接 /// WebSocket 是可靠的TCP传输 ///</summary> ///<param name="wsURL"> 服务器地址</param> ///<param name="rtcWebSocketInit"> 配置参数</param> ///<param name="observer"> 事件侦听器</param> static public WebSocket Listen(string wsURL, string rtcWebSocketInit, RTCSocketObserver observer) { if (observer == null) { throw new ArgumentNullException(); } int index = 1; while (index < OBSERVERS.Length && OBSERVERS[index] != null) { ++index; } if (index == OBSERVERS.Length) { throw new OverflowException(); } OBSERVERS[index] = observer; IntPtr iface = JSEP._CreateWebSocketServer(wsURL, rtcWebSocketInit, (IntPtr)index, WebSocketCallback); if (iface == IntPtr.Zero) { OBSERVERS[index] = null; throw new ArgumentException(); } WebSocket self = new WebSocket(); SOCKETS.Add(iface, self); self.iface = iface; return(self); }
///<summary> 销毁所有资源 ///</summary> ///<param name="isDisposing"> 是否是主动丢弃</param> protected virtual void Dispose(bool isDisposing) { if (iface != IntPtr.Zero) { OBSERVERS[(int)JSEP._ReleasePeerConnection(iface)] = null; } iface = IntPtr.Zero; }
///<summary> 销毁所有资源 ///</summary> ///<param name="isDisposing"> 是否是主动丢弃</param> protected virtual void Dispose(bool isDisposing) { if (iface != IntPtr.Zero) { OBSERVERS[(int)JSEP._CloseSocket(iface)] = null; SOCKETS.Remove(iface); iface = IntPtr.Zero; } }
///<summary> 手工设置发送码率 ///</summary> ///<param name="current_bitrate_bps"> 当前码率,若不大于0,则不设置</param> ///<param name="max_bitrate_bps"> 允许的最大码率,若不大于0,则不设置</param> ///<param name="min_bitrate_bps"> 允许的最小码率,若不大于0,则不设置</param> ///<returns> 成功返回0</returns> public int SetBitrate(int current_bitrate_bps, int max_bitrate_bps, int min_bitrate_bps) { return(JSEP._SetBitrate(iface, current_bitrate_bps, max_bitrate_bps, min_bitrate_bps)); }
///<summary> 开始/停止记录通信事件 ///</summary> ///<param name="filename"> 日志文件名,空或null则停止记录</param> ///<param name="max_size_mb"> 日志文件允许大小MB</param> ///<returns> 成功返回0</returns> public int LogRtcEvent(string filename, int max_size_mb) { return(JSEP._LogRtcEvent(iface, Encoding.UTF8.GetBytes(filename), max_size_mb)); }
///<summary> 获取统计 ///</summary> ///<param name="statsType"> 统计类别,""或null表示获取所有统计</param> ///<param name="bDebug"> 是否更详细的调试级别</param> ///<returns> 成功返回0, 将触发 JsepEventStatsReport 事件</returns> public int GetStats(string statsType, bool bDebug) { return(JSEP._GetStats(iface, statsType, bDebug)); }
///<summary> 创建offer SDP ///</summary> ///<param name="constraints"> 可选的SDP的限制参数.JSON格式</param> ///<returns> 无效参数立即返回-1,反之异步过程,结果由JsepEventCreateDescription 事件返回</returns> ///<remarks> /// constraints 支持如下限制 /// - OfferToReceiveAudio: true /// - OfferToReceiveVideo: true /// - VoiceActivityDetection: true /// - IceRestart: false /// - googUseRtpMUX: true ///</remarks> public int CreateOffer(string constraints) { return(JSEP._CreateOffer(iface, constraints)); }
///<summary> 配置对端(发送)的SDP ///</summary> ///<param name="desc"> SDP的JSON串,通常对端由 JsepEventCreateDescription 事件的JsepSdp获得</param> ///<returns> 无效参数立即返回-1,反之异步过程,结果由JsepEventSetDescription 事件返回 </returns> public int SetRemoteDescription(string desc) { return(JSEP._SetRemoteDescription(iface, desc)); }
///<summary> 移除本地媒体流 ///</summary> ///<param name="streamId"> 媒体流ID,若""或null则移除所有本地流</param> public void RemoveLocalStream(string streamId) { JSEP._RemoveLocalStream(iface, streamId); }
///<summary> 添加对端的ICE备选地址 ///</summary> ///<param name="candidate"> 备选地址,通常对端由 JsepEventIceCandidate 事件的JsepIceCandidate字段获得</param> ///<returns> 成功返回0 </returns> public int AddIceCandidate(string candidate) { return(JSEP._AddIceCandidate(iface, candidate)); }
///<summary> 发送自定义数据 ///</summary> ///<param name="channelId"> 通道ID</param> ///<param name="message"> 消息 </param> ///<returns> 成功返回0 </returns> public int SendMessage(string channelId, string message) { byte[] buffer = Encoding.UTF8.GetBytes(message); return(JSEP._SendMessage(iface, channelId, buffer, buffer.Length)); }
///<summary> 设置对端的ICE参数 ///</summary> ///<param name="rtcIceParameters">对端参数, @see RTCIceParameters</param> ///<returns> 成功返回0 </returns> public int SetRemoteParameters(string rtcIceParameters) { return(JSEP._SetSocketIceParameters(iface, rtcIceParameters)); }
///<summary> 添加对端的ICE地址 ///</summary> ///<param name="candidate">对端地址</param> ///<returns> 成功返回0 </returns> public int AddRemoteCandidate(string candidate) { return(JSEP._AddSocketIceCandidate(iface, candidate)); }
///<summary> 发送DTMF ///</summary> ///<param name="tones"> DMTF的音符,0-9,A-D或a-d,#,*. 忽略无法识别的字符</param> ///<param name="duration"> 每个音符的持续毫秒MS,不能超过6000或小于70</param> ///<param name="inter_tone_gap"> 音符间隔,必须至少为50ms,但应尽可能短</param> ///<returns> 成功返回0,将触发 JsepEventToneChange 事件 </returns> ///<remarks> /// 队列化发送DTMF 任务. /// ','表示延迟2秒处理下一个字符 /// 若调用时,上次仍在运行,则之前的任务将被取消 ///</remarks> public int InsertDtmf(string tones, int duration, int inter_tone_gap) { return(JSEP._InsertDtmf(iface, tones, duration, inter_tone_gap)); }
///<summary> 将媒体流发布到ZMF中 ///</summary> ///<param name="streamId"> 对端媒体流ID</param> ///<param name="renderOrCapturerBits"> 按位将视频轨道作为0-ZMF渲染,1-ZMF镜头</param> ///<param name="videoTrackMask"> 上个参数renderOrCapturerBits中的有效位掩码</param> ///<returns> 成功返回0 </returns> public int PublishRemoteStream(string streamId, int renderOrCapturerBits, int videoTrackMask) { return(JSEP._PublishRemoteStream(iface, streamId, renderOrCapturerBits, videoTrackMask)); }
///<summary> 添加本地媒体流 ///</summary> ///<param name="streamId"> 媒体流ID</param> ///<param name="bAudio"> 是否含音频</param> ///<param name="bVideo"> 是否含视频</param> ///<param name="constraints"> 媒体流的限制参数,JSON格式</param> ///<returns> 成功返回0,成功返回0, bAudio, bVideo分别指示是否含音视频 </returns> ///<remarks> /// 本地媒体流通常在协商前添加,对端媒体流是自动添加的. /// streamId 要保证唯一性,通常用账户ID. /// /// constraints 目前支持 /// - 视频 /// video: { /// zmfCapture:Id0 //ZMF采集源ID /// zmfRender:Id0 //ZMF第三方渲染源ID,转接为采集 /// } /// - 音频 /// audio: { /// DTMF:false //不使用JSEP_InsertDtmf函数,可节省些内存. /// } ///</remarks> public int AddLocalStream(string streamId, ref bool bAudio, ref bool bVideo, string constraints) { return(JSEP._AddLocalStream(iface, streamId, ref bAudio, ref bVideo, constraints)); }
///<summary> 配置本地(接收)的SDP ///</summary> ///<param name="desc"> desc SDP的JSON串,通常对端由 JsepEventCreateDescription 事件的JsepSdp获得</param> ///<returns> 无效参数立即返回-1,反之异步过程,结果由JsepEventSetDescription 事件返回 </returns> public int SetLocalDescription(string desc) { return(JSEP._SetLocalDescription(iface, desc)); }
///<summary> 关闭数据通道 ///</summary> ///<param name="channelId"> 通道ID</param> public void CloseDataChannel(string channelId) { JSEP._CloseDataChannel(iface, channelId); }
///<summary> 发送数据 ///</summary> ///<param name="message"> 消息 </param> ///<returns> 成功返回0 </returns> public int Send(string message) { byte[] buffer = Encoding.UTF8.GetBytes(message); return(JSEP._SendSocket(iface, buffer, buffer.Length, 0)); }
///<summary> 动态创建数据通道 ///</summary> ///<param name="channelId"> 通道ID</param> ///<param name="constraints"> 配置参数</param> ///<returns> 成功返回0</returns> ///<remarks> /// 支持的配置参数 /// - ordered:true, //是否保证次序,默认true /// - maxPacketLifeTime:0,//超过限时,将不重发.默认-1,始终重发 /// - maxRetransmits:0, //超过次数,将不重发,默认-1,,始终重发 /// - negotiated:false, //是否由上层应用负责协商建立过程, /// 即不触发DataChannelOpen事件.默认false由内部自动完成 /// - protocol:'', //自定义的上层应用协议名,默认空 ///</remarks> public int CreateDataChannel(string channelId, string constraints) { return(JSEP._CreateDataChannel(iface, channelId, constraints)); }