Fix echo ai#16
Merged
Merged
Conversation
…io recording need: add media player settings
…rocess targeting and UWP window support
There was a problem hiding this comment.
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
.nodebinary 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 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 on lines
+144
to
+148
| const originalGeneratorStop = generator.stop.bind(generator); | ||
| generator.stop = () => { | ||
| stopNativeCapture(); | ||
| originalGeneratorStop(); | ||
| }; |
| }); | ||
| } | ||
|
|
||
| stream.addTrack(generator); |
| }); | ||
|
|
||
| timestamp += (frames / meta.sampleRate) * 1000000; | ||
| writer.write(audioData); |
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 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 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 | ||
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.