-
Notifications
You must be signed in to change notification settings - Fork 0
/
g711.go
154 lines (139 loc) · 4.24 KB
/
g711.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
Copyright (C) 2016 - 2024, Lefteris Zafiris <zaf@fastmail.com>
This program is free software, distributed under the terms of
the BSD 3-Clause License. See the LICENSE file
at the top of the source tree.
*/
/*
Package g711 implements encoding and decoding of G711 PCM sound data.
G.711 is an ITU-T standard for audio companding.
For usage details please see the code snippets in the cmd folder.
*/
package g711
import (
"errors"
"io"
)
const (
// Input and output formats
Alaw = iota // Alaw G711 encoded PCM data
Ulaw // Ulaw G711 encoded PCM data
Lpcm // Lpcm 16bit signed linear data
)
// Decoder reads G711 PCM data and decodes it to 16bit 8000Hz LPCM
type Decoder struct {
decode func([]byte) []byte // decoding function
source io.Reader // source data
}
// Encoder encodes 16bit 8000Hz LPCM data to G711 PCM or
// directly transcodes between A-law and u-law
type Encoder struct {
input int // input format
encode func([]byte) []byte // encoding function
transcode func([]byte) []byte // transcoding function
destination io.Writer // output data
}
// NewAlawDecoder returns a pointer to a Decoder that implements an io.Reader.
// It takes as input the source data Reader.
func NewAlawDecoder(reader io.Reader) (*Decoder, error) {
if reader == nil {
return nil, errors.New("io.Reader is nil")
}
r := Decoder{
decode: DecodeAlaw,
source: reader,
}
return &r, nil
}
// NewUlawDecoder returns a pointer to a Decoder that implements an io.Reader.
// It takes as input the source data Reader.
func NewUlawDecoder(reader io.Reader) (*Decoder, error) {
if reader == nil {
return nil, errors.New("io.Reader is nil")
}
r := Decoder{
decode: DecodeUlaw,
source: reader,
}
return &r, nil
}
// NewAlawEncoder returns a pointer to an Encoder that implements an io.Writer.
// It takes as input the destination data Writer and the input encoding format.
func NewAlawEncoder(writer io.Writer, input int) (*Encoder, error) {
if writer == nil {
return nil, errors.New("io.Writer is nil")
}
if input != Ulaw && input != Lpcm {
return nil, errors.New("invalid input format")
}
w := Encoder{
input: input,
encode: EncodeAlaw,
transcode: Ulaw2Alaw,
destination: writer,
}
return &w, nil
}
// NewUlawEncoder returns a pointer to an Encoder that implements an io.Writer.
// It takes as input the destination data Writer and the input encoding format.
func NewUlawEncoder(writer io.Writer, input int) (*Encoder, error) {
if writer == nil {
return nil, errors.New("io.Writer is nil")
}
if input != Alaw && input != Lpcm {
return nil, errors.New("invalid input format")
}
w := Encoder{
input: input,
encode: EncodeUlaw,
transcode: Alaw2Ulaw,
destination: writer,
}
return &w, nil
}
// Reset discards the Decoder state. This permits reusing a Decoder rather than allocating a new one.
func (r *Decoder) Reset(reader io.Reader) error {
if reader == nil {
return errors.New("io.Reader is nil")
}
r.source = reader
return nil
}
// Reset discards the Encoder state. This permits reusing an Encoder rather than allocating a new one.
func (w *Encoder) Reset(writer io.Writer) error {
if writer == nil {
return errors.New("io.Writer is nil")
}
w.destination = writer
return nil
}
// Read decodes G711 data. Reads up to len(p) bytes into p, returns the number
// of bytes read and any error encountered.
func (r *Decoder) Read(p []byte) (i int, err error) {
if len(p) == 0 {
return
}
b := make([]byte, len(p)/2)
i, err = r.source.Read(b)
copy(p, r.decode(b))
i *= 2 // Report back the correct number of bytes
return
}
// Write encodes G711 Data. Writes len(p) bytes from p to the underlying data stream,
// returns the number of bytes written from p (0 <= n <= len(p)) and any error encountered
// that caused the write to stop early.
func (w *Encoder) Write(p []byte) (i int, err error) {
if len(p) == 0 {
return
}
if w.input == Lpcm { // Encode LPCM data to G711
i, err = w.destination.Write(w.encode(p))
if err == nil && len(p)%2 != 0 {
err = errors.New("odd number of LPCM bytes, incomplete frame")
}
i *= 2 // Report back the correct number of bytes written from p
} else { // Trans-code
i, err = w.destination.Write(w.transcode(p))
}
return
}