Initial commit of ZonePlayer

This commit is contained in:
Media
2025-06-28 01:05:35 -05:00
commit 2c188140b0
5486 changed files with 940469 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
import yaml
import paho.mqtt.client as mqtt # type: ignore
from paho.mqtt.client import Client # type: ignore
import jack # type: ignore
import time
client_jack = jack.Client("router")
with open("config.yaml", "r") as f:
config = yaml.safe_load(f)
zones = config.get("zones", {})
sources = config.get("sources", {})
DEFAULT_SOURCE = "worship"
print("Zones loaded:", zones.keys())
print("Sources loaded:", sources.keys())
def fade_transition(source_left, source_right, zone_left, zone_right):
# Disconnect all existing connections to zone inputs
for dest_port in (zone_left, zone_right):
for conn in client_jack.get_all_connections(dest_port):
client_jack.disconnect(conn.name, dest_port)
print(f"Disconnected {conn.name} → {dest_port}")
# Connect new source to zone inputs
for src_port, dest_port in zip((source_left, source_right), (zone_left, zone_right)):
client_jack.connect(src_port, dest_port)
print(f"Connected {src_port} → {dest_port}")
def wait_for_available_zone_ports():
print("Checking which zone destination ports are currently active...")
active_zones = {}
for zone_name, zone_ports in zones.items():
try:
client_jack.get_port_by_name(zone_ports["left"])
client_jack.get_port_by_name(zone_ports["right"])
active_zones[zone_name] = zone_ports
print(f"✔️ Zone '{zone_name}' ports are active.")
except jack.JackError:
print(f"⚠️ Skipping zone '{zone_name}' — ports not available yet.")
return active_zones
def apply_default_connections(active_zones):
for zone_name, zone_ports in active_zones.items():
if DEFAULT_SOURCE not in sources:
print(f"Default source '{DEFAULT_SOURCE}' not found. Skipping.")
continue
src_l = sources[DEFAULT_SOURCE]["left"]
src_r = sources[DEFAULT_SOURCE]["right"]
dst_l = zone_ports["left"]
dst_r = zone_ports["right"]
try:
existing = client_jack.get_all_connections(dst_l)
if not existing:
fade_transition(src_l, src_r, dst_l, dst_r)
print(f"Default connection: {DEFAULT_SOURCE} → {zone_name}")
else:
print(f"{zone_name} already connected — skipping default.")
except jack.JackError as e:
print(f"Error checking/connecting {zone_name}: {e}")
def on_connect(client, userdata, flags, rc):
print("Connected with result code", rc)
for zone in zones:
topic = f"music/{zone}"
client.subscribe(topic)
print(f"subscribed to {topic}")
time.sleep(1)
active_zones = wait_for_available_zone_ports()
apply_default_connections(active_zones)
def on_message(client, userdata, msg):
zone = msg.topic.split("/")[-1]
source = msg.payload.decode()
print(f"Message received: Zone={zone}, Source={source}")
if zone not in zones:
print(f"❌ Invalid zone: {zone}")
return
if source not in sources:
print(f"❌ Invalid source: {source}")
return
try:
zone_left = zones[zone]["left"]
zone_right = zones[zone]["right"]
source_left = sources[source]["left"]
source_right = sources[source]["right"]
# Check if source ports exist
client_jack.get_port_by_name(source_left)
client_jack.get_port_by_name(source_right)
# Check current connection on zone left
current = None
conns = client_jack.get_all_connections(zone_left)
if conns:
current = conns[0].name.split(":")[0]
if current != source_left:
print(f"🔄 Switching {zone} from {current} to {source}")
fade_transition(source_left, source_right, zone_left, zone_right)
else:
print(f"✅ {zone} already connected to {source}")
except jack.JackError as e:
print(f"⚠️ JACK error for zone '{zone}' or source '{source}': {e}")
print("⏩ Skipping transition.")
client = mqtt.Client(protocol=mqtt.MQTTv311)
client.on_connect = on_connect
client.on_message = on_message
client.connect("10.40.0.2", 1883)
client.loop_forever()