Fix mpv tile overlap portably; add make install/deploy
mpv 0.35 rejects --auto-window-resize, which crash-looped every player. Drop that flag and re-assert each tile geometry on a 1s timer in the daemon, overriding mpv auto-resize on any mpv version. Add make install (auto-sudo, native build + copy to /usr/local/bin) and make deploy (install + restart the kiosk getty unit). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
31
Makefile
31
Makefile
@@ -3,11 +3,22 @@ PKG := ./cmd/rtsp-streamer
|
|||||||
BINDIR := bin
|
BINDIR := bin
|
||||||
LDFLAGS := -s -w
|
LDFLAGS := -s -w
|
||||||
|
|
||||||
.PHONY: all build pi pi32 test vet clean run-tui
|
# Install location. Override with `make install PREFIX=/opt`.
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
DESTBIN := $(PREFIX)/bin/$(BINARY)
|
||||||
|
|
||||||
|
# Use sudo automatically when not already root, so `make install` /
|
||||||
|
# `make deploy` work whether or not you prefix them with sudo.
|
||||||
|
SUDO := $(shell [ "$$(id -u)" -eq 0 ] || echo sudo)
|
||||||
|
|
||||||
|
# The kiosk session unit restarted by `make deploy`.
|
||||||
|
KIOSK_UNIT ?= getty@tty1
|
||||||
|
|
||||||
|
.PHONY: all build pi pi32 test vet clean run-tui install deploy uninstall
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
## build: compile for the host platform
|
## build: compile for the host platform (native arch)
|
||||||
build:
|
build:
|
||||||
go build -ldflags '$(LDFLAGS)' -o $(BINDIR)/$(BINARY) $(PKG)
|
go build -ldflags '$(LDFLAGS)' -o $(BINDIR)/$(BINARY) $(PKG)
|
||||||
|
|
||||||
@@ -19,6 +30,22 @@ pi:
|
|||||||
pi32:
|
pi32:
|
||||||
GOOS=linux GOARCH=arm GOARM=7 go build -ldflags '$(LDFLAGS)' -o $(BINDIR)/$(BINARY)-armv7 $(PKG)
|
GOOS=linux GOARCH=arm GOARM=7 go build -ldflags '$(LDFLAGS)' -o $(BINDIR)/$(BINARY)-armv7 $(PKG)
|
||||||
|
|
||||||
|
## install: build for this machine and copy the binary to $(PREFIX)/bin
|
||||||
|
## (auto-sudo). This is the location the running daemon uses.
|
||||||
|
install: build
|
||||||
|
$(SUDO) install -m 0755 $(BINDIR)/$(BINARY) $(DESTBIN)
|
||||||
|
@echo "installed -> $(DESTBIN)"
|
||||||
|
|
||||||
|
## deploy: install, then restart the kiosk session so the wall picks it up
|
||||||
|
deploy: install
|
||||||
|
$(SUDO) systemctl restart $(KIOSK_UNIT)
|
||||||
|
@echo "restarted $(KIOSK_UNIT); run 'rtsp-streamer status' to check"
|
||||||
|
|
||||||
|
## uninstall: remove the installed binary
|
||||||
|
uninstall:
|
||||||
|
$(SUDO) rm -f $(DESTBIN)
|
||||||
|
@echo "removed $(DESTBIN)"
|
||||||
|
|
||||||
## test: run unit tests
|
## test: run unit tests
|
||||||
test:
|
test:
|
||||||
go test ./...
|
go test ./...
|
||||||
|
|||||||
@@ -153,27 +153,35 @@ func (d *Daemon) applyLayout(ctx context.Context, name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// placeWhenReady waits for the mpv window to map then tiles it, retrying while
|
// placeWhenReady waits for the mpv window to map, tiles it, then keeps
|
||||||
// the layout is active (Supervise may relaunch mpv with a new pid).
|
// re-asserting its geometry on a timer. The re-assertion matters because mpv
|
||||||
|
// resizes its own window to the camera's native resolution when the stream
|
||||||
|
// loads (and mpv 0.35 has no flag to disable that); re-issuing the sway
|
||||||
|
// resize snaps the window back into its cell, portably across mpv versions.
|
||||||
func (d *Daemon) placeWhenReady(ctx context.Context, p *player.Player, rect compositor.Rect) {
|
func (d *Daemon) placeWhenReady(ctx context.Context, p *player.Player, rect compositor.Rect) {
|
||||||
var lastPID int
|
var readyPID int
|
||||||
ticker := time.NewTicker(500 * time.Millisecond)
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for {
|
for {
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pid := p.PID()
|
pid := p.PID()
|
||||||
if pid != 0 && pid != lastPID {
|
if pid != 0 {
|
||||||
if err := d.comp.WaitForWindow(ctx, pid, 15*time.Second); err == nil {
|
// New process: wait for its window to map before positioning.
|
||||||
if err := d.comp.Place(ctx, pid, rect); err != nil {
|
if pid != readyPID {
|
||||||
d.log.Warn("place failed", "slot", p.Slot, "err", err)
|
if err := d.comp.WaitForWindow(ctx, pid, 15*time.Second); err != nil {
|
||||||
} else {
|
goto wait
|
||||||
lastPID = pid
|
|
||||||
d.log.Debug("window placed", "slot", p.Slot, "pid", pid, "rect", rect)
|
|
||||||
}
|
}
|
||||||
|
readyPID = pid
|
||||||
|
d.log.Debug("window mapped", "slot", p.Slot, "pid", pid, "rect", rect)
|
||||||
|
}
|
||||||
|
// Re-assert geometry every tick to override mpv's auto-resize.
|
||||||
|
if err := d.comp.Place(ctx, pid, rect); err != nil {
|
||||||
|
d.log.Debug("place failed", "slot", p.Slot, "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
wait:
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -67,12 +67,10 @@ func (p *Player) args() []string {
|
|||||||
"--cursor-autohide=always",
|
"--cursor-autohide=always",
|
||||||
"--no-border",
|
"--no-border",
|
||||||
"--fullscreen=no", // we tile via the compositor, not fullscreen
|
"--fullscreen=no", // we tile via the compositor, not fullscreen
|
||||||
// Never let mpv resize its own window to the camera's native
|
// Keep aspect (letterbox) inside the tile; the compositor owns the
|
||||||
// resolution — the compositor owns tile geometry. Without this a
|
// window size, not the video. mpv still resizes its window to the
|
||||||
// high-res camera grows its window and overlaps its neighbours.
|
// video resolution on load (and mpv 0.35 lacks the flag to disable
|
||||||
"--auto-window-resize=no",
|
// that), so the daemon re-asserts each tile's geometry on a timer.
|
||||||
// Scale video to fill the tile (letterboxed to preserve aspect); the
|
|
||||||
// window size is fixed by the compositor, not by the video.
|
|
||||||
"--keepaspect=yes",
|
"--keepaspect=yes",
|
||||||
"--title=" + p.Title(),
|
"--title=" + p.Title(),
|
||||||
"--input-ipc-server=" + p.ipcPath,
|
"--input-ipc-server=" + p.ipcPath,
|
||||||
|
|||||||
Reference in New Issue
Block a user