public RtpMediaConnection(MediaConfig config, MediaStatistics mediaStats) { _controlClient = new NetClient(config.MediaServerHost, config.MediaServerControlPort); _rtpClient = new NetClient(config.MediaServerHost, config.MediaServerStreamingPort, mediaStats); _rtpConnect = new RtpPacketConnect(); _rtpData = new RtpPacketData(); _rtpConnect.SsrcId = config.LocalSsrcId; _dataReceiveBuffer = new ByteStream(RtpPacketData.DataPacketMaxLength * 10); // Leave room for at least 10 packets. _rtpPacketDataListPool = new ObjectPool <List <RtpPacketData> >(() => new List <RtpPacketData>(), list => list.Clear()); _rtpPacketDataPool = new ObjectPool <RtpPacketData>(() => new RtpPacketData()); // No reset action needed _packetBufferPool = new ObjectPool <ByteStream>(() => new ByteStream(RtpPacketData.DataPacketMaxLength), bs => bs.Reset()); }
public static List <RtpPacketData> GetPacketsFromData(ByteStream buffer, IObjectPool <List <RtpPacketData> > rtpPacketDataListPool, IObjectPool <RtpPacketData> rtpPacketDataPool) { // Retrieve the list from an object pool (rather than creating a new one each time that has to be garbage-collected). var packets = rtpPacketDataListPool.GetNext(); while (buffer.CurrentOffset < buffer.EndOffset) { RtpPacketData packet = rtpPacketDataPool.GetNext(); RtpParseResult result = packet.ParsePacket(buffer); switch (result) { case RtpParseResult.Success: // Add the packet to the list and continue processing. packets.Add(packet); break; case RtpParseResult.DataIncomplete: // Tell the calling function that it can reuse the buffer after position <length>. // Move the data to the beginning of the buffer (so that we can get it next time) and stop parsing. Debug.Assert(buffer.CurrentOffset >= 0, "The current offset cannot be negative."); Debug.Assert(buffer.RemainingBytes >= 0, "The remaining bytes cannot be negative."); Buffer.BlockCopy(buffer.Data, buffer.CurrentOffset, buffer.Data, 0, buffer.RemainingBytes); buffer.DataLength = buffer.RemainingBytes; buffer.DataOffset = 0; buffer.CurrentOffset = 0; return(packets); case RtpParseResult.DataInvalid: // Don't add the current packet to the list, but continue processing at the current position. break; } } // If this is our exit point, tell the calling function that it can reuse the entire buffer. buffer.DataLength = 0; buffer.CurrentOffset = 0; return(packets); }
protected void HandleRtpData(byte[] buffer, int offset, int length) { if (_disposed) { return; } List <RtpPacketData> packets = null; try { // ks 8/23/11 - TODO: Investigate whether we can get rid of this memcpy(). // I think we can do it by passing the dataReceiveBuffer to the NetClient class, // and just keeping better track of what's been processed and what hasn't. // Kind of like how we handle it in the media server. lock (_dataReceiveBuffer) { // Copy the data in the network receive buffer to the packet receive buffer. int dataLength = _dataReceiveBuffer.CurrentOffset + length; _dataReceiveBuffer.TryWriteBytes(buffer, offset, length); _dataReceiveBuffer.DataOffset = 0; _dataReceiveBuffer.CurrentOffset = 0; _dataReceiveBuffer.DataLength = dataLength; // Pull the packets out of the packet receive buffer. packets = RtpPacketData.GetPacketsFromData(_dataReceiveBuffer, _rtpPacketDataListPool, _rtpPacketDataPool); } #region Packet Processor foreach (var packet in packets) { try { switch (packet.PayloadType) { case RtpPayloadType.Audio: if (AudioPacketHandler != null) { AudioPacketHandler(packet); } break; case RtpPayloadType.VideoFromServer: if (VideoPacketHandler != null) { VideoPacketHandler(packet); } break; default: ClientLogger.Debug("Unexpected packetBuffer type {0}", packet.PayloadType); break; } } finally { _rtpPacketDataPool.Recycle(packet); } } #endregion } catch (Exception ex) { ClientLogger.ErrorException(ex, "Error processing RTP data"); } finally { _rtpPacketDataListPool.Recycle(packets); } }