/// <summary> /// This method is called to update the local data from another SdesData /// </summary> /// <param name="data">what we want to update our data to</param> /// <returns>true if the local data was updated, otherwise false</returns> internal bool UpdateData(SdesData sdes) { bool ret = false; // Well-known properties // CName can never be updated, so start with Name for (int id = (int)Rtcp.SDESType.NAME; id <= (int)Rtcp.SDESType.NOTE; id++) { if (!BufferChunk.Compare(data[id], sdes.data[id])) { data[id] = BufferChunk.Copy(sdes.data[id]); ret = true; } } // Write private properties foreach (DictionaryEntry de in sdes.privs) { byte[] key = (byte[])de.Key; byte[] data = (byte[])de.Value; if (!privs.Contains(key) || !BufferChunk.Compare(data, privs[key])) { privs[BufferChunk.Copy(key)] = BufferChunk.Copy(data); ret = true; } } return(ret); }
internal static RtpStream CreateStream(RtpListener rtpListener, uint ssrc, string ipaddress, SdesData sdes) { string sPT = sdes.GetPrivateExtension(Rtcp.PEP_PAYLOADTYPE); PayloadType pt = (PayloadType)Enum.Parse(typeof(PayloadType), sPT); // RtpStreamFec string fecData = sdes.GetPrivateExtension(Rtcp.PEP_FEC); if(fecData != null) { string[] args = fecData.Split(new char[]{':'}); ushort dataPxExp = ushort.Parse(args[0]); ushort fecPxExp = ushort.Parse(args[1]); if(fecPxExp == 0) { throw new ArgumentOutOfRangeException("fecPxExp", fecPxExp, "Must be >= 1"); } // Frame based Fec if(dataPxExp == 0) { return new RtpStreamFFec(rtpListener, ssrc, ipaddress, sdes, pt, fecPxExp); } else // Constant Fec { return new RtpStreamCFec(rtpListener, ssrc, ipaddress, sdes, pt, dataPxExp, fecPxExp); } } // RtpStream return new RtpStream(rtpListener, ssrc, ipaddress,sdes, pt); }
internal static RtpStream CreateStream2(RtpListener rtpListener, uint ssrc, string ipaddress, SdesData sdes) { string sPT = sdes.GetPrivateExtension(Rtcp.PEP_PAYLOADTYPE); PayloadType pt = PayloadType.JPEG; // RtpStream return new RtpStream(rtpListener, ssrc, ipaddress, sdes, pt); }
/// <summary> /// Raises the ParticipantStatusChanged event if the data changed /// </summary> /// <param name="data"></param> internal new void UpdateData(SdesData data) { if (base.UpdateData(data)) { object[] args = { this, new RtpEvents.RtpParticipantEventArgs(this) }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaiseRtpParticipantDataChangedEvent), args); } }
internal RtpStreamCFec(RtpListener rtpListener, uint ssrc, string ipaddress, SdesData sdes, PayloadType pt, ushort dataPxExp, ushort fecPxExp) : base(rtpListener, ssrc, ipaddress, sdes, pt) { pcFecType = 1; this.dataPxExp = dataPxExp; this.fecPxExp = fecPxExp; SetDecoder(); InitializeDCRStorage(); }
internal RtpStream(RtpListener rtpListener, uint ssrc, string ipaddress, SdesData sdes, PayloadType pt) { Debug.Assert(rtpListener != null); Debug.Assert(ssrc != 0); Debug.Assert(sdes != null); Debug.Assert(ipaddress != null); this.returnBufferHandler = rtpListener.ReturnBufferCallback; this.ssrc = ssrc; this.pt = pt; this.ipaddress = ipaddress; properties = new SdesData(sdes); InitializePerformanceCounters(); }
internal RtpSender(IRtpSession rtpSession, string name, PayloadType payloadType, Hashtable priExns, Hashtable paraPay) { if (Thread.CurrentThread.Name == null) { Thread.CurrentThread.Name = "RtpSender - " + name; } this.rtpSession = rtpSession; this.payloadType = payloadType; this.payloadPara = paraPay; // Leave everything but CName and Name blank in order to reduce Rtcp bandwidth sdes = new SdesData(rtpSession.Sdes.CName, name); // Add private extensions sdes.SetPrivateExtension(Rtcp.PEP_SOURCE, Rtcp.PED_STREAM); sdes.SetPrivateExtension(Rtcp.PEP_PAYLOADTYPE, ((int)payloadType).ToString()); InitializeNetwork(); InitializeFrame(); InitializePerformanceCounters(); // This needs to be called after InitializeNetwork if (priExns != null) { foreach (DictionaryEntry de in priExns) { sdes.SetPrivateExtension((string)de.Key, (string)de.Value); } string dbpString = (string)priExns[Rtcp.PEP_DBP]; if (dbpString != null) { DelayBetweenPackets = short.Parse(dbpString); } } ResetState(); }
/// <summary> /// Constructs an SdesData instance by reading its properties from another instance /// </summary> /// <param name="data"></param> public SdesData(SdesData sdes) { // Skip the first index - see comments for member variable 'data' for (int i = 1; i < sdes.data.Length; i++) { byte[] data = sdes.data[i]; if (data != null) { byte[] copy = new byte[data.Length]; data.CopyTo(copy, 0); data = copy; } this.data[i] = data; } foreach (DictionaryEntry de in sdes.privs) { SetPrivateExtension((byte[])de.Key, (byte[])de.Value); } }
internal RtpStreamFec(RtpListener rtpListener, uint ssrc, string ipaddress, SdesData sdes, PayloadType pt) : base(rtpListener, ssrc, ipaddress, sdes, pt) { this.getBufferHandler = rtpListener.GetBufferCallback; }
private void ReadReportFromBuffer(BufferChunk buffer) { uint ssrc = buffer.NextUInt32(); SdesData props = new SdesData(buffer); AddReport(new SdesReport(ssrc, props)); }
internal SdesReport(uint ssrc, SdesData sdes) { this.ssrc = ssrc; this.sdes = sdes; }
internal static RtpStream CreateStream2(RtpListener rtpListener, uint ssrc, string ipaddress, SdesData sdes) { string sPT = sdes.GetPrivateExtension(Rtcp.PEP_PAYLOADTYPE); PayloadType pt = PayloadType.JPEG; // RtpStream return(new RtpStream(rtpListener, ssrc, ipaddress, sdes, pt)); }
/// <summary> /// Constructs an SdesData instance by reading its properties from another instance /// </summary> /// <param name="data"></param> public SdesData(SdesData sdes) { // Skip the first index - see comments for member variable 'data' for(int i = 1; i < sdes.data.Length; i++) { byte[] data = sdes.data[i]; if(data != null) { byte[] copy = new byte[data.Length]; data.CopyTo(copy, 0); data = copy; } this.data[i] = data; } foreach(DictionaryEntry de in sdes.privs) { SetPrivateExtension((byte[])de.Key, (byte[])de.Value); } }
/// <summary> /// AddOrUpdateParticipant is called by the RtpSession ctor for adding the local participant and /// by ProcessSdesPacket when an SDES packet arrives on the RtcpListener thread /// /// If the participant does not exist in the session, we add them /// If the participant does exist in the session, we make sure there is no CName conflict /// </summary> /// <param name="ssrc">Unique identifier of the stream</param> /// <param name="sdes">CName, Name, Email, etc from which to create the Participant</param> /// <param name="ip">Originating IP address of the ssrc and SdesData</param> private void AddOrUpdateParticipant(uint ssrc, SdesData sdes, IPAddress ip) { lock(participants) { string cName = sdes.CName; RtpParticipant participant = participants[cName]; // Participant does not exist if(participant == null) { // Create a new participant AddParticipant(ssrc, new RtpParticipant(sdes, ip)); } else // Participant exists { CheckForCNameConflict(cName, new IPAddress[]{participant.IPAddress, ip}); participant.Stale = 0; participant.UpdateData(sdes); } } }
/// <summary> /// Raises the ParticipantStatusChanged event if the data changed /// </summary> /// <param name="data"></param> internal new void UpdateData(SdesData data) { if(base.UpdateData(data)) { object[] args = {this, new RtpEvents.RtpParticipantEventArgs(this)}; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaiseRtpParticipantDataChangedEvent), args); } }
/// <summary> /// Called to create a stream via Rtcp and have all the "links" created /// /// CXP always stores the Participant ssrc/SdesData first in the SdesPacket. So a /// participant should always exist before the stream is created in this code. /// /// AddStream is called by the RtcpListener thread via ProcessSdesPacket /// </summary> private void AddOrUpdateStream(uint ssrc, string ipaddress, SdesData sdes) { lock(participants) { lock(streamsAndIPs) { RtpParticipant participant = participants[sdes.CName]; if(participants[sdes.CName] == null) { Debug.Assert(false); throw new InvalidOperationException("Can't create a stream if there is " + "no participant to associate it with!"); } IPStreamPairHashtable.IPStreamPair ipsp = streamsAndIPs[ssrc]; Debug.Assert(ipsp != null); if(ipsp.stream == null) { ipsp.stream = RtpStream.CreateStream(rtpListener, ssrc, ipaddress, sdes); ssrcToParticipant[ssrc] = participant; participant.AddSSRC(ssrc); RaiseRtpStreamAddedEvent(ipsp.stream); } else // Update { ipsp.stream.Stale = 0; ipsp.stream.Properties.UpdateData(sdes); } } } }
/// <summary> /// Called to create a stream via Rtcp and have all the "links" created /// /// CXP always stores the Participant ssrc/SdesData first in the SdesPacket. So a /// participant should always exist before the stream is created in this code. /// /// AddStream is called by the RtcpListener thread via ProcessSdesPacket /// </summary> private void AddOrUpdateStream2(uint ssrc, string ipaddress, SdesData sdes) { lock (participants) { lock (streamsAndIPs) { IPStreamPairHashtable.IPStreamPair ipsp = streamsAndIPs[ssrc]; Debug.Assert(ipsp != null); if (ipsp.stream == null) { ipsp.stream = RtpStream.CreateStream2(rtpListener, ssrc, ipaddress, sdes); RaiseRtpStreamAddedEvent(ipsp.stream); } else // Update { ipsp.stream.Stale = 0; ipsp.stream.Properties.UpdateData(sdes); } } } }
void RtpSender.IRtpSession.AddSdes(uint ssrc, SdesData sdes) { AddSdes(ssrc, sdes); }
private void AddSdes(uint ssrc, SdesData sdes) { cpb.Add_SDESReport(ssrc, sdes); }
public void Add_SDESReport(uint ssrc, SdesData sdes) { sdesReports.Push(new SdesReport(ssrc, sdes)); }
/// <summary> /// Called when an SdesPacket arrives with an ID (CNAME) that no other session Participant has /// </summary> /// <param name="rtcp">SdesData containing the information for the participant</param> /// <param name="ipAddress">IpAddress this participant originates from</param> internal RtpParticipant(SdesData data, IPAddress ipAddress) : base(data) { this.ipAddress = ipAddress; SetPrivateExtension(Rtcp.PEP_SOURCE, Rtcp.PED_PARTICIPANT); }
public void Add(uint ssrc, SdesData props) { Dictionary.Add(ssrc, props); }
internal RtpStreamFFec(RtpListener rtpListener, uint ssrc, string ipaddress, SdesData sdes, PayloadType pt, ushort fecPxExp) : base(rtpListener, ssrc, ipaddress, sdes, pt) { fecPercent = fecPxExp; pcFecType = 2; }
/// <summary> /// This method is called to update the local data from another SdesData /// </summary> /// <param name="data">what we want to update our data to</param> /// <returns>true if the local data was updated, otherwise false</returns> internal bool UpdateData(SdesData sdes) { bool ret = false; // Well-known properties // CName can never be updated, so start with Name for(int id = (int)Rtcp.SDESType.NAME; id <= (int)Rtcp.SDESType.NOTE; id++) { if(!BufferChunk.Compare(data[id], sdes.data[id])) { data[id] = BufferChunk.Copy(sdes.data[id]); ret = true; } } // Write private properties foreach(DictionaryEntry de in sdes.privs) { byte[] key = (byte[])de.Key; byte[] data = (byte[])de.Value; if(!privs.Contains(key) || !BufferChunk.Compare(data, privs[key])) { privs[BufferChunk.Copy(key)] = BufferChunk.Copy(data); ret = true; } } return ret; }
/// <summary> /// Construct an SDES packet from existing properties /// </summary> public SdesPacket(uint ssrc, SdesData props) : base(Rtcp.PacketType.SDES) { AddReport(new SdesReport(ssrc, props)); }
internal static RtpStream CreateStream(RtpListener rtpListener, uint ssrc, string ipaddress, SdesData sdes) { string sPT = sdes.GetPrivateExtension(Rtcp.PEP_PAYLOADTYPE); PayloadType pt = (PayloadType)Enum.Parse(typeof(PayloadType), sPT); // RtpStreamFec string fecData = sdes.GetPrivateExtension(Rtcp.PEP_FEC); if (fecData != null) { string[] args = fecData.Split(new char[] { ':' }); ushort dataPxExp = ushort.Parse(args[0]); ushort fecPxExp = ushort.Parse(args[1]); if (fecPxExp == 0) { throw new ArgumentOutOfRangeException("fecPxExp", fecPxExp, "Must be >= 1"); } // Frame based Fec if (dataPxExp == 0) { return(new RtpStreamFFec(rtpListener, ssrc, ipaddress, sdes, pt, fecPxExp)); } else // Constant Fec { return(new RtpStreamCFec(rtpListener, ssrc, ipaddress, sdes, pt, dataPxExp, fecPxExp)); } } // RtpStream return(new RtpStream(rtpListener, ssrc, ipaddress, sdes, pt)); }
internal RtpSender(IRtpSession rtpSession, string name, PayloadType payloadType, Hashtable priExns, Hashtable paraPay) { if(Thread.CurrentThread.Name == null) { Thread.CurrentThread.Name = "RtpSender - " + name; } this.rtpSession = rtpSession; this.payloadType = payloadType; this.payloadPara = paraPay; // Leave everything but CName and Name blank in order to reduce Rtcp bandwidth sdes = new SdesData(rtpSession.Sdes.CName, name); // Add private extensions sdes.SetPrivateExtension(Rtcp.PEP_SOURCE, Rtcp.PED_STREAM); sdes.SetPrivateExtension(Rtcp.PEP_PAYLOADTYPE, ((int)payloadType).ToString()); InitializeNetwork(); InitializeFrame(); InitializePerformanceCounters(); // This needs to be called after InitializeNetwork if( priExns != null ) { foreach(DictionaryEntry de in priExns) { sdes.SetPrivateExtension((string)de.Key, (string)de.Value); } string dbpString = (string)priExns[Rtcp.PEP_DBP]; if( dbpString != null ) DelayBetweenPackets = short.Parse(dbpString); } ResetState(); }
/// <summary> /// Write a report (ssrc + SdesData) to the buffer /// </summary> /// <param name="ssrc">uint was cast to int because that's how BufferChunk writes 32 bits</param> /// <param name="props"></param> private void WriteReportToBuffer(BufferChunk buffer, uint ssrc, SdesData props) { buffer += ssrc; props.WriteDataToBuffer(buffer); }