feat!: [Experimental hotfix 2] Fix Audio stream handling on windows electron
Experimental fix for solving replacement of mic audio when enabling screenshare audio on windows electron
On Windows Electron, startWithElectronDesktopCapturer uses getUserMedia({ chromeMediaSource: 'desktop' }) for both video and audio. This getUserMedia desktop audio call can interfere with / replace the existing mic getUserMedia stream, killing voice audio.
BREAKING CHANGE: possibly streaming
This commit is contained in:
@@ -190,10 +190,12 @@ export class ScreenShareManager {
|
||||
/**
|
||||
* Begin screen sharing.
|
||||
*
|
||||
* On Linux Electron builds, prefers a dedicated PulseAudio/PipeWire routing
|
||||
* path so remote voice playback is kept out of captured system audio.
|
||||
* On other Electron builds, uses desktop capture. In browser contexts, uses
|
||||
* `getDisplayMedia`.
|
||||
* On Linux Electron builds, prefers a dedicated PulseAudio/PipeWire routing
|
||||
* path so remote voice playback is kept out of captured system audio.
|
||||
* On Windows Electron builds, prefers `getDisplayMedia` with system audio
|
||||
* so the separate mic `getUserMedia` stream is not disrupted; falls back to
|
||||
* Electron desktop capture only when `getDisplayMedia` fails entirely.
|
||||
* In browser contexts, uses `getDisplayMedia`.
|
||||
*
|
||||
* @param options - Screen-share capture options.
|
||||
* @returns The captured screen {@link MediaStream}.
|
||||
@@ -230,16 +232,27 @@ export class ScreenShareManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.activeScreenStream && shareOptions.includeSystemAudio && !electronDesktopCaptureAvailable) {
|
||||
if (!this.activeScreenStream && shareOptions.includeSystemAudio) {
|
||||
try {
|
||||
this.activeScreenStream = await this.startWithDisplayMedia(shareOptions, preset);
|
||||
captureMethod = 'display-media';
|
||||
|
||||
if (this.activeScreenStream.getAudioTracks().length === 0) {
|
||||
this.logger.warn('getDisplayMedia did not provide system audio; trying Electron desktop capture');
|
||||
this.activeScreenStream.getTracks().forEach((track) => track.stop());
|
||||
this.activeScreenStream = null;
|
||||
captureMethod = null;
|
||||
if (electronDesktopCaptureAvailable) {
|
||||
// On Windows Electron, keep the getDisplayMedia stream for video
|
||||
// rather than falling through to getUserMedia desktop audio which
|
||||
// can replace or kill the active mic stream.
|
||||
this.logger.warn(
|
||||
'getDisplayMedia did not provide system audio; '
|
||||
+ 'continuing without system audio to preserve mic stream'
|
||||
);
|
||||
shareOptions.includeSystemAudio = false;
|
||||
} else {
|
||||
this.logger.warn('getDisplayMedia did not provide system audio; trying next capture method');
|
||||
this.activeScreenStream.getTracks().forEach((track) => track.stop());
|
||||
this.activeScreenStream = null;
|
||||
captureMethod = null;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.rethrowIfScreenShareAborted(error);
|
||||
@@ -426,9 +439,12 @@ export class ScreenShareManager {
|
||||
|
||||
private shouldSuppressRemotePlaybackDuringShare(
|
||||
includeSystemAudio: boolean,
|
||||
captureMethod: ScreenShareCaptureMethod | null
|
||||
_captureMethod: ScreenShareCaptureMethod | null
|
||||
): boolean {
|
||||
return includeSystemAudio && captureMethod === 'electron-desktop' && this.isWindowsElectron();
|
||||
// On Windows Electron, system audio capture (via getDisplayMedia or
|
||||
// desktop capturer) includes all output audio. Remote voice playback
|
||||
// must be suppressed to avoid a feedback loop regardless of capture method.
|
||||
return includeSystemAudio && this.isWindowsElectron();
|
||||
}
|
||||
|
||||
private getRequiredLinuxElectronApi(): Required<Pick<
|
||||
|
||||
Reference in New Issue
Block a user