-
Notifications
You must be signed in to change notification settings - Fork 0
/
listener.go
98 lines (80 loc) · 2.18 KB
/
listener.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
package audiostream
import (
"github.com/gofrs/uuid"
)
// Listener is a client used to listen to the stream of audio
type Listener struct {
uuid string
frame chan frame
stream chan []byte
isStreaming bool
metadataInterval int64
supportMetadata bool
}
// ListenerOption is a func used to configure the listener upon initialization
type ListenerOption func(*Listener)
// WithIcyMetadataSupport is usually confirmed when checking the incoming
// request header icy-metadata: 1
func WithIcyMetadataSupport(interval int64) ListenerOption {
return func(l *Listener) {
l.supportMetadata = true
l.metadataInterval = interval
}
}
// NewListener initializes and return a Listener
func NewListener(opts ...ListenerOption) (*Listener, error) {
uuid, err := uuid.NewV4()
if err != nil {
return nil, err
}
l := &Listener{
uuid: uuid.String(),
stream: make(chan []byte),
frame: make(chan frame),
}
for _, o := range opts {
o(l)
}
return l, nil
}
// Stream returns a channel that sends audio from the stream
func (l *Listener) Stream() <-chan []byte {
if l.isStreaming {
return l.stream
}
l.isStreaming = true
go func() {
var framesWrittenInInterval int64
for {
dataFrame, ok := <-l.frame
if !ok {
return
}
frame := dataFrame.data
// metadata should be within this frame now
if l.supportMetadata && framesWrittenInInterval+int64(len(frame)) >= l.metadataInterval {
// how much can we write to stream before we need to send metadata
preMetadata := l.metadataInterval - framesWrittenInInterval
if preMetadata > 0 {
l.stream <- frame[:preMetadata]
framesWrittenInInterval += preMetadata
// remainder of the frame that is to be send after metadata
frame = frame[preMetadata:]
}
// at this point in time, we've reached the interval
framesWrittenInInterval = 0
// write metdata
metadata := dataFrame.IcyMetadata()
l.stream <- metadata
framesWrittenInInterval += int64(len(metadata))
// write remainder frame
l.stream <- frame
framesWrittenInInterval += int64(len(frame))
return
}
framesWrittenInInterval += int64(len(frame))
l.stream <- frame
}
}()
return l.stream
}