Add sACN unicast target support
This commit is contained in:
@@ -5,9 +5,9 @@
|
|||||||
# --artnet-listen=:6454 ArtNet listen address (empty to disable)
|
# --artnet-listen=:6454 ArtNet listen address (empty to disable)
|
||||||
# --artnet-broadcast=auto Broadcast addresses (comma-separated, or 'auto')
|
# --artnet-broadcast=auto Broadcast addresses (comma-separated, or 'auto')
|
||||||
|
|
||||||
# Target addresses for ArtNet output universes
|
# Target addresses for output universes
|
||||||
# Each output universe needs a target IP (broadcast or unicast)
|
# ArtNet: target IP (broadcast or unicast), ArtPoll discovery sent to all
|
||||||
# ArtPoll discovery will be sent to all unique target addresses
|
# sACN: unicast targets sent in addition to multicast
|
||||||
[[target]]
|
[[target]]
|
||||||
universe = "artnet:0.0.0"
|
universe = "artnet:0.0.0"
|
||||||
address = "2.255.255.255"
|
address = "2.255.255.255"
|
||||||
@@ -16,6 +16,10 @@ address = "2.255.255.255"
|
|||||||
universe = "artnet:0.0.5"
|
universe = "artnet:0.0.5"
|
||||||
address = "10.50.255.255"
|
address = "10.50.255.255"
|
||||||
|
|
||||||
|
[[target]]
|
||||||
|
universe = "sacn:1"
|
||||||
|
address = "192.168.1.100"
|
||||||
|
|
||||||
# Address format:
|
# Address format:
|
||||||
# proto:universe[:channels]
|
# proto:universe[:channels]
|
||||||
#
|
#
|
||||||
|
|||||||
53
main.go
53
main.go
@@ -25,7 +25,8 @@ type App struct {
|
|||||||
sacnSender *sacn.Sender
|
sacnSender *sacn.Sender
|
||||||
discovery *artnet.Discovery
|
discovery *artnet.Discovery
|
||||||
engine *remap.Engine
|
engine *remap.Engine
|
||||||
targets map[artnet.Universe]*net.UDPAddr
|
artTargets map[artnet.Universe]*net.UDPAddr
|
||||||
|
sacnTargets map[uint16][]*net.UDPAddr
|
||||||
debug bool
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,19 +54,28 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse targets
|
// Parse targets
|
||||||
targets := make(map[artnet.Universe]*net.UDPAddr)
|
artTargets := make(map[artnet.Universe]*net.UDPAddr)
|
||||||
|
sacnTargets := make(map[uint16][]*net.UDPAddr)
|
||||||
pollTargets := make(map[string]*net.UDPAddr) // dedupe by address string
|
pollTargets := make(map[string]*net.UDPAddr) // dedupe by address string
|
||||||
for _, t := range cfg.Targets {
|
for _, t := range cfg.Targets {
|
||||||
if t.Universe.Protocol != config.ProtocolArtNet {
|
switch t.Universe.Protocol {
|
||||||
continue // only artnet targets need addresses
|
case config.ProtocolArtNet:
|
||||||
}
|
addr, err := parseTargetAddr(t.Address, artnet.Port)
|
||||||
addr, err := parseTargetAddr(t.Address)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("target error: address=%q err=%v", t.Address, err)
|
log.Fatalf("target error: address=%q err=%v", t.Address, err)
|
||||||
}
|
}
|
||||||
targets[t.Universe.Universe] = addr
|
artTargets[t.Universe.Universe] = addr
|
||||||
pollTargets[addr.String()] = addr
|
pollTargets[addr.String()] = addr
|
||||||
log.Printf("[config] target %s -> %s", t.Universe, addr)
|
log.Printf("[config] target %s -> %s", t.Universe, addr)
|
||||||
|
case config.ProtocolSACN:
|
||||||
|
addr, err := parseTargetAddr(t.Address, sacn.Port)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("target error: address=%q err=%v", t.Address, err)
|
||||||
|
}
|
||||||
|
u := uint16(t.Universe.Universe)
|
||||||
|
sacnTargets[u] = append(sacnTargets[u], addr)
|
||||||
|
log.Printf("[config] target %s -> %s", t.Universe, addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse broadcast addresses
|
// Parse broadcast addresses
|
||||||
@@ -76,7 +86,7 @@ func main() {
|
|||||||
} else {
|
} else {
|
||||||
for _, addrStr := range strings.Split(*artnetBroadcast, ",") {
|
for _, addrStr := range strings.Split(*artnetBroadcast, ",") {
|
||||||
addrStr = strings.TrimSpace(addrStr)
|
addrStr = strings.TrimSpace(addrStr)
|
||||||
addr, err := parseTargetAddr(addrStr)
|
addr, err := parseTargetAddr(addrStr, artnet.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("broadcast error: address=%q err=%v", addrStr, err)
|
log.Fatalf("broadcast error: address=%q err=%v", addrStr, err)
|
||||||
}
|
}
|
||||||
@@ -120,7 +130,8 @@ func main() {
|
|||||||
sacnSender: sacnSender,
|
sacnSender: sacnSender,
|
||||||
discovery: discovery,
|
discovery: discovery,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
targets: targets,
|
artTargets: artTargets,
|
||||||
|
sacnTargets: sacnTargets,
|
||||||
debug: *debug,
|
debug: *debug,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,16 +219,24 @@ func (a *App) sendOutputs(outputs []remap.Output) {
|
|||||||
for _, out := range outputs {
|
for _, out := range outputs {
|
||||||
switch out.Protocol {
|
switch out.Protocol {
|
||||||
case config.ProtocolSACN:
|
case config.ProtocolSACN:
|
||||||
|
u := uint16(out.Universe)
|
||||||
if a.debug {
|
if a.debug {
|
||||||
log.Printf("[->sacn] universe=%d", uint16(out.Universe))
|
log.Printf("[->sacn] universe=%d", u)
|
||||||
|
}
|
||||||
|
if err := a.sacnSender.SendDMX(u, out.Data[:]); err != nil {
|
||||||
|
log.Printf("[->sacn] error: universe=%d err=%v", u, err)
|
||||||
|
}
|
||||||
|
for _, target := range a.sacnTargets[u] {
|
||||||
|
if a.debug {
|
||||||
|
log.Printf("[->sacn] unicast dst=%s universe=%d", target.IP, u)
|
||||||
|
}
|
||||||
|
if err := a.sacnSender.SendDMXUnicast(target, u, out.Data[:]); err != nil {
|
||||||
|
log.Printf("[->sacn] error: dst=%s err=%v", target.IP, err)
|
||||||
}
|
}
|
||||||
if err := a.sacnSender.SendDMX(uint16(out.Universe), out.Data[:]); err != nil {
|
|
||||||
log.Printf("[->sacn] error: universe=%d err=%v", uint16(out.Universe), err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default: // ArtNet
|
default: // ArtNet
|
||||||
// Configured target takes priority over discovery
|
if target, ok := a.artTargets[out.Universe]; ok {
|
||||||
if target, ok := a.targets[out.Universe]; ok {
|
|
||||||
if a.debug {
|
if a.debug {
|
||||||
log.Printf("[->artnet] dst=%s universe=%s", target.IP, out.Universe)
|
log.Printf("[->artnet] dst=%s universe=%s", target.IP, out.Universe)
|
||||||
}
|
}
|
||||||
@@ -288,8 +307,8 @@ func parseListenAddr(s string) (*net.UDPAddr, error) {
|
|||||||
|
|
||||||
// parseTargetAddr parses target address formats:
|
// parseTargetAddr parses target address formats:
|
||||||
// - "host:port" -> specific host and port
|
// - "host:port" -> specific host and port
|
||||||
// - "host" -> specific host, default ArtNet port
|
// - "host" -> specific host, default port
|
||||||
func parseTargetAddr(s string) (*net.UDPAddr, error) {
|
func parseTargetAddr(s string, defaultPort int) (*net.UDPAddr, error) {
|
||||||
var host string
|
var host string
|
||||||
var port int
|
var port int
|
||||||
|
|
||||||
@@ -305,7 +324,7 @@ func parseTargetAddr(s string) (*net.UDPAddr, error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
host = s
|
host = s
|
||||||
port = artnet.Port
|
port = defaultPort
|
||||||
}
|
}
|
||||||
|
|
||||||
ip := net.ParseIP(host)
|
ip := net.ParseIP(host)
|
||||||
|
|||||||
Reference in New Issue
Block a user