From 2bfc87a36d61a4a2ea6b15df1a23c5276d3ec8cd Mon Sep 17 00:00:00 2001 From: Daniel Ponte Date: Mon, 5 Aug 2024 14:42:38 -0400 Subject: [PATCH] Make calls command concurrent, also update README --- README.md | 9 +++++++- cmd/calls/audio.go | 52 +++++++++++++++++++++++++++++++++++++++------- cmd/calls/main.go | 11 +++++----- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 216ee86..ee51125 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ # stillbox -A Golang scanner call server, with the Calls webapp. +A Golang scanner call server (`gordio`), with the Calls webapp. + +**NOTE** + +If this message is still here, the database schema *initial migration* and protobuf definitions are **still subject to change**. + +Once `gordio` is actually usable (but not necessarily feature-complete), I will remove this note, and start using DB migrations and +protobuf best practices (i.e. not changing field numbers). diff --git a/cmd/calls/audio.go b/cmd/calls/audio.go index 12fbadf..d51ad70 100644 --- a/cmd/calls/audio.go +++ b/cmd/calls/audio.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log" "time" "dynatron.me/x/go-minimp3" @@ -9,17 +10,24 @@ import ( ) type Player struct { + c chan playReq ctx *oto.Context sampleRate int channels int } func NewPlayer() *Player { - p := &Player{} + p := &Player{ + c: make(chan playReq, 256), + } return p } +func (p *Player) Queue() int { + return len(p.c) +} + func (p *Player) initOto(samp, channels int) error { if samp != p.sampleRate || channels != p.channels { if p.ctx != nil { @@ -64,15 +72,45 @@ func (p *Player) playMP3(audio []byte) error { return nil } -func (p *Player) Play(audio []byte, mimeType string) error { - switch mimeType { +type playReq struct { + audio []byte + mimeType string +} + +func (p *Player) Play(audio []byte, mimeType string) { + p.c <- playReq{audio, mimeType} +} + +func (p *Player) play(req playReq) error { + switch req.mimeType { case "audio/mpeg": - return p.playMP3(audio) + return p.playMP3(req.audio) case "audio/wav": panic("wav not implemented yet") default: - return fmt.Errorf("unknown format %s", mimeType) + return fmt.Errorf("unknown format %s", req.mimeType) + } +} + +func (p *Player) Go(done <-chan struct{}) { + for { + select { + case <-done: + close(p.c) + p.ctx.Close() + return + case r, ok := <-p.c: + if !ok { + p.ctx.Close() + return + } + + fmt.Printf("> [Q: %d]\r", p.Queue()) + err := p.play(r) + fmt.Printf("\033[2K") + if err != nil { + log.Println(err) + } + } } - - return nil } diff --git a/cmd/calls/main.go b/cmd/calls/main.go index 2bab1db..dfca6c6 100644 --- a/cmd/calls/main.go +++ b/cmd/calls/main.go @@ -81,6 +81,10 @@ func main() { log.Printf("connected") done := make(chan struct{}) + playDone := make(chan struct{}) + + go play.Go(playDone) + defer close(playDone) go func() { defer close(done) @@ -101,11 +105,8 @@ func main() { switch v := m.ToClientMessage.(type) { case *pb.Message_Call: - log.Printf("call tg %d", v.Call.Talkgroup) - err := play.Play(v.Call.Audio, v.Call.AudioType) - if err != nil { - log.Println(err) - } + log.Printf("call tg %d [Q: %d]", v.Call.Talkgroup, play.Queue()) + play.Play(v.Call.Audio, v.Call.AudioType) case *pb.Message_Notification: log.Println(v.Notification.Msg) default: