native-recorder-nodejs 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts ADDED
@@ -0,0 +1,206 @@
1
+ import bindings from "./bindings";
2
+ import { EventEmitter } from "events";
3
+
4
+ /**
5
+ * Special device ID for system-wide audio capture (macOS)
6
+ */
7
+ export const SYSTEM_AUDIO_DEVICE_ID = "system";
8
+
9
+ /**
10
+ * Device type classification
11
+ */
12
+ export type DeviceType = "input" | "output";
13
+
14
+ /**
15
+ * Permission type for requesting access
16
+ */
17
+ export type PermissionType = "mic" | "system";
18
+
19
+ /**
20
+ * Permission status for audio recording
21
+ */
22
+ export interface PermissionStatus {
23
+ /** Microphone permission granted */
24
+ mic: boolean;
25
+ /** System audio permission granted (screen recording permission on macOS) */
26
+ system: boolean;
27
+ }
28
+
29
+ /**
30
+ * Represents an audio device
31
+ */
32
+ export interface AudioDevice {
33
+ /** Unique device identifier (always has a value) */
34
+ id: string;
35
+ /** Human-readable device name */
36
+ name: string;
37
+ /** Device type: 'input' for microphones, 'output' for system audio */
38
+ type: DeviceType;
39
+ /** Whether this is the default device for its type */
40
+ isDefault: boolean;
41
+ }
42
+
43
+ /**
44
+ * Audio format information
45
+ */
46
+ export interface AudioFormat {
47
+ /** Sample rate in Hz (e.g., 44100, 48000) */
48
+ sampleRate: number;
49
+ /** Number of channels (1 = Mono, 2 = Stereo) */
50
+ channels: number;
51
+ /** Output bit depth (currently fixed at 16) */
52
+ bitDepth: number;
53
+ /** Native device bit depth */
54
+ rawBitDepth: number;
55
+ }
56
+
57
+ /**
58
+ * Recording configuration
59
+ * Both deviceType and deviceId are required for consistent cross-platform behavior
60
+ */
61
+ export interface RecordingConfig {
62
+ /**
63
+ * Type of device to record from.
64
+ * - 'input': Record from microphone
65
+ * - 'output': Record system audio (loopback)
66
+ */
67
+ deviceType: DeviceType;
68
+
69
+ /**
70
+ * Device ID to record from (obtained from getDevices()).
71
+ * Every device has a valid ID - use the ID from the device list.
72
+ */
73
+ deviceId: string;
74
+ }
75
+
76
+ // Define the native controller interface
77
+ interface NativeAudioController {
78
+ start(
79
+ config: RecordingConfig,
80
+ callback: (error: Error | null, data: Buffer | null) => void
81
+ ): void;
82
+ stop(): void;
83
+ }
84
+
85
+ // Define the native module interface
86
+ interface NativeModule {
87
+ AudioController: {
88
+ new (): NativeAudioController;
89
+ getDevices(): AudioDevice[];
90
+ getDeviceFormat(deviceId: string): AudioFormat;
91
+ checkPermission(): PermissionStatus;
92
+ requestPermission(type: PermissionType): boolean;
93
+ };
94
+ }
95
+
96
+ const native = bindings as NativeModule;
97
+
98
+ export class AudioRecorder extends EventEmitter {
99
+ private controller: NativeAudioController;
100
+ private isRecording: boolean = false;
101
+
102
+ constructor() {
103
+ super();
104
+ this.controller = new native.AudioController();
105
+ }
106
+
107
+ /**
108
+ * Starts the recording session.
109
+ * @param config Configuration object with deviceType and deviceId (both required)
110
+ */
111
+ async start(config: RecordingConfig): Promise<void> {
112
+ if (this.isRecording) {
113
+ throw new Error("Already recording");
114
+ }
115
+
116
+ // Validate config
117
+ if (!config.deviceType || !config.deviceId) {
118
+ throw new Error("Both deviceType and deviceId are required");
119
+ }
120
+
121
+ if (config.deviceType !== "input" && config.deviceType !== "output") {
122
+ throw new Error("deviceType must be 'input' or 'output'");
123
+ }
124
+
125
+ return new Promise((resolve, reject) => {
126
+ try {
127
+ this.controller.start(
128
+ config,
129
+ (error: Error | null, data: Buffer | null) => {
130
+ if (error) {
131
+ this.emit("error", error);
132
+ } else if (data) {
133
+ this.emit("data", data);
134
+ }
135
+ }
136
+ );
137
+ this.isRecording = true;
138
+ resolve();
139
+ } catch (error) {
140
+ reject(error);
141
+ }
142
+ });
143
+ }
144
+
145
+ async stop(): Promise<void> {
146
+ if (!this.isRecording) {
147
+ return;
148
+ }
149
+
150
+ return new Promise((resolve, reject) => {
151
+ try {
152
+ this.controller.stop();
153
+ this.isRecording = false;
154
+ resolve();
155
+ } catch (error) {
156
+ reject(error);
157
+ }
158
+ });
159
+ }
160
+
161
+ /**
162
+ * Lists available audio devices.
163
+ * @param type Optional filter by device type
164
+ * @returns Array of AudioDevice objects (all with valid id values)
165
+ */
166
+ static getDevices(type?: DeviceType): AudioDevice[] {
167
+ const devices = native.AudioController.getDevices();
168
+ if (type) {
169
+ return devices.filter((d) => d.type === type);
170
+ }
171
+ return devices;
172
+ }
173
+
174
+ /**
175
+ * Gets the audio format of a specific device.
176
+ * @param deviceId The device ID to query
177
+ * @returns AudioFormat object
178
+ */
179
+ static getDeviceFormat(deviceId: string): AudioFormat {
180
+ return native.AudioController.getDeviceFormat(deviceId);
181
+ }
182
+
183
+ /**
184
+ * Checks the current permission status for audio recording.
185
+ * On Windows, always returns { mic: true, system: true } as no explicit permissions are required.
186
+ * On macOS, checks actual permission status for microphone and screen recording.
187
+ * @returns PermissionStatus object with mic and system boolean fields
188
+ */
189
+ static checkPermission(): PermissionStatus {
190
+ return native.AudioController.checkPermission();
191
+ }
192
+
193
+ /**
194
+ * Requests permission for the specified type.
195
+ * On Windows, always returns true as no explicit permissions are required.
196
+ * On macOS, prompts the user to grant the requested permission.
197
+ * @param type The permission type to request: 'mic' for microphone, 'system' for system audio
198
+ * @returns true if permission was granted, false otherwise
199
+ */
200
+ static requestPermission(type: PermissionType): boolean {
201
+ return native.AudioController.requestPermission(type);
202
+ }
203
+ }
204
+
205
+ // Export raw bindings for testing if needed
206
+ export const nativeBindings = bindings;