Warning: This is a development version. The latest stable version is Version 4.0.0.
In this example shows how to use the otacast.Source() and
otacast.Sink(). The Source and Sink enables support for memory mapped IO.
1#!/usr/bin/env python
2# encoding: utf-8
3
4"""An example showing how to OTAcast Source and Sink."""
5
6# License for Commercial Usage
7# Distributed under the "OTACAST EVALUATION LICENSE 1.2"
8# Licensees holding a valid commercial license may use this project in
9# accordance with the standard license agreement terms provided with the
10# Software (see accompanying file LICENSE.rst or
11# https://www.steinwurf.com/license), unless otherwise different terms and
12# conditions are agreed in writing between Licensee and Steinwurf ApS in which
13# case the license will be regulated by that separate written agreement.
14# License for Non-Commercial Usage
15# Distributed under the "OTACAST RESEARCH LICENSE 1.2"
16# Licensees holding a valid research license may use this project in accordance
17# with the license agreement terms provided with the Software
18# See accompanying file LICENSE.rst or https://www.steinwurf.com/license
19
20import otacast
21import filecmp
22import tempfile
23import os
24
25
26def generate_file(bytes):
27 print(f"Generating file of {bytes / 1000 / 1000.0} Mb ", end="", flush=True)
28 fd, name = tempfile.mkstemp()
29 f = os.fdopen(fd, "wb")
30 max_chunk = bytes // 5
31 while bytes != 0:
32 chunk = min(max_chunk, bytes)
33 f.write(os.urandom(chunk))
34 bytes -= chunk
35 print(".", end="", flush=True)
36
37 f.close()
38 print(" Done!")
39 return name
40
41
42def main():
43
44 # Generate a random file
45 file_path = generate_file(1000 * 1000 * 40) # 40MB
46
47 # Instantiate file source
48 source = otacast.Source()
49
50 # The symbol bytes determine the size of the produced symbols.
51 # In most cases it makes sense to make this value fit the MTU size of the
52 # network.
53 symbol_bytes = 1350
54
55 # The width manages a tradeoff between code
56 # effectiveness and computational complexity.
57 # A higher width causes higher code effectiveness, but also a higher memory
58 # footprint and computational complexity.
59 width = otacast.CodecWidth._32
60
61 # You can either configure the source giving the specific width and
62 # symbol_bytes as seperate arguments, or gather them in a set.
63 source_config = {width, symbol_bytes}
64 source.configure(*source_config)
65 source.open(file_path)
66
67 output_directory = tempfile.mkdtemp(suffix="otacast.out")
68
69 # Instantiate file sink
70 sink = otacast.Sink()
71 sink.open(output_directory)
72
73 # We create a meta-packet containing the meta information the source shares
74 # with the sink
75 meta_packet = bytearray(otacast.Source.meta_packet_size(source))
76
77 # Source writes the meta packet to the meta packet buffer
78 otacast.Source.meta_packet_serialize(source, meta_packet)
79
80 # The sink unpacks the data into a dictionary
81 sink_config = otacast.Sink.meta_packet_deserialize(meta_packet)
82 if sink_config is None:
83 raise Exception("Could not deserialize meta packet")
84
85 sink.configure(**sink_config)
86
87 # This bytearray will contain the generated symbols.
88 symbol = bytearray(source.packet_size)
89
90 while not sink.is_complete():
91
92 # Generate an encoded packet
93 source.write_packet(symbol)
94 # Decode the encoded packet
95 sink.read_packet(symbol)
96
97 if filecmp.cmp(file_path, sink.output_file_path, shallow=False):
98 print("Decoding finished successfully!")
99 else:
100 print("Something went wrong!")
101
102 # Close source and sink
103 source.close()
104 sink.close()
105
106
107if __name__ == "__main__":
108 main()