Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An easier way to send and receive from the same port ? #165

Open
hoh opened this issue Dec 2, 2022 · 1 comment
Open

An easier way to send and receive from the same port ? #165

hoh opened this issue Dec 2, 2022 · 1 comment

Comments

@hoh
Copy link

hoh commented Dec 2, 2022

Some devices such as the Behringer XR12-XR16-XR18 are using a communication protocol that is compatible to standard OSC with MUSIC Group specific extensions (e.g. parameter enquiry, subscriptions). As detailed in the specification, OSC packets are received on UDP port 10024 and replies are sent back to the requester's IP/port.

The codes below allow to do just that, but they contain some complexity that would be better located inside the python-osc library.

1. Blocking server that sends and receives on the same UDP port

from typing import Optional, Union

from pythonosc.dispatcher import Dispatcher
from pythonosc.osc_message_builder import OscMessageBuilder
from pythonosc.osc_server import BlockingOSCUDPServer


def handler(*args, **kwargs):
    print("handler", args, kwargs)


dispatcher = Dispatcher()
dispatcher.set_default_handler(handler)


class OSCClientServer(BlockingOSCUDPServer):
    def __init__(self, address: str, dispatcher: Dispatcher):
        super().__init__(("", 0), dispatcher)
        self.xr_address = address

    def send_message(self, address: str, vals: Optional[Union[str, list]]):
        builder = OscMessageBuilder(address=address)
        vals = vals if vals is not None else []
        if not isinstance(vals, list):
            vals = [vals]
        for val in vals:
            builder.add_arg(val)
        msg = builder.build()
        self.socket.sendto(msg.dgram, self.xr_address)


server = OSCClientServer(("192.168.1.1", 10024), dispatcher)

import threading
thread = threading.Thread(target=server.serve_forever, args=tuple())
thread.start()

server.send_message("/info", None)

2. Asyncio server that sends and receives on the same UDP port

import asyncio
from typing import Optional, Union

from pythonosc.dispatcher import Dispatcher
from pythonosc.osc_message_builder import OscMessageBuilder
from pythonosc.osc_server import AsyncIOOSCUDPServer


def handler(*args, **kwargs):
    print("handler", args, kwargs)


dispatcher = Dispatcher()
dispatcher.set_default_handler(handler)


class OSCClientServer(AsyncIOOSCUDPServer):
    def __init__(self, address: str, dispatcher: Dispatcher):
        super().__init__(server_address=("0.0.0.0", 0), dispatcher=dispatcher, loop=asyncio.get_event_loop())
        self.xr_address = address

    def send_message(self, address: str, transport: asyncio.DatagramTransport, vals: Optional[Union[str, list]]):
        builder = OscMessageBuilder(address=address)
        vals = vals if vals is not None else []
        if not isinstance(vals, list):
            vals = [vals]
        for val in vals:
            builder.add_arg(val)
        msg = builder.build()
        transport.sendto(msg.dgram, self.xr_address)


async def main():
    server = OSCClientServer(("192.168.1.1", 10024), dispatcher)
    transport, protocol = await server.create_serve_endpoint()
    server.send_message("/info", transport, None)

    await asyncio.sleep(10)

asyncio.run(main())
@bobh66
Copy link
Contributor

bobh66 commented Aug 17, 2024

@hoh take a look at the changes merged in #173 released in 1.9.0 - it supports bi-directional communication on the same port.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants