public static VidyoConversation CreateVideoConversation(VideoConversationInitializationParameters parameters) { using (Trace.Config.scope()) { try { // Initialize the conversation object var conversation = new VidyoConversation { ScopedQueueName = parameters.ScopedQueueName, Room = VidyoServiceClient.CreateRoom(), InitializationParameters = parameters }; // Commit the conversation Save(conversation); return(conversation); } catch (Exception ex) { Trace.WriteEventError(ex, "Error in CreateConversation: " + ex.Message, EventId.GenericError); return(null); } } }
private void CicOnInteractionChanged(long interactionId, IDictionary <string, string> attributes) { using (Trace.Cic.scope()) { try { // Get conversation var conversation = ConversationManager.GetConversation(interactionId); if (conversation == null) { throw new ConversationNotFoundException(interactionId); } // Update attributes conversation.UpdateAttributes(attributes); // Action on hold if (conversation.IsConversationMuted && !_cic.InteractionIsHeld(interactionId)) { // Unmute conversation.IsConversationMuted = false; foreach (var participant in VidyoServiceClient.GetParticipants(conversation.Room.RoomId)) { VidyoServiceClient.PerformAction(conversation.Room.RoomId, participant, RoomAction.MuteBoth, false.ToString()); } } else if (!conversation.IsConversationMuted && _cic.InteractionIsHeld(interactionId)) { // Mute conversation.IsConversationMuted = true; foreach (var participant in VidyoServiceClient.GetParticipants(conversation.Room.RoomId)) { VidyoServiceClient.PerformAction(conversation.Room.RoomId, participant, RoomAction.MuteBoth, true.ToString()); } } } catch (ConversationNotFoundException ex) { Trace.Cic.warning(ex.Message); } catch (Exception ex) { Trace.WriteEventError(ex, "Error in CicOnInteractionChanged: " + ex.Message, EventId.GenericError); } } }
public void DoKickParticipant(object data) { using (Trace.Main.scope()) { try { var participant = data as Participant; VidyoServiceClient.KickParticipant(VidyoRoomId, participant); } catch (Exception ex) { Console.WriteLine(ex); Trace.Main.exception(ex, ex.Message); } } }
public void DoMuteVideo(object data) { using (Trace.Main.scope()) { try { var parts = data as Tuple <Participant, bool>; VidyoServiceClient.MuteVideo(VidyoRoomId, parts.Item1, parts.Item2); } catch (Exception ex) { Console.WriteLine(ex); Trace.Main.exception(ex, ex.Message); } } }
private bool CleanupConversation(VidyoConversation conversation) { using (Trace.Cic.scope()) { // Delete room if (!VidyoServiceClient.DeleteRoom(conversation.Room.RoomId)) { Console.WriteLine("Error deleting room; deletion failed."); } // Cleanup conversation ConversationManager.RemoveConversation(conversation); return(true); } }
private void ParticipantCheckerTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs) { using (Trace.Main.scope()) { try { Context.Send(s => IsCheckingParticipants = true, null); // Stop the timer so we can't back up on web service calls _participantCheckerTimer.Stop(); //Console.WriteLine("Getting participants for room " + VidyoRoomId); // Call web service to get participant list var participants = VidyoServiceClient.GetParticipants(VidyoRoomId); //Console.WriteLine("Participants (" + participants.Count + "): " + participants.Select(p => p.DisplayName).Aggregate((a, b) => a + "; " + b)); // Update list Context.Send(s => Participants.AddRange(participants, true), null); } catch (Exception ex) { Console.WriteLine("Error getting participants: " + ex.Message); Trace.Main.exception(ex); } finally { Context.Send(s => IsCheckingParticipants = false, null); // Only restart the timer if the interaction isn't disconnected if (!_interaction.IsDisconnected) { _participantCheckerTimer.Start(); } } } }
private void ReconstituteConversations() { using (Trace.Cic.scope()) { try { // Load previous data ConversationManager.LoadConversations(); // Check each conversation var conversationsToDelete = new List <VidyoConversation>(); foreach (var conversation in ConversationManager.ConversationList) { using (Trace.Core.scope("Reconstitute " + conversation.ConversationId)) { try { /* Store off the old interaction ID. This is necessary because of a race condition. When the old * interaction is disconnected, but not deallocated, the disconnected event will be raised when * the interaction reference is recreated and watches started. The disconnected event causes the * conversation object to be cleaned up, which deletes the Vidyo room. That's bad. * * This workaround clears the old conversation ID so that the conversation object won't be found * as a match when the disconnected event handler looks for a conversation by interaction ID. If * things are found to be in order, the interaction ID will be set back to the conversation. */ var oldInteractionId = conversation.InteractionId; conversation.InteractionId = 0; conversation.Save(); var needsInteraction = false; // Does the interaction exist? if (!_cic.InteractionExists(oldInteractionId)) { // No, but was the conversation waiting to be assigned? if (string.IsNullOrEmpty(conversation.UserOwner)) { needsInteraction = true; } else { // It was assigned to a user, but are there people still in the room? (if yes, probably GI after switchover) if (VidyoServiceClient.GetParticipantCount(conversation.Room.RoomId).Count == 0) { throw new ConversationReconstitutionException( "Interaction did not exist and nobody was in the Vidyo room."); } // People are in the room! Trace.Core.status( "Interaction {} did not exist, but participants exist in room {}. Creating new interaction.", oldInteractionId, conversation.Room.RoomId); // Need to make an interaction needsInteraction = true; } } // Interaction exists, validate it if (_cic.InteractionIsDisconnected(oldInteractionId)) { // Was it waiting in queue and unassigned? if (string.IsNullOrEmpty(_cic.GetUserQueueName(oldInteractionId))) { // Yes. Need to make an interaction needsInteraction = true; } else { // Nope. Clean up (was assigned to user, but was disconnected while we weren't looking) throw new ConversationReconstitutionException("Interaction " + oldInteractionId + " is disconnected."); } } // Need to make a new interaction for the conversation? if (needsInteraction) { // Make a new interaction //TODO: How to handle chat after switchover? Does the interaction ID change? var interactionId = _cic.MakeInteraction(conversation.InitializationParameters); if (interactionId == 0) { throw new Exception("Failed to create new interaction!"); } // Update conversation conversation.InteractionId = interactionId; conversation.UpdateAttributes(_cic.GetAttributes(interactionId, conversation.AttributeDictionary.Select(kvp => kvp.Key).ToArray())); conversation.Save(); // Done. Move on to next Trace.Core.status("Created new interaction {} for conversation", interactionId); continue; } // If we got here, everything is still in place conversation.InteractionId = oldInteractionId; conversation.Save(); Trace.Core.status("Conversation is still active"); } catch (ConversationReconstitutionException ex) { Trace.Core.status("Marking conversation {} for cleanup. Reason: {}", conversation.ConversationId, ex.Message); conversationsToDelete.Add(conversation); } catch (Exception ex) { Trace.WriteEventError(ex, "Failed to reconstitute conversation " + conversation.ConversationId + ". Message: " + ex.Message, EventId.GenericError); conversationsToDelete.Add(conversation); } } } // Remove inactive conversations foreach (var conversation in conversationsToDelete) { CleanupConversation(conversation); } } catch (Exception ex) { Trace.WriteEventError(ex, "Error in ReconstituteConversations: " + ex.Message, EventId.GenericError); } } }