Skip to content

Commit d89c241

Browse files
Bob HaddletonBob Haddleton
authored andcommitted
Add tcp support
1 parent d9a29a0 commit d89c241

12 files changed

Lines changed: 1220 additions & 0 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,6 @@ bin/
5858

5959
# PyBuilder
6060
target/
61+
62+
# PyCharm
63+
.idea/
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""Small example Asynchronous OSC TCP client
2+
3+
This program listens for incoming messages in one task, and
4+
sends 10 random values between 0.0 and 1.0 to the /filter address,
5+
waiting for 1 seconds between each value in a second task.
6+
"""
7+
import argparse
8+
import asyncio
9+
import random
10+
import sys
11+
12+
from pythonosc import tcp_client
13+
14+
15+
async def get_messages(client):
16+
async for msg in client.get_messages(60):
17+
print(msg)
18+
19+
20+
async def send_messages(client):
21+
for x in range(10):
22+
r = random.random()
23+
print(f"Sending /filter {r}")
24+
await client.send_message("/filter", r)
25+
await asyncio.sleep(1)
26+
27+
28+
async def init_main():
29+
parser = argparse.ArgumentParser()
30+
parser.add_argument("--ip", default="127.0.0.1",
31+
help="The ip of the OSC server")
32+
parser.add_argument("--port", type=int, default=5005,
33+
help="The port the OSC server is listening on")
34+
parser.add_argument("--mode", default="1.1",
35+
help="The OSC protocol version of the server (default is 1.1)")
36+
args = parser.parse_args()
37+
38+
async with tcp_client.AsyncSimpleTCPClient(args.ip, args.port, mode=args.mode) as client:
39+
async with asyncio.TaskGroup() as tg:
40+
tg.create_task(get_messages(client))
41+
tg.create_task(send_messages(client))
42+
43+
if sys.version_info >= (3, 7):
44+
asyncio.run(init_main())
45+
else:
46+
# TODO(python-upgrade): drop this once 3.6 is no longer supported
47+
event_loop = asyncio.get_event_loop()
48+
event_loop.run_until_complete(init_main())
49+
event_loop.close()

examples/async_tcp_server.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import argparse
2+
import asyncio
3+
import sys
4+
5+
from pythonosc.dispatcher import Dispatcher
6+
from pythonosc.osc_tcp_server import AsyncOSCTCPServer
7+
8+
9+
def filter_handler(address, *args):
10+
print(f"{address}: {args}")
11+
12+
13+
dispatcher = Dispatcher()
14+
dispatcher.map("/filter", filter_handler)
15+
16+
17+
async def loop():
18+
"""Example main loop that only runs for 10 iterations before finishing"""
19+
for i in range(10):
20+
print(f"Loop {i}")
21+
await asyncio.sleep(10)
22+
23+
24+
async def init_main():
25+
parser = argparse.ArgumentParser()
26+
parser.add_argument("--ip", default="127.0.0.1",
27+
help="The ip of the OSC server")
28+
parser.add_argument("--port", type=int, default=5005,
29+
help="The port the OSC server is listening on")
30+
parser.add_argument("--mode", default="1.1",
31+
help="The OSC protocol version of the server (default is 1.1)")
32+
args = parser.parse_args()
33+
34+
async with AsyncOSCTCPServer(args.ip, args.port, dispatcher, mode=args.mode) as server:
35+
async with asyncio.TaskGroup() as tg:
36+
tg.create_task(server.start())
37+
tg.create_task(loop())
38+
39+
40+
if sys.version_info >= (3, 7):
41+
asyncio.run(init_main())
42+
else:
43+
# TODO(python-upgrade): drop this once 3.6 is no longer supported
44+
event_loop = asyncio.get_event_loop()
45+
event_loop.run_until_complete(init_main())
46+
event_loop.close()

examples/simple_tcp_client.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Small example OSC client
2+
3+
This program sends 10 random values between 0.0 and 1.0 to the /filter address,
4+
and listens for incoming messages for 1 second between each value.
5+
"""
6+
import argparse
7+
import random
8+
9+
from pythonosc import tcp_client
10+
11+
if __name__ == "__main__":
12+
parser = argparse.ArgumentParser()
13+
parser.add_argument("--ip", default="127.0.0.1",
14+
help="The ip of the OSC server")
15+
parser.add_argument("--port", type=int, default=5005,
16+
help="The port the OSC server is listening on")
17+
parser.add_argument("--mode", default="1.1",
18+
help="The OSC protocol version of the server (default is 1.1)")
19+
args = parser.parse_args()
20+
21+
with tcp_client.SimpleTCPClient(args.ip, args.port, mode=args.mode) as client:
22+
for x in range(10):
23+
n = random.random()
24+
print(f"Sending /filter {n}")
25+
client.send_message("/filter", n)
26+
resp = client.get_messages(1)
27+
for r in resp:
28+
try:
29+
print(r)
30+
except Exception as e:
31+
print(f"oops {str(e)}: {r}")

examples/simple_tcp_server.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Small example OSC server
2+
3+
This program listens to the specified address and port, and prints some information about
4+
received packets.
5+
"""
6+
import argparse
7+
import math
8+
9+
from pythonosc import osc_tcp_server
10+
from pythonosc.dispatcher import Dispatcher
11+
12+
13+
def print_volume_handler(unused_addr, args, volume):
14+
print("[{0}] ~ {1}".format(args[0], volume))
15+
16+
17+
def print_compute_handler(unused_addr, args, volume):
18+
try:
19+
print("[{0}] ~ {1}".format(args[0], args[1](volume)))
20+
except ValueError:
21+
pass
22+
23+
24+
if __name__ == "__main__":
25+
parser = argparse.ArgumentParser()
26+
parser.add_argument("--ip",
27+
default="127.0.0.1", help="The ip to listen on")
28+
parser.add_argument("--port",
29+
type=int, default=5005, help="The port to listen on")
30+
parser.add_argument("--mode", default="1.1",
31+
help="The OSC protocol version of the server (default is 1.1)")
32+
33+
args = parser.parse_args()
34+
35+
dispatcher = Dispatcher()
36+
dispatcher.map("/filter", print)
37+
dispatcher.map("/volume", print_volume_handler, "Volume")
38+
dispatcher.map("/logvolume", print_compute_handler, "Log volume", math.log)
39+
40+
server = osc_tcp_server.ThreadingOSCTCPServer(
41+
(args.ip, args.port), dispatcher, mode=args.mode)
42+
print("Serving on {}".format(server.server_address))
43+
server.serve_forever()

pythonosc/osc_message.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ def __init__(self, dgram: bytes) -> None:
2222
self._parameters = [] # type: List[Any]
2323
self._parse_datagram()
2424

25+
def __str__(self):
26+
return f"{self.address} {' '.join(str(p) for p in self.params)}"
27+
2528
def _parse_datagram(self) -> None:
2629
try:
2730
self._address_regexp, index = osc_types.get_string(self._dgram, 0)

pythonosc/osc_message_builder.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Build OSC messages for client applications."""
2+
from typing import Iterable
23

34
from pythonosc import osc_message
45
from pythonosc.parsing import osc_types
@@ -195,3 +196,16 @@ def build(self) -> osc_message.OscMessage:
195196
return osc_message.OscMessage(dgram)
196197
except osc_types.BuildError as be:
197198
raise BuildError("Could not build the message: {}".format(be))
199+
200+
201+
def build_msg(address: str, value: ArgValue):
202+
builder = OscMessageBuilder(address=address)
203+
if value is None:
204+
values = []
205+
elif not isinstance(value, Iterable) or isinstance(value, (str, bytes)):
206+
values = [value]
207+
else:
208+
values = value
209+
for val in values:
210+
builder.add_arg(val)
211+
return builder.build()

0 commit comments

Comments
 (0)