private void StartEmptyPresentation()
        {
            // Make sure we have a suitable RoleModel for broadcasting a presentation.
            InstructorModel instructor;
            using(Synchronizer.Lock(this.m_Model.Participant.SyncRoot)) {
                instructor = this.m_Model.Participant.Role as InstructorModel;
                if(instructor == null) {
                    // Make the participant representing this user an Instructor,
                    // which tells the ConnectionManager to broadcast the presentation
                    // once it's added to the classroom.
                    instructor = new InstructorModel(Guid.NewGuid());
                    this.m_Model.Participant.Role = instructor;
                }
            }

            // Create the presentation.
            // TODO: Find something useful to use as the Presentation's HumanName.
            PresentationModel pres = new PresentationModel(Guid.NewGuid(), this.m_Model.Participant, "No presentation yet");

            using(Synchronizer.Lock(this.m_Model.Network.SyncRoot)) {
                // Associate the participant with itself.  This removes any existing association
                // (since an Instructor should not be processing broadcasts from other clients),
                // and also causes the NetworkAssociationService to copy anything we do to the
                // InstructorModel to the WorkspaceModel.
                this.m_Model.Network.Association = this.m_Model.Participant;
            }

            // Here's the kicker, which triggers the viewer to hide the classroom browser
            // and start displaying the presentation.  The NetworkAssociationService copies
            // the presentation to the WorkspaceModel, which causes it to be displayed by the UI.
            using(Synchronizer.Lock(instructor.SyncRoot)) {
                instructor.CurrentPresentation = pres;
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="sender">The sending queue to post messages to</param>
        /// <param name="role">The InstructorModel to create this class for</param>
        public InstructorWebService(SendingQueue sender, InstructorModel role)
        {
            this.m_Sender = sender;
            this.m_Instructor = role;

            // Handle basic changes
            this.m_GenericChangeDispatcher = new EventQueue.PropertyEventDispatcher(this.m_Sender, new PropertyEventHandler(this.HandleGenericChange));
            this.m_Instructor.Changed["ForcingStudentNavigationLock"].Add(this.m_GenericChangeDispatcher.Dispatcher);
            this.m_Instructor.Changed["AcceptingStudentSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher);
            this.m_Instructor.Changed["AcceptingQuickPollSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher);

            // Handle changes to the current deck traversal
            this.m_CurrentDeckTraversalChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.m_Sender, new PropertyEventHandler(this.HandleCurrentDeckTraversalChanged));
            this.m_Instructor.Changed["CurrentDeckTraversal"].Add(this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher);
            this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher(this, null);
        }
예제 #3
0
        private void SetNetworkAssociationRole(RoleModel role)
        {
            // Remove any old event listeners.
            if (this.m_NetworkAssociationRole != null)
            {
                this.m_NetworkAssociationRole.Changed["ForcingStudentNavigationLock"].Remove(this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher);
            }

            this.m_NetworkAssociationRole = role as InstructorModel;

            // If we're now associated with an instructor, we must obey its ForcingStudentNavigationLock policy.
            // So we register event listeners to watch for changes to that property.
            if (this.m_NetworkAssociationRole != null)
            {
                this.m_NetworkAssociationRole.Changed["ForcingStudentNavigationLock"].Add(this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher);
                this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher(this, null);
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="sender">The sending queue to post messages to</param>
        /// <param name="role">The InstructorModel to create this class for</param>
        public InstructorNetworkService(SendingQueue sender, InstructorModel role)
            : base(sender, role)
        {
            this.m_Instructor = role;

            // Create the submission status service
            submission_status_service_ = new SubmissionStatusNetworkService(this.Sender, role);

            // Handle basic changes
            this.m_GenericChangeDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleGenericChange));
            this.m_Instructor.Changed["ForcingStudentNavigationLock"].Add(this.m_GenericChangeDispatcher.Dispatcher);
            this.m_Instructor.Changed["AcceptingStudentSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher);
            this.m_Instructor.Changed["AcceptingQuickPollSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher);

            // Handle changes to the current presentation
            this.m_CurrentPresentationChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentPresentationChanged));
            this.m_Instructor.Changed["CurrentPresentation"].Add(this.m_CurrentPresentationChangedDispatcher.Dispatcher);
            this.m_CurrentPresentationChangedDispatcher.Dispatcher(this, null);

            // Handle changes to the current deck traversal
            this.m_CurrentDeckTraversalChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentDeckTraversalChanged));
            this.m_Instructor.Changed["CurrentDeckTraversal"].Add(this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher);
            this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher(this, null);
        }
 private void HandleRoleChanged(object sender, PropertyEventArgs args_)
 {
     using(Synchronizer.Lock(this)) {
         if(this.m_Association != null) {
             using(Synchronizer.Lock(this.m_Association.SyncRoot)) {
                 this.Instructor = this.m_Association.Role as InstructorModel;
             }
         } else {
             this.Instructor = null;
         }
     }
 }
예제 #6
0
        protected override bool UpdateTarget(ReceiveContext context)
        {
            InstructorModel role = this.Target as InstructorModel;
            if(role == null)
                this.Target = role = new InstructorModel(((Guid) this.TargetId));

            using(Synchronizer.Lock(role.SyncRoot)) {
                role.AcceptingStudentSubmissions = this.AcceptingStudentSubmissions;
                // Deserialize the extension
                ExtensionWrapper extension = this.Extension as ExtensionWrapper;
                if (extension != null) {
                    if( extension.ExtensionType.Equals( new Guid( "{65A946F4-D1C5-426b-96DB-7AF4863CE296}" ) ) ) {
                        bool acceptingQuickPollSubmissions = (bool)extension.ExtensionObject;
                        role.AcceptingQuickPollSubmissions = acceptingQuickPollSubmissions;
                    }
                    else {
                        Trace.WriteLine("Unknown Extension id=" + extension.ExtensionType.ToString());
                    }
                }
                role.ForcingStudentNavigationLock = this.ForcingStudentNavigationLock;
            }

            // Update the clock skew from our current value.
            using( Synchronizer.Lock( context.Model.ViewerState.Diagnostic.SyncRoot ) ) {
                context.Model.ViewerState.Diagnostic.AddSkewEntry( this.InstructorClockTicks );
            }

            base.UpdateTarget(context);

            return true;
        }
예제 #7
0
 public InstructorMessage(InstructorModel role)
     : base(role)
 {
     using(Synchronizer.Lock(role.SyncRoot)) {
         this.AcceptingStudentSubmissions = role.AcceptingStudentSubmissions;
         // Need to add as an extension to maintain backward compatability
         this.Extension = new ExtensionWrapper( role.AcceptingQuickPollSubmissions, new Guid("{65A946F4-D1C5-426b-96DB-7AF4863CE296}") );
         this.ForcingStudentNavigationLock = role.ForcingStudentNavigationLock;
         this.InstructorClockTicks = UW.ClassroomPresenter.Misc.AccurateTiming.Now;
     }
 }
예제 #8
0
        public override void AddCapability(ICapability capability) {
            base.AddCapability(capability);

            if (m_Capability == null) {
                m_Capability = (PresenterCapability)capability;

                // Hook the ObjectReceived event so we can receive incoming data
                m_Capability.ObjectReceived += new CapabilityObjectReceivedEventHandler(objectReceived);

                //Set the role to instructor if we initiated the capability.
                if (m_Capability.IsSender) {
                    //Set the instructor role
                    InstructorModel instructor = new InstructorModel(Guid.NewGuid());
                    using (Synchronizer.Lock(this.m_Model.Participant.SyncRoot)) {
                        m_Model.Participant.Role = instructor;
                    }
                    using (Synchronizer.Lock(this.m_Model.ViewerState.SyncRoot)) {
                        this.m_Model.ViewerState.iRole = 2;
                    }
                    //We also need to set up a couple of other things to make the instructor functional:  A network association
                    // and an empty presentation.
                    PresentationModel pres = new PresentationModel(Guid.NewGuid(), m_Model.Participant, "Untitled Presentation", true);
                    using (Synchronizer.Lock(m_Model.Network.SyncRoot)) {
                        m_Model.Network.Association = m_Model.Participant;
                    }
                    using (Synchronizer.Lock(instructor.SyncRoot)) {
                        instructor.CurrentPresentation = pres;
                    }
                }
                else { 
                    //Set student role
                    using (Synchronizer.Lock(this.m_Model.Participant.SyncRoot)) {
                        m_Model.Participant.Role = new StudentModel(Guid.NewGuid());
                    }
                    using (Synchronizer.Lock(this.m_Model.ViewerState.SyncRoot)) {
                        this.m_Model.ViewerState.iRole = 1;
                    }
                }

                //Before we create the CXPCapabilityMessageSender, we want to wait until the Play and Send methods have completed.
                //Otherwise we can end up trying to send before the capability is ready to accept messages.
                bool createCapabilitySenderNow = false;
                lock (m_Capability) { //This section synchronized with the PresenterCapability instance.
                    if (m_Capability.IsPlayingAndSending) {
                        createCapabilitySenderNow = true;
                    }
                    else {
                        m_Capability.OnPlay += new PresenterCapability.OnPlayHandler(OnCapabilityPlay);
                    }
                }
                if (createCapabilitySenderNow) {
                    m_CapabilitySender = new CXPCapabilityMessageSender(m_Model, m_Capability);
                }
            }
        }
        private void SetNetworkAssociationRole(RoleModel role)
        {
            // Remove any old event listeners.
            if (this.m_NetworkAssociationRole != null) {
                this.m_NetworkAssociationRole.Changed["ForcingStudentNavigationLock"].Remove(this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher);
            }

            this.m_NetworkAssociationRole = role as InstructorModel;

            // If we're now associated with an instructor, we must obey its ForcingStudentNavigationLock policy.
            // So we register event listeners to watch for changes to that property.
            if (this.m_NetworkAssociationRole != null) {
                this.m_NetworkAssociationRole.Changed["ForcingStudentNavigationLock"].Add(this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher);
                this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher(this, null);
            }
        }
예제 #10
0
 /// <summary>
 /// Find the current slide
 /// </summary>
 /// <param name="instructor"></param>
 /// <returns></returns>
 private Guid GetSlideID(InstructorModel instructor)
 {
     using (Synchronizer.Lock(instructor.SyncRoot)) {
         DeckTraversalModel dtm = instructor.CurrentDeckTraversal;
         if (dtm == null)
             return Guid.Empty;
         using (Synchronizer.Lock(dtm.SyncRoot)) {
             TableOfContentsModel.Entry e = dtm.Current;
             using (Synchronizer.Lock(e.SyncRoot)) {
                 SlideModel s = e.Slide;
                 using (Synchronizer.Lock(s.SyncRoot)) {
                     return s.Id;
                 }
             }
         }
     }
 }
예제 #11
0
        /// <summary>
        /// Even though we are not an instructor, here we fake an instructor beacon message for the purpose of unicast to multicast
        /// bridging.
        /// </summary>
        /// <returns></returns>
        protected Message NonInstructorMakeBeaconMessage()
        {
            InstructorModel instructor = new InstructorModel(m_NonInstructorId);
            Message role = RoleMessage.ForRole(instructor);

            using (Synchronizer.Lock(this.m_Model.Workspace)) {
                if (this.m_Model.Workspace.CurrentPresentation != null) {
                    using (Synchronizer.Lock(this.m_Model.Workspace.CurrentPresentation.SyncRoot)) {
                        if (this.m_Model.Workspace.CurrentPresentation.Value != null) {
                            role.InsertChild(new InstructorCurrentPresentationChangedMessage(this.m_Model.Workspace.CurrentPresentation));
                        }
                    }
                }

                if (this.m_Model.Workspace.CurrentDeckTraversal != null) {
                    using (Synchronizer.Lock(this.m_Model.Workspace.CurrentDeckTraversal.SyncRoot)) {
                        if (this.m_Model.Workspace.CurrentDeckTraversal.Value != null) {
                            Message traversal = new InstructorCurrentDeckTraversalChangedMessage(this.m_Model.Workspace.CurrentDeckTraversal.Value,false);
                            Message predecessor = traversal.Predecessor;
                            using (Synchronizer.Lock((~this.m_Model.Workspace.CurrentDeckTraversal).SyncRoot)) {
                                using (Synchronizer.Lock((~this.m_Model.Workspace.CurrentDeckTraversal).Current.SyncRoot)) {
                                    traversal.Predecessor = new SlideInformationMessage((~this.m_Model.Workspace.CurrentDeckTraversal).Current.Slide);
                                    TableOfContentsModel.Entry entry = (~this.m_Model.Workspace.CurrentDeckTraversal).Current;
                                    if (entry != null)
                                        traversal.Predecessor.InsertChild(new TableOfContentsEntryMessage(entry));
                                    traversal.Predecessor.AddOldestPredecessor(predecessor);
                                    role.InsertChild(traversal);
                                }
                            }
                        }
                    }
                }
            }
            return role;
        }
예제 #12
0
        protected override bool UpdateTarget(ReceiveContext context)
        {
            bool naviChanged = false;
            InstructorModel role = this.Target as InstructorModel;
            if(role == null)
                this.Target = role = new InstructorModel(((Guid) this.TargetId));

            using(Synchronizer.Lock(role.SyncRoot)) {
                role.AcceptingStudentSubmissions = this.AcceptingStudentSubmissions;
                // Deserialize the extension
                ExtensionWrapper extension = this.Extension as ExtensionWrapper;
                if (extension != null) {
                    try {
                        if (extension.ContainsKey(new Guid("{65A946F4-D1C5-426b-96DB-7AF4863CE296}")) || extension.ContainsKey(new Guid("{4795707C-9F85-CA1F-FEBA-5E851CF9E1DE}"))) {
                            bool acceptingQuickPollSubmissions = (bool)extension.GetExtension(new Guid("{65A946F4-D1C5-426b-96DB-7AF4863CE296}")).ExtensionObject;
                            this.AcceptingQuickPollSubmissions = acceptingQuickPollSubmissions;
                            LinkedDeckTraversalModel.NavigationSelector studentNavigationType = (LinkedDeckTraversalModel.NavigationSelector)extension.GetExtension(new Guid("{4795707C-9F85-CA1F-FEBA-5E851CF9E1DE}")).ExtensionObject;
                            this.StudentNavigationType = studentNavigationType;
                            using (Synchronizer.Lock(context.Model.ViewerState)) {
                                context.Model.ViewerState.StudentNavigationType = studentNavigationType;
                            }
                        }
                        else {
                            Trace.WriteLine("Unknown Extension id=" + extension.ExtensionType.ToString());
                        }
                    }
                    catch (Exception) {
                        if (extension.ExtensionType.Equals(new Guid("{65A946F4-D1C5-426b-96DB-7AF4863CE296}"))) {
                            bool acceptingQuickPollSubmissions = (bool)extension.ExtensionObject;
                                this.AcceptingQuickPollSubmissions = acceptingQuickPollSubmissions;
                         }
                         else {
                             Trace.WriteLine("Unknown Extension id=" + extension.ExtensionType.ToString());
                         }
                    }
                }
                else {
                    Trace.WriteLine("Unknown Extension id=" + this.Extension.GetType().ToString());
                }
                role.AcceptingQuickPollSubmissions = this.AcceptingQuickPollSubmissions;
                role.ForcingStudentNavigationLock = this.ForcingStudentNavigationLock;
                if (this.StudentNavigationType == LinkedDeckTraversalModel.NavigationSelector.None)
                    role.ForcingStudentNavigationLock = true;
                if (role.StudentNavigationType != this.StudentNavigationType)
                    naviChanged = true;
                role.StudentNavigationType = this.StudentNavigationType;
            }

            //if StudentNavigationType changed, refresh FilmStrip region
            if (naviChanged) {
                using (Synchronizer.Lock(context.Model.ViewerState.SyncRoot)) {
                    bool oldShowFilmStrip = context.Model.ViewerState.FilmStripEnabled;
                    context.Model.ViewerState.FilmStripEnabled = false;
                    context.Model.ViewerState.FilmStripEnabled = oldShowFilmStrip;
                }
            }

            // Update the clock skew from our current value.
            using( Synchronizer.Lock( context.Model.ViewerState.Diagnostic.SyncRoot ) ) {
                context.Model.ViewerState.Diagnostic.AddSkewEntry( this.InstructorClockTicks );
            }

            base.UpdateTarget(context);

            return true;
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="sender">The sending queue to post messages to</param>
        /// <param name="role">The InstructorModel to create this class for</param>
        public InstructorNetworkService(SendingQueue sender, InstructorModel role)
            : base(sender, role)
        {
            this.m_Instructor = role;

            // Create the submission status service
            submission_status_service_ = new SubmissionStatusNetworkService(this.Sender, role);

            // Handle basic changes
            this.m_GenericChangeDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleGenericChange));
            this.m_Instructor.Changed["ForcingStudentNavigationLock"].Add(this.m_GenericChangeDispatcher.Dispatcher);
            this.m_Instructor.Changed["AcceptingStudentSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher);
            this.m_Instructor.Changed["AcceptingQuickPollSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher);
            this.m_Instructor.Changed["StudentNavigationType"].Add(this.m_GenericChangeDispatcher.Dispatcher);

            // Handle changes to the current presentation
            this.m_CurrentPresentationChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentPresentationChanged));
            this.m_Instructor.Changed["CurrentPresentation"].Add(this.m_CurrentPresentationChangedDispatcher.Dispatcher);
            this.m_CurrentPresentationChangedDispatcher.Dispatcher(this, null);

            // Handle changes to the current deck traversal
            this.m_CurrentDeckTraversalChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentDeckTraversalChanged));
            this.m_Instructor.Changed["CurrentDeckTraversal"].Add(this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher);
            this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher(this, null);

            #if WEBSERVER
            // Create the web service equivalent to this service
            this.m_InstructorWebService = new Web.Network.InstructorWebService( this.Sender, role );

            using (Synchronizer.Lock(PresenterModel.TheInstance.SyncRoot)) {
                using (Synchronizer.Lock(PresenterModel.TheInstance.ViewerState.SyncRoot)) {
                    this.m_WebPerformanceWebService = new Web.Network.WebPerformanceWebService(this.Sender, PresenterModel.TheInstance.ViewerState.WebPerformance);
                }
            }
            #endif
        }
예제 #14
0
        public TCPServer(IPEndPoint localEP, PresenterModel model, ClassroomModel classroom,
            InstructorModel instructor)
        {
            RestoreConfig();
            m_ClientConnected = new ManualResetEvent(false);
            m_Participant = model.Participant;
            m_Classroom = classroom;
            m_ClientCount = 0;
            this.m_Network = model.Network;
            m_NetworkStatus = new NetworkStatus(ConnectionStatus.Disconnected, ConnectionProtocolType.TCP, TCPRole.Server, 0);
            this.m_Network.RegisterNetworkStatusProvider(this, true, m_NetworkStatus);

            if (localEP != null) {
                this.m_ListenEP = localEP;
            }
            else {
                this.m_ListenEP = new IPEndPoint(IPAddress.Any, DefaultPort);
            }

            m_AllClients = new Hashtable();
            m_ReceiveQueue = new Queue();

            this.m_Encoder = new Chunk.ChunkEncoder();
            this.m_ServerSender = new TCPServerSender(instructor);

            //Start bridging if config file says so
            #if RTP_BUILD
            m_U2MBridge = null;
            string enableBridge = System.Configuration.ConfigurationManager.AppSettings[this.GetType().ToString() + ".EnableBridge"];
            if (enableBridge != null) {
                bool enable = false;
                if (bool.TryParse(enableBridge, out enable) && enable) {
                    Trace.WriteLine("Unicast to Multicast Bridge enabled.", this.GetType().ToString());
                    m_U2MBridge = new UnicastToMulticastBridge(model);
                }
            }
            #endif
        }
예제 #15
0
 public TCPServer(PresenterModel model, ClassroomModel classroom, InstructorModel instructor)
     : this(null,model,classroom,instructor)
 {
 }
예제 #16
0
        private void StartServer(InstructorModel instructor)
        {
            if (m_Server != null) {
                Trace.WriteLine("Attempt to start a TCPServer when a server is already running.", this.GetType().ToString());
                return;

                //throw (new ApplicationException("Attempt to start a TCPServer when a server is already running."));
            }

            m_Server = new TCPServer(this.m_Model, this.m_Classroom, instructor);
            m_Sender = new TCPMessageSender(m_Server, this.m_Model, this.m_Classroom);
            m_Server.Start(m_Sender);
            m_Receiver = new TCPMessageReceiver(m_Server, this.m_Model, this.m_Classroom);
            using (Synchronizer.Lock(this.SyncRoot))
                this.SetPublishedProperty("ServerStarted", ref m_ServerStarted, true);
        }
예제 #17
0
        Hashtable m_SocketMap; //Key is Guid, value is Socket

        #endregion Fields

        #region Constructors

        public TCPServerSender(InstructorModel instructor)
        {
            m_MaxConcurrentSends = MAX_CONCURRENT_SENDS;
            this.RestoreConfig();

            //Register for events to track current slide
            m_Instructor = instructor;
            m_CurrentSlideID = GetSlideID(instructor); // Get initial slide if any
            m_Instructor.Changed["CurrentDeckTraversal"].Add(new PropertyEventHandler(OnCurrentDeckTraversalChanged));

            //Create the queue
            m_SendQueue = new TCPServerSendQueue();
            //Clients currently engaged in a send operation
            m_SendingParticipants = new Hashtable();
            //For synchronizing the closing of client sockets
            m_ClosingSockets = new Hashtable();
            //Current map of Client Guid to Socket
            m_SocketMap = new Hashtable();

            ///A thread to keep data flowing from the queue:
            Thread sendThread = new Thread(new ThreadStart(SendThread));
            sendThread.Name = "TCPServer Send Thread";
            sendThread.Start();
        }
예제 #18
0
        public TCPServer(IPEndPoint localEP, PresenterModel model, ClassroomModel classroom,
            InstructorModel instructor)
        {
            string portStr = System.Configuration.ConfigurationManager.AppSettings[this.GetType().ToString() + ".TCPListenPort"];
            int p;
            if (Int32.TryParse(portStr, out p)) {
                TCPListenPort = p;
            }
            RestoreConfig();
            m_ClientConnected = new ManualResetEvent(false);
            m_Participant = model.Participant;
            m_Classroom = classroom;
            m_ClientCount = 0;
            this.m_Network = model.Network;
            m_NetworkStatus = new NetworkStatus(ConnectionStatus.Disconnected, ConnectionProtocolType.TCP, TCPRole.Server, 0);
            this.m_Network.RegisterNetworkStatusProvider(this, true, m_NetworkStatus);

            if (localEP != null) {
                this.m_ListenEP = localEP;
            }
            else {
                IPAddress ip = IPAddress.Any;
                //Use IPv4 unless it is unavailable.  TODO: Maybe this should be a configurable parameter?
                if ((!Socket.OSSupportsIPv4) && (Socket.OSSupportsIPv6)) {
                    ip = IPAddress.IPv6Any;
                }
                this.m_ListenEP = new IPEndPoint(ip, TCPListenPort);
            }

            m_AllClients = new Hashtable();
            m_ReceiveQueue = new Queue();

            this.m_Encoder = new Chunk.ChunkEncoder();
            this.m_ServerSender = new TCPServerSender(instructor);

            //Start bridging if config file says so
            #if RTP_BUILD
            m_U2MBridge = null;
            string enableBridge = System.Configuration.ConfigurationManager.AppSettings[this.GetType().ToString() + ".EnableBridge"];
            if (enableBridge != null) {
                bool enable = false;
                if (bool.TryParse(enableBridge, out enable) && enable) {
                    Trace.WriteLine("Unicast to Multicast Bridge enabled.", this.GetType().ToString());
                    m_U2MBridge = new UnicastToMulticastBridge(model);
                }
            }
            #endif
        }