Esempio n. 1
0
        /// <summary>
        /// setup the initial buffers and write the basic stream data to the db
        /// </summary>
        /// <param name="participant">for this participant</param>
        /// <param name="stream">using this rtp stream</param>
        public StreamRecorder( int participantID, RtpStream stream, ConferenceRecorderPC conferencePerfCounter )
        {
            this.rtpStream = stream;
            this.perfCounter = conferencePerfCounter;
            this.partID = participantID;

            // We do *not* re-use existing streams if a stream goes away and comes back.  This decision was made
            //  becuase it causes the client not to see the Rtcp data die & come back during playback, though it
            //  did during recording.  This inconsistency was viewed to cause problems, and was removed.
            InitStream();

            buffers = new BufferRecorder[Constants.MaxBuffers];
            bufferCount = Constants.InitialBuffers;

            for ( int i = 0; i < bufferCount; i++)
            {
                buffers[i] = new BufferRecorder( i, streamID );
                buffers[i].Overflowed += new EventHandler(this.OnOverflowException);

                perfCounter.AddInstanceForCollection(buffers[i]);
            }

            curBufIndex = 0;
            currentBuffer = buffers[curBufIndex];

            rtpStream.FrameReceived += new MSR.LST.Net.Rtp.RtpStream.FrameReceivedEventHandler(FrameReceived);
        }
Esempio n. 2
0
        void OnStreamRemoved(MSR.LST.Net.Rtp.RtpStream rtpStream)
        {
            //Debug.WriteLine("OnStreamRemoved ssrc=" + rtpStream.SSRC.ToString() + ";cname=" + rtpStream.Properties.CName);
            // Do not check (or care) whether the RTPMessageSender has been disposed,
            // because we will get lots of RtpStreamRemoved events when the RtpSession is closed.

            // Unregister the ParticipantModel and remove it from the classroom.
            string cname = rtpStream.Properties.CName;

            if (this.m_Participants.ContainsKey(cname))
            {
                using (Synchronizer.Lock(this.m_Classroom.SyncRoot)) {
                    if (this.m_Classroom.Participants.Contains(m_Participants[cname]))
                    {
                        this.m_Classroom.Participants.Remove(m_Participants[cname]);
                    }
                }
                this.m_Participants.Remove(cname);
            }

            //If the stream being removed is our currently associated instructor:
            if (cname.Equals(m_AssociationCname))
            {
                using (Synchronizer.Lock(this.m_Model.Network.SyncRoot)) {
                    this.m_Model.Network.Association = null;
                }
                m_AssociationCname = null;
            }

            if (this.m_Receivers.ContainsKey(cname))
            {
                uint remoteSsrc = this.m_Receivers[cname].RemoteSsrc;
                if (this.m_SsrcToSenderId.ContainsKey(remoteSsrc))
                {
                    this.m_SsrcToSenderId.Remove(remoteSsrc);
                }
                else
                {
                    Trace.WriteLine("!!!!Warning: Failed to find SSRC in lookup table when removing stream.");
                }

                // Discard all pending Nacks so the NackManager doesn't keep nacking them forever.
                this.NackManager.Discard(remoteSsrc, Range.UNIVERSE);

                //Clean up the receiver
                //Debug.WriteLine("Removed receiver cname: " + cname + "; receiver SSRC: " + remoteSsrc.ToString());
                this.m_Receivers[cname].Dispose();
                this.m_Receivers.Remove(cname);
            }
            else
            {
                //Debug.WriteLine("Removed a stream for which we have no capability receiver cname: " + cname);
            }
        }
Esempio n. 3
0
 public static Guid IDFromRtpStream(RtpStream rtpStream)
 {
     string id = rtpStream.Properties.GetPrivateExtension(PEP_IDENTIFIER);
     if(id != null)
     {
         return new Guid(id);
     }
     else
     {
         throw new InvalidOperationException(Strings.StreamLacksACapabilityidentifier);
     }
 }
Esempio n. 4
0
 void OnStreamAdded(MSR.LST.Net.Rtp.RtpStream rtpStream)
 {
     //Debug.WriteLine("OnStreamAdded ssrc=" + rtpStream.SSRC.ToString() + ";cname=" + rtpStream.Properties.CName);
     using (Synchronizer.Lock(this.m_Classroom.SyncRoot)) {
         if (rtpStream.SSRC != this.m_Capability.RtpSender.SSRC)
         {
             //We need the participant Guid before we can set up the participant model.  Do that on receipt of the first message from a given remote node.
             //Debug.WriteLine("Adding stream ssrc: " + rtpStream.SSRC.ToString());
         }
         else
         {
             //Debug.WriteLine("Ignoring RTP Stream Add because the stream SSRC matches the RTPSender SSRC");
         }
     }
 }
        public RTPMessageReceiver(RTPMessageSender sender, RtpStream stream, PresenterModel model, ClassroomModel classroom, ParticipantModel participant)
        {
            this.m_Model = model;
            this.m_Sender = sender;
            this.m_RtpStream = stream;

            this.m_Context = new ReceiveContext(model, classroom, participant);
            this.m_ContextArgs = new object[] { this.m_Context };
            this.m_Queue = new MessageProcessingQueue(this);

            this.m_Serializer = new BinaryFormatter();

            this.m_Assembler = new ChunkAssembler();
            this.m_Assembler.Nack += new ChunkAssembler.NackDelegate(this.HandleAssemblerNack);

            this.m_RtpStream.FrameReceived += new RtpStream.FrameReceivedEventHandler(this.HandleFrameReceived);
        }
Esempio n. 6
0
        static void stream_FrameReceived(object sender, RtpStream.FrameReceivedEventArgs ea)
        {
            Console.Out.WriteLine("Frame received of length: " + ea.Frame.Length);

            byte[] hash = MD5.Create().ComputeHash(ea.Frame.Buffer, ea.Frame.Index, ea.Frame.Length);

            // compare arrays:
            for (int i = 0; i < oracleHash.Length; i++)
            {
                if (oracleHash[i] != hash[i])
                {
                    Console.Out.WriteLine("Hash values not equal!");
                    return;
                }
            }
            Console.Out.WriteLine("Hash value is good!");
        }
Esempio n. 7
0
 public static CapabilityType ChannelFromRtpStream(RtpStream rtpStream)
 {
     string chan = rtpStream.Properties.GetPrivateExtension(PEP_CHANNEL);
     if(chan != null)
     {
         if (Boolean.Parse(chan))
         {
             return CapabilityType.Channel;
         }
         else
         {
             return CapabilityType.Owned;
         }
     }
     else
     {
         return CapabilityType.Unknown;
     }
 }
Esempio n. 8
0
        public static DynamicProperties DynaPropsFromRtpStream(RtpStream rtpStream)
        {
            DynamicProperties dynaProps = new DynamicProperties();

            dynaProps.ID = IDFromRtpStream(rtpStream);
            dynaProps.Name = rtpStream.Properties.Name;
            dynaProps.SharedFormID = SharedFormIDFromRtpStream(rtpStream);

            // Establish the channelness or ownership of this capability
            CapabilityType streamType = ChannelFromRtpStream(rtpStream);
            // by default, capabilities are owned (i.e. the "unknown" streams are considered owned)
            dynaProps.Channel = (streamType == CapabilityType.Channel);
            if (streamType == CapabilityType.Owned) // the stream is being sent by the owner
            {
                dynaProps.OwnerName = rtpStream.Properties.CName;
            }

            return dynaProps;
        }
Esempio n. 9
0
 public FrameReceivedEventArgs(RtpStream rtpStream, BufferChunk frame)
 {
     RtpStream = rtpStream;
     Frame = frame;
 }
Esempio n. 10
0
 public IPStreamPair(IPAddress ip, RtpStream rtp)
 { senderIP = ip; stream = rtp; }
Esempio n. 11
0
        public void StopListening()
        {
            if( rtpStream != null )
            {
                rtpStream.FrameReceived -= new RtpStream.FrameReceivedEventHandler(FrameReceived);
                this.rtpStream = null;
            }

            int curIndex = curBufIndex;

            if( buffers != null )
            {
                do
                {
                    BufferRecorder buf = buffers[curBufIndex];
                    perfCounter.RemoveInstanceForCollection(buf);
                    buf.Dispose();

                    curBufIndex = (curBufIndex + 1) % bufferCount;
                }
                while ( curBufIndex != curIndex);

                this.buffers = null;
            }
        }
Esempio n. 12
0
 private void ValidateStream(RtpStream rtpStream)
 {
     // Make sure that the capability properties of the streams agree
     if((ChannelFromRtpStream(rtpStream) == CapabilityType.Channel) != Channel ||
         IDFromRtpStream(rtpStream) != ID  ||
         SharedFormIDFromRtpStream(rtpStream) != SharedFormID)
     {
         throw new ArgumentException("Stream to add does not match the settings for this capability.");
     }
 }
Esempio n. 13
0
        /// <summary>
        /// DistributePackets is responsible for receiving all incoming packets on the Rtp Listener,
        /// casting them into RtpPackets, creating new RtpStreams if one doesn't exist for the RtpPacket's SSRC,
        /// then calling RtpStream.newPacket(rtpPacket) to place the RtpPacket into the RtpStream's Queue for processing.
        /// </summary>
        private void DistributePackets()
        {
            while (newPacket.WaitOne())
            {
                while (receivedPackets.Count > 0)
                {
                    object[] ao = (object[])receivedPackets.Dequeue();

                    BufferChunk bc = (BufferChunk)ao[0];
                    IPEndPoint  ep = (IPEndPoint)ao[1];

                    try
                    {
                        //Turn the raw UDP packet data into an Rtp packet
                        RtpPacketBase packet = new RtpPacketBase(bc);

                        // For now, we support 2 types of packets - RtpPacket and RtpPacketFec.  If
                        // the number of packet types grows, we may need to push the casting onto
                        // the streams, since they know what type of packets they expect.  For now
                        // we will handle the casting here. JVE 6/17/2004
                        if (packet.PayloadType == PayloadType.FEC)
                        {
                            packet = new RtpPacketFec(packet);
                        }
                        else
                        {
                            packet = new RtpPacket(packet);
                        }


                        #region Fault Injection
                        #if FaultInjection
                        if (rtpSession.DropPacketsPercent > 0)
                        {
                            if (rtpSession.Rnd.Next(1, 100) <= rtpSession.DropPacketsPercent)
                            {
                                if (packet.PayloadType == PayloadType.FEC)
                                {
                                    RtpPacketFec fecPacket = (RtpPacketFec)packet;

                                    string msg = string.Format(CultureInfo.CurrentCulture,
                                                               "Dropping fec packet: {0}, FecIndex: {1}, DataRangeMin: {2}",
                                                               fecPacket.Sequence, fecPacket.FecIndex, fecPacket.DataRangeMin);

                                    Trace.WriteLine(msg);

                                    pcDroppedFecPackets++;
                                    pcDroppedFecBytes += packet.PayloadSize;
                                }
                                else
                                {
                                    RtpPacket dataPacket = (RtpPacket)packet;

                                    string msg = string.Format(CultureInfo.CurrentCulture,
                                                               "Dropping data packet: {0}, FecIndex: {1}, FrameIndex: {2}, TS: {3}",
                                                               dataPacket.Sequence, dataPacket.FecIndex, dataPacket.FrameIndex, dataPacket.TimeStamp);

                                    Trace.WriteLine(msg);

                                    pcDroppedDataPackets++;
                                    pcDroppedDataBytes += packet.PayloadSize;
                                }

                                ReturnBuffer(bc);
                                continue;
                            }
                        }
#endif
                        #endregion Fault Injection

                        // Get the stream if it exists
                        RtpStream stream = rtpSession.GetStream(packet.SSRC, ep.Address);

                        if (stream != null)
                        {
                            stream.ProcessPacket(packet);
                        }
                        else
                        {
                            // Otherwise return the packet to the pool
                            ReturnBuffer(bc);
                            unchecked { pcStreamlessPackets++; }
                        }
                    }
                    catch (ThreadAbortException) {}
                    catch (InvalidRtpPacketException e)
                    {
                        HandleInvalidPacket(bc, ep, e.ToString());
                        ReturnBuffer(bc);
                    }
                    catch (PoolExhaustedException e)
                    {
                        LogEvent(e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.UnboundedGrowth);
                        return; // Exit the thread gracefully
                    }
                    catch (Exception e)
                    {
                        ReturnBuffer(bc);
                        LogEvent(e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.Error);
                    }
                }
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Overridden because we don't want to hook the frame received event
        /// </summary>
        /// <param name="rtpStream"></param>
        public override void StreamAdded(RtpStream rtpStream)
        {
            if(this.rtpStream != null)
            {
                this.rtpStream.DataStarted -= new MSR.LST.Net.Rtp.RtpStream.DataStartedEventHandler(rtpStream_DataStarted);
                this.rtpStream.DataStopped -= new MSR.LST.Net.Rtp.RtpStream.DataStoppedEventHandler(rtpStream_DataStopped);
            }

            lock(this)
            {
                this.rtpStream = rtpStream;
                this.rtpStreams.Add(rtpStream);
            }

            rtpStream.IsUsingNextFrame = true;

            // We only need to hook these events if we are remote players, not senders
            if(!IsSender)
            {
                rtpStream.DataStarted += new MSR.LST.Net.Rtp.RtpStream.DataStartedEventHandler(rtpStream_DataStarted);
                rtpStream.DataStopped += new MSR.LST.Net.Rtp.RtpStream.DataStoppedEventHandler(rtpStream_DataStopped);
            }
        }
        // CF1
        private void LeaveRtpSession()
        {
            UnhookRtpEvents();

            if(rtpSession != null)
            {
                rtpSession.Dispose();
                rtpSession = null;
                rtpSender = null;
                rtpStream = null;
            }
        }
Esempio n. 16
0
 public IPStreamPair(IPAddress ip, RtpStream rtp)
 { senderIP = ip; stream = rtp; }
Esempio n. 17
0
        public virtual void StreamRemoved(RtpStream rtpStream)
        {
            lock(this)
            {
                if(isPlaying)
                {
                    rtpStream.FrameReceived -= new RtpStream.FrameReceivedEventHandler(frameReceived);
                }

                rtpStreams.Remove(rtpStream);
            }

            // We keep playing regardless of who leaves if it's a capability channel.  
            //    If it's not a channel, then close it if the owner leaves
            // (pfb, 21-Sep-04) Removing code here because Conference checks for no streams left.
        }
Esempio n. 18
0
        public virtual void StreamAdded(RtpStream rtpStream)
        {
            ValidateStream(rtpStream);

            lock(this)
            {
                if (isPlaying)
                {
                    rtpStream.FrameReceived += new RtpStream.FrameReceivedEventHandler(frameReceived);
                }

                rtpStreams.Add(rtpStream);
            }
        }
Esempio n. 19
0
 private void ValidateStream(RtpStream rtpStream)
 {
     // Make sure that the capability properties of the streams agree
     if((ChannelFromRtpStream(rtpStream) == CapabilityType.Channel) != Channel ||
         IDFromRtpStream(rtpStream) != ID  ||
         SharedFormIDFromRtpStream(rtpStream) != SharedFormID)
     {
         throw new ArgumentException(Strings.StreamDoesNotMatchSettings);
     }
 }
Esempio n. 20
0
        private void frameReceived(object sender, RtpStream.FrameReceivedEventArgs frea)
        {
            MemoryStream ms = new System.IO.MemoryStream((byte[])frea.Frame);
            object o = bf.Deserialize(ms);

            Participant participant = (Participant)Conference.participants[frea.RtpStream.Properties.CName];

            Conference.FormInvoke(ObjectReceived, new object[] { this, new ObjectReceivedEventArgs(participant, o) } );
        }
Esempio n. 21
0
        /// <summary>
        /// Processes a message received over the RTP network interface.
        /// </summary>
        private void HandleFrameReceived(object sender, RtpStream.FrameReceivedEventArgs args)
        {
            Debug.Assert(args.RtpStream == this.m_RtpStream);

            BufferChunk chunk = args.Frame;

            try {
                // Attempt to deserialize the contents of the frame.
                using (MemoryStream stream = new MemoryStream(chunk.Buffer, chunk.Index, chunk.Length)) {
                    object message = this.m_Serializer.Deserialize(stream);

                    // If the message is a chunked, process it with the Chunk Assembler.
                    // (Messages don't have to be chunked, in which case they are processed
                    // immediately below).  If the chunk is the last remaining chunk composing
                    // a message, then the Assembler returns the completed message.
                    if (message is Chunk) {
                        Chunk chunked = ((Chunk)message);
                        // Ensure that no more NACKs are sent for this chunk, if it was recovered.
                        if (chunked.FrameSequence > ulong.MinValue)
                            this.m_Sender.NackManager.Discard(this.m_RtpStream.SSRC, chunked.FrameSequence);

                        // Ensure that no futile NACKs are sent for unrecoverable chunks.
                        if (chunked.OldestRecoverableFrame - 1 > ulong.MinValue)
                            this.m_Sender.NackManager.Discard(this.m_RtpStream.SSRC,
                                new Range(ulong.MinValue, chunked.OldestRecoverableFrame - 1));

                        message = this.m_Assembler.Add(chunked);

                    } else if (message is RtpNackMessage) {
                        // Otherwise, if the message is a NACK, delegate it to the RTP sender,
                        // which attempts to resend chunks from its buffer.
                        RtpNackMessage nack = ((RtpNackMessage)message);
                        this.m_Sender.ProcessNack(nack);
                        return;
                    }

                    // If we have a valid/complete message, queue it for processing on the separate
                    // message execution thread.
                    if (message is IEnumerable<object>) {
                        foreach (object decoded in (IEnumerable<object>)message) {
                            if (decoded is Message) {
                                // NOTE: Added by CMPRINCE for testing network performance
                                // Save this message
                                this.m_Model.ViewerState.Diagnostic.LogMessageRecv((Message)decoded);

                                Debug.WriteLine(string.Format("Received message: {0} bytes, type {1}",
                                    chunk.Length, decoded.GetType()), this.GetType().ToString());
                                Debug.Indent();
                                try {
                                    this.m_Queue.ProcessMessage((Message)decoded);
                                } finally {
                                    Debug.Unindent();
                                }
                            } else {
                                Trace.WriteLine("Received invalid message: " + decoded != null ? decoded.GetType().ToString() : null,
                                    this.GetType().ToString());
                            }
                        }
                    } else if (message != null) {
                        Trace.WriteLine("Received invalid message: " + message.GetType().ToString(),
                            this.GetType().ToString());
                    }
                }
            }

            catch(Exception e) {
                // The application should not crash on account of malformed messages sent from remote clients.
                // Therefore, we catch all exceptions.  We only want to print an error message.
                Trace.WriteLine("Error deserializing a message: " + e.ToString() + "\r\n" + e.StackTrace, this.GetType().ToString());
            }
        }
Esempio n. 22
0
        internal void RaiseRtpStreamTimeoutEvent(RtpStream stream)
        {
            rtpStreamTimeoutEvents++;

            object[] args = {this, new RtpEvents.RtpStreamEventArgs(stream)};
            EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaiseRtpStreamTimeoutEvent), args);
        }
Esempio n. 23
0
 public void Add(uint ssrc, RtpStream rtpStream)
 {
     Dictionary.Add(ssrc, rtpStream);
 }
Esempio n. 24
0
 public InvalidPacketInFrameEventArgs(RtpStream rtpStream, string reason)
 {
     RtpStream = rtpStream;
     Reason = reason;
 }
 // CF1, CF3
 private void RtpStreamAdded(object sender, RtpEvents.RtpStreamEventArgs ea)
 {
     rtpStream = ea.RtpStream;
 }
Esempio n. 26
0
 public RtpStreamEventArgs(RtpStream rtpStream)
 {
     RtpStream = rtpStream;
 }
Esempio n. 27
0
 public void Add(uint ssrc, RtpStream rtpStream)
 {
     Dictionary.Add(ssrc, rtpStream);
 }
Esempio n. 28
0
 public static Guid IDFromRtpStream(RtpStream rtpStream)
 {
     string id = rtpStream.Properties.GetPrivateExtension(PEP_IDENTIFIER);
     if(id != null)
     {
         return new Guid(id);
     }
     else
     {
         throw new InvalidOperationException("Stream lacks a CapabilityIdentifier in the external private extensions.  \n"
             + "Streams without this are not supported by the ConferenceXP API.");
     }
 }
Esempio n. 29
0
 public bool ContainsStream(RtpStream stream)
 {
     return (streamsAndIPs.GetStream(stream.SSRC) != null);
 }
Esempio n. 30
0
 public static Guid SharedFormIDFromRtpStream(RtpStream rtpStream)
 {
     string sfid = rtpStream.Properties.GetPrivateExtension(PEP_SHAREDFORM);
     if(sfid != null)
     {
         return new Guid(sfid);
     }
     else
     {
         return Guid.Empty;
     }
 }
Esempio n. 31
0
 public FrameOutOfSequenceEventArgs(RtpStream rtpStream, int lostFrames, string message)
 {
     RtpStream = rtpStream;
     LostFrames = lostFrames;
     Message = message;
 }
Esempio n. 32
0
 private void FrameReceived(object sender, RtpStream.FrameReceivedEventArgs ea)
 {
     ShowMessage(string.Format(CultureInfo.CurrentCulture, "{0}: {1}", ea.RtpStream.Properties.Name, 
         (string)ea.Frame));
 }
Esempio n. 33
0
 public PacketOutOfSequenceEventArgs ( RtpStream rtpStream, int lostPackets, string message )
 {
     RtpStream = rtpStream;
     LostPackets = lostPackets;
     Message = message;
 }
Esempio n. 34
0
        private void FrameReceived(object sender, RtpStream.FrameReceivedEventArgs frea)
        {
            FrameWithTicks frame = new FrameWithTicks(frea.Frame);

            /* A number of considerations caused this design...
             * 
             * Due to wanting the most accurate timestamp possible, the frame is stamped with the time
             * (by putting it in the FrameWithTicks structure), and then the ProcessFrame method is
             * called from the ThreadPool.
             * 
             * However, this caused problems because processing the frames and saving them to disk were
             * contending for time on the threadpool.  Due to the nature of the design of Archiver, it's
             * important that the frames are processed with higher priority than saving them to disk
             * (this minimizes the overhead of exceptions (cpu utilization) during high-stress periods,
             * causing the frames to be lost with the least amount of hiccups on the server.
             * 
             * So here we choose to process the frame on this thread only if we know that it won't get
             * immediate attention on the threadpool.
             */

            int workerThreads, ioThreads;
            ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads);

            if( workerThreads > 0 )
            {
                ThreadPool.QueueUserWorkItem( new WaitCallback(ProcessFrame), frame );
            }
            else
            {
                Trace.WriteLine("No threads available.  Processing frame on EventThrower thread.");
                ProcessFrame(frame);
            }
        }
Esempio n. 35
0
 public static void FrameIncomplete(RtpStream rtpStream, int framesLost)
 {
     // Event logging and perf counting are done in called method
     rtpStream.RaiseFrameOutOfSequenceEvent(framesLost, Strings.IncompleteFrameReceived);
 }
Esempio n. 36
0
 public static void FrameIncomplete(RtpStream rtpStream, int framesLost)
 {
     // Event logging and perf counting are done in called method
     rtpStream.RaiseFrameOutOfSequenceEvent(framesLost, "Incomplete Frame Received -- Frame Lost");
 }