forked from Streampunk/naudiodon
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.ts
186 lines (167 loc) · 4.8 KB
/
index.ts
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import bindings from "bindings";
import { Readable, Writable } from "stream";
const NodePA = bindings("node_pa.node");
///////////////////////////////////////////////////////////////////////////////
// Sample format widths //
///////////////////////////////////////////////////////////////////////////////
/** Use 8-bit samples to read/write to PortAudio */
export const SampleFormat8Bit = 8;
/** Use 16-bit samples to read/write to PortAudio */
export const SampleFormat16Bit = 16;
/** Use 24-bit samples to read/write to PortAudio */
export const SampleFormat24Bit = 24;
/** Use 32-bit samples to read/write to PortAudio */
export const SampleFormat32Bit = 32;
///////////////////////////////////////////////////////////////////////////////
/** Get available devices from PortAudio */
export const getDevices = NodePA.getDevices;
/**
* Available options to initialize audio input and output
*/
export interface AudioOptions {
/**
* The device ID to use. These correspond to device IDs returned by
* `getDevices`. Omit or set this to -1 to use the default device
*/
deviceId?: number;
/**
* Sample rate to read/write from/to the audio device (samples/sec)
*/
sampleRate?: number;
/**
* Number of channels to read/write audio from/to
*/
channelCount?: number;
/**
* The sample width. Use one of the exported constants (8, 16, 24, or 32)
*/
sampleFormat?: number;
/**
* Enable debug mode. This will print out messages from the C bindings onto
* stderr when an error occurs
*/
debug?: boolean;
}
/**
* The function signature of the callbacks to various `AudioInput` and
* `AudioOutput` methods.
*/
export type AudioCallback = (error?: Error | null | undefined) => void;
/**
* AudioInput is a readable stream that records audio from the given device
*/
export class AudioInput extends Readable {
/** audio is an instance of the node_pa PortAudio binding (input stream) */
private audio: any;
/**
* Creates the AudioInput instance by initializing the Readable stream
* and initializing the underlying PortAudio instance with the given
* options.
*
* @param options options to pass to PortAudio
*/
constructor(options: AudioOptions) {
super({
highWaterMark: 16384,
objectMode: false,
});
this.audio = new NodePA.AudioIn(options);
}
/**
* Reads some data from PortAudio and pushes it into the stream
*
* @param size number of bytes to read
*/
public _read(size: number = 1024) {
this.audio.read(size, (err: Error, buf: Buffer) => {
if (!err) {
this.push(buf);
}
});
}
/**
* Start reading data from the input device
*/
public start() {
this.audio.start();
}
/**
* Immediately aborts recording without waiting for the buffers to flush
*/
public abort() {
this.audio.abort();
}
/**
* Gracefully stops the recording device, flushing all buffers, and then calls
* the given function.
*
* @param cb callback to call after quit has completed
*/
public quit(cb?: AudioCallback) {
this.audio.quit(() => {
if (cb && typeof cb === "function") {
cb();
}
});
}
}
/**
* AudioOutput is a writeable stream that plays audio on the given device
*/
export class AudioOutput extends Writable {
/** audio is an instance of the node_pa PortAudio binding (output stream) */
private audio: any;
/**
* Creates the AudioOutput instance by initializing the Writable stream
* and initializing the underlying PortAudio instance with the given
* options.
*
* @param options options to initialize PortAudio with
*/
constructor(options: AudioOptions) {
super({
decodeStrings: false,
highWaterMark: 16384,
objectMode: false,
});
this.audio = new NodePA.AudioOut(options);
this.on("finish", this.quit.bind(this));
}
/**
* Write some data to the PortAudio output device and call the given callback
* upon completion.
*
* @param chunk data to write to the device
* @param encoding encoding of the data
* @param cb callback to call after write is completed
*/
public write(chunk: any, encoding?: any, cb: AudioCallback = (() => undefined)) {
this.audio.write(chunk, cb);
return true;
}
/**
* Start writing data to the output device
*/
public start() {
this.audio.start();
}
/**
* Immediately aborts playback without waiting for the buffers to flush
*/
public abort() {
this.audio.abort();
}
/**
* Gracefully stops the playback device, flushing all buffers, and then calls
* the given function.
*
* @param cb callback to call after quit has completed
*/
public quit(cb?: AudioCallback) {
this.audio.quit(() => {
if (cb && typeof cb === "function") {
cb();
}
});
}
}