public RtpUdpReceiver(RtpSession session) { this.session = session; }
public RtpTcpSender(RtpSession session) { this.session = session; }
public List <RtspFrame> ProcessData(byte[] buf, int length, RtpSession session) { List <RtspFrame> frames = new List <RtspFrame>(); int offset = 0; int pos = 0; while (true) { if (offset >= length) { logger.Debug("!!!!!!!!!!!!!!!!!!! " + offset + " >= " + length); break; //return; } if (tcpBufferOffset > 0) {// если остались не обработанные данные int len = length - offset; int newSize = tcpBufferOffset + len; byte[] newBuf = new byte[newSize]; Array.Copy(tcpBuffer, 0, newBuf, 0, tcpBufferOffset); Array.Copy(buf, offset, newBuf, tcpBufferOffset, len); tcpBufferOffset = 0; // Debug.WriteLine("ProcessTcpBuffer newSize " + newSize); buf = newBuf; length = newSize; } if (streamState == RtspStreamState.WaitDollar || streamState == RtspStreamState.ReadHeader || streamState == RtspStreamState.ReadContent) { for (int i = offset; i < length; i++) { char ch = (char)buf[i]; if (ch == '$') { //Console.WriteLine("Find dollar at pos: " + i); streamState = RtspStreamState.ReadId; pos = i + 1; //header rtspFrame = new RtspFrame(); break; } } } if (streamState == RtspStreamState.ReadId) {// идентификатор 1 байт int len = length - pos; if (len > 0) { rtspFrame.Id = buf[pos]; //Console.WriteLine("ID: " + rtspFrame.Id + " pos: " + pos); pos++; streamState = RtspStreamState.ReadLen; } else { // буфер закончился выходим break; } } if (streamState == RtspStreamState.ReadLen) {// длина пакета с данными 2 байта int len = length - pos; if (len > 1) { //int frameLength = BitConverter.ToInt16(buf, pos); int frameLength = BigEndian.ReadInt16(buf, pos); if (frameLength <= 0) { logger.Warn("frameLength " + frameLength); //TODO: //... } rtspFrame.Init(frameLength); //Console.WriteLine("frameLength: " + frameLength + " pos: " + pos); pos += 2; streamState = RtspStreamState.ReadPkt; } else {// сохраняем в буффер то что есть и выходим // Debug.WriteLine(len + " < " + 2); Array.Copy(buf, pos, tcpBuffer, tcpBufferOffset, len); tcpBufferOffset += len; //... break; } } if (streamState == RtspStreamState.ReadPkt) { if (rtspFrame != null && rtspFrame.Length > 0) { // сколькоданных в буфере int bufToRead = length - pos; int bytesAdded = rtspFrame.AddData(buf, pos, bufToRead); pos += bytesAdded; if (rtspFrame.BytesToRead == 0) {// все данные прочитаны // client.ProcessRtspFrame(rtspFrame); //Console.WriteLine(rtspFrame.ToString()); var rtpData = rtspFrame.Data; RtpPacket rtpPacket = RtpPacket.Create(rtpData, rtpData.Length, session); // OnRtpPacketReceived(rtpPacket); frames.Add(rtspFrame); // переходим в режим ожидания доллара streamState = RtspStreamState.WaitDollar; // читаем следующий rtsp frame rtspFrame = null; } if (pos < length) { //ProcessTcpBuffer(buf, pos, length); offset = pos; continue; } break; // return; } } { // понять что это за данные пока не удалось копируем в буфер int bufToRead = length - offset; Array.Copy(buf, offset, tcpBuffer, tcpBufferOffset, bufToRead); tcpBufferOffset += bufToRead; logger.Debug("Array.Copy tcpBufferOffset " + tcpBufferOffset); break; } } return(frames); }
//public static RtpPacket Create(byte[] data) //{ // return Create(data, data.Length); //} public static RtpPacket Create(byte[] data, int len, RtpSession session) { if (len < RtpConst.MinRtpLength) { throw new InvalidOperationException("Invalid RTP packet. Packet size < " + RtpConst.MinRtpLength); } RtpPacket packet = new RtpPacket(); packet.packetBytes = data; int dataLength = len;//data.Length; int offset = 0; byte firstByte = data[offset++]; packet.Version = (byte)(firstByte >> 6); if (packet.Version != RtpConst.Version) { throw new InvalidOperationException("Invalid RTP packet. Unsupported version " + packet.Version); } /* * If the padding bit is set, the packet contains one or more * additional padding octets at the end which are not part of the * payload. The last octet of the padding contains a count of how * many padding octets should be ignored, including itself. Padding * may be needed by some encryption algorithms with fixed block sizes * or for carrying several RTP packets in a lower-layer protocol data * unit. */ packet.Padding = ((firstByte & 0x20) == 0x20); if (packet.Padding) {// последний байт в пакете длинна области заполнения byte padding = data.Last(); dataLength -= padding; } packet.Extension = (firstByte & 0x10) == 0x10; packet.CSRCCount = (byte)(firstByte & 0x0F); byte secondByte = data[offset++]; packet.Marker = (secondByte & 0x80) == 0x80; packet.PayloadType = (secondByte & 0x7F); packet.Sequence = BigEndian.ReadUInt16(data, offset); offset += 2; packet.Timestamp = BigEndian.ReadUInt32(data, offset); offset += 4; packet.SSRC = BigEndian.ReadUInt32(data, offset); offset += 4; if (packet.SSRC != session.SSRC) {// Invalid session id return(null); } offset += packet.CSRCCount * 4; if (packet.Extension) { /* * An extension mechanism is provided to allow individual * implementations to experiment with new payload-format-independent * functions that require additional information to be carried in the * RTP data packet header. This mechanism is designed so that the * header extension may be ignored by other interoperating * implementations that have not been extended. */ packet.HeaderExtensionProfile = BigEndian.ReadUInt16(data, offset); offset += 2; var headerExtensionLength = BigEndian.ReadUInt16(data, offset); offset += 2; packet.HeaderExtension = new ArraySegment <byte>(data, offset, headerExtensionLength); offset += headerExtensionLength; } else { packet.HeaderExtensionProfile = 0; } int payloadLength = (dataLength - offset); packet.Payload = new ArraySegment <byte>(data, offset, payloadLength); return(packet); }