示例#1
0
 public void Send(RtpNackMessage message)
 {
     using (MemoryStream ms = new MemoryStream()) {
         this.m_bf.Serialize(ms, message);
         this.m_Sender.Send(new BufferChunk(ms.GetBuffer(), 0, (int)ms.Length));
     }
 }
示例#2
0
 /// <summary>
 /// This method is intended to be called only by <see cref="RTPMessageReceiver.HandleAssemblerNack"/>.
 /// Serialize the NACK packet (as a single chunk), and
 /// broadcast it <i>immediately</i> (preempting all other prioritized
 /// chunks in the queue, except a chunk which is currently being sent).
 /// </summary>
 /// <param name="nack">The NACK packet to send</param>
 public void SendNack(RtpNackMessage nack)
 {
     using (Synchronizer.Lock(this)) {
         if (this.m_SsrcToSenderId.ContainsKey(nack.SenderSSRC))
         {
             //Debug.WriteLine(string.Format("NACKing frames {0}", nack.MissingSequences.ToString()), this.GetType().ToString());
             SendObject(new CapabilityMessageWrapper(nack, m_LocalId, this.m_SsrcToSenderId[nack.SenderSSRC], m_Capability.IsSender));
         }
         else
         {
             Trace.WriteLine("!!!!!Warning: Failed to find sender SSRC in lookup table while trying to send NACK");
         }
     }
 }
示例#3
0
        /// <summary>
        /// This method is intended to be called only by <see cref="RTPMessageReceiver.HandleFrameReceived"/>.
        /// If the NACK is addressed to this sender, the requested
        /// frames are retrieved from our buffer and resent, if available.  Otherwise,
        /// the <see cref="RTPNackManager"/> is notified so we don't send duplicate NACKs
        /// to the addressee.
        /// </summary>
        /// <remarks>
        /// The frames are enqueued with <see cref="MessagePriority.RealTime"/>real-time priority</see>.
        /// The rationale behind this is that, even if a frame was originally low-priority, the clients
        /// have already waited "long enough".  Also, a replacement frame shouldn't
        /// be subject to NACKing.
        /// </remarks>
        /// <param name="nack">The received/deserialized NACK message</param>
        internal void ProcessNack(RtpNackMessage nack, Guid intendedNackRecipientId)
        {
            // If the NACK was not meant for us, send it to the NackManager so
            // we can avoid duplicating it.
            if (!this.m_LocalId.Equals(intendedNackRecipientId))
            {
                this.m_NackManager.Delay(nack.SenderSSRC, nack.MissingSequences);
            }
            else
            {
                // Otherwise send all frames which are not already queued and
                // which are still available in the frame buffer.
                //Debug.WriteLine(string.Format("Received NACK requesting frames {0}",
                //    nack.MissingSequences.ToString()), this.GetType().ToString());

                foreach (ulong missing in nack.MissingSequences)
                {
                    Chunk chunk;
                    if (this.m_FrameBuffer.Take(missing, out chunk))
                    {
                        if (chunk != null)
                        {
                            //Debug.WriteLine(string.Format("Queueing REPLACEMENT for frame #{0} ({1} bytes, message #{2}, chunk #{3} of {4})",
                            //    chunk.FrameSequence,
                            //    chunk.Data.Length,
                            //    chunk.MessageSequence,
                            //    chunk.ChunkSequenceInMessage + 1,
                            //    chunk.NumberOfChunksInMessage),
                            //    this.GetType().ToString());

                            this.Post(delegate() {
                                this.CapabilitySend(chunk, MessagePriority.RealTime);
                            }, MessagePriority.RealTime);
                        }
                        else
                        {
                            //Debug.WriteLine(string.Format("NOT queueing replacement for frame #{0} (already in queue or missing)",
                            //    missing), this.GetType().ToString());
                        }
                    }
                    else
                    {
                        //Debug.WriteLine(string.Format("Frame #{0} not in buffer; giving up",
                        //    missing), this.GetType().ToString());
                    }
                }
            }
        }
示例#4
0
 public void Send(RtpNackMessage message)
 {
     this.Post(this.m_SendNACKDelegate, new object[] { message });
 }
        /// <summary>
        /// Processes a message received over a Capability channel
        /// </summary>
        public void Receive(object message)
        {
            // If the message is a chunk, 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.
            object unwrappedMessage = null;

            if (message is CapabilityMessageWrapper)
            {
                unwrappedMessage = ((CapabilityMessageWrapper)message).Message;
                if (unwrappedMessage is Chunk)
                {
                    Chunk chunked = (Chunk)unwrappedMessage;
                    // 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_RemoteSSRC, 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_RemoteSSRC,
                                                          new Range(ulong.MinValue, chunked.OldestRecoverableFrame - 1));
                    }

                    message = this.m_Assembler.Add(chunked);
                }
                else if (unwrappedMessage 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)unwrappedMessage);
                    Guid           destinationId = ((CapabilityMessageWrapper)message).RecipientId;
                    this.m_Sender.ProcessNack(nack, destinationId);
                    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: type {0}",
                                                      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());
            }
        }
示例#6
0
 public NetworkNACKMessageEvent(RtpNackMessage msg, long timeIndex, string source) : base(timeIndex, source)
 {
     this.message = msg;
 }