diff --git a/src/auracast/server/multicast_server.py b/src/auracast/server/multicast_server.py index c1e644e..4cbd3b1 100644 --- a/src/auracast/server/multicast_server.py +++ b/src/auracast/server/multicast_server.py @@ -221,7 +221,7 @@ async def scan_audio_devices(): sd._initialize() # TODO: select this dynamically from pw-cli ls Node determine id - #os.environ["PIPEWIRE_NODE"] = "101" + #os.environ["PIPEWIRE_NODE"] = "76" devs = sd.query_devices() inputs = [ {"id": idx, "name": d["name"]} diff --git a/src/service/aes67/pipewire-aes67.conf b/src/service/aes67/pipewire-aes67.conf new file mode 100644 index 0000000..574a614 --- /dev/null +++ b/src/service/aes67/pipewire-aes67.conf @@ -0,0 +1,153 @@ +# AES67 config file for PipeWire version "1.2.7" # +# +# Copy and edit this file in /etc/pipewire for system-wide changes +# or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# /etc/pipewire/pipewire-aes67.conf.d/ for system-wide changes or in +# ~/.config/pipewire/pipewire-aes67.conf.d/ for local changes. +# + +context.properties = { + ## Configure properties in the system. + #mem.warn-mlock = false + #mem.allow-mlock = true + #mem.mlock-all = false + #log.level = 2 + + #default.clock.quantum-limit = 8192 +} + +context.spa-libs = { + support.* = support/libspa-support +} + +context.objects = [ + # An example clock reading from /dev/ptp0. You can also specify the network interface name, + # pipewire will query the interface for the current active PHC index. Another option is to + # sync the ptp clock to CLOCK_TAI and then set clock.id = tai, keep in mind that tai may + # also be synced by a NTP client. + # The precedence is: device, interface, id + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = PTP0-Driver + node.group = pipewire.ptp0 + # This driver should only be used for network nodes marked with group + priority.driver = 100000 + clock.name = "clock.system.ptp0" + ### Please select the PTP hardware clock here + # Interface name is the preferred method of specifying the PHC + clock.interface = "eth0" + #clock.device = "/dev/ptp0" + #clock.id = tai + # Lower this in case of periodic out-of-sync + resync.ms = 1.5 + object.export = true + } + } +] + +context.modules = [ + { name = libpipewire-module-rt + args = { + nice.level = -11 + #rt.prio = 83 + #rt.time.soft = -1 + #rt.time.hard = -1 + } + flags = [ ifexists nofail ] + } + { name = libpipewire-module-protocol-native } + { name = libpipewire-module-client-node } + { name = libpipewire-module-spa-node-factory } + { name = libpipewire-module-adapter } + { name = libpipewire-module-rtp-sap + args = { + ### Please select the interface here + local.ifname = eth0 + sap.ip = 239.255.255.255 + sap.port = 9875 + net.ttl = 32 + net.loop = false + # If you use another PTPv2 daemon supporting management + # messages over a UNIX socket, specify its path here + ptp.management-socket = "/var/run/ptp4lro" + + stream.rules = [ + { + matches = [ + { + rtp.session = "~.*" + } + ] + actions = { + create-stream = { + node.virtual = false + media.class = "Audio/Source" + device.api = aes67 + # You can adjust the latency buffering here. Use integer values only + sess.latency.msec = 50 + node.group = pipewire.ptp0 + } + } + }, + { + matches = [ + { + sess.sap.announce = true + } + ] + actions = { + announce-stream = {} + } + } + ] + } + }, + { name = libpipewire-module-rtp-sink + args = { + ### Please select the interface here + local.ifname = eth0 + ### If you want to create multiple output streams, please copy the whole + ### module-rtp-sink block, but change this multicast IP to another unused + ### one keeping 239.69.x.x range unless you know you need another one + destination.ip = 239.69.150.243 + destination.port = 5004 + net.mtu = 1280 + net.ttl = 32 + net.loop = false + # These should typically be equal + # You can customize packet length, but 1 ms should work for every device + # Consult receiver documentation to ensure it supports the value you set + sess.min-ptime = 1 + sess.max-ptime = 1 + ### Please change this, especially if you create multiple sinks + sess.name = "PipeWire RTP stream" + sess.media = "audio" + # This property is used if you aren't using ptp4l 4 + sess.ts-refclk = "ptp=traceable" + sess.ts-offset = 0 + # You can adjust the latency buffering here. Use integer values only + sess.latency.msec = 3 + audio.format = "S24BE" + audio.rate = 48000 + audio.channels = 2 + # These channel names will be visible both to applications and AES67 receivers + node.channel-names = ["CH1", "CH2"] + + stream.props = { + ### Please change the sink name, this is necessary when you create multiple sinks + node.name = "rtp-sink" + media.class = "Audio/Sink" + node.virtual = false + device.api = aes67 + sess.sap.announce = true + node.always-process = true + node.group = pipewire.ptp0 + rtp.ntp = 0 + rtp.fetch-ts-refclk = true + } + } + }, +] diff --git a/src/service/aes67/ptp_aes67_1.conf b/src/service/aes67/ptp_aes67_1.conf new file mode 100644 index 0000000..c4c1283 --- /dev/null +++ b/src/service/aes67/ptp_aes67_1.conf @@ -0,0 +1,19 @@ +[global] +priority1 255 +priority2 254 +# Lower = more likely to become Grandmaster. Keep the same on both for "either can be master". +domainNumber 0 +# Default domain +logSyncInterval -3 +# AES67 profile: Sync messages every 125ms +logAnnounceInterval 1 +# Announce messages every 2s (AES67 default) +logMinDelayReqInterval 0 +dscp_event 46 +# QoS for event messages +dscp_general 0 +# QoS for general messages +step_threshold 1 +# Fast convergence on time jumps + +tx_timestamp_timeout 20 \ No newline at end of file diff --git a/auracast-frontend.service b/src/service/auracast-frontend.service similarity index 100% rename from auracast-frontend.service rename to src/service/auracast-frontend.service diff --git a/auracast-server.service b/src/service/auracast-server.service similarity index 100% rename from auracast-server.service rename to src/service/auracast-server.service diff --git a/src/service/pipewire-aes67.service b/src/service/pipewire-aes67.service new file mode 100644 index 0000000..b800101 --- /dev/null +++ b/src/service/pipewire-aes67.service @@ -0,0 +1,11 @@ +[Unit] +Description=PipeWire AES67 Service +After=network.target + +[Service] +Type=simple +ExecStart=/usr/bin/pipewire-aes67 -c /home/caster/bumble-auracast/src/service/aes67/pipewire-aes67.conf +Restart=on-failure + +[Install] +WantedBy=default.target diff --git a/src/service/ptp_aes67.service b/src/service/ptp_aes67.service new file mode 100644 index 0000000..99097bf --- /dev/null +++ b/src/service/ptp_aes67.service @@ -0,0 +1,13 @@ +[Unit] +Description=PTP AES67 Service +After=network.target + +[Service] +Type=simple +ExecStart=/usr/sbin/ptp4l -i eth0 -f /home/caster/bumble-auracast/src/service/aes67/ptp_aes67_1.conf +Restart=on-failure +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target diff --git a/src/service/update_and_run_aes67.sh b/src/service/update_and_run_aes67.sh new file mode 100644 index 0000000..86eefa3 --- /dev/null +++ b/src/service/update_and_run_aes67.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -e + +# This script installs, enables, and restarts the AES67 services +# Requires sudo privileges + +# Copy system service file for ptp_aes67 +sudo cp /home/caster/bumble-auracast/src/service/ptp_aes67.service /etc/systemd/system/ptp_aes67.service + +# Copy user service file for pipewire-aes67 +mkdir -p /home/caster/.config/systemd/user +cp /home/caster/bumble-auracast/src/service/pipewire-aes67.service /home/caster/.config/systemd/user/pipewire-aes67.service + +# Reload systemd to recognize new/updated services +sudo systemctl daemon-reload +systemctl --user daemon-reload + +# Enable services to start on boot +sudo systemctl enable ptp_aes67.service +systemctl --user enable pipewire-aes67.service + +# Restart services +sudo systemctl restart ptp_aes67.service +systemctl --user restart pipewire-aes67.service + +echo "\n--- ptp_aes67.service status ---" +sudo systemctl status ptp_aes67.service --no-pager + +echo "\n--- pipewire-aes67.service status (user) ---" +systemctl --user status pipewire-aes67.service --no-pager + +echo "AES67 services updated, enabled, restarted, and status printed successfully."