Warning: This is a development version. The latest stable version is Version 7.0.0.

Code Example: Content-Aware Coding

In this example shows how to use the API of rely to implement content Aware coding.

The example shows how to use the manual repair generation strategy.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <algorithm>
#include <cassert>
#include <iomanip>
#include <iostream>
#include <regex>
#include <vector>

// Include the relevant header files.
#include <rely/decoder.hpp>
#include <rely/utils.hpp>
#include <rely/encoder.hpp>

// In this example we will look at how to work with the boundaries of the
// content. For more information see the section about Content-Aware coding.
int main()
{
    // The max size of packets produced by the encoder and consumed by the
    // decoder. Make sure this is set so that packets generated by rely is less
    // than the network's MTU.
    std::size_t max_packet_bytes = 1400U;

    // The timeout specifies how long the packets are kept.
    // A higher value will result in a higher added latency but a greater level
    // of protection. So it should be maximimed for the given use case.
    int64_t timeout = 120U;

    // The maximum number of packets that will be held by the decoder. This
    // effectively limits the maximum memory consumption of the algorithm. In
    // practice it makes sense to maximize this parameter as much as possible.
    // If packets are removed due to a full stream rather than a timeout,
    // decodable data be dropped.
    std::size_t max_stream_size = 20U;

    // Create the encoder and decoder
    rely::encoder encoder;
    rely::decoder decoder;

    encoder.configure(max_packet_bytes, timeout, max_stream_size);
    decoder.configure(max_packet_bytes, timeout, max_stream_size);

    // Disable the repair trigger so that repair can be handled in a manual and
    // content-aware manner.
    encoder.disable_repair_trigger();

    // Maximum number of interations
    const uint32_t max_iterations = 100000U;
    uint32_t iterations = 0;

    // Counter for keeping track of the number of lost packets
    uint32_t lost = 0;

    // In this example, time is simply simulated.
    int64_t time = 0;

    std::cout << "Running ..." << std::endl;

    while (iterations < max_iterations)
    {
        // Increment the time.
        time += 1;

        // Create a payload, the size is between 1350 and 6350 bytes.
        std::vector<uint8_t> payload(1350 + (rand() % 5000));

        // Fill the payload with random data
        std::generate(payload.begin(), payload.end(), rand);

        // Insert the data into the encoder.
        encoder.consume(payload.data(), payload.size(), time);

        // Generate repair for every odd payload. This is just an arbitrary
        // strategy picked for this example.
        if (time % 1 == 0 && encoder.has_unprotected_symbols())
        {
            auto repair_packets = rely::utils::to_repair_count(
                0.1, encoder.unprotected_symbols());
            encoder.generate_repair(repair_packets);
        }

        // Handle the the output from the encoder
        while (encoder.can_produce())
        {
            // Simulate 10% packet loss
            if (rand() % 100 < 10)
            {
                // Packet lost, advance the encoder
                encoder.produce_next();
                lost += 1;
                continue;
            }
            // Feed the produced packets from the encoder to the decoder.
            decoder.consume(encoder.produce_data(), encoder.produce_bytes(),
                            time);
            // Advance the encoder
            encoder.produce_next();
        }

        // Handle the the output from the decoder
        while (decoder.can_produce())
        {
            // Read the decoded payload
            auto data = decoder.produce_data();
            auto bytes = decoder.produce_bytes();

            // In a real world scenario the payload would be forwarded to
            // the appropriate application
            assert(data != nullptr);
            assert(bytes != 0U);

            // Silence warnings when compiling without asserts
            (void)data;
            (void)bytes;

            // Advance the decoder to see if more decoded payloads are
            // available.
            decoder.produce_next();
        }

        ++iterations;
    }

    uint64_t packets_produced =
        encoder.counter_value(rely::counter::packets_produced);

    uint64_t repair_produced =
        encoder.counter_value(rely::counter::repair_symbols_produced);

    uint64_t payloads_consumed =
        encoder.counter_value(rely::counter::payloads_consumed);

    uint64_t payloads_produced =
        decoder.counter_value(rely::counter::payloads_produced);

    std::cout << "\nStatistics\n";
    std::cout << "Packets produced = " << packets_produced << "\n";
    std::cout << "Repair produced = " << repair_produced << "\n";
    std::cout << "Lost packets = " << lost << "\n";
    std::cout << "Packet loss rate = "
              << (lost / double(packets_produced)) * 100 << "%\n";
    std::cout << "Payloads consumed = " << payloads_consumed << "\n";
    std::cout << "Payloads produced = " << payloads_produced << "\n";
    std::cout << "Payload loss rate = "
              << (1.0 - payloads_produced / double(payloads_consumed)) * 100
              << "%\n";

    std::cout << "Encoder performance counters:\n"
              << encoder.counters_to_json() << "\n";
    std::cout << "Decoder performance counters:\n"
              << decoder.counters_to_json() << "\n";
    return 0;
}