iPad + Mac: TouchOSC via USB cable

This gave me an idea: Instead of juggling IP addresses, the devices get assigned names via Bonjour. You can check this either on the command line via dns-sd or using a nice GUI like Discovery.app:

Critically, you can see domain names here: My iPad is iLeiner-Pro.local and my Mac is Simons-MacBook-Pro-4.local. So we can use these domain names instead of hardcoding IP addresses. I have modified my script to do so.

The modified script (a.k.a. OSCmux)
#!/bin/bash

# oscmux: Set up a UDP packet proxy between a local IPv4-only application and a
# partner on the network.
# (c) 2023 Simon Leiner, licensed under the MIT license

set -eu

PARTNER_HOST="iLeiner-Pro.local"
PARTNER_PORT_RX=54346
PARTNER_PORT_TX=54347 # We bind to this port. If this is the same as
#                       LOCAL_PORT_RX, there might be conflicts.

LOCAL_PORT_RX=54345
LOCAL_PORT_TX=$PARTNER_PORT_RX

################################################################################
# Helper functions

function log_prefix() {
    name=$1

    expr=$(printf 's/^/%-6s |> /' "$name")
    sed -u -e "$expr"
}

function resolve_partner_ip() {
    name=$1

    cache_results=$(dscacheutil -q host -a name "$name")
    ip_address_line=$(echo "$cache_results" | grep -e "ipv6_address:" -e "ip_address:" | head -n 1)
    ip_address=$(echo "$ip_address_line" | awk -F ': ' '{print $2}')

    if echo "$ip_address_line" | grep -e "^ipv6" >/dev/null; then
        ip_version=6
        ip_address_wrapped="[$ip_address]"
    else
        ip_version=4
        ip_address_wrapped="$ip_address"
    fi

    echo "$ip_address;$ip_address_wrapped;$ip_version"
}

function ping_ip() {
    ip_version=$1
    shift

    if [ "$ip_version" -eq 6 ]; then
        ping6 "$@"
    else
        ping "$@"
    fi
}

################################################################################
# Proxy setup

# Ensure that all child processes are terminated when the script terminates
trap "echo && echo && echo '🛑 Shutting down...' && trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

# Resolve hostname
IFS=";" read PARTNER_IP PARTNER_IP_WRAPPED PARTNER_IP_VERSION < <(resolve_partner_ip $PARTNER_HOST)
echo "✅ Found partner $PARTNER_HOST on IPv$PARTNER_IP_VERSION address $PARTNER_IP"

# Check connection initially
if ping_ip "$PARTNER_IP_VERSION" "$PARTNER_IP" -c 1 >/dev/null; then
    echo "✅ Confirmed a connection to $PARTNER_IP via ping"
else
    echo "❌ Failed to ping $PARTNER_IP" >/dev/stderr
    exit 1
fi

echo ""

echo "➡️  Forwarding 127.0.0.1:$LOCAL_PORT_TX -> $PARTNER_IP_WRAPPED:$PARTNER_PORT_RX..."
socat -d -s UDP-RECV:$LOCAL_PORT_TX,reuseaddr "UDP-SENDTO:$PARTNER_IP_WRAPPED:$PARTNER_PORT_RX" &

echo "➡️  Forwarding *:$PARTNER_PORT_TX -> 127.0.0.1:$LOCAL_PORT_RX..."
socat -d -s UDP-RECV:$PARTNER_PORT_TX,reuseaddr "UDP-SENDTO:127.0.0.1:$LOCAL_PORT_RX" &

echo "➡️  Advertising OSCmux via Bonjour"
dns-sd -R OSCmux _osc._udp . $PARTNER_PORT_TX | log_prefix "dns-sd" &

################################################################################
# Regular operation

sleep 1 # not strictly needed, but it improves log layout since after the delay,
#         dns-sd should have written all its output
echo "➡️  Continuously pinging partner to show connection status..."
ping_ip "$PARTNER_IP_VERSION" "$PARTNER_IP" | awk '(NR>1); fflush()' | log_prefix "ping"

Summary of the setup

The principle has not changed very much: It’s just no hardcoded IP addresses anymore (except for 127.0.0.1, fine) and the UDP communication between socat/OSCmux and iPad may use either IPv4 or IPv6.

Principle

TouchOSC settings


Note that the Host value is not an IP address, but a host name. You will not get this through the Browse button, so you will need to enter this manually through the keyboard.

Gig Performer OSC settings

Why is this an improvement

  1. No need for fiddling with IP addresses anymore :raised_hands:
  2. Notably, this will work over any connection (be it your home WiFi, another stage WiFi, a direct USB connection). Any network connection works (so long as it does not suppress Bonjour).
  3. You do not need to modify these settings after reboots any more (but you do if you rename your devices).
  4. In my testing so far, it was really stable.

It’s still not perfect though

Both iPad (i.e. TouchOSC) and Mac (i.e. OSCmux) look up the other side’s IP address on application start. If it changes (e.g. because you disconnect your Home WiFi and connect via USB instead - or even getting a different DHCP lease for some reason), you need to restart both. Apple’s framework are actually able to give an application “push updates” about the IPs under which a device is available, but TouchOSC does not use it, so OSCmux doesn’t either (that would also be the point where I would strongly consider using a “real” programming language instead of shell scripting).

3 Likes