prototype apps removed

This commit is contained in:
Dmitry Sergeev
2026-08-26 22:58:54 +03:00
parent 61c770d722
commit 7c0709cf58
3 changed files with 0 additions and 321 deletions
-144
View File
@@ -1,144 +0,0 @@
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
"mxl-player/internal/sdl"
"mxl-player/internal/source"
)
func main() {
domain := flag.String("d", "/dev/shm/mxl", "MXL domain")
flowID := flag.String("a", "", "MXL audio flow UUID")
list := flag.Bool("l", false, "List playback audio devices and exit")
audioDeviceId := flag.Uint("ad", uint(sdl.AudioDeviceDefaultPlayback), "Audio device SDL id")
flag.Parse()
if err := sdl.Load(); err != nil {
log.Fatal(err)
}
if !sdl.Init(sdl.InitVideo | sdl.InitAudio) {
log.Fatalf("SDL_Init: %s", sdl.GetError())
}
defer sdl.Quit()
if *list {
for _, d := range sdl.GetAudioPlaybackDevices() {
fmt.Printf("%d: %s\n", d.ID, d.Name)
}
return
}
if *flowID == "" {
log.Fatal("missing -a <audio-flow-uuid>")
}
src, err := source.OpenAudio(*domain, *flowID)
if err != nil {
log.Fatal(err)
}
defer src.Close()
rate := src.Rate()
chans := src.Channels()
fmt.Printf("audio: %dch %d/%d Hz\n", chans, rate.Num, rate.Den)
stream := sdl.OpenAudioDeviceStream(uint32(*audioDeviceId), sdl.AudioSpec{
Format: sdl.AudioF32,
Channels: int32(chans),
Freq: int32(rate.Num / rate.Den),
})
if stream == 0 {
log.Fatalf("OpenAudioDeviceStream: %s", sdl.GetError())
}
defer sdl.DestroyAudioStream(stream)
if !sdl.ResumeAudioStreamDevice(stream) {
log.Fatalf("ResumeAudioStreamDevice: %s", sdl.GetError())
}
// ~10ms batch: sampleRate / 100
batch := uint64(rate.Num / (100 * rate.Den))
if batch == 0 {
batch = 1
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
go func() {
<-stop
cancel()
}()
var debugCount int
for {
select {
case <-ctx.Done():
fmt.Println("\nstopped")
return
default:
}
// Backpressure: if SDL has > 200ms buffered, wait for it to drain.
queued := sdl.GetAudioStreamQueued(stream)
maxQueued := int32(rate.Num/(100*rate.Den)) * int32(chans) * 4 * 20 // 200ms
if queued > maxQueued {
time.Sleep(10 * time.Millisecond)
continue
}
f, err := src.NextAudio(ctx, batch, 20*time.Millisecond)
if err != nil {
if ctx.Err() != nil {
fmt.Println("\nstopped")
return
}
log.Printf("audio read: %v", err)
continue
}
// Debug: scan for non-zero samples
if debugCount < 5 {
sizes := make([]int, len(f.Samples))
nonZero := 0
for i, s := range f.Samples {
sizes[i] = len(s)
for _, b := range s {
if b != 0 {
nonZero++
}
}
}
fmt.Printf("read idx=%d batch=%d sampleSizes=%v queued=%d nonZeroBytes=%d\n",
f.Index, batch, sizes, queued, nonZero)
debugCount++
}
// Interleave per-channel Float32 into a single buffer.
frameBytes := int(batch) * int(chans) * 4
interleaved := make([]byte, frameBytes)
for ch := uint64(0); ch < chans; ch++ {
srcBytes := f.Samples[ch]
for i := uint64(0); i < batch; i++ {
srcOff := i * 4
dstOff := (i*chans + ch) * 4
if srcOff+4 <= uint64(len(srcBytes)) {
copy(interleaved[dstOff:dstOff+4], srcBytes[srcOff:srcOff+4])
}
}
}
if !sdl.PutAudioStreamData(stream, interleaved) {
log.Printf("PutAudioStreamData: %s", sdl.GetError())
}
}
}
-61
View File
@@ -1,61 +0,0 @@
package main
import (
"flag"
"fmt"
"log"
"mxl-player/internal/source"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
domain := flag.String("domain", "/dev/shm/mxl", "MXL domain")
flowID := flag.String("flow", "5fbec3b1-1b0f-417d-9059-8b94a47197ed", "Flow UUID")
timeout := flag.Duration("timeout", 200*time.Millisecond, "Per-grain read timeout")
count := flag.Int("count", 10, "Stop after N grains (0 = run forever)")
flag.Parse()
src, err := source.Open(*domain, *flowID)
if err != nil {
log.Fatal(err)
}
defer src.Close()
fmt.Printf("format=%s rate=%d/%d stride=%d grainCount=%d\n",
src.Format(),
src.Rate().Num,
src.Rate().Den,
src.Stride(),
src.GrainCount())
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
grains := 0
for {
select {
case <-stop:
fmt.Printf("\nstopping: %d grains read\n", grains)
return
default:
}
f, err := src.Next(*timeout)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
lines := uint32(0)
if src.Stride() > 0 {
lines = f.Size / src.Stride()
}
fmt.Printf("idx=%d size=%d (%dx%d, %d lines) invalid=%v\n",
f.Index, f.Size, f.Width, f.Height, lines, f.Invalid)
grains++
if *count > 0 && grains >= *count {
fmt.Printf("done: %d grains read\n", grains)
return
}
}
}
-116
View File
@@ -1,116 +0,0 @@
package main
import (
"errors"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/qvest-digital/go-mxl/mxl"
)
func main() {
domain := flag.String("d", "/dev/shm/mxl", "MXL domain")
videoFlow := flag.String("v", "5fbec3b1-1b0f-417d-9059-8b94a47197ed", "Video flow UUID")
audioFlow := flag.String("a", "5fbec3b1-1b0f-417d-9059-8b94a47197ec", "Audio flow UUID")
flag.Parse()
if *videoFlow == "" || *audioFlow == "" {
log.Fatal("need both -v <video-flow> and -a <audio-flow>")
}
inst, err := mxl.NewInstance(*domain, "")
if err != nil {
log.Fatal(err)
}
defer inst.Close()
vr, err := inst.NewReader(*videoFlow)
if err != nil {
log.Fatal(err)
}
defer vr.Close()
ar, err := inst.NewReader(*audioFlow)
if err != nil {
log.Fatal(err)
}
defer ar.Close()
vInfo, _ := vr.Info()
aInfo, _ := ar.Info()
vRate := vInfo.Config.Common.GrainRate
aRate := aInfo.Config.Common.GrainRate
aChans := aInfo.Config.Continuous.ChannelCount
fmt.Printf("video: %dx%d %d/%d | audio: %dch %d/%d\n",
vInfo.Config.Discrete.SliceSizes[0],
vInfo.Config.Discrete.GrainCount,
vRate.Num, vRate.Den,
aChans, aRate.Num, aRate.Den)
group, err := inst.NewSyncGroup()
if err != nil {
log.Fatal(err)
}
defer group.Close()
if err := group.AddReader(vr); err != nil {
log.Fatal(err)
}
if err := group.AddReader(ar); err != nil {
log.Fatal(err)
}
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
idx := mxl.CurrentIndex(vRate)
audioBatch := uint64(aRate.Num / (100 * aRate.Den)) // ~10ms
if audioBatch == 0 {
audioBatch = 1
}
var ticks int
for {
select {
case <-stop:
fmt.Printf("\nstopped after %d ticks\n", ticks)
return
default:
}
ts := mxl.IndexToTimestamp(vRate, idx)
err := group.WaitForDataAt(ts, 500*time.Millisecond)
switch {
case err == nil:
// Read video grain
g, gerr := vr.GetGrain(idx, 50*time.Millisecond)
// Read audio samples at the same timestamp
aIdx := mxl.TimestampToIndex(aRate, ts)
_, aerr := ar.GetSamples(aIdx, int(audioBatch), 50*time.Millisecond)
if gerr != nil {
log.Printf("grain: %v", gerr)
} else if aerr != nil {
log.Printf("samples: %v", aerr)
} else {
fmt.Printf("tick idx=%d ts=%d grainSize=%d audioIdx=%d\n",
idx, ts, g.GrainSize, aIdx)
ticks++
if ticks >= 10 {
fmt.Println("done")
return
}
}
idx++
case errors.Is(err, mxl.ErrTimeout), errors.Is(err, mxl.ErrOutOfRangeEarly):
time.Sleep(5 * time.Millisecond)
case errors.Is(err, mxl.ErrOutOfRangeLate):
log.Printf("fell behind, resyncing")
idx = mxl.CurrentIndex(vRate)
default:
log.Fatalf("WaitForDataAt: %v", err)
}
}
}