/// <summary> /// Subscribe to video or vbss sharer. /// if we set the flag forceSubscribe to true, the behavior is to subscribe to a video even if there is no available socket left. /// in that case we use the LRU cache to free socket and subscribe to the new MSI. /// </summary> /// <param name="participant">Participant sending the video or VBSS stream.</param> /// <param name="forceSubscribe">If forced, the least recently used video socket is released if no sockets are available.</param> private void SubscribeToParticipantVideo(ICallParticipant participant, bool forceSubscribe = true) { bool subscribeToVideo = false; uint socketId = uint.MaxValue; // filter the mediaStreams to see if the participant has a video send var participantSendCapableVideoStream = participant.Resource.MediaStreams.Where(x => x.MediaType == Modality.Video && (x.Direction == MediaDirection.SendReceive || x.Direction == MediaDirection.SendOnly)).FirstOrDefault(); if (participantSendCapableVideoStream != null) { bool updateMSICache = false; var msi = uint.Parse(participantSendCapableVideoStream.SourceId); lock (this.subscriptionLock) { if (this.currentVideoSubscriptions.Count < this.Call.GetLocalMediaSession().VideoSockets.Count) { // we want to verify if we already have a socket subscribed to the MSI if (!this.msiToSocketIdMapping.ContainsKey(msi)) { if (this.availableSocketIds.Any()) { socketId = this.availableSocketIds.Last(); this.availableSocketIds.Remove((uint)socketId); subscribeToVideo = true; } } updateMSICache = true; this.logger.Info($"[{this.Call.Id}:SubscribeToParticipant(socket {socketId} available, the number of remaining sockets is {this.availableSocketIds.Count}, subscribing to the participant {participant.Id})"); } else if (forceSubscribe) { // here we know that all the sockets subscribed to a video we need to update the msi cache, // and obtain the socketId to reuse with the new MSI updateMSICache = true; subscribeToVideo = true; } if (updateMSICache) { this.currentVideoSubscriptions.TryInsert(msi, out uint?dequeuedMSIValue); if (dequeuedMSIValue != null) { // Cache was updated, we need to use the new available socket to subscribe to the MSI this.msiToSocketIdMapping.TryRemove((uint)dequeuedMSIValue, out socketId); } } } if (subscribeToVideo && socketId != uint.MaxValue) { this.msiToSocketIdMapping.AddOrUpdate(msi, socketId, (k, v) => socketId); this.logger.Info($"[{this.Call.Id}:SubscribeToParticipant(subscribing to the participant {participant.Id} on socket {socketId})"); this.BotMediaStream.Subscribe(MediaType.Video, msi, VideoResolution.HD1080p, socketId); } } // vbss viewer subscription var vbssParticipant = participant.Resource.MediaStreams.SingleOrDefault(x => x.MediaType == Modality.VideoBasedScreenSharing && x.Direction == MediaDirection.SendOnly); if (vbssParticipant != null) { // new sharer this.logger.Info($"[{this.Call.Id}:SubscribeToParticipant(subscribing to the VBSS sharer {participant.Id})"); this.BotMediaStream.Subscribe(MediaType.Vbss, uint.Parse(vbssParticipant.SourceId), VideoResolution.HD1080p, socketId); } }
/// <summary> /// Event handler when participan is updated. /// </summary> /// <param name="sender">The sender.</param> /// <param name="args">The arguments.</param> protected virtual void ParticipantOnUpdated(ICallParticipant sender, ResourceEventArgs <Participant> args) { // do nothing in base class. }
/// <inheritdoc/> protected override void ParticipantOnUpdated(ICallParticipant sender, ResourceEventArgs <Participant> args) { // do nothing. }