/
audio_common.go
137 lines (115 loc) · 3.17 KB
/
audio_common.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
128
129
130
131
132
133
134
135
136
137
package glimmer
import (
"sync"
"time"
)
// AudioBuffer lets you play sound.
type AudioBuffer struct {
SamplesPerSecond int
BitsPerSample int
ChannelCount int
buf []byte
bufMutex sync.Mutex
output audioOutput
outputBufDuration time.Duration
// ReadLenNotifier is used at the end of every time the audio device
// consumes the buffer, sending the number of bytes consumed
// in the buffer consumption
ReadLenNotifier chan int
bufUnderflows int
prevReadLen int
maxWaited time.Duration
}
// GetPrevCallbackReadLen returns the size of the last buffer chunk the system asked for in its audio callback
func (ab *AudioBuffer) GetPrevCallbackReadLen() int {
return ab.prevReadLen
}
// GetMaxWaited is to learn the max amount WaitForPlaybackIfAhead has waited in between this and the last call of
// GetMaxWaited. It's for debugging.
func (ab *AudioBuffer) GetMaxWaited() time.Duration {
out := ab.maxWaited
ab.maxWaited = time.Duration(0)
return out
}
// WaitForPlaybackIfAhead waits until one buffer chunk length is yet to be processed by the OS.
func (ab *AudioBuffer) WaitForPlaybackIfAhead() {
start := time.Now()
for ab.GetUnplayedDataLen() > ab.prevReadLen {
ab.prevReadLen = <-ab.ReadLenNotifier
}
audioDiff := time.Now().Sub(start)
if audioDiff > ab.maxWaited {
ab.maxWaited = audioDiff
}
}
type OpenAudioBufferOptions struct {
OutputBufDuration time.Duration
SamplesPerSecond int
BitsPerSample int
ChannelCount int
}
// OpenAudioBuffer creates and returns a new playing buffer
func OpenAudioBuffer(opts OpenAudioBufferOptions) (*AudioBuffer, error) {
ab := AudioBuffer{
SamplesPerSecond: opts.SamplesPerSecond,
BitsPerSample: opts.BitsPerSample,
ChannelCount: opts.ChannelCount,
outputBufDuration: opts.OutputBufDuration,
ReadLenNotifier: make(chan int),
}
err := ab.output.init(&ab)
if err != nil {
return nil, err
}
// wait to be sure audio is ready, and to get exact len data
ab.prevReadLen = <-ab.ReadLenNotifier
return &ab, nil
}
func (ab *AudioBuffer) GetLatestUnderflowCount() int {
ab.bufMutex.Lock()
count := ab.bufUnderflows
ab.bufUnderflows = 0
ab.bufMutex.Unlock()
return count
}
func (ab *AudioBuffer) GetUnplayedDataLen() int {
ab.bufMutex.Lock()
bLen := len(ab.buf)
ab.bufMutex.Unlock()
return bLen
}
func (ab *AudioBuffer) Write(data []byte) (int, error) {
ab.bufMutex.Lock()
ab.buf = append(ab.buf, data...)
ab.bufMutex.Unlock()
return len(data), nil
}
func (ab *AudioBuffer) Read(buf []byte) (int, error) {
ab.bufMutex.Lock()
if len(buf) > len(ab.buf) {
// fmt.Println("[glimmer-audio] buf underflow:", len(buf), "vs", len(ab.buf))
ab.bufUnderflows++
}
n := copy(buf, ab.buf)
ab.buf = ab.buf[n:]
ab.bufMutex.Unlock()
// fill with zero if wrote nothing, otherwise fill with last val to give the buffer a chance to avoid a click if it can catch up
if n == 0 {
for i := range buf {
buf[i] = 0
}
} else {
for i := n + 1; i < len(buf); i++ {
buf[i] = buf[i-1]
}
}
select {
case ab.ReadLenNotifier <- len(buf):
default:
}
return len(buf), nil
}
// Close closes the buffer and releases all resourses.
func (ab *AudioBuffer) Close() error {
return ab.output.close()
}