Skip to content

Commit

Permalink
fix(Voice): crash on dc, member connect
Browse files Browse the repository at this point in the history
Solves crashes when disconnecting.
Fixes members not connecting and disconnecting from audio mixer.
Also adds a voice settings button in the voice panel.
  • Loading branch information
Garifullin Ruslan committed Jan 8, 2021
1 parent 2b416e4 commit 794be74
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 28 deletions.
Binary file added assets/icons/microphone-settings-outline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/microphone-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 50 additions & 19 deletions src/components/VoicePanel/VoicePanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ export class VoicePanel extends QWidget {

private infoLabel = new QLabel(this);

private voiceBtn = new DIconButton({
iconPath: join(__dirname, 'assets/icons/microphone-settings.png'),
iconQSize: new QSize(24, 24),
tooltipText: 'Voice Settings',
});

private discntBtn = new DIconButton({
iconPath: join(__dirname, 'assets/icons/phone-remove.png'),
iconQSize: new QSize(24, 24),
Expand Down Expand Up @@ -123,17 +129,17 @@ export class VoicePanel extends QWidget {
return;
}

if (o.channel === this.channel && n.channel !== this.channel) {
if (o.channel !== this.channel && n.channel === this.channel) {
this.connectToMixer(n.member);
}

if (o.channel !== this.channel && n.channel === this.channel) {
if (o.channel === this.channel && n.channel !== this.channel) {
this.disconnectFromMixer(n.member);
}
}

private initComponent() {
const { layout, infoLabel, statusLabel, discntBtn } = this;
const { layout, infoLabel, statusLabel, discntBtn, voiceBtn } = this;

layout.setContentsMargins(8, 8, 8, 8);
layout.setSpacing(8);
Expand All @@ -148,24 +154,30 @@ export class VoicePanel extends QWidget {
infoLayout.addWidget(infoLabel);
infoLayout.setSpacing(0);
voiceLayout.addLayout(infoLayout, 1);
voiceLayout.addWidget(voiceBtn, 0);
voiceLayout.addWidget(discntBtn, 0);
layout.addLayout(voiceLayout);
discntBtn.addEventListener('clicked', this.handleDisconnectButton.bind(this));
discntBtn.addEventListener('clicked', () => this.connection?.disconnect());
discntBtn.setFixedSize(32, 32);
voiceBtn.setFixedSize(32, 32);
voiceBtn.addEventListener('clicked', () => {
app.emit(AppEvents.SWITCH_VIEW, 'settings');
app.emit(AppEvents.OPEN_SETTINGS_PAGE, __('VOICE'));
});

this.setLayout(layout);
}

private handleDisconnectButton() {
private handleDisconnect = () => {
this.statusLabel.setText("<font color='#f04747'>Disconnecting</font>");
this.connection?.disconnect();
this.recordStream?.end();
this.playbackStream?.end();
this.mixer?.close();
this.streams.clear();
this.hide();
this.channel = undefined;
this.connection = undefined;
}
};

private static openVoiceNotSupportedDialog(channel: VoiceChannel) {
const msgBox = new QMessageBox();
Expand Down Expand Up @@ -210,6 +222,7 @@ export class VoicePanel extends QWidget {
this.streams.set(member, input);
this.mixer.addInput(input);
stream.pipe(input);
debug(`Connected member ${member}.`);
} else {
error(`Couldn't connect member ${member} to the voice channel ${this.channel?.name}.`);
}
Expand All @@ -230,7 +243,7 @@ export class VoicePanel extends QWidget {
}
}

private initPlayback() {
private initPlayback = () => {
if (!this.connection || !this.channel || !vp) {
return;
}
Expand All @@ -253,9 +266,9 @@ export class VoicePanel extends QWidget {
for (const member of channel.members.filter((m) => m.user !== app.client.user).values()) {
this.connectToMixer(member);
}
}
};

private initRecord() {
private initRecord = () => {
if (!this.connection || !vp) {
return;
}
Expand All @@ -273,30 +286,48 @@ export class VoicePanel extends QWidget {
);

this.connection.play(recorder, { bitrate: 256, type: 'converted', highWaterMark: 0 });
}
};

private async joinChannel(channel: VoiceChannel) {
const { infoLabel, statusLabel, createConnection, initPlayback, initRecord } = this;
const {
infoLabel,
statusLabel,
handleDisconnect,
createConnection,
initPlayback,
initRecord,
} = this;

if (!vp) {
VoicePanel.openVoiceNotSupportedDialog(channel);

return;
}

this.handleDisconnectButton();
handleDisconnect();
statusLabel.setText("<font color='#faa61a'>Joining Voice Channel</font>");
this.show();
this.channel = channel;
infoLabel.setText(channel.name);

try {
this.connection = await createConnection.call(this, channel);
this.connection = await createConnection(channel);
this.connection.on('disconnect', handleDisconnect);
this.connection.on('error', error);
this.connection.on('warn', warn);
this.connection.on('reconnecting', () => {
statusLabel.setText("<font color='#faa61a'>Reconnecting...</font>");
});

this.connection.on('ready', () => {
statusLabel.setText("<font color='#43b581'>Voice Connected</font>");
});

statusLabel.setText("<font color='#faa61a'>Connecting Devices</font>");
this.connection.play(new Silence(), { type: 'opus' }); // To receive audio we need to send something.

initPlayback.call(this);
initRecord.call(this);
initPlayback();
initRecord();

this.handleConfigUpdate(app.config);
statusLabel.setText("<font color='#43b581'>Voice Connected</font>");
Expand All @@ -311,17 +342,17 @@ export class VoicePanel extends QWidget {
return;
}

this.connection.setSpeaking(value ? 1 : 4);
this.connection.setSpeaking(value ? 1 : 0);
this.connection.emit('speaking', app.client.user, this.connection.speaking);
}

private async createConnection(channel: VoiceChannel) {
private createConnection = async (channel: VoiceChannel) => {
const connection = await channel.join();

connection.on('warn', warn.bind(this, '[djs]'));
connection.on('error', error.bind(this, '[djs]'));
connection.on('failed', error.bind(this, '[djs]'));

return connection;
}
};
}
21 changes: 12 additions & 9 deletions src/utilities/voice/VoiceProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,38 @@ export abstract class VoiceProvider {
const { args, device } = processArgs(this, options, PLAYBACK_OPTIONS);

debug(`Starting the playback stream, args: ${args.join(' ')}`);
const { kill, stdin: stream, stderr } = spawn(FFplay, args);
const proc = spawn(FFplay, args);

stderr.on('data', (chunk) => debug(chunk.toString()));
proc.on('exit', (code) => debug(`Playback stream closed with code ${code}.`));
proc.stderr.on('data', (chunk) => debug(chunk.toString()));

return { device, stream, end: () => kill('SIGKILL') };
return { device, stream: proc.stdin, end: () => proc.kill() };
};

protected createFFmpegPlaybackStream = (options: VoiceOptions = {}) => {
const { FFmpeg, PLAYBACK_OPTIONS } = this;
const { args, device } = processArgs(this, options, PLAYBACK_OPTIONS);

debug(`Starting the playback stream, args: ${args.join(' ')}`);
const { kill, stdin: stream, stderr } = spawn(FFmpeg, args);
const proc = spawn(FFmpeg, args);

stderr.on('data', (chunk) => debug(chunk.toString()));
proc.on('exit', (code) => debug(`Playback stream closed with code ${code}.`));
proc.stderr.on('data', (chunk) => debug(chunk.toString()));

return { device, stream, end: () => kill('SIGKILL') };
return { device, stream: proc.stdin, end: () => proc.kill() };
};

protected createFFmpegRecordStream = (options: VoiceOptions = {}) => {
const { FFmpeg, RECORD_OPTIONS } = this;
const { args, device } = processArgs(this, options, RECORD_OPTIONS);

debug(`Starting the record stream, args: ${args.join(' ')}`);
const { kill, stdout: stream, stderr } = spawn(FFmpeg, args);
const proc = spawn(FFmpeg, args);

stderr.on('data', (chunk) => debug(chunk.toString()));
proc.on('exit', (code) => debug(`Record stream closed with code ${code}.`));
proc.stderr.on('data', (chunk) => debug(chunk.toString()));

return { device, stream, end: () => kill('SIGKILL') };
return { device, stream: proc.stdout, end: () => proc.kill() };
};

/**
Expand Down

0 comments on commit 794be74

Please sign in to comment.