truehear-audio-library-node 1.0.0
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/README.md +220 -0
- package/binding.gyp +45 -0
- package/dist/domain/audio-device.types.d.ts +240 -0
- package/dist/domain/audio-device.types.d.ts.map +1 -0
- package/dist/domain/audio-device.types.js +13 -0
- package/dist/domain/audio-device.types.js.map +1 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +154 -0
- package/dist/index.js.map +1 -0
- package/include/audio_device_types.h +169 -0
- package/include/ipolicy_config.h +420 -0
- package/include/mmdevice_guids.h +9 -0
- package/include/truehear_audio.h +348 -0
- package/package.json +85 -0
- package/prebuilds/win32-x64/truehear_audio_native.node +0 -0
- package/src/addon.c +612 -0
- package/src/mmdevice_guids.c +8 -0
- package/src/policy_config_guids.c +26 -0
- package/src/truehear_audio_win.c +888 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
#ifndef TRUEHEAR_AUDIO_H
|
|
2
|
+
#define TRUEHEAR_AUDIO_H
|
|
3
|
+
|
|
4
|
+
#include "audio_device_types.h"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @file truehear_audio.h
|
|
8
|
+
* @brief Public, platform-agnostic Truehear audio API.
|
|
9
|
+
*
|
|
10
|
+
* This header exposes a stable C interface for audio device discovery and
|
|
11
|
+
* default-device management across supported operating systems.
|
|
12
|
+
*
|
|
13
|
+
* Intended consumers:
|
|
14
|
+
* - Node/NPM native addon layer
|
|
15
|
+
* - integration tests
|
|
16
|
+
* - CLI / application code that must remain platform-neutral
|
|
17
|
+
*
|
|
18
|
+
* ---------------------------------------------------------------------------
|
|
19
|
+
* Why this API exists
|
|
20
|
+
* ---------------------------------------------------------------------------
|
|
21
|
+
* Platform audio APIs are different (Windows COM, CoreAudio, PipeWire, etc.).
|
|
22
|
+
* This file hides those differences behind one portable interface.
|
|
23
|
+
*
|
|
24
|
+
* Keep this API clean:
|
|
25
|
+
* - No COM/Windows-only types
|
|
26
|
+
* - No IMMDevice/IPolicyConfig in public signatures
|
|
27
|
+
* - No platform-specific structs in public contracts
|
|
28
|
+
*
|
|
29
|
+
* Layering:
|
|
30
|
+
* App / Node addon / tests
|
|
31
|
+
* ↓
|
|
32
|
+
* truehear_audio.h (this file)
|
|
33
|
+
* ↓
|
|
34
|
+
* platform implementation
|
|
35
|
+
* ↓
|
|
36
|
+
* Windows Core Audio | macOS CoreAudio | Linux PipeWire/Pulse/ALSA
|
|
37
|
+
*
|
|
38
|
+
* ---------------------------------------------------------------------------
|
|
39
|
+
* Error model
|
|
40
|
+
* ---------------------------------------------------------------------------
|
|
41
|
+
* Most functions return:
|
|
42
|
+
* - 0 on success
|
|
43
|
+
* - -1 on failure
|
|
44
|
+
*
|
|
45
|
+
* On failure, call truehear_audio_get_last_error() for a human-readable reason.
|
|
46
|
+
*
|
|
47
|
+
* ---------------------------------------------------------------------------
|
|
48
|
+
* Memory model
|
|
49
|
+
* ---------------------------------------------------------------------------
|
|
50
|
+
* truehear_audio_list_devices() allocates memory for the output list.
|
|
51
|
+
* Caller MUST free it using truehear_audio_free_device_list().
|
|
52
|
+
*
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
#ifdef __cplusplus
|
|
56
|
+
extern "C" {
|
|
57
|
+
#endif
|
|
58
|
+
|
|
59
|
+
/* ============================================================================================== */
|
|
60
|
+
/* Quick Start */
|
|
61
|
+
/* ============================================================================================== */
|
|
62
|
+
/**
|
|
63
|
+
* Basic flow:
|
|
64
|
+
*
|
|
65
|
+
* 1) Enumerate devices:
|
|
66
|
+
* truehear_audio_list_devices(type, &list)
|
|
67
|
+
* 2) Pick a device ID from list.items[i].id
|
|
68
|
+
* 3) Set default:
|
|
69
|
+
* truehear_audio_set_default_device(type, device_id)
|
|
70
|
+
* Optional (communication profile):
|
|
71
|
+
* truehear_audio_set_default_communication_device(type, device_id)
|
|
72
|
+
* 4) Cleanup:
|
|
73
|
+
* truehear_audio_free_device_list(&list)
|
|
74
|
+
*
|
|
75
|
+
* Typical type mapping:
|
|
76
|
+
* - TRUEHEAR_AUDIO_DEVICE_TYPE_PLAYBACK -> output devices (speakers/headphones)
|
|
77
|
+
* - TRUEHEAR_AUDIO_DEVICE_TYPE_RECORDING -> input devices (microphones)
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
/* ============================================================================================== */
|
|
81
|
+
/* Device Enumeration */
|
|
82
|
+
/* ============================================================================================== */
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @brief Enumerate audio devices for a given device class.
|
|
86
|
+
*
|
|
87
|
+
* @param type
|
|
88
|
+
* Device class to enumerate:
|
|
89
|
+
* - TRUEHEAR_AUDIO_DEVICE_TYPE_PLAYBACK
|
|
90
|
+
* - TRUEHEAR_AUDIO_DEVICE_TYPE_RECORDING
|
|
91
|
+
*
|
|
92
|
+
* @param[out] out_list
|
|
93
|
+
* Receives an allocated device list on success.
|
|
94
|
+
*
|
|
95
|
+
* @return
|
|
96
|
+
* - 0 on success
|
|
97
|
+
* - -1 on failure (use truehear_audio_get_last_error())
|
|
98
|
+
*
|
|
99
|
+
* @pre
|
|
100
|
+
* - out_list != NULL
|
|
101
|
+
*
|
|
102
|
+
* @post (on success)
|
|
103
|
+
* - out_list is initialized and owns allocated memory
|
|
104
|
+
* - caller must call truehear_audio_free_device_list(out_list)
|
|
105
|
+
*
|
|
106
|
+
* @post (on failure)
|
|
107
|
+
* - out_list content is implementation-defined; caller should still treat
|
|
108
|
+
* cleanup as safe via truehear_audio_free_device_list(out_list)
|
|
109
|
+
*
|
|
110
|
+
* @Example:
|
|
111
|
+
* @code
|
|
112
|
+
* #include <stdio.h>
|
|
113
|
+
* #include "truehear_audio.h"
|
|
114
|
+
*
|
|
115
|
+
* static void print_devices(TruehearAudioDeviceType type) {
|
|
116
|
+
* TruehearAudioDeviceInfoList list;
|
|
117
|
+
*
|
|
118
|
+
* if (truehear_audio_list_devices(type, &list) != 0) {
|
|
119
|
+
* fprintf(stderr, "List failed: %s\n", truehear_audio_get_last_error());
|
|
120
|
+
* return;
|
|
121
|
+
* }
|
|
122
|
+
*
|
|
123
|
+
* for (int i = 0; i < list.count; ++i) {
|
|
124
|
+
* const TruehearAudioDeviceInfo *d = &list.items[i];
|
|
125
|
+
* printf("[%d] name='%s' id='%s' is_default=%d\n",
|
|
126
|
+
* i,
|
|
127
|
+
* d->name ? d->name : "(null)",
|
|
128
|
+
* d->id ? d->id : "(null)",
|
|
129
|
+
* d->is_default);
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* truehear_audio_free_device_list(&list);
|
|
133
|
+
* }
|
|
134
|
+
* @endcode
|
|
135
|
+
*/
|
|
136
|
+
int truehear_audio_list_devices(
|
|
137
|
+
TruehearAudioDeviceType type,
|
|
138
|
+
TruehearAudioDeviceInfoList *out_list);
|
|
139
|
+
|
|
140
|
+
/* ============================================================================================== */
|
|
141
|
+
/* Default Device Management */
|
|
142
|
+
/* ============================================================================================== */
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @brief Set the system default audio device.
|
|
146
|
+
*
|
|
147
|
+
* Typical meaning:
|
|
148
|
+
* - playback => system default output
|
|
149
|
+
* - recording => system default input
|
|
150
|
+
*
|
|
151
|
+
* @param type
|
|
152
|
+
* Playback or recording device class.
|
|
153
|
+
*
|
|
154
|
+
* @param device_id
|
|
155
|
+
* Non-NULL, non-empty device ID from truehear_audio_list_devices().
|
|
156
|
+
*
|
|
157
|
+
* @return
|
|
158
|
+
* - 0 on success
|
|
159
|
+
* - -1 on failure (use truehear_audio_get_last_error())
|
|
160
|
+
*
|
|
161
|
+
* @pre
|
|
162
|
+
* - device_id != NULL
|
|
163
|
+
* - device_id points to a valid, null-terminated string
|
|
164
|
+
*
|
|
165
|
+
* Example:
|
|
166
|
+
* @code
|
|
167
|
+
* // Set first playback device as system default (demo only).
|
|
168
|
+
* TruehearAudioDeviceInfoList list;
|
|
169
|
+
* if (truehear_audio_list_devices(TRUEHEAR_AUDIO_DEVICE_TYPE_PLAYBACK, &list) != 0) {
|
|
170
|
+
* fprintf(stderr, "List failed: %s\n", truehear_audio_get_last_error());
|
|
171
|
+
* return;
|
|
172
|
+
* }
|
|
173
|
+
*
|
|
174
|
+
* if (list.count > 0 && list.items[0].id) {
|
|
175
|
+
* if (truehear_audio_set_default_device(
|
|
176
|
+
* TRUEHEAR_AUDIO_DEVICE_TYPE_PLAYBACK,
|
|
177
|
+
* list.items[0].id) != 0) {
|
|
178
|
+
* fprintf(stderr, "Set default failed: %s\n", truehear_audio_get_last_error());
|
|
179
|
+
* }
|
|
180
|
+
* }
|
|
181
|
+
*
|
|
182
|
+
* truehear_audio_free_device_list(&list);
|
|
183
|
+
* @endcode
|
|
184
|
+
*/
|
|
185
|
+
int truehear_audio_set_default_device(
|
|
186
|
+
TruehearAudioDeviceType type,
|
|
187
|
+
const char *device_id);
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @brief Set the default communication audio device.
|
|
191
|
+
*
|
|
192
|
+
* Some platforms (notably Windows) distinguish:
|
|
193
|
+
* - regular multimedia default
|
|
194
|
+
* - communication default (calls/conferencing apps)
|
|
195
|
+
*
|
|
196
|
+
* On platforms without a communication role, this may return failure with an
|
|
197
|
+
* "unsupported" style error message.
|
|
198
|
+
*
|
|
199
|
+
* @param type
|
|
200
|
+
* Playback or recording device class.
|
|
201
|
+
*
|
|
202
|
+
* @param device_id
|
|
203
|
+
* Non-NULL, non-empty device ID from truehear_audio_list_devices().
|
|
204
|
+
*
|
|
205
|
+
* @return
|
|
206
|
+
* - 0 on success
|
|
207
|
+
* - -1 on failure (use truehear_audio_get_last_error())
|
|
208
|
+
*
|
|
209
|
+
* Example:
|
|
210
|
+
* @code
|
|
211
|
+
* // Try to set communication default for microphones.
|
|
212
|
+
* TruehearAudioDeviceInfoList list;
|
|
213
|
+
* if (truehear_audio_list_devices(TRUEHEAR_AUDIO_DEVICE_TYPE_RECORDING, &list) != 0) {
|
|
214
|
+
* fprintf(stderr, "List failed: %s\n", truehear_audio_get_last_error());
|
|
215
|
+
* return;
|
|
216
|
+
* }
|
|
217
|
+
*
|
|
218
|
+
* // Pick a candidate by your own policy (name match, index, etc.)
|
|
219
|
+
* for (int i = 0; i < list.count; ++i) {
|
|
220
|
+
* if (list.items[i].id) {
|
|
221
|
+
* if (truehear_audio_set_default_communication_device(
|
|
222
|
+
* TRUEHEAR_AUDIO_DEVICE_TYPE_RECORDING,
|
|
223
|
+
* list.items[i].id) != 0) {
|
|
224
|
+
* fprintf(stderr, "Set comm default failed: %s\n",
|
|
225
|
+
* truehear_audio_get_last_error());
|
|
226
|
+
* }
|
|
227
|
+
* break;
|
|
228
|
+
* }
|
|
229
|
+
* }
|
|
230
|
+
*
|
|
231
|
+
* truehear_audio_free_device_list(&list);
|
|
232
|
+
* @endcode
|
|
233
|
+
*/
|
|
234
|
+
int truehear_audio_set_default_communication_device(
|
|
235
|
+
TruehearAudioDeviceType type,
|
|
236
|
+
const char *device_id);
|
|
237
|
+
|
|
238
|
+
/* ============================================================================================== */
|
|
239
|
+
/* Memory Management */
|
|
240
|
+
/* ============================================================================================== */
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* @brief Free resources in a device list returned by truehear_audio_list_devices().
|
|
244
|
+
*
|
|
245
|
+
* Releases:
|
|
246
|
+
* - list->items
|
|
247
|
+
* - item.name
|
|
248
|
+
* - item.id
|
|
249
|
+
* - item.device
|
|
250
|
+
*
|
|
251
|
+
* Safe to call with:
|
|
252
|
+
* - NULL
|
|
253
|
+
* - list with count == 0
|
|
254
|
+
* - list with items == NULL
|
|
255
|
+
*
|
|
256
|
+
* After return, callers should not read prior pointers from @p list.
|
|
257
|
+
*
|
|
258
|
+
* @param list
|
|
259
|
+
* Pointer to a list previously used with truehear_audio_list_devices().
|
|
260
|
+
*/
|
|
261
|
+
void truehear_audio_free_device_list(
|
|
262
|
+
TruehearAudioDeviceInfoList *list);
|
|
263
|
+
|
|
264
|
+
/* ============================================================================================== */
|
|
265
|
+
/* Error Reporting */
|
|
266
|
+
/* ============================================================================================== */
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* @brief Return a human-readable message for the most recent API failure.
|
|
270
|
+
*
|
|
271
|
+
* Use immediately after a function returns -1.
|
|
272
|
+
*
|
|
273
|
+
* @return
|
|
274
|
+
* Library-owned const string pointer.
|
|
275
|
+
* - Do NOT free
|
|
276
|
+
* - Do NOT modify
|
|
277
|
+
* - May be overwritten by subsequent API calls
|
|
278
|
+
*
|
|
279
|
+
* Example:
|
|
280
|
+
* @code
|
|
281
|
+
* if (truehear_audio_set_default_device(type, id) != 0) {
|
|
282
|
+
* const char *err = truehear_audio_get_last_error();
|
|
283
|
+
* fprintf(stderr, "truehear error: %s\n", err ? err : "(unknown)");
|
|
284
|
+
* }
|
|
285
|
+
* @endcode
|
|
286
|
+
*/
|
|
287
|
+
const char *truehear_audio_get_last_error(void);
|
|
288
|
+
|
|
289
|
+
/* ============================================================================================== */
|
|
290
|
+
/* End-to-End Example */
|
|
291
|
+
/* ============================================================================================== */
|
|
292
|
+
/**
|
|
293
|
+
* @code
|
|
294
|
+
* #include <stdio.h>
|
|
295
|
+
* #include <string.h>
|
|
296
|
+
* #include "truehear_audio.h"
|
|
297
|
+
*
|
|
298
|
+
* // Demo: set playback default by substring match on device name.
|
|
299
|
+
* int set_playback_default_by_name(const char *needle) {
|
|
300
|
+
* TruehearAudioDeviceInfoList list;
|
|
301
|
+
* int rc = truehear_audio_list_devices(TRUEHEAR_AUDIO_DEVICE_TYPE_PLAYBACK, &list);
|
|
302
|
+
* if (rc != 0) {
|
|
303
|
+
* fprintf(stderr, "List failed: %s\n", truehear_audio_get_last_error());
|
|
304
|
+
* return -1;
|
|
305
|
+
* }
|
|
306
|
+
*
|
|
307
|
+
* const char *selected_id = NULL;
|
|
308
|
+
* for (int i = 0; i < list.count; ++i) {
|
|
309
|
+
* const TruehearAudioDeviceInfo *d = &list.items[i];
|
|
310
|
+
* if (d->name && strstr(d->name, needle) && d->id) {
|
|
311
|
+
* selected_id = d->id;
|
|
312
|
+
* break;
|
|
313
|
+
* }
|
|
314
|
+
* }
|
|
315
|
+
*
|
|
316
|
+
* if (!selected_id) {
|
|
317
|
+
* fprintf(stderr, "No matching playback device for '%s'\n", needle);
|
|
318
|
+
* truehear_audio_free_device_list(&list);
|
|
319
|
+
* return -1;
|
|
320
|
+
* }
|
|
321
|
+
*
|
|
322
|
+
* rc = truehear_audio_set_default_device(
|
|
323
|
+
* TRUEHEAR_AUDIO_DEVICE_TYPE_PLAYBACK, selected_id);
|
|
324
|
+
* if (rc != 0) {
|
|
325
|
+
* fprintf(stderr, "Set default failed: %s\n", truehear_audio_get_last_error());
|
|
326
|
+
* truehear_audio_free_device_list(&list);
|
|
327
|
+
* return -1;
|
|
328
|
+
* }
|
|
329
|
+
*
|
|
330
|
+
* // Optional: also set communication default.
|
|
331
|
+
* if (truehear_audio_set_default_communication_device(
|
|
332
|
+
* TRUEHEAR_AUDIO_DEVICE_TYPE_PLAYBACK, selected_id) != 0) {
|
|
333
|
+
* // Not fatal on platforms where unsupported.
|
|
334
|
+
* fprintf(stderr, "Set communication default warning: %s\n",
|
|
335
|
+
* truehear_audio_get_last_error());
|
|
336
|
+
* }
|
|
337
|
+
*
|
|
338
|
+
* truehear_audio_free_device_list(&list);
|
|
339
|
+
* return 0;
|
|
340
|
+
* }
|
|
341
|
+
* @endcode
|
|
342
|
+
*/
|
|
343
|
+
|
|
344
|
+
#ifdef __cplusplus
|
|
345
|
+
} /* extern "C" */
|
|
346
|
+
#endif
|
|
347
|
+
|
|
348
|
+
#endif /* TRUEHEAR_AUDIO_H */
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "truehear-audio-library-node",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Native Node.js audio device listing and default-device switching library.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"os": [
|
|
16
|
+
"win32"
|
|
17
|
+
],
|
|
18
|
+
"cpu": [
|
|
19
|
+
"x64"
|
|
20
|
+
],
|
|
21
|
+
"files": [
|
|
22
|
+
"dist/**/*.js",
|
|
23
|
+
"dist/**/*.js.map",
|
|
24
|
+
"dist/**/*.d.ts",
|
|
25
|
+
"dist/**/*.d.ts.map",
|
|
26
|
+
"prebuilds",
|
|
27
|
+
"include",
|
|
28
|
+
"src",
|
|
29
|
+
"binding.gyp",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"gypfile": true,
|
|
34
|
+
"scripts": {
|
|
35
|
+
"install": "node-gyp-build",
|
|
36
|
+
"clean:dist": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
37
|
+
"clean:prebuilds": "node -e \"require('fs').rmSync('prebuilds', { recursive: true, force: true })\"",
|
|
38
|
+
"clean:native": "node-gyp clean",
|
|
39
|
+
"build:native": "node-gyp rebuild",
|
|
40
|
+
"build:native:debug": "node-gyp rebuild --debug",
|
|
41
|
+
"build:ts": "npm run clean:dist && tsc -p tsconfig.lib.json",
|
|
42
|
+
"copy:prebuild": "node scripts/copy-prebuild.cjs",
|
|
43
|
+
"build:prebuild": "npm run clean:prebuilds && npm run build:native && npm run copy:prebuild",
|
|
44
|
+
"build": "npm run build:native && npm run build:ts",
|
|
45
|
+
"build:package": "npm run build:ts && npm run build:prebuild",
|
|
46
|
+
"prepack": "npm run build:package",
|
|
47
|
+
"typecheck": "tsc -b",
|
|
48
|
+
"test:native": "node node/tests/native.test.cjs",
|
|
49
|
+
"test:list": "tsx node/tests/list.devices.ts",
|
|
50
|
+
"test:set": "tsx node/tests/set.device.ts",
|
|
51
|
+
"test": "npm run test:native && npm run test:list",
|
|
52
|
+
"pack:check": "npm pack --dry-run",
|
|
53
|
+
"pack:local": "npm pack"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"audio",
|
|
57
|
+
"device",
|
|
58
|
+
"windows",
|
|
59
|
+
"core-audio",
|
|
60
|
+
"wasapi",
|
|
61
|
+
"node-api",
|
|
62
|
+
"napi",
|
|
63
|
+
"native-addon",
|
|
64
|
+
"default-audio-device"
|
|
65
|
+
],
|
|
66
|
+
"author": "@truehear team",
|
|
67
|
+
"license": "ISC",
|
|
68
|
+
"repository": {
|
|
69
|
+
"type": "git",
|
|
70
|
+
"url": "git+https://github.com/TrueHear/truehear-audio-library-node.git"
|
|
71
|
+
},
|
|
72
|
+
"bugs": {
|
|
73
|
+
"url": "https://github.com/TrueHear/truehear-audio-library-node/issues"
|
|
74
|
+
},
|
|
75
|
+
"homepage": "https://github.com/TrueHear/truehear-audio-library-node#readme",
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"node-gyp-build": "^4.8.4"
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@types/node": "^25.9.3",
|
|
81
|
+
"node-gyp": "^13.0.0",
|
|
82
|
+
"tsx": "^4.20.0",
|
|
83
|
+
"typescript": "^5.0.0"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
Binary file
|