-
Notifications
You must be signed in to change notification settings - Fork 60
/
decode.go
116 lines (96 loc) · 2.48 KB
/
decode.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
package dca
import (
"bufio"
"encoding/binary"
"encoding/json"
"errors"
"io"
"strconv"
"time"
)
var (
ErrNotDCA = errors.New("DCA Magic header not found, either not dca or raw dca frames")
ErrNotFirstFrame = errors.New("Metadata can only be found in the first frame")
)
type Decoder struct {
r *bufio.Reader
Metadata *Metadata
FormatVersion int
// Set to true after the first frame has been read
firstFrameProcessed bool
}
// NewDecoder returns a new dca decoder
func NewDecoder(r io.Reader) *Decoder {
decoder := &Decoder{
r: bufio.NewReader(r),
}
return decoder
}
// ReadMetadata reads the first metadata frame
// OpusFrame will call this automatically if
func (d *Decoder) ReadMetadata() error {
if d.firstFrameProcessed {
return ErrNotFirstFrame
}
d.firstFrameProcessed = true
fingerprint, err := d.r.Peek(4)
if err != nil {
return err
}
if string(fingerprint[:3]) != "DCA" {
return ErrNotDCA
}
// We just peeked earlier, mark this portion as read
d.r.Discard(4)
// Read the format version
version, err := strconv.ParseInt(string(fingerprint[3:]), 10, 32)
if err != nil {
return err
}
d.FormatVersion = int(version)
// The length of the metadata
var metaLen int32
err = binary.Read(d.r, binary.LittleEndian, &metaLen)
if err != nil {
return err
}
// Read in the metadata itself
jsonBuf := make([]byte, metaLen)
err = binary.Read(d.r, binary.LittleEndian, &jsonBuf)
if err != nil {
return err
}
// And unmarshal it
var metadata *Metadata
err = json.Unmarshal(jsonBuf, &metadata)
d.Metadata = metadata
return err
}
// OpusFrame returns the next audio frame
// If this is the first frame it will also check for metadata in it
func (d *Decoder) OpusFrame() (frame []byte, err error) {
if !d.firstFrameProcessed {
// Check to see if this contains metadata and read the metadata if so
magic, err := d.r.Peek(3)
if err != nil {
return nil, err
}
if string(magic) == "DCA" {
err = d.ReadMetadata()
if err != nil {
return nil, err
}
}
}
frame, err = DecodeFrame(d.r)
return
}
// FrameDuration implements OpusReader, returnining the specified duration per frame
func (d *Decoder) FrameDuration() time.Duration {
if d.Metadata == nil {
return 20
}
// I don't understand nick, why does it have to be like this nick, please nick, im not having a good time nick.
// 960B = pcm framesize of 20ms 1 channel audio
return time.Duration(((d.Metadata.Opus.FrameSize/d.Metadata.Opus.Channels)/960)*20) * time.Millisecond
}