/// <summary> /// Parses the an DCEP open message from a buffer. /// </summary> /// <param name="buffer">The buffer to parse the message from.</param> /// <param name="posn">The position in the buffer to start parsing from.</param> /// <returns>A new DCEP open message instance.</returns> public static DataChannelOpenMessage Parse(byte[] buffer, int posn) { if (buffer.Length < DCEP_OPEN_FIXED_PARAMETERS_LENGTH) { throw new ApplicationException("The buffer did not contain the minimum number of bytes for a DCEP open message."); } var dcepOpen = new DataChannelOpenMessage(); dcepOpen.MessageType = buffer[posn]; dcepOpen.ChannelType = buffer[posn + 1]; dcepOpen.Priority = NetConvert.ParseUInt16(buffer, posn + 2); dcepOpen.Reliability = NetConvert.ParseUInt32(buffer, posn + 4); ushort labelLength = NetConvert.ParseUInt16(buffer, posn + 8); ushort protocolLength = NetConvert.ParseUInt16(buffer, posn + 10); if (labelLength > 0) { dcepOpen.Label = Encoding.UTF8.GetString(buffer, 12, labelLength); } if (protocolLength > 0) { dcepOpen.Protocol = Encoding.UTF8.GetString(buffer, 12 + labelLength, protocolLength); } return(dcepOpen); }
/// <summary> /// Event handler for a DATA chunk being received. The chunk can be either a DCEP message or data channel data /// payload. /// </summary> /// <param name="dataFrame">The received data frame which could represent one or more chunks depending /// on fragmentation..</param> private void OnDataFrameReceived(SctpDataFrame dataFrame) { switch (dataFrame) { case var frame when frame.PPID == (uint)DataChannelPayloadProtocols.WebRTC_DCEP: switch (frame.UserData[0]) { case (byte)DataChannelMessageTypes.ACK: OnDataChannelOpened?.Invoke(frame.StreamID); break; case (byte)DataChannelMessageTypes.OPEN: var dcepOpen = DataChannelOpenMessage.Parse(frame.UserData, 0); logger.LogDebug($"DCEP OPEN channel type {dcepOpen.ChannelType}, priority {dcepOpen.Priority}, " + $"reliability {dcepOpen.Reliability}, label {dcepOpen.Label}, protocol {dcepOpen.Protocol}."); DataChannelTypes channelType = DataChannelTypes.DATA_CHANNEL_RELIABLE; if (Enum.IsDefined(typeof(DataChannelTypes), dcepOpen.ChannelType)) { channelType = (DataChannelTypes)dcepOpen.ChannelType; } else { logger.LogWarning($"DECP OPEN channel type of {dcepOpen.ChannelType} not recognised, defaulting to {channelType}."); } OnNewDataChannel?.Invoke( frame.StreamID, channelType, dcepOpen.Priority, dcepOpen.Reliability, dcepOpen.Label, dcepOpen.Protocol); break; default: logger.LogWarning($"DCEP message type {frame.UserData[0]} not recognised, ignoring."); break; } break; default: OnDataChannelData?.Invoke(dataFrame); break; } }
/// <summary> /// Sends an OPEN Data Channel Establishment Protocol (DCEP) message /// to open a data channel on the remote peer for send/receive. /// </summary> internal void SendDcepOpen() { var dcepOpen = new DataChannelOpenMessage() { MessageType = (byte)DataChannelMessageTypes.OPEN, ChannelType = (byte)DataChannelTypes.DATA_CHANNEL_RELIABLE_UNORDERED, Label = label }; lock (this) { _transport.RTCSctpAssociation.SendData(id.GetValueOrDefault(), (uint)DataChannelPayloadProtocols.WebRTC_DCEP, dcepOpen.GetBytes()); } }