/// <summary> /// An SdesPacket can contain multiple Sdes reports (ssrc, SdesData) which we process here /// /// Due to our architecture with 1 RtpSession / RtpParticipant and multiple RtpSenders / /// RtpStreams (each of which get their own ssrc and SdesData) it is difficult to properly /// map the SdesData to the participant, because they all share the same CName. /// /// The participant properties will have a CName, Name, Email, Phone, etc plus any private /// extensions for the participant. In order to conserve Rtcp bandwidth, the streams will /// only send out CName, Name and any private extensions for the stream. And the stream's /// Name may be completely different from the participant's name. /// /// The problem is that we don't want the participant to be updated from the stream's /// properties due to sharing a CName. So we use the private extension "Source" to /// distinguish between a participant's SdesData and a Stream's SdesData /// /// The last complication is that AccessGrid doesn't have this private extension, probably /// because they have a 1:1 mapping between a sender and receiver. In order to not break /// interop, we allow for the case of the private extension not being there, in which case /// the participant data will be updated from any and all SdesData that share that CName /// </summary> /// <param name="packet">Rtcp packet to process</param> /// <param name="ipAddress">Originating IP address of the packet</param> private void ProcessSDESPacket(SdesPacket packet, IPAddress ipAddress) { foreach(SdesReport report in packet.Reports()) { uint ssrc = report.ssrc; SdesData sdes = report.sdes; // Check for SSRC conflict AddSsrcToIp(ssrc, ipAddress); // Find out what source generated this data string role = sdes.GetPrivateExtension(Rtcp.PEP_SOURCE); if(role != null) { // Update the participant's properties if(role == Rtcp.PED_PARTICIPANT) { AddOrUpdateParticipant(ssrc, sdes, ipAddress); } else if(role == Rtcp.PED_STREAM) { if(RtpTraffic) { AddOrUpdateStream(ssrc, ipAddress.ToString(), sdes); } } else { Debug.Assert(false); throw new ArgumentException("Unsupported role: " + role); } } else // Doesn't have CXP specific extensions { // This code is not currently guaranteed to work // Debug.Assert(false); //AddOrUpdateParticipant(ssrc, sdes, ipAddress); //UpdateStream(ssrc, sdes); AddOrUpdateStream2(ssrc, ipAddress.ToString(), sdes); } } }
private void AddSdesReports(CompoundPacket cp) { while(!cpComplete && sdesReports.Count > 0) { bool sdespComplete = false; bool addedReport = false; SdesPacket sdesp = new SdesPacket(); if(space >= sdesp.Size) { space -= sdesp.Size; while(sdesReports.Count > 0) { SdesReport report = (SdesReport)sdesReports.Peek(); if( space >= report.Size ) { try { sdesp.AddReport(report); sdesReports.Pop(); space -= report.Size; addedReport = true; } catch(RtcpPacket.InsufficientItemSpaceException) { // No more room in rrp for reports sdespComplete = true; break; } } else { break; // while loop } } } // We broke out of the loop for one of 3 reasons // 1. There were no more sdesReports // 2. There was no more room in sdesp // 3. There was no more room in cp (cpComplete) // If we added a report to sdesp, add sdesp to cp if(addedReport) { int start = cp.Buffer.Length; cp.AddPacket(sdesp); int end = cp.Buffer.Length; Debug.Assert( (end-start) == sdesp.Size ); // math check } // Figure out if we exited because cp is complete if(sdesReports.Count > 0 && sdespComplete == false) { cpComplete = true; } } }