// VoRS -- Vo(IP) Really Simple // Copyright (C) 2024-2025 Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, version 3 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package main import ( "fmt" "math" "strings" "sync/atomic" "time" "github.com/dustin/go-humanize" "github.com/jroimartin/gocui" vors "go.stargrave.org/vors/v4/internal" ) type Stats struct { dead chan struct{} last time.Time bytes uint64 vol uint64 volN uint64 pkts int64 bads int64 lost int64 reorder int64 } func (stats *Stats) AddRMS(pcm []int16) { var vol uint64 for _, s := range pcm { vol += uint64(int64(s) * int64(s)) } atomic.AddUint64(&stats.vol, vol) atomic.AddUint64(&stats.volN, uint64(len(pcm))) } func statsDrawer(s *Stream) { var err error tick := time.Tick(vors.ScreenRefresh) var now time.Time var v *gocui.View var vol, volN float64 var maxRMS float64 var rep int for { select { case <-s.stats.dead: GUI.DeleteView(s.name) GUI.DeleteView(s.name + "-vol") return case now = <-tick: l := fmt.Sprintf( " %s | %s | S/B/L/R: %s/%s/%s/%s", humanize.Comma(s.stats.pkts), humanize.IBytes(s.stats.bytes), humanize.Comma(int64(s.actr-(s.ctr&0x00FFFF))/50), humanize.Comma(s.stats.bads), humanize.Comma(s.stats.lost), humanize.Comma(s.stats.reorder), ) peerFlags := []string{" ", " ", " "} if s.name == *Name && Muted { peerFlags[0] = vors.CRed + "M" + vors.CReset } else { if s.silenced { peerFlags[2] = vors.CMagenta + "S" + vors.CReset } if s.stats.last.Add(vors.ScreenRefresh).After(now) { peerFlags[1] = vors.CGreen + "T" + vors.CReset } if s.muted { peerFlags[0] = vors.CRed + "M" + vors.CReset } } l = strings.Join(peerFlags, "") + l v, err = GUI.View(s.name) if err == nil { v.Clear() v.Write([]byte(l)) } vol = float64(atomic.SwapUint64(&s.stats.vol, 0)) volN = float64(atomic.SwapUint64(&s.stats.volN, 0)) v, err = GUI.View(s.name + "-vol") if err == nil { v.Clear() if volN == 0 { continue } vol = math.Sqrt(vol / volN) if vol/4 > maxRMS { maxRMS = vol / 4 } rep = max(int(float64(GUIMaxY)*vol/maxRMS), 0) v.Write([]byte(strings.Repeat("▒", rep))) } } } }