public static void Classify(UdpSocket udpSocket, ICollection <Receiver> receivers,
                                List <ConfirmPacketInfo> confirmPacketInfos,
                                Dictionary <int, SenderPacketInfo> senderPacketInfos)
    {
        foreach (var receiver in receivers)
        {
            senderPacketInfos.Add(receiver.SenderId, new SenderPacketInfo());
        }

        while (true)
        {
            var packet = udpSocket.Receive();
            if (packet == null)
            {
                break;
            }

            int senderId   = PacketUtils.getSessionIdFromSenderPacketBytes(packet.Bytes);
            var packetType = PacketUtils.getPacketTypeFromSenderPacketBytes(packet.Bytes);

            if (packetType == SenderPacketType.Confirm)
            {
                confirmPacketInfos.Add(new ConfirmPacketInfo(packet.EndPoint, ConfirmSenderPacket.Create(packet.Bytes)));
                continue;
            }

            // Ignore packet if it is sent from a sender without a corresponding receiver.
            if (!senderPacketInfos.TryGetValue(senderId, out SenderPacketInfo senderPacketInfo))
            {
                continue;
            }

            senderPacketInfo.ReceivedAny = true;
            switch (packetType)
            {
            case SenderPacketType.Heartbeat:
                break;

            case SenderPacketType.Video:
                senderPacketInfo.VideoPackets.Add(VideoSenderPacket.Create(packet.Bytes));
                break;

            case SenderPacketType.Parity:
                senderPacketInfo.ParityPackets.Add(ParitySenderPacket.Create(packet.Bytes));
                break;

            case SenderPacketType.Audio:
                senderPacketInfo.AudioPackets.Add(AudioSenderPacket.Create(packet.Bytes));
                break;
            }
        }
    }
Пример #2
0
    public void Assemble(UdpSocket udpSocket,
                         List <VideoSenderPacket> videoPacketDataList,
                         List <ParitySenderPacket> parityPacketDataList,
                         int lastVideoFrameId,
                         IDictionary <int, VideoSenderMessage> videoMessages)
    {
        int?addedFrameId = null;

        // Collect the received video packets.
        foreach (var videoSenderPacketData in videoPacketDataList)
        {
            if (videoSenderPacketData.frameId <= lastVideoFrameId)
            {
                continue;
            }

            if (!videoPacketCollections.ContainsKey(videoSenderPacketData.frameId))
            {
                videoPacketCollections[videoSenderPacketData.frameId] = new VideoSenderPacket[videoSenderPacketData.packetCount];
                // Assign the largest new frame_id.
                if (!addedFrameId.HasValue || addedFrameId < videoSenderPacketData.frameId)
                {
                    addedFrameId = videoSenderPacketData.frameId;
                }
            }

            videoPacketCollections[videoSenderPacketData.frameId][videoSenderPacketData.packetIndex] = videoSenderPacketData;
        }

        // Collect the received parity packets.
        foreach (var paritySenderPacketData in parityPacketDataList)
        {
            if (paritySenderPacketData.frameId <= lastVideoFrameId)
            {
                continue;
            }

            if (!parityPacketCollections.ContainsKey(paritySenderPacketData.frameId))
            {
                int parityPacketCount = (paritySenderPacketData.videoPacketCount - 1) / FEC_GROUP_SIZE + 1;
                parityPacketCollections[paritySenderPacketData.frameId] = new ParitySenderPacket[parityPacketCount];
            }

            parityPacketCollections[paritySenderPacketData.frameId][paritySenderPacketData.packetIndex] = paritySenderPacketData;
        }

        if (addedFrameId.HasValue)
        {
            foreach (var videoPacketCollection in videoPacketCollections)
            {
                int frameId = videoPacketCollection.Key;
                VideoSenderPacket[] videoPackets = videoPacketCollection.Value;

                // Skip the frame that just got added or even newer.
                if (frameId >= addedFrameId)
                {
                    continue;
                }

                // Find the parity packet collection corresponding to the video packet collection.
                // Skip if there is no parity packet collection for the video frame.
                if (!parityPacketCollections.ContainsKey(frameId))
                {
                    continue;
                }

                ParitySenderPacket[] parityPackets = parityPacketCollections[frameId];

                // Loop per each parity packet.
                // Collect video packet indices to request.
                List <int> videoPacketIndiecsToRequest  = new List <int>();
                List <int> parityPacketIndiecsToRequest = new List <int>();

                for (int parityPacketIndex = 0; parityPacketIndex < parityPackets.Length; ++parityPacketIndex)
                {
                    // Range of the video packets that correspond to the parity packet.
                    int videoPacketStartIndex = parityPacketIndex * FEC_GROUP_SIZE;
                    // Pick the end index with the end of video packet indices in mind (i.e., prevent overflow).
                    int videoPacketEndIndex = Math.Min(videoPacketStartIndex + FEC_GROUP_SIZE, videoPackets.Length);

                    // If the parity packet is missing, request all missing video packets and skip the FEC process.
                    // Also request the parity packet if there is a relevant missing video packet.
                    if (parityPackets[parityPacketIndex] == null)
                    {
                        bool parityPacketNeeded = false;
                        for (int videoPacketIndex = videoPacketStartIndex; videoPacketIndex < videoPacketEndIndex; ++videoPacketIndex)
                        {
                            if (videoPackets[videoPacketIndex] == null)
                            {
                                videoPacketIndiecsToRequest.Add(videoPacketIndex);
                                parityPacketNeeded = true;
                            }
                        }
                        if (parityPacketNeeded)
                        {
                            parityPacketIndiecsToRequest.Add(parityPacketIndex);
                        }
                        continue;
                    }

                    // Find if there is existing video packets and missing video packet indices.
                    // Check all video packets that relates to this parity packet.
                    var existingVideoPackets      = new List <VideoSenderPacket>();
                    var missingVideoPacketIndices = new List <int>();
                    for (int videoPacketIndex = videoPacketStartIndex; videoPacketIndex < videoPacketEndIndex; ++videoPacketIndex)
                    {
                        if (videoPackets[videoPacketIndex] != null)
                        {
                            existingVideoPackets.Add(videoPackets[videoPacketIndex]);
                        }
                        else
                        {
                            missingVideoPacketIndices.Add(videoPacketIndex);
                        }
                    }

                    // Skip if there all video packets already exist.
                    if (missingVideoPacketIndices.Count == 0)
                    {
                        continue;
                    }

                    // XOR based FEC only works for a single missing packet.
                    if (missingVideoPacketIndices.Count > 1)
                    {
                        foreach (int missingIndex in missingVideoPacketIndices)
                        {
                            // Add the missing video packet indices for the vector to request them.
                            videoPacketIndiecsToRequest.Add(missingIndex);
                        }
                        continue;
                    }

                    // The missing video packet index.
                    int missingVideoPacketIndex = missingVideoPacketIndices[0];

                    // Reconstruct the missing video packet.
                    VideoSenderPacket fecVideoPacketData = new VideoSenderPacket();
                    fecVideoPacketData.frameId     = frameId;
                    fecVideoPacketData.packetIndex = missingVideoPacketIndex;
                    fecVideoPacketData.packetCount = videoPackets.Length;
                    // Assign from the parity packet here since other video packets will be XOR'ed in the below loop.
                    fecVideoPacketData.messageData = parityPackets[parityPacketIndex].bytes;

                    foreach (var existingVideoPacket in existingVideoPackets)
                    {
                        for (int i = 0; i < fecVideoPacketData.messageData.Length; ++i)
                        {
                            fecVideoPacketData.messageData[i] ^= existingVideoPacket.messageData[i];
                        }
                    }

                    // Insert the reconstructed packet.
                    videoPacketCollections[frameId][missingVideoPacketIndex] = fecVideoPacketData;
                }
                // Request the video packets that FEC was not enough to fix.
                udpSocket.Send(PacketUtils.createRequestReceiverPacketBytes(sessionId, frameId, false, videoPacketIndiecsToRequest, parityPacketIndiecsToRequest).bytes, remoteEndPoint);
            }
        }

        // Find all full collections and their frame_ids.
        var fullFrameIds = new List <int>();

        foreach (var collectionPair in videoPacketCollections)
        {
            bool full = true;
            foreach (var packetData in collectionPair.Value)
            {
                if (packetData == null)
                {
                    full = false;
                    break;
                }
            }

            if (full)
            {
                int frameId = collectionPair.Key;
                fullFrameIds.Add(frameId);
            }
        }

        // Extract messages from the full collections.
        foreach (int fullFrameId in fullFrameIds)
        {
            var ms = new MemoryStream();
            foreach (var packetData in videoPacketCollections[fullFrameId])
            {
                ms.Write(packetData.messageData, 0, packetData.messageData.Length);
            }

            var videoMessageData = VideoSenderMessage.Create(ms.ToArray());
            videoMessages.Add(fullFrameId, videoMessageData);

            videoPacketCollections.Remove(fullFrameId);
        }

        // Clean up frame_packet_collections.
        var obsoleteFrameIds = new List <int>();

        foreach (var collectionPair in videoPacketCollections)
        {
            if (collectionPair.Key <= lastVideoFrameId)
            {
                obsoleteFrameIds.Add(collectionPair.Key);
            }
        }

        foreach (int obsoleteFrameId in obsoleteFrameIds)
        {
            videoPacketCollections.Remove(obsoleteFrameId);
        }
    }