aboutsummaryrefslogtreecommitdiff
path: root/src/services/player.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/services/player.ts')
-rw-r--r--src/services/player.ts66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/services/player.ts b/src/services/player.ts
index 5e284a6..b833022 100644
--- a/src/services/player.ts
+++ b/src/services/player.ts
@@ -20,6 +20,7 @@ import FileCacheProvider from './file-cache.js';
import debug from '../utils/debug.js';
import {getGuildSettings} from '../utils/get-guild-settings.js';
import {buildPlayingMessageEmbed} from '../utils/build-embed.js';
+import {Setting} from '@prisma/client';
export enum MediaSource {
Youtube,
@@ -82,6 +83,8 @@ export default class {
private readonly fileCache: FileCacheProvider;
private disconnectTimer: NodeJS.Timeout | null = null;
+ private readonly channelToSpeakingUsers: Map<string, Set<string>> = new Map();
+
constructor(fileCache: FileCacheProvider, guildId: string) {
this.fileCache = fileCache;
this.guildId = guildId;
@@ -96,9 +99,12 @@ export default class {
this.voiceConnection = joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
+ selfDeaf: false,
adapterCreator: channel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator,
});
+ const guildSettings = await getGuildSettings(this.guildId);
+
// Workaround to disable keepAlive
this.voiceConnection.on('stateChange', (oldState, newState) => {
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
@@ -115,6 +121,9 @@ export default class {
/* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
this.currentChannel = channel;
+ if (newState.status === VoiceConnectionStatus.Ready) {
+ this.registerVoiceActivityListener(guildSettings);
+ }
});
}
@@ -302,6 +311,63 @@ export default class {
}
}
+ registerVoiceActivityListener(guildSettings: Setting) {
+ const {turnDownVolumeWhenPeopleSpeak, turnDownVolumeWhenPeopleSpeakTarget} = guildSettings;
+ if (!turnDownVolumeWhenPeopleSpeak || !this.voiceConnection) {
+ return;
+ }
+
+ this.voiceConnection.receiver.speaking.on('start', (userId: string) => {
+ if (!this.currentChannel) {
+ return;
+ }
+
+ const member = this.currentChannel.members.get(userId);
+ const channelId = this.currentChannel?.id;
+
+ if (member) {
+ if (!this.channelToSpeakingUsers.has(channelId)) {
+ this.channelToSpeakingUsers.set(channelId, new Set());
+ }
+
+ this.channelToSpeakingUsers.get(channelId)?.add(member.id);
+ }
+
+ this.suppressVoiceWhenPeopleAreSpeaking(turnDownVolumeWhenPeopleSpeakTarget);
+ });
+
+ this.voiceConnection.receiver.speaking.on('end', (userId: string) => {
+ if (!this.currentChannel) {
+ return;
+ }
+
+ const member = this.currentChannel.members.get(userId);
+ const channelId = this.currentChannel.id;
+ if (member) {
+ if (!this.channelToSpeakingUsers.has(channelId)) {
+ this.channelToSpeakingUsers.set(channelId, new Set());
+ }
+
+ this.channelToSpeakingUsers.get(channelId)?.delete(member.id);
+ }
+
+ this.suppressVoiceWhenPeopleAreSpeaking(turnDownVolumeWhenPeopleSpeakTarget);
+ });
+ }
+
+ suppressVoiceWhenPeopleAreSpeaking(turnDownVolumeWhenPeopleSpeakTarget: number): void {
+ if (!this.currentChannel) {
+ return;
+ }
+
+ const speakingUsers = this.channelToSpeakingUsers.get(this.currentChannel.id);
+ if (speakingUsers && speakingUsers.size > 0) {
+ this.setVolume(turnDownVolumeWhenPeopleSpeakTarget);
+ } else {
+ this.setVolume(this.defaultVolume);
+ }
+ }
+
canGoForward(skip: number) {
return (this.queuePosition + skip - 1) < this.queue.length;
}