示例#1
0
        /// <summary>
        /// Get a snapshot of all transceivers associated with this PeerConnection.
        /// This PeerConnection owns the returned transceivers.
        /// </summary>
        /// <remarks>This method is thread safe</remarks>
        /// <returns></returns>
        public IReadOnlyList <RtpTransceiver> GetTransceivers()
        {
            SafetyCheck();

            PeerConnectionInterop.GetTransceivers(_handle,
                                                  out var nativeTransceiverArray,
                                                  out var nativeTransceiverArraySize);

            // When there is no transceivers,
            // The unmanaged code returns size = 0 and nativeTransceiverArray will be IntPtr.Zero,
            // therefore we ignore that.
            if (nativeTransceiverArraySize > 0)
            {
                try
                {
                    for (var i = 0; i < nativeTransceiverArraySize; i++)
                    {
                        var nativeTransceiverIntPtr = Marshal.ReadIntPtr(nativeTransceiverArray, i * IntPtr.Size);
                        if (false == _knownTransceivers.ContainsKey(nativeTransceiverIntPtr))
                        {
                            _knownTransceivers[nativeTransceiverIntPtr] = new RtpTransceiver(
                                nativeTransceiverIntPtr,
                                _signallingThread);
                        }
                    }
                }
                finally
                {
                    PeerConnectionInterop.FreeGetTransceiversResult(_handle, nativeTransceiverArray);
                }
            }
            // Return transceivers as a copy
            return(_knownTransceivers.Values.ToList());
        }
示例#2
0
        /// <summary>
        /// Call this immediately after CreateAnswer()
        /// </summary>
        /// <exception cref="Errors.SetSessionDescriptionFailedException"></exception>
        public void SetLocalSessionDescription(string type, string sdp, Callback observer)
        {
            if (type is null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (sdp is null)
            {
                throw new ArgumentNullException(nameof(sdp));
            }
            if (observer is null)
            {
                throw new ArgumentNullException(nameof(observer));
            }

            SafetyCheck();
            RequireCallbackNotSet(_setLocalSessionDescCallback);
            _setLocalSessionDescCallback = new PeerConnectionInterop.SetSessionDescriptionCallback(
                (userData, sucess, errorMessage) =>
            {
                _signallingThread.EnsureCurrentThread();
                _setLocalSessionDescCallback = null;
                Complete(observer, sucess, errorMessage);
            });
            _pendingCallbacks.Add(observer);
            PeerConnectionInterop.SetLocalSessionDescription(_handle, type, sdp, _setLocalSessionDescCallback, IntPtr.Zero);
        }
示例#3
0
 /// <summary>
 /// Generate an SDP offer.
 /// </summary>
 /// <remarks>Can be called from any thread</remarks>
 /// <returns></returns>
 public void CreateOffer(Callback <RTCSessionDescription> callback)
 {
     SafetyCheck();
     RequireCallbackNotSet(_createOfferCallback);
     _createOfferCallback = new PeerConnectionInterop.CreateSdpResultCallback((userData, result) =>
     {
         _signallingThread.EnsureCurrentThread();
         _createOfferCallback = null;
         Complete(callback, result);
     });
     _pendingCallbacks.Add(callback);
     PeerConnectionInterop.CreateOffer(_handle, _createOfferCallback, IntPtr.Zero);
 }
示例#4
0
 /// <summary>
 /// Only call this after SetRemoteSessionDescriptionAsync completes
 /// </summary>
 /// <exception cref="Errors.AddIceCandidateFailedException"
 public void AddIceCandidate(RTCIceCandidate iceCandidate)
 {
     SafetyCheck();
     Require.NotEmpty(iceCandidate);
     if (false == PeerConnectionInterop.AddIceCandidate(
             _handle,
             iceCandidate.SdpMid,
             iceCandidate.SdpMLineIndex,
             iceCandidate.Candidate))
     {
         throw new Errors.AddIceCandidateFailedException("Add ICE candidate failed, check RTC logs");
     }
 }
示例#5
0
        /// <summary>
        /// Close the native PeerConnection,
        /// note that pending async operations such as the CreateAnswer()
        /// method may still continue execute after the PeerConnection is closed.
        /// </summary>
        public void Close()
        {
            SafetyCheck();
            if (_isClosed)
            {
                throw new InvalidOperationException("Already closed");
            }
            _isClosed = true;

            _pendingCallbacks.ToList().ForEach(l => l.Error("Cancelled"));
            _pendingCallbacks.Clear();

            PeerConnectionInterop.Close(_handle);
        }
示例#6
0
        /// <summary>
        /// No longer used but still keep here for integration tests
        /// </summary>
        /// <param name="track"></param>
        /// <param name="streamId">Id of the stream, doesn't have to exist</param>
        /// <exception cref="AddTrackFailedException"></exception>
        /// <remarks>Can be called from anythread, the libWebRTC will proxy to the correct thread</remarks>
        /// <returns>RtpSender, this PeerConnection takes ownership</returns>
        internal RtpSender AddTrack(MediaStreamTrack track, Guid streamId)
        {
            SafetyCheck();
            Require.NotNull(track);
            Require.NotEmpty(streamId);
            var rtpSenderPtr = PeerConnectionInterop.AddTrack(_handle, track.Handle, streamId.ToString());

            if (rtpSenderPtr == IntPtr.Zero)
            {
                throw new AddTrackFailedException();
            }
            var rtpSender = new RtpSender(rtpSenderPtr, _signallingThread);

            return(rtpSender);
        }
示例#7
0
 /// <summary>
 /// Generate an answer after the remote sdp is set
 /// </summary>
 /// <returns></returns>
 /// <remarks>Can be called from any thread</remarks>
 /// <exception cref="Errors.CreateAnswerFailedException" />
 public void CreateAnswer(Callback <RTCSessionDescription> callback)
 {
     if (callback is null)
     {
         throw new ArgumentNullException(nameof(callback));
     }
     SafetyCheck();
     RequireCallbackNotSet(_createAnswerCallback);
     _createAnswerCallback = new PeerConnectionInterop.CreateSdpResultCallback((userData, result) =>
     {
         _signallingThread.EnsureCurrentThread();
         _createAnswerCallback = null;
         Complete(callback, result);
     });
     _pendingCallbacks.Add(callback);
     PeerConnectionInterop.CreateAnswer(_handle, _createAnswerCallback, IntPtr.Zero);
 }
示例#8
0
        public RtpTransceiver AddTransceiver(MediaKind kind, RtpTransceiverDirection direction)
        {
            SafetyCheck();
            if (kind == MediaKind.Data)
            {
                throw new NotSupportedException();
            }

            var transceiverPtr = PeerConnectionInterop.AddTransceiver(_handle, kind == MediaKind.Audio, direction);

            if (transceiverPtr == IntPtr.Zero)
            {
                throw new AddTransceiverFailedException();
            }

            var tmp = new RtpTransceiver(transceiverPtr, _signallingThread);

            _knownTransceivers.Add(transceiverPtr, tmp);
            return(tmp);
        }
 protected override void ReleaseHandle(IntPtr handle) => PeerConnectionInterop.Destroy(handle);
示例#10
0
 /// <summary>
 /// No longer used but still keep it here for tests
 /// </summary>
 /// <param name="rtpSender">The track, represented by its RtpSender</param>
 /// <remarks>Can be called from any thread, will be proxied to signalling thread by the lib.</remarks>
 internal void RemoveTrack(RtpSender rtpSender)
 {
     SafetyCheck();
     PeerConnectionInterop.RemoveTrack(_handle, rtpSender.Handle);
 }