Skip to content

Fix echo ai#16

Merged
CilginSinek merged 4 commits into
mainfrom
fix-echo-ai
Jul 2, 2026
Merged

Fix echo ai#16
CilginSinek merged 4 commits into
mainfrom
fix-echo-ai

Conversation

@CilginSinek

Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings July 2, 2026 01:18
@CilginSinek CilginSinek merged commit 489dc9a into main Jul 2, 2026
4 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to reduce/avoid screen-share audio echo by introducing native audio capture/routing (Windows WASAPI process loopback and Linux PulseAudio routing), wiring that into the app’s getDisplayMedia flow, and updating the screen-source picker UI.

Changes:

  • Adds a native Windows capture addon (native/topluyo-capture) and integrates it via new IPC (start-native-audio / stop-native-audio).
  • Updates the screen share source selection window (UI + tabbed filtering) and tracks the last selected source for audio routing decisions.
  • Updates packaging/build config for the native .node binary and bumps Electron/electron-builder versions.

Reviewed changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
Windows.js Disables devtools and enables Node integration in subframes for the main window.
utils.js Adjusts the stream picker window (size, devtools), and stores the last selected source globally.
ScreenShare.html Major UI refresh and adds tabs for screen/window filtering; updates selection flow.
preload.js Intercepts getDisplayMedia to swap default loopback audio with native-captured audio.
main.js Loads native capture module (if available) and adds IPC handlers for native audio start/stop.
linux-audio.js Adds PulseAudio-based routing for Linux audio capture fallback.
package.json Bumps Electron/electron-builder; adds optional native dependency and asar unpack rules.
electron-builder.config.js Adds native .node binary inclusion and asar unpack configuration.
native/topluyo-capture/src/wasapi_capture.h Introduces WASAPI capture class definition.
native/topluyo-capture/src/wasapi_capture.cpp Implements WASAPI process loopback capture.
native/topluyo-capture/src/addon.cpp Exposes capture start/stop + PID-from-HWND via N-API.
native/topluyo-capture/binding.gyp Adds node-gyp build config for the addon.
native/topluyo-capture/package.json Adds addon package metadata and build scripts.
native/topluyo-capture/package-lock.json Locks addon dependency tree.
native/topluyo-capture/index.js Provides a JS wrapper around the compiled addon.
native/topluyo-capture/.gitignore Ignores addon build outputs.
native/.gitignore Ignores native-level node_modules.
Files not reviewed (1)
  • native/topluyo-capture/package-lock.json: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread preload.js
Comment on lines 22 to +26
documenter.on("input", "#run-on-startup", function () {
ipcRenderer.send("set-Startup", this.checked);
});
});

contextBridge.exposeInMainWorld("stream", {
getSources: () => ipcRenderer.invoke("getSources"),
setSource: (data) =>
ipcRenderer.invoke("setSource", { id:data.id, isAudioEnabled:data.audio }),
documenter.on("input", "#run-on-startup", function () {
Comment thread preload.js
Comment on lines +144 to +148
const originalGeneratorStop = generator.stop.bind(generator);
generator.stop = () => {
stopNativeCapture();
originalGeneratorStop();
};
Comment thread preload.js
});
}

stream.addTrack(generator);
Comment thread preload.js
});

timestamp += (frames / meta.sampleRate) * 1000000;
writer.write(audioData);
Comment thread ScreenShare.html
Comment on lines 328 to +332
let html;
if (source.thumbnail) {
html = `<img src='${source.thumbnail}'><div>${source.name}</div>`;
html = `<img src='${source.thumbnail}' alt='Thumbnail'><div class="name">${source.name}</div>`;
} else {
html = `<div>${source.name}</div>`;
html = `<div class="placeholder">
Comment thread main.js
Comment on lines +400 to +404
ipcMain.handle("start-native-audio", (event) => {
const sourceId = global.lastSelectedSource || "";
console.log("start-native-audio invoked. Selected source:", sourceId);

if (process.platform === "linux") {
Comment thread linux-audio.js
Comment on lines +9 to +13
console.log("[PulseAudio] Creating Null Sink TopluyoCaptureSink");
const sinkOut = execSync('pactl load-module module-null-sink sink_name=TopluyoCaptureSink sink_properties=device.description="TopluyoCapture"').toString().trim();
virtualSinkId = sinkOut;

// Get all sink inputs
Comment on lines +22 to +25
"libraries": [
"-lMmdevapi.lib",
"-lAvrt.lib"
]
Comment on lines +12 to +13
#include <functional>
#include <functional>
Comment on lines +40 to +46
tsfn = Napi::ThreadSafeFunction::New(
env,
info[2].As<Napi::Function>(),
"WASAPICaptureCallback",
0,
1
);
@CilginSinek CilginSinek deleted the fix-echo-ai branch July 3, 2026 01:16
@CilginSinek CilginSinek restored the fix-echo-ai branch July 3, 2026 01:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants