@bryan-gc/transcribe-cli 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 +46 -0
- package/dist/audio/audioPlayer.d.ts +7 -0
- package/dist/audio/audioPlayer.d.ts.map +1 -0
- package/dist/audio/audioPlayer.js +49 -0
- package/dist/audio/audioPlayer.js.map +1 -0
- package/dist/audio/micDevices.d.ts +17 -0
- package/dist/audio/micDevices.d.ts.map +1 -0
- package/dist/audio/micDevices.js +120 -0
- package/dist/audio/micDevices.js.map +1 -0
- package/dist/audio/recorder.d.ts +16 -0
- package/dist/audio/recorder.d.ts.map +1 -0
- package/dist/audio/recorder.js +149 -0
- package/dist/audio/recorder.js.map +1 -0
- package/dist/components/App.d.ts +5 -0
- package/dist/components/App.d.ts.map +1 -0
- package/dist/components/App.js +279 -0
- package/dist/components/App.js.map +1 -0
- package/dist/components/MicTest.d.ts +10 -0
- package/dist/components/MicTest.d.ts.map +1 -0
- package/dist/components/MicTest.js +150 -0
- package/dist/components/MicTest.js.map +1 -0
- package/dist/components/Picker.d.ts +13 -0
- package/dist/components/Picker.d.ts.map +1 -0
- package/dist/components/Picker.js +20 -0
- package/dist/components/Picker.js.map +1 -0
- package/dist/components/SetupPrompt.d.ts +8 -0
- package/dist/components/SetupPrompt.d.ts.map +1 -0
- package/dist/components/SetupPrompt.js +39 -0
- package/dist/components/SetupPrompt.js.map +1 -0
- package/dist/config/configManager.d.ts +15 -0
- package/dist/config/configManager.d.ts.map +1 -0
- package/dist/config/configManager.js +50 -0
- package/dist/config/configManager.js.map +1 -0
- package/dist/constants.d.ts +134 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +169 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/src/audio/audioPlayer.d.ts +7 -0
- package/dist/src/audio/audioPlayer.d.ts.map +1 -0
- package/dist/src/audio/audioPlayer.js +49 -0
- package/dist/src/audio/audioPlayer.js.map +1 -0
- package/dist/src/audio/micDevices.d.ts +17 -0
- package/dist/src/audio/micDevices.d.ts.map +1 -0
- package/dist/src/audio/micDevices.js +120 -0
- package/dist/src/audio/micDevices.js.map +1 -0
- package/dist/src/audio/recorder.d.ts +16 -0
- package/dist/src/audio/recorder.d.ts.map +1 -0
- package/dist/src/audio/recorder.js +149 -0
- package/dist/src/audio/recorder.js.map +1 -0
- package/dist/src/components/App.d.ts +5 -0
- package/dist/src/components/App.d.ts.map +1 -0
- package/dist/src/components/App.js +279 -0
- package/dist/src/components/App.js.map +1 -0
- package/dist/src/components/MicTest.d.ts +10 -0
- package/dist/src/components/MicTest.d.ts.map +1 -0
- package/dist/src/components/MicTest.js +150 -0
- package/dist/src/components/MicTest.js.map +1 -0
- package/dist/src/components/Picker.d.ts +13 -0
- package/dist/src/components/Picker.d.ts.map +1 -0
- package/dist/src/components/Picker.js +20 -0
- package/dist/src/components/Picker.js.map +1 -0
- package/dist/src/components/SetupPrompt.d.ts +8 -0
- package/dist/src/components/SetupPrompt.d.ts.map +1 -0
- package/dist/src/components/SetupPrompt.js +39 -0
- package/dist/src/components/SetupPrompt.js.map +1 -0
- package/dist/src/config/configManager.d.ts +15 -0
- package/dist/src/config/configManager.d.ts.map +1 -0
- package/dist/src/config/configManager.js +50 -0
- package/dist/src/config/configManager.js.map +1 -0
- package/dist/src/constants.d.ts +134 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +169 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +34 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/transcriber/ITranscriber.d.ts +12 -0
- package/dist/src/transcriber/ITranscriber.d.ts.map +1 -0
- package/dist/src/transcriber/ITranscriber.js +2 -0
- package/dist/src/transcriber/ITranscriber.js.map +1 -0
- package/dist/src/transcriber/WhisperTranscriber.d.ts +8 -0
- package/dist/src/transcriber/WhisperTranscriber.d.ts.map +1 -0
- package/dist/src/transcriber/WhisperTranscriber.js +35 -0
- package/dist/src/transcriber/WhisperTranscriber.js.map +1 -0
- package/dist/src/utils/clipboard.d.ts +11 -0
- package/dist/src/utils/clipboard.d.ts.map +1 -0
- package/dist/src/utils/clipboard.js +56 -0
- package/dist/src/utils/clipboard.js.map +1 -0
- package/dist/src/utils/srtParser.d.ts +6 -0
- package/dist/src/utils/srtParser.d.ts.map +1 -0
- package/dist/src/utils/srtParser.js +25 -0
- package/dist/src/utils/srtParser.js.map +1 -0
- package/dist/transcriber/ITranscriber.d.ts +12 -0
- package/dist/transcriber/ITranscriber.d.ts.map +1 -0
- package/dist/transcriber/ITranscriber.js +2 -0
- package/dist/transcriber/ITranscriber.js.map +1 -0
- package/dist/transcriber/WhisperTranscriber.d.ts +8 -0
- package/dist/transcriber/WhisperTranscriber.d.ts.map +1 -0
- package/dist/transcriber/WhisperTranscriber.js +35 -0
- package/dist/transcriber/WhisperTranscriber.js.map +1 -0
- package/dist/utils/clipboard.d.ts +11 -0
- package/dist/utils/clipboard.d.ts.map +1 -0
- package/dist/utils/clipboard.js +56 -0
- package/dist/utils/clipboard.js.map +1 -0
- package/dist/utils/srtParser.d.ts +6 -0
- package/dist/utils/srtParser.d.ts.map +1 -0
- package/dist/utils/srtParser.js +25 -0
- package/dist/utils/srtParser.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# transcribe-cli
|
|
2
|
+
|
|
3
|
+
Una aplicación de terminal (CLI) escrita en Node.js y TypeScript para grabar audio desde el micrófono y transcribirlo utilizando la API Whisper de OpenAI.
|
|
4
|
+
|
|
5
|
+
## Requisitos Previos del Sistema (Importante)
|
|
6
|
+
|
|
7
|
+
Para que Node.js pueda grabar audio desde tu micrófono, necesita apoyarse en herramientas del sistema operativo. Dependiendo de tu sistema, debes instalar lo siguiente **antes** de correr el proyecto:
|
|
8
|
+
|
|
9
|
+
### Linux (Ubuntu / Debian)
|
|
10
|
+
Necesitas instalar `sox` y las librerías de soporte de formatos de audio:
|
|
11
|
+
```bash
|
|
12
|
+
sudo apt-get update
|
|
13
|
+
sudo apt-get install sox libsox-fmt-all
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### macOS
|
|
17
|
+
Puedes instalar `sox` usando Homebrew:
|
|
18
|
+
```bash
|
|
19
|
+
brew install sox
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Windows
|
|
23
|
+
1. Descarga los binarios de [SoX](https://sourceforge.net/projects/sox/).
|
|
24
|
+
2. Añade la carpeta donde extrajiste SoX a tu variable de entorno `PATH`.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Instalación del Proyecto
|
|
29
|
+
|
|
30
|
+
1. Clona el repositorio o descarga los archivos.
|
|
31
|
+
2. Instala las dependencias de Node:
|
|
32
|
+
```bash
|
|
33
|
+
npm install
|
|
34
|
+
```
|
|
35
|
+
3. Al iniciar la aplicación por primera vez, un prompt interactivo te pedirá tu **API Key de OpenAI** y la **ruta base** para guardar los audios y glosarios. Estos datos se guardarán de forma persistente en `~/.transcribe-cli/config.json`.
|
|
36
|
+
|
|
37
|
+
## Uso
|
|
38
|
+
|
|
39
|
+
Para iniciar la aplicación, simplemente corre:
|
|
40
|
+
```bash
|
|
41
|
+
npm start
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
La aplicación mostrará un menú interactivo en la terminal. Puedes controlarlo de dos formas:
|
|
45
|
+
- **Flechas Direccionales:** Usa Arriba/Abajo para moverte y Enter para seleccionar una opción.
|
|
46
|
+
- **Atajos de Teclado:** Presiona `r` para grabar, `p` para pausar, `s` para detener y `t` para transcribir.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function stopPlayback(): void;
|
|
2
|
+
/**
|
|
3
|
+
* Plays a WAV file. Tries 'play' (sox) first, falls back to 'aplay' on Linux,
|
|
4
|
+
* or 'afplay' on macOS. Resolves when playback finishes or is stopped.
|
|
5
|
+
*/
|
|
6
|
+
export declare function playAudio(filepath: string): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=audioPlayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioPlayer.d.ts","sourceRoot":"","sources":["../../src/audio/audioPlayer.ts"],"names":[],"mappings":"AAQA,wBAAgB,YAAY,SAK3B;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCzD"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { Platform, Cmd, Signal, ProcessEvent, StdioOption } from '../constants';
|
|
5
|
+
let playProcess = null;
|
|
6
|
+
export function stopPlayback() {
|
|
7
|
+
if (playProcess) {
|
|
8
|
+
playProcess.kill(Signal.SIGTERM);
|
|
9
|
+
playProcess = null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Plays a WAV file. Tries 'play' (sox) first, falls back to 'aplay' on Linux,
|
|
14
|
+
* or 'afplay' on macOS. Resolves when playback finishes or is stopped.
|
|
15
|
+
*/
|
|
16
|
+
export function playAudio(filepath) {
|
|
17
|
+
stopPlayback();
|
|
18
|
+
const platform = os.platform();
|
|
19
|
+
const getCmdArgs = () => {
|
|
20
|
+
if (platform === Platform.DARWIN) {
|
|
21
|
+
return { cmd: Cmd.AFPLAY, args: [filepath] };
|
|
22
|
+
}
|
|
23
|
+
// Try sox's 'play' first (already installed for recording)
|
|
24
|
+
try {
|
|
25
|
+
execSync(`which ${Cmd.PLAY}`, { stdio: StdioOption.IGNORE });
|
|
26
|
+
return { cmd: Cmd.PLAY, args: [filepath] };
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return { cmd: Cmd.APLAY, args: [filepath] };
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const { cmd, args } = getCmdArgs();
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
playProcess = spawn(cmd, args, { stdio: StdioOption.IGNORE });
|
|
35
|
+
playProcess.on(ProcessEvent.CLOSE, (code) => {
|
|
36
|
+
playProcess = null;
|
|
37
|
+
if (code === null || code === 0) {
|
|
38
|
+
resolve();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
reject(new Error(`Playback exited with code ${code}`));
|
|
42
|
+
});
|
|
43
|
+
playProcess.on(ProcessEvent.ERROR, (err) => {
|
|
44
|
+
playProcess = null;
|
|
45
|
+
reject(err);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=audioPlayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioPlayer.js","sourceRoot":"","sources":["../../src/audio/audioPlayer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhF,IAAI,WAAW,GAAwB,IAAI,CAAC;AAE5C,MAAM,UAAU,YAAY;IAC1B,IAAI,WAAW,EAAE,CAAC;QAChB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,YAAY,EAAE,CAAC;IAEf,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,GAAoC,EAAE;QACvD,IAAI,QAAQ,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;YACjC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/C,CAAC;QACD,2DAA2D;QAC3D,IAAI,CAAC;YACH,QAAQ,CAAC,SAAS,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7D,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,UAAU,EAAE,CAAC;IAEnC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,WAAW,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9D,WAAW,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1C,WAAW,GAAG,IAAI,CAAC;YACnB,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBAChC,OAAO,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE;YACzC,WAAW,GAAG,IAAI,CAAC;YACnB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface MicDevice {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Detects the current platform and returns a list of available
|
|
7
|
+
* microphone/capture devices dynamically.
|
|
8
|
+
*
|
|
9
|
+
* Supported platforms:
|
|
10
|
+
* - Linux → uses `arecord -L` (ALSA)
|
|
11
|
+
* - macOS → uses `system_profiler SPAudioDataType`
|
|
12
|
+
* - Windows → falls back to "Default Device" (sox handles selection natively)
|
|
13
|
+
*
|
|
14
|
+
* Always includes a "Default Device" entry as a safe fallback.
|
|
15
|
+
*/
|
|
16
|
+
export declare function listMicDevices(): MicDevice[];
|
|
17
|
+
//# sourceMappingURL=micDevices.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"micDevices.d.ts","sourceRoot":"","sources":["../../src/audio/micDevices.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,IAAI,SAAS,EAAE,CAe5C"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import { DEFAULT_DEVICE_ID, DEFAULT_DEVICE_LABEL, Platform, Cmd, Encoding, AlsaDevice, ALSA_VIRTUAL_DEVICES, } from '../constants';
|
|
4
|
+
/**
|
|
5
|
+
* Detects the current platform and returns a list of available
|
|
6
|
+
* microphone/capture devices dynamically.
|
|
7
|
+
*
|
|
8
|
+
* Supported platforms:
|
|
9
|
+
* - Linux → uses `arecord -L` (ALSA)
|
|
10
|
+
* - macOS → uses `system_profiler SPAudioDataType`
|
|
11
|
+
* - Windows → falls back to "Default Device" (sox handles selection natively)
|
|
12
|
+
*
|
|
13
|
+
* Always includes a "Default Device" entry as a safe fallback.
|
|
14
|
+
*/
|
|
15
|
+
export function listMicDevices() {
|
|
16
|
+
const platform = os.platform();
|
|
17
|
+
try {
|
|
18
|
+
if (platform === Platform.LINUX) {
|
|
19
|
+
return listLinuxDevices();
|
|
20
|
+
}
|
|
21
|
+
if (platform === Platform.DARWIN) {
|
|
22
|
+
return listMacDevices();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// If detection fails for any reason, fall back silently
|
|
27
|
+
}
|
|
28
|
+
return [{ id: DEFAULT_DEVICE_ID, label: DEFAULT_DEVICE_LABEL }];
|
|
29
|
+
}
|
|
30
|
+
// ─── Linux (ALSA via arecord / PipeWire via pw-dump) ──────────────────────────
|
|
31
|
+
function listLinuxDevices() {
|
|
32
|
+
const devices = [{ id: DEFAULT_DEVICE_ID, label: DEFAULT_DEVICE_LABEL }];
|
|
33
|
+
// 1. Try PipeWire (pw-dump) for user-friendly names matching Ubuntu settings
|
|
34
|
+
try {
|
|
35
|
+
const rawPw = execSync(`${Cmd.PW_DUMP} 2>/dev/null`, { encoding: Encoding.UTF8 });
|
|
36
|
+
const nodes = JSON.parse(rawPw);
|
|
37
|
+
let foundPwDevices = false;
|
|
38
|
+
for (const node of nodes) {
|
|
39
|
+
const props = node?.info?.props;
|
|
40
|
+
if (props && props['media.class'] === 'Audio/Source') {
|
|
41
|
+
const id = props['node.name'];
|
|
42
|
+
const label = props['node.description'] || id;
|
|
43
|
+
if (id) {
|
|
44
|
+
devices.push({ id, label });
|
|
45
|
+
foundPwDevices = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (foundPwDevices) {
|
|
50
|
+
return devices;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Fallback to arecord if pw-dump fails or isn't installed
|
|
55
|
+
}
|
|
56
|
+
// 2. Fallback to ALSA (arecord -L)
|
|
57
|
+
try {
|
|
58
|
+
const raw = execSync(`${Cmd.ARECORD} -L 2>/dev/null`, { encoding: Encoding.UTF8 });
|
|
59
|
+
// Top-level lines (no leading whitespace) are device IDs.
|
|
60
|
+
// Lines starting with spaces are descriptions → skip them.
|
|
61
|
+
const topLevel = raw
|
|
62
|
+
.split('\n')
|
|
63
|
+
.filter((line) => line.trim() && !line.startsWith(' ') && !line.startsWith('\t'));
|
|
64
|
+
for (const id of topLevel) {
|
|
65
|
+
if (ALSA_VIRTUAL_DEVICES.has(id) || id === DEFAULT_DEVICE_ID)
|
|
66
|
+
continue;
|
|
67
|
+
devices.push({ id, label: formatAlsaLabel(id) });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Ignore error
|
|
72
|
+
}
|
|
73
|
+
return devices;
|
|
74
|
+
}
|
|
75
|
+
function formatAlsaLabel(id) {
|
|
76
|
+
if (id === AlsaDevice.PULSE)
|
|
77
|
+
return 'PulseAudio';
|
|
78
|
+
if (id === AlsaDevice.PIPEWIRE)
|
|
79
|
+
return 'PipeWire';
|
|
80
|
+
// plughw:CARD=sofhdadsp,DEV=0 → "sofhdadsp DEV 0 (plug)"
|
|
81
|
+
const hwMatch = id.match(/^(plughw|hw):CARD=([^,]+),DEV=(\d+)$/);
|
|
82
|
+
if (hwMatch) {
|
|
83
|
+
const plug = hwMatch[1] === AlsaDevice.PLUGHW ? ' (plug)' : '';
|
|
84
|
+
return `${hwMatch[2]} DEV ${hwMatch[3]}${plug}`;
|
|
85
|
+
}
|
|
86
|
+
// sysdefault:CARD=X → "X (sysdefault)"
|
|
87
|
+
const sysMatch = id.match(/^sysdefault:CARD=(.+)$/);
|
|
88
|
+
if (sysMatch)
|
|
89
|
+
return `${sysMatch[1]} (sysdefault)`;
|
|
90
|
+
// dsnoop:CARD=X,DEV=N → "X DEV N (dsnoop)"
|
|
91
|
+
const dsnoopMatch = id.match(/^dsnoop:CARD=([^,]+),DEV=(\d+)$/);
|
|
92
|
+
if (dsnoopMatch)
|
|
93
|
+
return `${dsnoopMatch[1]} DEV ${dsnoopMatch[2]} (dsnoop)`;
|
|
94
|
+
return id;
|
|
95
|
+
}
|
|
96
|
+
// ─── macOS (system_profiler) ──────────────────────────────────────────────────
|
|
97
|
+
function listMacDevices() {
|
|
98
|
+
const raw = execSync(`${Cmd.SYSTEM_PROFILER} SPAudioDataType 2>/dev/null`, {
|
|
99
|
+
encoding: Encoding.UTF8,
|
|
100
|
+
});
|
|
101
|
+
const devices = [{ id: DEFAULT_DEVICE_ID, label: DEFAULT_DEVICE_LABEL }];
|
|
102
|
+
// system_profiler outputs sections like:
|
|
103
|
+
// Built-in Microphone:
|
|
104
|
+
// Input Channels: 1
|
|
105
|
+
// …
|
|
106
|
+
// We grab names of sections that contain "Input Channels" (i.e., are inputs).
|
|
107
|
+
const sections = raw.split(/\n(?=\s{4}\S)/);
|
|
108
|
+
for (const section of sections) {
|
|
109
|
+
if (!section.includes('Input Channels'))
|
|
110
|
+
continue;
|
|
111
|
+
const nameLine = section.match(/^\s{4}(.+):$/m);
|
|
112
|
+
if (nameLine) {
|
|
113
|
+
const label = nameLine[1].trim();
|
|
114
|
+
// sox on macOS uses device names directly
|
|
115
|
+
devices.push({ id: label, label });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return devices.length > 1 ? devices : [{ id: DEFAULT_DEVICE_ID, label: DEFAULT_DEVICE_LABEL }];
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=micDevices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"micDevices.js","sourceRoot":"","sources":["../../src/audio/micDevices.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class AudioRecorder {
|
|
2
|
+
private cp;
|
|
3
|
+
private fileStream;
|
|
4
|
+
private filepath;
|
|
5
|
+
private device;
|
|
6
|
+
private _isPaused;
|
|
7
|
+
setDevice(device: string): void;
|
|
8
|
+
getDevice(): string;
|
|
9
|
+
start(filepath: string): void;
|
|
10
|
+
pause(): void;
|
|
11
|
+
resume(): void;
|
|
12
|
+
/** Stops the recording and resolves only when the audio file has been fully written to disk. */
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
getFilepath(): string;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/audio/recorder.ts"],"names":[],"mappings":"AAiBA,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAA6B;IACvC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,SAAS,CAAkB;IAEnC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO/B,SAAS,IAAI,MAAM;IAInB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAoE7B,KAAK,IAAI,IAAI;IAab,MAAM,IAAI,IAAI;IAOd,gGAAgG;IAChG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqDrB,WAAW,IAAI,MAAM;CAGtB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { DEFAULT_DEVICE_ID, Platform, Cmd, Signal, AUDIO_CONFIG, ALSA_PREFIXES, Encoding, StdioOption, StreamEvent, ProcessEvent, } from '../constants';
|
|
5
|
+
export class AudioRecorder {
|
|
6
|
+
cp = null;
|
|
7
|
+
fileStream = null;
|
|
8
|
+
filepath = '';
|
|
9
|
+
device = DEFAULT_DEVICE_ID;
|
|
10
|
+
_isPaused = false;
|
|
11
|
+
setDevice(device) {
|
|
12
|
+
if (this.cp) {
|
|
13
|
+
throw new Error('Cannot change device while recording is in progress.');
|
|
14
|
+
}
|
|
15
|
+
this.device = device;
|
|
16
|
+
}
|
|
17
|
+
getDevice() {
|
|
18
|
+
return this.device;
|
|
19
|
+
}
|
|
20
|
+
start(filepath) {
|
|
21
|
+
if (this.cp) {
|
|
22
|
+
throw new Error('A recording is already in progress.');
|
|
23
|
+
}
|
|
24
|
+
this.filepath = filepath;
|
|
25
|
+
this.fileStream = fs.createWriteStream(filepath, { encoding: Encoding.BINARY });
|
|
26
|
+
this._isPaused = false;
|
|
27
|
+
let env = process.env;
|
|
28
|
+
if (os.platform() === Platform.DARWIN) {
|
|
29
|
+
const args = [
|
|
30
|
+
'-d',
|
|
31
|
+
'-q',
|
|
32
|
+
'-r',
|
|
33
|
+
AUDIO_CONFIG.SAMPLE_RATE,
|
|
34
|
+
'-c',
|
|
35
|
+
AUDIO_CONFIG.CHANNELS,
|
|
36
|
+
'-e',
|
|
37
|
+
AUDIO_CONFIG.ENCODING_SOX,
|
|
38
|
+
'-b',
|
|
39
|
+
AUDIO_CONFIG.BITS,
|
|
40
|
+
'-t',
|
|
41
|
+
AUDIO_CONFIG.TYPE,
|
|
42
|
+
'-',
|
|
43
|
+
];
|
|
44
|
+
if (this.device !== DEFAULT_DEVICE_ID) {
|
|
45
|
+
env = { ...process.env, AUDIODEV: this.device };
|
|
46
|
+
}
|
|
47
|
+
this.cp = spawn(Cmd.SOX, args, {
|
|
48
|
+
stdio: [StdioOption.IGNORE, StdioOption.PIPE, StdioOption.IGNORE],
|
|
49
|
+
env,
|
|
50
|
+
});
|
|
51
|
+
this.cp.stdout?.pipe(this.fileStream);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Linux (arecord)
|
|
55
|
+
const args = [
|
|
56
|
+
'-q',
|
|
57
|
+
'-f',
|
|
58
|
+
AUDIO_CONFIG.FORMAT_ARECORD,
|
|
59
|
+
'-c',
|
|
60
|
+
AUDIO_CONFIG.CHANNELS,
|
|
61
|
+
'-r',
|
|
62
|
+
AUDIO_CONFIG.SAMPLE_RATE,
|
|
63
|
+
'-t',
|
|
64
|
+
AUDIO_CONFIG.TYPE,
|
|
65
|
+
];
|
|
66
|
+
if (this.device !== DEFAULT_DEVICE_ID) {
|
|
67
|
+
// If the device ID is from PipeWire/PulseAudio (e.g. alsa_input.usb-...)
|
|
68
|
+
// we use the 'pulse' ALSA device and tell Pulse/PipeWire which source to use.
|
|
69
|
+
const isPulse = this.device.startsWith(ALSA_PREFIXES.ALSA_INPUT) ||
|
|
70
|
+
this.device.startsWith(ALSA_PREFIXES.BLUEZ_INPUT);
|
|
71
|
+
args.push('-D', isPulse ? AUDIO_CONFIG.DEVICE_PULSE : this.device);
|
|
72
|
+
if (isPulse)
|
|
73
|
+
env = { ...process.env, PULSE_SOURCE: this.device };
|
|
74
|
+
}
|
|
75
|
+
this.cp = spawn(Cmd.ARECORD, args, {
|
|
76
|
+
stdio: [StdioOption.IGNORE, StdioOption.PIPE, StdioOption.IGNORE],
|
|
77
|
+
env,
|
|
78
|
+
});
|
|
79
|
+
this.cp.stdout?.pipe(this.fileStream);
|
|
80
|
+
}
|
|
81
|
+
pause() {
|
|
82
|
+
if (!this.cp || this._isPaused)
|
|
83
|
+
return;
|
|
84
|
+
// Delaying the SIGSTOP by a short moment allows the OS audio buffer to flush
|
|
85
|
+
// the last spoken words before the process freezes.
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
if (!this.cp || this._isPaused)
|
|
88
|
+
return;
|
|
89
|
+
this.cp.kill(Signal.SIGSTOP);
|
|
90
|
+
this._isPaused = true;
|
|
91
|
+
}, 500);
|
|
92
|
+
}
|
|
93
|
+
resume() {
|
|
94
|
+
if (!this.cp || !this._isPaused)
|
|
95
|
+
return;
|
|
96
|
+
this.cp.kill(Signal.SIGCONT);
|
|
97
|
+
this._isPaused = false;
|
|
98
|
+
}
|
|
99
|
+
/** Stops the recording and resolves only when the audio file has been fully written to disk. */
|
|
100
|
+
stop() {
|
|
101
|
+
return new Promise((resolve) => {
|
|
102
|
+
if (!this.cp) {
|
|
103
|
+
resolve();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// If the process was paused, we MUST resume it first so it can process
|
|
107
|
+
// the SIGINT/SIGTERM and flush any remaining buffer.
|
|
108
|
+
if (this._isPaused) {
|
|
109
|
+
this.cp.kill(Signal.SIGCONT);
|
|
110
|
+
this._isPaused = false;
|
|
111
|
+
}
|
|
112
|
+
// Wait a brief moment to capture the trailing audio from the hardware buffer
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
if (this.cp) {
|
|
115
|
+
// Attempt a graceful exit first (SIGINT) so wav headers and buffers can be flushed
|
|
116
|
+
this.cp.kill(Signal.SIGINT);
|
|
117
|
+
// Safety fallback to SIGTERM if it doesn't exit
|
|
118
|
+
const fallback = setTimeout(() => {
|
|
119
|
+
if (this.cp)
|
|
120
|
+
this.cp.kill(Signal.SIGTERM);
|
|
121
|
+
}, 500);
|
|
122
|
+
this.cp.on(ProcessEvent.EXIT, () => clearTimeout(fallback));
|
|
123
|
+
this.cp = null;
|
|
124
|
+
}
|
|
125
|
+
if (!this.fileStream) {
|
|
126
|
+
resolve();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const stream = this.fileStream;
|
|
130
|
+
this.fileStream = null;
|
|
131
|
+
let resolved = false;
|
|
132
|
+
const done = () => {
|
|
133
|
+
if (resolved)
|
|
134
|
+
return;
|
|
135
|
+
resolved = true;
|
|
136
|
+
resolve();
|
|
137
|
+
};
|
|
138
|
+
stream.on(StreamEvent.FINISH, done);
|
|
139
|
+
stream.on(StreamEvent.CLOSE, done);
|
|
140
|
+
stream.on(StreamEvent.ERROR, done);
|
|
141
|
+
setTimeout(done, 1500);
|
|
142
|
+
}, 500);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
getFilepath() {
|
|
146
|
+
return this.filepath;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/audio/recorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,4BAA4B,CAAC;AAsE3E,wBAAgB,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,2CA0V1D"}
|