void GetOrCreateTransceiver(out RtpTransceiver transceiver, out bool isReusingTransceivers) { var mediaKind = _track.Kind; var transceivers = TargetPeerConnection.Native.GetTransceivers(); transceiver = null; isReusingTransceivers = true; for (var i = 0; i < transceivers.Count; i++) { if (transceivers[i].ReusabilityState == TransceiverReusabilityState.Available && false == string.IsNullOrWhiteSpace(transceivers[i].Mid) && transceivers[i].MediaKind == mediaKind && transceivers[i].Direction != RtpTransceiverDirection.RecvOnly) { transceiver = transceivers[i]; break; } } // If no available transceiver, create a new one if (transceiver is null || true) { transceiver = TargetPeerConnection.Native.AddTransceiver(mediaKind, RtpTransceiverDirection.SendOnly); isReusingTransceivers = false; } transceiver.CustomData = this; }
internal void OnRemoteTrackRemoved(RtpTransceiver transceiver) { _signallingThread.EnsureCurrentThread(); VideoRouterThrowHelper.WhenInvalidReceiver(transceiver); _remoteVideoLinks.RemoveByRemoteTrack(transceiver.Receiver); _logger.Info($"Removed {transceiver.Receiver} from {_remoteVideoLinks}"); }
public LocalVideoLink(VideoRouter parent, VideoSource source, IPeerConnection target) { if (source is null) { throw new ArgumentNullException(nameof(source)); } if (target is null) { throw new ArgumentNullException(nameof(target)); } if (null == source.VideoTrackSource) { throw new InvalidProgramException("VideoTrackSource is NULL"); } TargetPeerConnection = target; VideoSource = source; _parent = parent ?? throw new ArgumentNullException(nameof(parent)); // Create track var trackId = Guid.NewGuid(); _track = parent.PeerConnectionFactory.CreateVideoTrack(trackId.ToString(), source.VideoTrackSource); // Find the first available transceiver (or create it) GetOrCreateTransceiver(out var transceiver, out var isReusingTransceiver); Transceiver = transceiver; // Next, set/replace the track: Transceiver.ToBusyState(_track); // If we're re-using an existing transceivers. // Transceiver metadata will need to be sent for clients to update their UIs. // If we are creating new transceivers, no need to do this, // since PeerConnection will re-negotiate automatically if (isReusingTransceiver) { RaiseTransceiverMetadataUdatedEvent(); } // If stream id has not been set, set it. // WebRTC does not allow us to change the stream id, but we don't care either, // we just want it to be unique. if (string.IsNullOrWhiteSpace(Transceiver.Sender.StreamId)) { Transceiver.Sender.StreamId = Guid.NewGuid().ToString(); } // Add track to peer _logger.Debug($"Local track created {_track}"); }
public static void WhenInvalidReceiver(RtpTransceiver transceiver) { var track = transceiver.Receiver.Track; if (track == null) { throw new InvalidProgramException("Track is NULL"); } if (string.IsNullOrWhiteSpace(track.Id)) { throw new ArgumentNullException($"Track id is null for {transceiver}, Track {transceiver.Receiver.Track}"); } }
internal void OnRemoteTrackAdded(Client client, IPeerConnection peerConnection, RtpTransceiver transceiver) { _signallingThread.EnsureCurrentThread(); Require.NotNull(peerConnection); VideoRouterThrowHelper.WhenInvalidReceiver(transceiver); // Ignore audio tracks for now if (transceiver.Receiver.Track.Kind != MediaKind.Video) { return; } // What's the video source that this track should be connected to? var transceiverMid = transceiver.Mid; var videoSource = client.VideoSources .FirstOrDefault(kv => string.Equals(kv.Value.ExpectedTransceiverMid, transceiverMid, StringComparison.InvariantCultureIgnoreCase)) .Value; // videoSource could be null when the client doesn't have any input devices, // therefore it never calls SetRemoteTransceiverMetadata() if (videoSource != null) { VideoRouterThrowHelper.WhenSourceIsEmpty(videoSource, transceiver.Receiver); var remoteVideoLink = new RemoteVideoLink(peerConnection, videoSource, transceiver.Receiver); _remoteVideoLinks.AddOrUpdate(remoteVideoLink); _logger.Info($"Added {remoteVideoLink} into {_remoteVideoLinks}"); } }
public RtpTransceiverNative(RtpTransceiver rtpTransceiverNative) : base(rtpTransceiverNative) { _rtpTransceiver = rtpTransceiverNative; }
public PlatformRtpTransceiver(RtpTransceiver transceiver) : base(transceiver) => _transceiver = transceiver;
private RTCRtpTransceiver(RtpTransceiver nativeTransceiver) : base(nativeTransceiver) { }