In this example shows how to use the otacast.Source() and
otacast.Sink(). The Source and Sink enables support for memory mapped IO.
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 | #!/usr/bin/env python
# encoding: utf-8
"""An example showing how to OTAcast Source and Sink."""
# License for Commercial Usage
# Distributed under the "OTACAST EVALUATION LICENSE 1.2"
# Licensees holding a valid commercial license may use this project in
# accordance with the standard license agreement terms provided with the
# Software (see accompanying file LICENSE.rst or
# https://www.steinwurf.com/license), unless otherwise different terms and
# conditions are agreed in writing between Licensee and Steinwurf ApS in which
# case the license will be regulated by that separate written agreement.
# License for Non-Commercial Usage
# Distributed under the "OTACAST RESEARCH LICENSE 1.2"
# Licensees holding a valid research license may use this project in accordance
# with the license agreement terms provided with the Software
# See accompanying file LICENSE.rst or https://www.steinwurf.com/license
import otacast
import filecmp
import tempfile
import os
def generate_file(bytes):
print(f"Generating file of {bytes / 1000 / 1000.0} Mb ", end="", flush=True)
fd, name = tempfile.mkstemp()
f = os.fdopen(fd, "wb")
max_chunk = bytes // 5
while bytes != 0:
chunk = min(max_chunk, bytes)
f.write(os.urandom(chunk))
bytes -= chunk
print(".", end="", flush=True)
f.close()
print(" Done!")
return name
def main():
# Generate a random file
file_path = generate_file(1000 * 1000 * 40) # 40MB
# Instantiate file source
source = otacast.Source()
# The symbol bytes determine the size of the produced symbols.
# In most cases it makes sense to make this value fit the MTU size of the
# network.
symbol_bytes = 1350
# The width manages a tradeoff between code
# effectiveness and computational complexity.
# A higher width causes higher code effectiveness, but also a higher memory
# footprint and computational complexity.
width = otacast.CodecWidth._32
# You can either configure the source giving the specific width and
# symbol_bytes as seperate arguments, or gather them in a set.
source_config = {width, symbol_bytes}
source.configure(*source_config)
source.open(file_path)
output_directory = tempfile.mkdtemp(suffix="otacast.out")
# Instantiate file sink
sink = otacast.Sink()
sink.open(output_directory)
# We create a meta-packet containing the meta information the source shares
# with the sink
meta_packet = bytearray(otacast.Source.meta_packet_size(source))
# Source writes the meta packet to the meta packet buffer
otacast.Source.meta_packet_serialize(source, meta_packet)
# The sink unpacks the data into a dictionary
sink_config = otacast.Sink.meta_packet_deserialize(meta_packet)
if sink_config is None:
raise Exception("Could not deserialize meta packet")
sink.configure(**sink_config)
# This bytearray will contain the generated symbols.
symbol = bytearray(source.packet_size)
while not sink.is_complete():
# Generate an encoded packet
source.write_packet(symbol)
# Decode the encoded packet
sink.read_packet(symbol)
if filecmp.cmp(file_path, sink.output_file_path, shallow=False):
print("Decoding finished successfully!")
else:
print("Something went wrong!")
# Close source and sink
source.close()
sink.close()
if __name__ == "__main__":
main()
|