internal static string ToTextualConvention(Rtcp.GoodbyeReport bye) { string blockString = string.Empty; if (bye == null || bye.IsDisposed) return blockString; //if HasReasonForLeaving add if (bye.HasReasonForLeaving)//reason= blockString += string.Format(QuotedFormat, "reason", System.Text.Encoding.ASCII.GetString(bye.ReasonForLeaving.ToArray())); //Write each entry in bye.GetSourceList using (var sourceList = bye.GetSourceList()) { if (sourceList == null) blockString += "#Incomplete Source List Not Included" + (char)Common.ASCII.LineFeed; else foreach (uint partyId in sourceList)//ssrc= blockString += string.Format(HexFormat, "ssrc", HexSpecifier + partyId.ToString("X"), (char)Common.ASCII.LineFeed); } return blockString; }
/// <summary> /// Prepares the text in the stream which corresponds to the RtcpData of a Rtcp.RtcpPacket. /// </summary> /// <param name="format">The <see cref="FileFormat"/> to output.</param> /// <param name="packet">The <see cref="Rtcp.RtcpPacket"/> to describe</param> /// <returns>The text describes the packet if the <paramref name="format"/> is a text format, otherwise an empty string</returns> public static string ToTextualConvention(FileFormat format, Rtcp.RtcpPacket packet) { if (packet == null || packet.Payload.Count == 0 || format < FileFormat.Text || format == FileFormat.Short) return string.Empty; if(format == FileFormat.Unknown) return UnknownSpecifier; //Determine the format to use as well as the `Conventional Abbreviation` switch (packet.PayloadType) { case Rtcp.SourceDescriptionReport.PayloadType: //Use a SourceDescriptionReport to enumerate the SourceDescriptionChunk's and SourceDescriptionItem's contained in the packet. using (var sdes = new Rtcp.SourceDescriptionReport(packet, false)) //Don't dispose the packet when done. { return string.Format(RtcpExpressionFormat, "SDES", packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(), packet.BlockCount, packet.Header.LengthInWordsMinusOne, ToTextualConvention(sdes)); } case Rtcp.SendersReport.PayloadType: using (var sr = new Rtcp.SendersReport(packet, false)) { return string.Format(RtcpExpressionFormat, "SR", packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(), packet.BlockCount, packet.Header.LengthInWordsMinusOne, (ToTextualConvention(sr) + (char)Common.ASCII.Space + string.Format(RtcpSendersInformationFormat, //0 (DateTime.UtcNow - sr.NtpTime).TotalSeconds.ToString("0.000000"), //ts= //1 sr.NtpTimestamp, //ntp= //2 sr.SendersOctetCount, //osent= //3 sr.SendersPacketCount))); //psent= } case Rtcp.ReceiversReport.PayloadType: using (var rr = new Rtcp.ReceiversReport(packet, false)) { return string.Format(RtcpExpressionFormat, "RR", packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(), packet.BlockCount, packet.Header.LengthInWordsMinusOne, ToTextualConvention(rr)); } case Rtcp.GoodbyeReport.PayloadType: using (var bye = new Rtcp.GoodbyeReport(packet, false)) { return string.Format(RtcpExpressionFormat, "BYE", packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(), packet.BlockCount, packet.Header.LengthInWordsMinusOne, ToTextualConvention(bye)); } case Rtcp.ApplicationSpecificReport.PayloadType: return string.Format(RtcpExpressionFormat, "APP", packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(), packet.BlockCount, packet.Header.LengthInWordsMinusOne, string.Empty); default: //Unknown PayloadType use a Hex Representation of the PayloadType return string.Format(RtcpExpressionFormat, packet.PayloadType.ToString("X"), packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(), packet.BlockCount, packet.Header.LengthInWordsMinusOne, string.Empty); } }
/// <summary> /// Internal use only provides a `rtpsend` compatible text description of a <see cref="SourceDescriptionReport"/>. /// </summary> /// <param name="sdes">The <see cref="SourceDescriptionReport"/> to describe</param> /// <returns>The string</returns> internal static string ToTextualConvention(Rtcp.SourceDescriptionReport sdes) { if (sdes == null || sdes.IsDisposed) return string.Empty; StringBuilder blockStringBuilder = new StringBuilder(sdes.BlockCount * Rtcp.SourceDescriptionReport.SourceDescriptionItem.ItemHeaderSize); //The blockString is formatted per chunk of the sdes foreach (Media.Rtcp.SourceDescriptionReport.SourceDescriptionChunk chunk in sdes) { //A SDES packet description requires an item sub description in `QuotedFormat` StringBuilder itemStringBuilder = new StringBuilder(); //For each item in the chunk build up the item string foreach (Media.Rtcp.SourceDescriptionReport.SourceDescriptionItem item in chunk) { string typedName = Enum.GetName(typeof(Rtcp.SourceDescriptionReport.SourceDescriptionItem.SourceDescriptionItemType), item.ItemType); if (string.IsNullOrWhiteSpace(typedName)) typedName = Media.Common.Extensions.String.StringExtensions.UnknownString; itemStringBuilder.AppendFormat(QuotedFormat, //0 typedName, //1 Encoding.ASCII.GetString(item.ItemData.ToArray())); } blockStringBuilder.Append((char)Common.ASCII.LineFeed); blockStringBuilder.AppendFormat(SourceDescriptionChunkFormat, chunk.ChunkIdentifer, itemStringBuilder.ToString()); } return blockStringBuilder.ToString(); }
public void SendReceiverReport(Rtcp.Stats stats) { // Make sure we have the necessary information to send the report if (this.ServerSsrc == 0 && stats.ServerSsrc == 0) throw new InvalidOperationException(); var report = new RtcpReceiverReport(); report.Header.ItemCount = 1; report.Ssrc = this.Ssrc; report.SsrcOnly = this.UseShortReportFormat; report.ReporteeSsrc = (this.ServerSsrc != 0 ? this.ServerSsrc : stats.ServerSsrc); report.CumulativeLoss = stats.ExpectedPacketCount - stats.ActualPacketCount; report.LossFraction = (byte)((256 * report.CumulativeLoss) / stats.ExpectedPacketCount); report.ExtendedHighestSequenceNumber = stats.HighestSequenceNumber; report.InterarrivalJitter = stats.Jitter; report.LastSenderReportTimestamp = (uint)this.LastSenderReport.ToFileTimeUtc(); report.LastSenderReportDelay = (uint)(DateTime.UtcNow.ToFileTimeUtc() - this.LastSenderReport.ToFileTimeUtc()); this.SendPacket(report); }