public static CitpPacket FromByteArray(byte[] data, IpEndpoint?remoteEndpoint = null) { CitpPacket packet; var layerType = getLayerType(data); if (layerType == null) { var layerTypeArray = new byte[4]; Buffer.BlockCopy(data, CitpContentTypePosition, layerTypeArray, 0, 4); throw new InvalidOperationException( $"Unrecognised CITP content type: {Encoding.UTF8.GetString(layerTypeArray, 0, layerTypeArray.Length)}"); } switch (layerType) { case CitpLayerType.PeerInformationLayer: { var messageType = PinfPacket.GetMessageType(data); if (messageType == null) { var messageTypeArray = new byte[4]; Buffer.BlockCopy(data, PinfPacket.CitpMessageTypePosition, messageTypeArray, 0, 4); throw new InvalidOperationException( $"Unrecognised PING message type: {Encoding.UTF8.GetString(messageTypeArray, 0, messageTypeArray.Length)}"); } switch (messageType) { case PinfMessageType.PeerLocationMessage: packet = new PeerLocationMessagePacket(); break; case PinfMessageType.PeerNameMessage: packet = new PeerNameMessagePacket(); break; default: throw new NotImplementedException("Unimplemented PINF message type"); } break; } case CitpLayerType.MediaServerExtensionsLayer: { var messageType = MsexPacket.GetMessageType(data); if (messageType == null) { var messageTypeArray = new byte[4]; Buffer.BlockCopy(data, MsexPacket.CitpMessageTypePosition, messageTypeArray, 0, 4); throw new InvalidOperationException( $"Unrecognised MSEX message type: {Encoding.UTF8.GetString(messageTypeArray, 0, messageTypeArray.Length)}"); } switch (messageType) { case MsexMessageType.ClientInformationMessage: packet = new ClientInformationMessagePacket(); break; case MsexMessageType.ServerInformationMessage: packet = new ServerInformationMessagePacket(); break; case MsexMessageType.NegativeAcknowledgeMessage: packet = new NegativeAcknowledgeMessagePacket(); break; case MsexMessageType.LayerStatusMessage: packet = new LayerStatusMessagePacket(); break; case MsexMessageType.GetElementLibraryInformationMessage: packet = new GetElementLibraryInformationMessagePacket(); break; case MsexMessageType.ElementLibraryInformationMessage: packet = new ElementLibraryInformationMessagePacket(); break; case MsexMessageType.ElementLibraryUpdatedMessage: packet = new ElementLibraryUpdatedMessagePacket(); break; case MsexMessageType.GetElementInformationMessage: packet = new GetElementInformationMessagePacket(); break; case MsexMessageType.MediaElementInformationMessage: packet = new MediaElementInformationMessagePacket(); break; case MsexMessageType.EffectElementInformationMessage: packet = new EffectElementInformationMessagePacket(); break; case MsexMessageType.GenericElementInformationMessage: packet = new GenericElementInformationMessagePacket(); break; case MsexMessageType.GetElementLibraryThumbnailMessage: packet = new GetElementLibraryThumbnailMessagePacket(); break; case MsexMessageType.ElementLibraryThumbnailMessage: packet = new ElementLibraryThumbnailMessagePacket(); break; case MsexMessageType.GetElementThumbnailMessage: packet = new GetElementThumbnailMessagePacket(); break; case MsexMessageType.ElementThumbnailMessage: packet = new ElementThumbnailMessagePacket(); break; case MsexMessageType.GetVideoSourcesMessage: packet = new GetVideoSourcesMessagePacket(); break; case MsexMessageType.RequestStreamMessage: packet = new RequestStreamMessagePacket(); break; case MsexMessageType.StreamFrameMessage: packet = new StreamFrameMessagePacket(); break; default: throw new NotImplementedException("Unimplemented MSEX message type"); } break; } default: throw new NotImplementedException("Unimplemented CITP content type"); } using (var reader = new CitpBinaryReader(new MemoryStream(data))) packet.DeserializeFromStream(reader); packet.RemoteEndpoint = remoteEndpoint; return(packet); }
public async Task ProcessStreamRequestsAsync() { foreach (var request in _streamRequests.Values.ToList()) { foreach (var formatRequest in request.Formats) { if (Math.Abs(request.Fps) < float.Epsilon || DateTime.Now < formatRequest.LastOutput + TimeSpan.FromSeconds(1.0f / request.Fps)) { break; } var imageRequest = new CitpImageRequest(request.FrameWidth, request.FrameHeight, formatRequest.FrameFormat, true, formatRequest.FrameFormat == MsexImageFormat.Rgb8 && formatRequest.Version == MsexVersion.Version1_0); var frame = _streamProvider.GetVideoSourceFrame(request.SourceIdentifier, imageRequest); if (frame == null) { break; } var packet = new StreamFrameMessagePacket { Version = formatRequest.Version, MediaServerUuid = _streamProvider.Uuid, SourceIdentifier = Convert.ToUInt16(request.SourceIdentifier), FrameFormat = formatRequest.FrameFormat, FrameWidth = Convert.ToUInt16(frame.ActualWidth), FrameHeight = Convert.ToUInt16(frame.ActualHeight) }; if (formatRequest.FrameFormat == MsexImageFormat.FragmentedJpeg || formatRequest.FrameFormat == MsexImageFormat.FragmentedPng) { var fragments = frame.Data.Split(MaximumImageBufferSize); packet.FragmentInfo = new StreamFrameMessagePacket.FragmentPreamble() { FrameIndex = request.FrameCounter, FragmentCount = (ushort)fragments.Length }; if (fragments.Length > ushort.MaxValue) { _log.LogWarning("Cannot send streaming frame, too many image fragments"); return; } for (uint i = 0; i < fragments.Length; ++i) { packet.FragmentInfo.FragmentIndex = (ushort)i; packet.FragmentInfo.FragmentByteOffset = MaximumImageBufferSize * i; packet.FrameBuffer = fragments[i]; await _networkService.SendMulticastPacketAsync(packet).ConfigureAwait(false); } } else { if (frame.Data.Length > MaximumImageBufferSize) { _log.LogWarning($"Cannot send streaming frame request '{imageRequest}', image buffer too large"); return; } packet.FrameBuffer = frame.Data; await _networkService.SendMulticastPacketAsync(packet).ConfigureAwait(false); } formatRequest.LastOutput = DateTime.Now; } request.RemoveTimedOutRequests(); if (request.Formats.Count == 0) { _streamRequests.Remove(request.SourceIdentifier); } ++request.FrameCounter; } }