-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
127 lines (120 loc) · 2.62 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"encoding/binary"
"fmt"
"io"
"os"
"time"
)
func main() {
config := Config{
SampleRate: 44100,
NumChannels: 2,
BitRate: 16,
ByteOrder: binary.LittleEndian,
CompLevel: 8,
SilenceThreshold: 30 * 44100 / 1000,
}
err := runMain(config, os.Stdin)
if err != nil {
panic(err)
}
}
func runMain(cfg Config, stdin io.Reader) error {
sessId := time.Now().Unix()
streamId := 0
var filename string
for {
streamId++
filename = fmt.Sprintf("stream_%d-%d.flac", sessId, streamId)
fmt.Println(filename)
err := processPcmStream(cfg, stdin, filename)
if err == io.EOF {
break
}
if err != nil {
return fmt.Errorf("processing stdin: %w", err)
}
}
// remove the last stream since it's garbage (either silence or not finished)
err := os.Remove(filename)
if err != nil {
return fmt.Errorf("performing cleanup: %w", err)
}
return nil
}
func processPcmStream(cfg Config, stdin io.Reader, filename string) error {
cmd := cfg.FlacCmd(filename)
output, err := cmd.StdinPipe()
if err != nil {
return fmt.Errorf("obtaining cmd stdin pipe: %w", err)
}
err = cmd.Start()
if err != nil {
return fmt.Errorf("starting cmd: %w", err)
}
defer withErrLog(cmd.Wait, "waiting on cmd")
defer withErrLog(output.Close, "closing cmd stdin")
err = copyPcmSubstream(cfg, stdin, output)
if err == io.EOF {
return err
}
if err != nil {
return fmt.Errorf("processing substream: %w", err)
}
return nil
}
func copyPcmSubstream(
cfg Config,
stdin io.Reader,
output io.Writer,
) error {
streamStarted := false
var buf []int16
for {
s1, s2, err := readTwoSamples(stdin, cfg.ByteOrder)
if err == io.EOF {
return io.EOF
}
if err != nil {
return fmt.Errorf("reading samples: %w", err)
}
buf = append(buf, s1, s2)
if s1 == 0 && s2 == 0 {
if len(buf) >= cfg.SilenceThreshold*cfg.NumChannels && streamStarted {
return nil // stream ended
}
} else {
if !streamStarted {
fmt.Println("Stream started")
buf = []int16{s1, s2}
streamStarted = true
}
err = binary.Write(output, cfg.ByteOrder, buf[:])
if err != nil {
return fmt.Errorf("writing to output: %w", err)
}
buf = nil
}
}
}
func readTwoSamples(r io.Reader, byteOrder binary.ByteOrder) (int16, int16, error) {
var s1, s2 int16
err := binary.Read(r, byteOrder, &s1)
if err != nil {
return s1, s2, err
}
err = binary.Read(r, byteOrder, &s2)
if err != nil {
return s1, s2, err
}
return s1, s2, nil
}
func withErrLog(f func() error, msg string) {
err := f()
if err != nil {
fmt.Printf("ERROR: %s: %s\n", msg, err)
} else {
fmt.Printf("OK: %s\n", msg)
}
}