rtpsynth 1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rtpsynth-1.0/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2018, Sippy Labs
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,3 @@
1
+ include setup/__init__.py setup/RunCTest.py
2
+ include src/rsth_timeops.h src/rtp.h src/rtp_info.h src/rtpjbuf.h src/rtpsynth.h src/Symbol.map
3
+ include README.md
rtpsynth-1.0/PKG-INFO ADDED
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.1
2
+ Name: rtpsynth
3
+ Version: 1.0
4
+ Summary: Library optimized to generate/process sequence of the RTP packets
5
+ Home-page: https://github.com/sippy/librtpsynth.git
6
+ Author: Maksym Sobolyev
7
+ Author-email: sobomax@gmail.com
8
+ Classifier: License :: OSI Approved :: BSD License
9
+ Classifier: Operating System :: POSIX
10
+ Classifier: Programming Language :: C
11
+ Classifier: Programming Language :: Python
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+
15
+ # librtpsynth
16
+
17
+ Low-level library optimized to generate and/or consume sequence of the RTP
18
+ packets. Based on some code and ideas from the RTPProxy projects.
19
+
20
+ Originally designed to supplement Python code to do low-level bits shuffling
21
+ for the proof of concept IoT implementation.
22
+
23
+ Reasonably fast, 100-200x real-time (i.e. 100-200K packets per second) when
24
+ used from the Python code. 100x of that (10-20M PPS) if used from C code
25
+ directly.
26
+
27
+ ## RTP Generation
28
+
29
+ Generate continuous sequence of RTP packets of the same payload type.
30
+
31
+ ### C API Functions
32
+
33
+ `#include <rtpsynth.h>`
34
+
35
+ - `void *rsynth_ctor(int srate, int ptime);`
36
+ Initializes the RTP synthesizer with given sample rate and packet time.
37
+ Returns a handle to be used in other calls.
38
+
39
+ - `void *rsynth_next_pkt(void *ri, int plen, int pt);`
40
+ Generates the next RTP packet. Takes the handle, packet length, and
41
+ payload type as parameters. Returns a pointer to the generated packet.
42
+
43
+ - `int rsynth_next_pkt_pa(void *ri, int plen, int pt, char *buf, unsigned int blen, int pa);`
44
+ Similar to `rsynth_next_pkt` but allows pre-allocated buffer and packet
45
+ attributes. Returns the length of the packet generated.
46
+
47
+ - `void rsynth_pkt_free(void *rnp);`
48
+ Frees the allocated packet. Takes a pointer to the packet as parameter.
49
+
50
+ - `void rsynth_dtor(void *ri);`
51
+ Destroys the RTP synthesizer and frees resources. Takes the handle as
52
+ parameter.
53
+
54
+ - `unsigned int rsynth_set_mbt(void *ri, unsigned int new_st);`
55
+ Sets a new marker bit toggle state. Takes the handle and the new state
56
+ as parameters. Returns the old state.
57
+
58
+ - `void rsynth_resync(void *ri, struct rsynth_seq *rsp);`
59
+ Resynchronizes the RTP packet sequence. Takes the handle and optionally
60
+ a sequence structure as parameters. Use this function when a time
61
+ discontinuity is expected in packet generation, such as when VAD (Voice
62
+ Activity Detection) is active. The library will recalculate the timestamp
63
+ for the next packet based on the current system clock and the time the
64
+ last packet was generated.
65
+
66
+ ### RtpGen (Python)
67
+
68
+ ## RTP Parser & Validator / Jitter Buffer
69
+
70
+ Simple RTP parser and validator to process incoming UDP datagrams,
71
+ parse & validate RTP headers. Resulting RTP stream is passed through
72
+ fixed-size jitter buffer to de-duplicate and re-order packets if
73
+ needed.
74
+
75
+ ### rtpjbuf (c)
76
+
77
+ ### RtpJBuf (Python)
rtpsynth-1.0/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # librtpsynth
2
+
3
+ Low-level library optimized to generate and/or consume sequence of the RTP
4
+ packets. Based on some code and ideas from the RTPProxy projects.
5
+
6
+ Originally designed to supplement Python code to do low-level bits shuffling
7
+ for the proof of concept IoT implementation.
8
+
9
+ Reasonably fast, 100-200x real-time (i.e. 100-200K packets per second) when
10
+ used from the Python code. 100x of that (10-20M PPS) if used from C code
11
+ directly.
12
+
13
+ ## RTP Generation
14
+
15
+ Generate continuous sequence of RTP packets of the same payload type.
16
+
17
+ ### C API Functions
18
+
19
+ `#include <rtpsynth.h>`
20
+
21
+ - `void *rsynth_ctor(int srate, int ptime);`
22
+ Initializes the RTP synthesizer with given sample rate and packet time.
23
+ Returns a handle to be used in other calls.
24
+
25
+ - `void *rsynth_next_pkt(void *ri, int plen, int pt);`
26
+ Generates the next RTP packet. Takes the handle, packet length, and
27
+ payload type as parameters. Returns a pointer to the generated packet.
28
+
29
+ - `int rsynth_next_pkt_pa(void *ri, int plen, int pt, char *buf, unsigned int blen, int pa);`
30
+ Similar to `rsynth_next_pkt` but allows pre-allocated buffer and packet
31
+ attributes. Returns the length of the packet generated.
32
+
33
+ - `void rsynth_pkt_free(void *rnp);`
34
+ Frees the allocated packet. Takes a pointer to the packet as parameter.
35
+
36
+ - `void rsynth_dtor(void *ri);`
37
+ Destroys the RTP synthesizer and frees resources. Takes the handle as
38
+ parameter.
39
+
40
+ - `unsigned int rsynth_set_mbt(void *ri, unsigned int new_st);`
41
+ Sets a new marker bit toggle state. Takes the handle and the new state
42
+ as parameters. Returns the old state.
43
+
44
+ - `void rsynth_resync(void *ri, struct rsynth_seq *rsp);`
45
+ Resynchronizes the RTP packet sequence. Takes the handle and optionally
46
+ a sequence structure as parameters. Use this function when a time
47
+ discontinuity is expected in packet generation, such as when VAD (Voice
48
+ Activity Detection) is active. The library will recalculate the timestamp
49
+ for the next packet based on the current system clock and the time the
50
+ last packet was generated.
51
+
52
+ ### RtpGen (Python)
53
+
54
+ ## RTP Parser & Validator / Jitter Buffer
55
+
56
+ Simple RTP parser and validator to process incoming UDP datagrams,
57
+ parse & validate RTP headers. Resulting RTP stream is passed through
58
+ fixed-size jitter buffer to de-duplicate and re-order packets if
59
+ needed.
60
+
61
+ ### rtpjbuf (c)
62
+
63
+ ### RtpJBuf (Python)
@@ -0,0 +1,162 @@
1
+ from ctypes import c_void_p, c_int, c_size_t, c_uint32, c_uint16, c_uint64, \
2
+ POINTER, Union, Structure, create_string_buffer, addressof, string_at, cast
3
+
4
+ from .RtpSynth import _rsth
5
+
6
+ class RTPInfo(Structure):
7
+ _fields_ = [
8
+ ("data_size", c_size_t),
9
+ ("data_offset", c_int),
10
+ ("nsamples", c_int),
11
+ ("ts", c_uint32),
12
+ ("seq", c_uint16),
13
+ ("ssrc", c_uint32),
14
+ ("appendable", c_int),
15
+ ("rtp_profile", c_void_p) # replace with actual type
16
+ ]
17
+
18
+ class RTPPacket(Structure):
19
+ _fields_ = [
20
+ ("info", RTPInfo),
21
+ ("lseq", c_uint64),
22
+ ("data", c_void_p)
23
+ ]
24
+
25
+ class ERSFrame(Structure):
26
+ _fields_ = [
27
+ ("lseq_start", c_uint64),
28
+ ("lseq_end", c_uint64),
29
+ ("ts_diff", c_uint32),
30
+ ]
31
+
32
+ class RTPFrameType():
33
+ RTP = 0
34
+ ERS = 1
35
+
36
+ class RTPFrameUnion(Union):
37
+ _fields_ = [
38
+ ("rtp", RTPPacket),
39
+ ("ers", ERSFrame)
40
+ ]
41
+
42
+ class RTPFrame(Structure):
43
+ pass
44
+
45
+ RTPFrame._fields_ = [
46
+ ("type", c_int),
47
+ ("frame", RTPFrameUnion),
48
+ ("next", POINTER(RTPFrame))
49
+ ]
50
+
51
+ class RJBUdpInR(Structure):
52
+ _fields_ = [
53
+ ("error", c_int),
54
+ ("ready", POINTER(RTPFrame)),
55
+ ("drop", POINTER(RTPFrame)),
56
+ ]
57
+
58
+ _rsth.rtpjbuf_ctor.argtypes = [c_int]
59
+ _rsth.rtpjbuf_ctor.restype = c_void_p
60
+ _rsth.rtpjbuf_dtor.argtypes = [c_void_p,]
61
+ _rsth.rtpjbuf_frame_dtor.argtypes = [c_void_p,]
62
+ _rsth.rtpjbuf_udp_in.argtypes = [c_void_p, c_void_p, c_size_t]
63
+ _rsth.rtpjbuf_udp_in.restype = RJBUdpInR
64
+ _rsth.rtpjbuf_flush.argtypes = [c_void_p]
65
+ _rsth.rtpjbuf_flush.restype = RJBUdpInR
66
+
67
+ class ERSFrame():
68
+ lseq_start: int
69
+ lseq_end: int
70
+ ts_diff: int
71
+ type = RTPFrameType.ERS
72
+
73
+ def __init__(self, content):
74
+ self.lseq_start = content.frame.ers.lseq_start
75
+ self.lseq_end = content.frame.ers.lseq_end
76
+ self.ts_diff = content.frame.ers.ts_diff
77
+
78
+ class RTPParseError(Exception):
79
+ pass
80
+
81
+ class FrameWrapper():
82
+ _rsth = None
83
+ content = None
84
+ data = None
85
+ rtp_data: bytes
86
+
87
+ def __init__(self, _rsth, content: RTPFrame, data):
88
+ self._rsth = _rsth
89
+ if content.type == RTPFrameType.ERS:
90
+ self.content = ERSFrame(content)
91
+ else:
92
+ self.content = content
93
+ rtp_data = cast(content.frame.rtp.data + content.frame.rtp.info.data_offset, c_void_p)
94
+ self.rtp_data = string_at(rtp_data, content.frame.rtp.info.data_size)
95
+ self.data = data
96
+
97
+ def __del__(self):
98
+ if self.content.type == RTPFrameType.RTP:
99
+ self._rsth.rtpjbuf_frame_dtor(addressof(self.content))
100
+
101
+ def __str__(self):
102
+ if self.content.type == RTPFrameType.RTP:
103
+ return f'RTP_Frame(seq={self.content.frame.rtp.lseq})'
104
+ return f'RTP_Erasure(seq_range={self.content.lseq_start} ' + \
105
+ f'-- {self.content.lseq_end})'
106
+
107
+ def __repr__(self):
108
+ return self.__str__()
109
+
110
+ RTP_PARSER_OK = 1
111
+
112
+ class RtpJBuf(object):
113
+ _hndl = None
114
+ _rsth = None
115
+ _ref_cache = None
116
+
117
+ def __init__(self, capacity):
118
+ self._rsth = _rsth
119
+ self._hndl = self._rsth.rtpjbuf_ctor(capacity)
120
+ if not bool(self._hndl):
121
+ raise Exception('rtpjbuf_ctor() failed')
122
+ self._ref_cache = {}
123
+
124
+ def udp_in(self, data):
125
+ buffer = create_string_buffer(data)
126
+ size = len(data)
127
+ rval = self._rsth.rtpjbuf_udp_in(self._hndl, buffer, size)
128
+ return self._proc_RJBUdpInR(rval, (buffer, data))
129
+
130
+ def _proc_RJBUdpInR(self, rval, bdata = None):
131
+ if rval.error != 0:
132
+ if rval.error < RTP_PARSER_OK:
133
+ raise RTPParseError(f'rtpjbuf_udp_in(): error {rval.error}')
134
+ raise RuntimeError(f'rtpjbuf_udp_in(): error {rval.error}')
135
+ if bdata is not None:
136
+ self._ref_cache[addressof(bdata[0])] = bdata
137
+ ready = []
138
+ for i, bucket in enumerate((rval.ready, rval.drop)):
139
+ while bool(bucket):
140
+ current = bucket.contents
141
+ if current.type == RTPFrameType.RTP:
142
+ buffer, data = self._ref_cache.pop(current.frame.rtp.data)
143
+ else:
144
+ data = None
145
+ if i == 0:
146
+ ready.append(FrameWrapper(self._rsth, current, data))
147
+ else:
148
+ assert current.type == RTPFrameType.RTP
149
+ self._rsth.rtpjbuf_frame_dtor(addressof(current))
150
+ #print(current.frame.rtp.data, addressof(buffer))
151
+ bucket = current.next
152
+ return ready
153
+
154
+ def flush(self):
155
+ rval = self._rsth.rtpjbuf_flush(self._hndl)
156
+ rval = self._proc_RJBUdpInR(rval)
157
+ assert len(self._ref_cache.keys()) == 0
158
+ return rval
159
+
160
+ def __del__(self):
161
+ if bool(self._hndl):
162
+ self._rsth.rtpjbuf_dtor(self._hndl)
@@ -0,0 +1,118 @@
1
+ # Copyright (c) 2018 Sippy Software, Inc. All rights reserved.
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # * Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ #
9
+ # * Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ #
13
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ from ctypes import cdll, c_void_p, c_int, create_string_buffer, c_uint
25
+ from math import modf
26
+ import sys, os, site, sysconfig
27
+
28
+ from .env import RSTH_MOD_NAME
29
+
30
+ _esuf = sysconfig.get_config_var('EXT_SUFFIX')
31
+ if not _esuf:
32
+ _esuf = '.so'
33
+ try:
34
+ import pathlib
35
+ _ROOT = str(pathlib.Path(__file__).parent.absolute())
36
+ except ImportError:
37
+ _ROOT = os.path.abspath(os.path.dirname(__file__))
38
+ #print('ROOT: ' + str(_ROOT))
39
+ modloc = site.getsitepackages()
40
+ modloc.insert(0, os.path.join(_ROOT, ".."))
41
+ for p in modloc:
42
+ try:
43
+ #print("Trying %s" % os.path.join(p, RSTH_MOD_NAME + _esuf))
44
+ _rsth = cdll.LoadLibrary(os.path.join(p, RSTH_MOD_NAME + _esuf))
45
+ except:
46
+ continue
47
+ break
48
+ else:
49
+ _rsth = cdll.LoadLibrary('librtpsynth.so')
50
+
51
+ _rsth.rsynth_ctor.argtypes = [c_int, c_int]
52
+ _rsth.rsynth_ctor.restype = c_void_p
53
+ _rsth.rsynth_dtor.argtypes = [c_void_p,]
54
+ _rsth.rsynth_next_pkt.restype = c_void_p
55
+ _rsth.rsynth_next_pkt.argtypes = [c_void_p, c_int, c_int]
56
+ _rsth.rsynth_next_pkt_pa.restype = c_int
57
+ _rsth.rsynth_next_pkt_pa.argtypes = [c_void_p, c_int, c_int, c_void_p, c_uint, c_int]
58
+ _rsth.rsynth_set_mbt.argtypes = [c_void_p, c_uint]
59
+ _rsth.rsynth_set_mbt.restype = c_uint
60
+ _rsth.rsynth_resync.argtypes = [c_void_p, c_void_p]
61
+ _rsth.rsynth_skip.argtypes = [c_void_p, c_int]
62
+
63
+ _rsth.rsynth_pkt_free.argtypes = [c_void_p,]
64
+
65
+
66
+ class RtpSynth(object):
67
+ _hndl = None
68
+ _rsth = None
69
+
70
+ def __init__(self, srate, ptime):
71
+ self._rsth = _rsth
72
+ self._hndl = self._rsth.rsynth_ctor(srate, ptime)
73
+ if not bool(self._hndl):
74
+ raise Exception('rsynth_ctor() failed')
75
+
76
+ def next_pkt(self, plen, pt, pload = None):
77
+ pktlen = plen + 32
78
+ if pload != None:
79
+ pkt = create_string_buffer(pload, pktlen)
80
+ filled = 1
81
+ else:
82
+ pkt = create_string_buffer(pktlen)
83
+ filled = 0
84
+ plen = self._rsth.rsynth_next_pkt_pa(self._hndl, plen, pt, pkt, pktlen, filled)
85
+ return (pkt.raw[:plen])
86
+
87
+ def pkt_free(self, pkt):
88
+ self._rsth.rsynth_pkt_free(pkt)
89
+
90
+ def set_mbt(self, mbt):
91
+ return self._rsth.rsynth_set_mbt(self._hndl, mbt)
92
+
93
+ def resync(self):
94
+ self._rsth.rsynth_resync(self._hndl, None)
95
+
96
+ def skip(self, n):
97
+ self._rsth.rsynth_skip(self._hndl, n)
98
+
99
+ def __del__(self):
100
+ if bool(self._hndl):
101
+ self._rsth.rsynth_dtor(self._hndl)
102
+
103
+ if __name__ == '__main__':
104
+ from time import monotonic
105
+ i = 0
106
+ rs = RtpSynth(8000, 30)
107
+ stime = monotonic()
108
+ while monotonic() - stime < 5.0:
109
+ if i % 43 == 0:
110
+ rs.resync()
111
+ rp = rs.next_pkt(170, 0)
112
+ i += 1
113
+ if i % 4242 == 0:
114
+ res = rs.set_mbt(1)
115
+ assert res == 0
116
+ res = rs.set_mbt(0)
117
+ assert res == 1
118
+ del rs
File without changes
@@ -0,0 +1,24 @@
1
+ # Copyright (c) 2023 Sippy Software, Inc. All rights reserved.
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # * Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ #
9
+ # * Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ #
13
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ RSTH_MOD_NAME = '_rtpsynth'
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.1
2
+ Name: rtpsynth
3
+ Version: 1.0
4
+ Summary: Library optimized to generate/process sequence of the RTP packets
5
+ Home-page: https://github.com/sippy/librtpsynth.git
6
+ Author: Maksym Sobolyev
7
+ Author-email: sobomax@gmail.com
8
+ Classifier: License :: OSI Approved :: BSD License
9
+ Classifier: Operating System :: POSIX
10
+ Classifier: Programming Language :: C
11
+ Classifier: Programming Language :: Python
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+
15
+ # librtpsynth
16
+
17
+ Low-level library optimized to generate and/or consume sequence of the RTP
18
+ packets. Based on some code and ideas from the RTPProxy projects.
19
+
20
+ Originally designed to supplement Python code to do low-level bits shuffling
21
+ for the proof of concept IoT implementation.
22
+
23
+ Reasonably fast, 100-200x real-time (i.e. 100-200K packets per second) when
24
+ used from the Python code. 100x of that (10-20M PPS) if used from C code
25
+ directly.
26
+
27
+ ## RTP Generation
28
+
29
+ Generate continuous sequence of RTP packets of the same payload type.
30
+
31
+ ### C API Functions
32
+
33
+ `#include <rtpsynth.h>`
34
+
35
+ - `void *rsynth_ctor(int srate, int ptime);`
36
+ Initializes the RTP synthesizer with given sample rate and packet time.
37
+ Returns a handle to be used in other calls.
38
+
39
+ - `void *rsynth_next_pkt(void *ri, int plen, int pt);`
40
+ Generates the next RTP packet. Takes the handle, packet length, and
41
+ payload type as parameters. Returns a pointer to the generated packet.
42
+
43
+ - `int rsynth_next_pkt_pa(void *ri, int plen, int pt, char *buf, unsigned int blen, int pa);`
44
+ Similar to `rsynth_next_pkt` but allows pre-allocated buffer and packet
45
+ attributes. Returns the length of the packet generated.
46
+
47
+ - `void rsynth_pkt_free(void *rnp);`
48
+ Frees the allocated packet. Takes a pointer to the packet as parameter.
49
+
50
+ - `void rsynth_dtor(void *ri);`
51
+ Destroys the RTP synthesizer and frees resources. Takes the handle as
52
+ parameter.
53
+
54
+ - `unsigned int rsynth_set_mbt(void *ri, unsigned int new_st);`
55
+ Sets a new marker bit toggle state. Takes the handle and the new state
56
+ as parameters. Returns the old state.
57
+
58
+ - `void rsynth_resync(void *ri, struct rsynth_seq *rsp);`
59
+ Resynchronizes the RTP packet sequence. Takes the handle and optionally
60
+ a sequence structure as parameters. Use this function when a time
61
+ discontinuity is expected in packet generation, such as when VAD (Voice
62
+ Activity Detection) is active. The library will recalculate the timestamp
63
+ for the next packet based on the current system clock and the time the
64
+ last packet was generated.
65
+
66
+ ### RtpGen (Python)
67
+
68
+ ## RTP Parser & Validator / Jitter Buffer
69
+
70
+ Simple RTP parser and validator to process incoming UDP datagrams,
71
+ parse & validate RTP headers. Resulting RTP stream is passed through
72
+ fixed-size jitter buffer to de-duplicate and re-order packets if
73
+ needed.
74
+
75
+ ### rtpjbuf (c)
76
+
77
+ ### RtpJBuf (Python)
@@ -0,0 +1,24 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ setup.py
5
+ python/RtpJBuf.py
6
+ python/RtpSynth.py
7
+ python/__init__.py
8
+ python/env.py
9
+ rtpsynth.egg-info/PKG-INFO
10
+ rtpsynth.egg-info/SOURCES.txt
11
+ rtpsynth.egg-info/dependency_links.txt
12
+ rtpsynth.egg-info/top_level.txt
13
+ setup/RunCTest.py
14
+ setup/__init__.py
15
+ src/Symbol.map
16
+ src/rsth_timeops.h
17
+ src/rtp.c
18
+ src/rtp.h
19
+ src/rtp_info.h
20
+ src/rtpjbuf.c
21
+ src/rtpjbuf.h
22
+ src/rtpsynth.c
23
+ src/rtpsynth.h
24
+ tests/test_jbuf.py
@@ -0,0 +1,2 @@
1
+ _rtpsynth
2
+ rtpsynth
@@ -0,0 +1,27 @@
1
+ from distutils.core import Command
2
+
3
+ class RunCTest(Command):
4
+ description = "Run C test"
5
+ user_options = []
6
+ extra_compile_args = []
7
+ extra_link_args = []
8
+
9
+ def initialize_options(self):
10
+ pass
11
+
12
+ def finalize_options(self):
13
+ pass
14
+
15
+ def run(self):
16
+ from distutils.ccompiler import new_compiler
17
+ import distutils.sysconfig as sysconfig
18
+
19
+ compiler = new_compiler()
20
+
21
+ # Compile and link
22
+ obj_files = compiler.compile(['src/rtpsynth.c', 'tests/test_synth.c'],
23
+ extra_preargs=self.extra_compile_args + ['-Isrc',])
24
+ compiler.link_executable(obj_files, 'build/test_synth', extra_postargs=self.extra_link_args)
25
+
26
+ import subprocess
27
+ subprocess.run(['./build/test_synth'])
File without changes
rtpsynth-1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
rtpsynth-1.0/setup.py ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env python
2
+
3
+ import os
4
+
5
+ from distutils.core import setup
6
+ from distutils.core import Extension
7
+
8
+ from python.env import RSTH_MOD_NAME
9
+ from setup.RunCTest import RunCTest
10
+
11
+ rs_srcs = ['src/rtpsynth.c', 'src/rtp.c', 'src/rtpjbuf.c']
12
+
13
+ extra_compile_args = ['--std=c11', '-Wno-zero-length-array', '-Wall', '-pedantic', '-flto']
14
+ extra_link_args = ['-flto']
15
+ debug_opts = (('-g3', '-O0'))
16
+ nodebug_opts = (('-march=native', '-O3'))
17
+ if False:
18
+ extra_compile_args.extend(debug_opts)
19
+ extra_link_args.extend(debug_opts)
20
+ else:
21
+ extra_compile_args.extend(nodebug_opts)
22
+ extra_link_args.extend(nodebug_opts)
23
+
24
+ module1 = Extension(RSTH_MOD_NAME, sources = rs_srcs, \
25
+ extra_link_args = extra_link_args, \
26
+ extra_compile_args = extra_compile_args)
27
+
28
+ RunCTest.extra_link_args = extra_link_args.copy()
29
+ RunCTest.extra_compile_args = extra_compile_args
30
+
31
+ extra_link_args.append('-Wl,--version-script=src/Symbol.map')
32
+
33
+ def get_ex_mod():
34
+ if 'NO_PY_EXT' in os.environ:
35
+ return None
36
+ return [module1]
37
+
38
+ with open("README.md", "r") as fh:
39
+ long_description = fh.read()
40
+
41
+ kwargs = {'name':'rtpsynth',
42
+ 'version':'1.0',
43
+ 'description':'Library optimized to generate/process sequence of the RTP packets',
44
+ 'long_description': long_description,
45
+ 'long_description_content_type': "text/markdown",
46
+ 'author':'Maksym Sobolyev',
47
+ 'author_email':'sobomax@gmail.com',
48
+ 'url':'https://github.com/sippy/librtpsynth.git',
49
+ 'packages':['rtpsynth',],
50
+ 'package_dir':{'rtpsynth':'python'},
51
+ 'ext_modules': get_ex_mod(),
52
+ 'cmdclass': {'runctest': RunCTest},
53
+ 'classifiers': [
54
+ 'License :: OSI Approved :: BSD License',
55
+ 'Operating System :: POSIX',
56
+ 'Programming Language :: C',
57
+ 'Programming Language :: Python'
58
+ ]
59
+ }
60
+
61
+ if __name__ == '__main__':
62
+ setup(**kwargs)