added an option to fix the "Zoom can't capture the sound" problem (it is IMPORTANT to choose "share sound" when share screen in Zoom).

This commit is contained in:
Xiaohan-Tian
2025-08-20 15:48:26 -07:00
parent 365acdae7e
commit c1112f41d5
4 changed files with 78 additions and 0 deletions
+3
View File
@@ -54,6 +54,9 @@
"chatbox": { "chatbox": {
"default_open": true "default_open": true
}, },
"audio": {
"enable_audio_capture_for_screen_sharing": false
},
"templates": { "templates": {
"custom_instructions": "" "custom_instructions": ""
} }
@@ -3,6 +3,7 @@ import { ConfigManager } from '../../../core/config/ConfigManager';
const BehaviorSettings: React.FC = () => { const BehaviorSettings: React.FC = () => {
const [chatboxDefaultOpen, setChatboxDefaultOpen] = useState<boolean>(true); const [chatboxDefaultOpen, setChatboxDefaultOpen] = useState<boolean>(true);
const [enableAudioCapture, setEnableAudioCapture] = useState<boolean>(false);
const configManager = ConfigManager.instance(); const configManager = ConfigManager.instance();
@@ -14,6 +15,7 @@ const BehaviorSettings: React.FC = () => {
} }
setChatboxDefaultOpen((configManager.get('chatbox.default_open') as boolean) ?? true); setChatboxDefaultOpen((configManager.get('chatbox.default_open') as boolean) ?? true);
setEnableAudioCapture((configManager.get('audio.enable_audio_capture_for_screen_sharing') as boolean) ?? false);
}; };
loadConfig(); loadConfig();
@@ -26,6 +28,12 @@ const BehaviorSettings: React.FC = () => {
await configManager.set('chatbox.default_open', boolValue); await configManager.set('chatbox.default_open', boolValue);
}; };
const handleEnableAudioCaptureChange = async (value: string) => {
const boolValue = value === 'yes';
setEnableAudioCapture(boolValue);
await configManager.set('audio.enable_audio_capture_for_screen_sharing', boolValue);
};
return ( return (
<div className="settings-section"> <div className="settings-section">
<div className="settings-section-header"> <div className="settings-section-header">
@@ -50,6 +58,29 @@ const BehaviorSettings: React.FC = () => {
</select> </select>
</div> </div>
</div> </div>
<div className="settings-group">
<h4>Audio</h4>
<div className="settings-item">
<label className="settings-label">
Capture Audio for Screen Sharing
</label>
<select
className="settings-select"
value={enableAudioCapture ? 'yes' : 'no'}
onChange={(e) => handleEnableAudioCaptureChange(e.target.value)}
>
<option value="no">No</option>
<option value="yes">Yes</option>
</select>
<div className="settings-help" style={{ fontSize: '12px', color: '#888', marginTop: '4px' }}>
Restart KGStudio (refresh the page) to take effect. Enable this option when KGStudio's audio cannot be captured during screen sharing in video calls (e.g., Zoom, Teams). This creates an additional audio stream that screen capture applications can detect.
<br />
<b>It is important to make sure when screen sharing in Zoom, the "Share Sound" option is enabled.</b>
</div>
</div>
</div>
</div> </div>
</div> </div>
); );
@@ -7,6 +7,7 @@ import * as Tone from 'tone';
import { KGAudioBus } from './KGAudioBus'; import { KGAudioBus } from './KGAudioBus';
import type { InstrumentType } from '../track/KGMidiTrack'; import type { InstrumentType } from '../track/KGMidiTrack';
import { KGCore } from '../KGCore'; import { KGCore } from '../KGCore';
import { ConfigManager } from '../config/ConfigManager';
/** /**
* KGAudioInterface - Audio engine interface for the DAW * KGAudioInterface - Audio engine interface for the DAW
@@ -32,6 +33,10 @@ export class KGAudioInterface {
// Master volume control // Master volume control
private masterGain: Tone.Gain | null = null; private masterGain: Tone.Gain | null = null;
// Audio capture for screen sharing
private captureDestination: MediaStreamAudioDestinationNode | null = null;
private captureStream: MediaStream | null = null;
// Private constructor to prevent direct instantiation // Private constructor to prevent direct instantiation
private constructor() { private constructor() {
console.log("KGAudioInterface initialized"); console.log("KGAudioInterface initialized");
@@ -66,6 +71,14 @@ export class KGAudioInterface {
Tone.Transport.bpm.value = TIME_CONSTANTS.DEFAULT_BPM; // Default BPM Tone.Transport.bpm.value = TIME_CONSTANTS.DEFAULT_BPM; // Default BPM
Tone.Transport.timeSignature = [TIME_CONSTANTS.DEFAULT_TIME_SIGNATURE.numerator, TIME_CONSTANTS.DEFAULT_TIME_SIGNATURE.denominator]; // Default time signature Tone.Transport.timeSignature = [TIME_CONSTANTS.DEFAULT_TIME_SIGNATURE.numerator, TIME_CONSTANTS.DEFAULT_TIME_SIGNATURE.denominator]; // Default time signature
// Check config and setup audio capture if enabled
const configManager = ConfigManager.instance();
const enableCapture = configManager.get('audio.enable_audio_capture_for_screen_sharing') as boolean;
if (enableCapture) {
this.setupAudioCapture();
}
this.isInitialized = true; this.isInitialized = true;
console.log("Audio engine initialized successfully"); console.log("Audio engine initialized successfully");
} catch (error) { } catch (error) {
@@ -115,6 +128,12 @@ export class KGAudioInterface {
this.masterGain = null; this.masterGain = null;
} }
// Clean up capture resources
if (this.captureDestination) {
this.captureDestination = null;
this.captureStream = null;
}
this.isInitialized = false; this.isInitialized = false;
this.isAudioContextStarted = false; this.isAudioContextStarted = false;
@@ -602,8 +621,27 @@ export class KGAudioInterface {
return Object.keys(FLUIDR3_INSTRUMENT_MAP) as InstrumentType[]; return Object.keys(FLUIDR3_INSTRUMENT_MAP) as InstrumentType[];
} }
public getCaptureStream(): MediaStream | null {
return this.captureStream;
}
// ===== PRIVATE UTILITY METHODS ===== // ===== PRIVATE UTILITY METHODS =====
/**
* Setup audio capture for screen sharing
*/
private setupAudioCapture(): void {
if (this.masterGain && !this.captureDestination) {
this.captureDestination = Tone.getContext().createMediaStreamDestination();
this.captureStream = this.captureDestination.stream;
// Connect master gain to both speakers AND capture destination
this.masterGain.connect(this.captureDestination);
console.log('Audio capture enabled for screen sharing');
}
}
/** /**
* Check if any tracks are currently soloed * Check if any tracks are currently soloed
*/ */
+6
View File
@@ -60,6 +60,9 @@ interface AppConfig {
chatbox: { chatbox: {
default_open: boolean; default_open: boolean;
}; };
audio: {
enable_audio_capture_for_screen_sharing: boolean;
};
templates: { templates: {
custom_instructions: string; custom_instructions: string;
}; };
@@ -205,6 +208,9 @@ export class ConfigManager {
chatbox: { chatbox: {
default_open: true default_open: true
}, },
audio: {
enable_audio_capture_for_screen_sharing: false
},
templates: { templates: {
custom_instructions: '' custom_instructions: ''
} }