@acpfx/mic-speaker 0.4.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.
Binary file
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ "use strict";
4
+
5
+ const { spawnSync } = require("child_process");
6
+ const { join } = require("path");
7
+ const { existsSync } = require("fs");
8
+
9
+ function getBinaryPath() {
10
+ // Allow override via env var (for local development)
11
+ if (process.env.MIC_SPEAKER_BINARY_PATH) {
12
+ return process.env.MIC_SPEAKER_BINARY_PATH;
13
+ }
14
+
15
+ const ext = process.platform === "win32" ? ".exe" : "";
16
+ const binName = `mic-speaker-${process.platform}-${process.arch}${ext}`;
17
+ const binPath = join(__dirname, binName);
18
+
19
+ if (!existsSync(binPath)) {
20
+ throw new Error(
21
+ `Could not find the mic-speaker binary for your platform (${process.platform} ${process.arch}).\n` +
22
+ `Expected: ${binPath}\n` +
23
+ `The postinstall script may have failed. Try reinstalling:\n` +
24
+ ` npm install @acpfx/mic-speaker\n` +
25
+ `Or set MIC_SPEAKER_BINARY_PATH to a local build.`
26
+ );
27
+ }
28
+
29
+ return binPath;
30
+ }
31
+
32
+ const binPath = getBinaryPath();
33
+ const { status } = spawnSync(binPath, process.argv.slice(2), {
34
+ stdio: "inherit",
35
+ });
36
+ process.exitCode = status !== null ? status : 1;
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@acpfx/mic-speaker",
3
+ "version": "0.4.0",
4
+ "description": "acpfx microphone with acoustic echo cancellation",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/thisnick/acpfx",
8
+ "directory": "packages/node-mic-speaker"
9
+ },
10
+ "license": "ISC",
11
+ "bin": {
12
+ "acpfx-mic-speaker": "./bin/mic-speaker"
13
+ },
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "files": [
18
+ "bin/",
19
+ "scripts/"
20
+ ],
21
+ "scripts": {
22
+ "build:native": "cargo build --release && mkdir -p bin && cp target/release/mic-speaker bin/",
23
+ "postinstall": "node scripts/postinstall.js"
24
+ }
25
+ }
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+
3
+ const https = require("https");
4
+ const http = require("http");
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+
8
+ const SUPPORTED_PLATFORMS = {
9
+ "darwin arm64": "mic-speaker-darwin-arm64",
10
+ "darwin x64": "mic-speaker-darwin-x64",
11
+ "linux x64": "mic-speaker-linux-x64",
12
+ "win32 x64": "mic-speaker-win32-x64.exe",
13
+ };
14
+
15
+ function hasNvidiaGpu() {
16
+ try {
17
+ require("child_process").execSync("nvidia-smi", { stdio: "ignore" });
18
+ return true;
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+
24
+ function getBinaryName() {
25
+ const key = `${process.platform} ${process.arch}`;
26
+ const base = SUPPORTED_PLATFORMS[key];
27
+ if (!base) {
28
+ throw new Error(
29
+ `Unsupported platform: ${process.platform} ${process.arch}.\n` +
30
+ `Supported: ${Object.keys(SUPPORTED_PLATFORMS).join(", ")}`
31
+ );
32
+ }
33
+
34
+ // Try CUDA variant on Linux/Windows when an NVIDIA GPU is present
35
+ if ((process.platform === "linux" || process.platform === "win32") && hasNvidiaGpu()) {
36
+ return base.replace(/(\.\w+)?$/, "-cuda$1");
37
+ }
38
+ return base;
39
+ }
40
+
41
+ function fetch(url) {
42
+ return new Promise((resolve, reject) => {
43
+ const lib = url.startsWith("https") ? https : http;
44
+ lib
45
+ .get(url, { headers: { "User-Agent": "mic-speaker-postinstall" } }, (res) => {
46
+ // Follow redirects (GitHub releases redirect to S3)
47
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
48
+ return fetch(res.headers.location).then(resolve, reject);
49
+ }
50
+ if (res.statusCode !== 200) {
51
+ reject(new Error(`HTTP ${res.statusCode} for ${url}`));
52
+ res.resume();
53
+ return;
54
+ }
55
+ const chunks = [];
56
+ res.on("data", (chunk) => chunks.push(chunk));
57
+ res.on("end", () => resolve(Buffer.concat(chunks)));
58
+ res.on("error", reject);
59
+ })
60
+ .on("error", reject);
61
+ });
62
+ }
63
+
64
+ async function main() {
65
+ const pkg = require("../package.json");
66
+ const version = pkg.version;
67
+ const binaryName = getBinaryName();
68
+ const binDir = path.join(__dirname, "..", "bin");
69
+ const destPath = path.join(binDir, binaryName);
70
+
71
+ // Skip if binary already exists (e.g. local dev with pre-built binary)
72
+ if (fs.existsSync(destPath)) {
73
+ console.log(`mic-speaker: binary already exists at ${destPath}, skipping download.`);
74
+ return;
75
+ }
76
+
77
+ const url = `https://github.com/thisnick/acpfx/releases/download/%40acpfx/mic-speaker%40${version}/${binaryName}`;
78
+ console.log(`mic-speaker: downloading ${binaryName} from GitHub Releases...`);
79
+ console.log(` ${url}`);
80
+
81
+ let data;
82
+ try {
83
+ data = await fetch(url);
84
+ } catch (err) {
85
+ // If CUDA variant failed, fall back to CPU binary
86
+ const cpuName = SUPPORTED_PLATFORMS[`${process.platform} ${process.arch}`];
87
+ if (binaryName !== cpuName) {
88
+ console.log(`mic-speaker: CUDA binary not available, falling back to CPU variant...`);
89
+ const cpuUrl = `https://github.com/thisnick/acpfx/releases/download/%40acpfx/mic-speaker%40${version}/${cpuName}`;
90
+ console.log(` ${cpuUrl}`);
91
+ data = await fetch(cpuUrl);
92
+ } else {
93
+ throw err;
94
+ }
95
+ }
96
+
97
+ // Ensure bin/ directory exists
98
+ fs.mkdirSync(binDir, { recursive: true });
99
+
100
+ fs.writeFileSync(destPath, data);
101
+ fs.chmodSync(destPath, 0o755);
102
+
103
+ console.log(`mic-speaker: installed ${binaryName} (${(data.length / 1024 / 1024).toFixed(1)} MB)`);
104
+ }
105
+
106
+ main().catch((err) => {
107
+ console.warn(`mic-speaker: postinstall failed — ${err.message}`);
108
+ console.warn(
109
+ "mic-speaker: the native binary could not be downloaded. " +
110
+ "You can build locally with: cargo build --release -p mic-speaker"
111
+ );
112
+ // Don't exit with error — allow npm install to succeed
113
+ });