]> Sergey Matveev's repositories - vors.git/blob - cmd/client/stats.go
28fe6477bbc07f6d40e4c5a1d10e8d06fe7abf08522bda16fe1274d6bc08f95b
[vors.git] / cmd / client / stats.go
1 // VoRS -- Vo(IP) Really Simple
2 // Copyright (C) 2024 Sergey Matveev <stargrave@stargrave.org>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, version 3 of the License.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU Affero General Public License for more details.
12 //
13 // You should have received a copy of the GNU Affero General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 package main
17
18 import (
19         "fmt"
20         "math"
21         "strings"
22         "sync/atomic"
23         "time"
24
25         "github.com/dustin/go-humanize"
26         "github.com/jroimartin/gocui"
27         vors "go.stargrave.org/vors/internal"
28 )
29
30 type Stats struct {
31         pkts    int64
32         bytes   uint64
33         bads    int64
34         lost    int64
35         reorder int64
36         last    time.Time
37         vol     uint64
38         volN    uint64
39         dead    chan struct{}
40 }
41
42 func (stats *Stats) AddRMS(pcm []int16) {
43         var vol uint64
44         for _, s := range pcm {
45                 vol += uint64(int64(s) * int64(s))
46         }
47         atomic.AddUint64(&stats.vol, vol)
48         atomic.AddUint64(&stats.volN, uint64(len(pcm)))
49 }
50
51 func statsDrawer(stats *Stats, name string) {
52         var err error
53         tick := time.Tick(vors.ScreenRefresh)
54         var now time.Time
55         var v *gocui.View
56         var vol, volN float64
57         var maxRMS float64
58         var rep int
59         for {
60                 select {
61                 case <-stats.dead:
62                         GUI.DeleteView(name)
63                         GUI.DeleteView(name + "-vol")
64                         return
65                 case now = <-tick:
66                         s := fmt.Sprintf(
67                                 "%s  |  %s  |  B/L/R: %s/%s/%s",
68                                 humanize.Comma(stats.pkts),
69                                 humanize.IBytes(stats.bytes),
70                                 humanize.Comma(stats.bads),
71                                 humanize.Comma(stats.lost),
72                                 humanize.Comma(stats.reorder),
73                         )
74                         if name == *Name && Muted {
75                                 s += "  |  " + vors.CRed + "MUTE" + vors.CReset
76                         } else {
77                                 if stats.last.Add(vors.ScreenRefresh).After(now) {
78                                         s += "  |  " + vors.CGreen + "TALK" + vors.CReset
79                                 }
80                         }
81                         v, err = GUI.View(name)
82                         if err == nil {
83                                 v.Clear()
84                                 v.Write([]byte(s))
85                         }
86                         vol = float64(atomic.SwapUint64(&stats.vol, 0))
87                         volN = float64(atomic.SwapUint64(&stats.volN, 0))
88                         v, err = GUI.View(name + "-vol")
89                         if err == nil {
90                                 v.Clear()
91                                 if volN == 0 {
92                                         continue
93                                 }
94                                 vol = math.Sqrt(vol / volN)
95                                 if vol/4 > maxRMS {
96                                         maxRMS = vol / 4
97                                 }
98                                 rep = int(float64(GUIMaxY) * vol / maxRMS)
99                                 v.Write([]byte(strings.Repeat("▒", rep)))
100                         }
101                 }
102         }
103 }