File: g711.go

package info (click to toggle)
golang-github-zaf-g711 1.2-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 252 kB
  • sloc: makefile: 4
file content (154 lines) | stat: -rw-r--r-- 4,342 bytes parent folder | download
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 - 2017, 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
}