Skip to content

Commit a6d0598

Browse files
authored
Merge pull request #41 from viruslox/jules-9366755757653057468-c72fc07f
Fix Discord bot crash and route overlay/Discord audio to SRT
2 parents e3d2dfa + bcc37be commit a6d0598

5 files changed

Lines changed: 98 additions & 2 deletions

File tree

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,5 @@ require (
4949
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
5050
google.golang.org/grpc v1.65.0-dev // indirect
5151
google.golang.org/protobuf v1.36.11 // indirect
52+
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302 // indirect
5253
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBN
204204
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
205205
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
206206
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
207+
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302 h1:xeVptzkP8BuJhoIjNizd2bRHfq9KB9HfOLZu90T04XM=
208+
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302/go.mod h1:/L5E7a21VWl8DeuCPKxQBdVG5cy+L0MRZ08B1wnqt7g=
207209
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
208210
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
209211
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/modules/audiobridge/bot/discord.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,18 @@ type DiscordBot struct {
2525
client bot.Client
2626
controller module.Controller
2727
pendingShutdown map[snowflake.ID]snowflake.ID // channelID -> authorID
28+
discordOutEnabled bool
29+
excludedUsers []string
2830
}
2931

30-
func NewBot(token string, prefix string, admins []string, ctrl module.Controller) *DiscordBot {
32+
func NewBot(token string, prefix string, admins []string, discordOutEnabled bool, excludedUsers []string, ctrl module.Controller) *DiscordBot {
3133
return &DiscordBot{
3234
token: token,
3335
prefix: prefix,
3436
admins: admins,
3537
controller: ctrl,
38+
discordOutEnabled: discordOutEnabled,
39+
excludedUsers: excludedUsers,
3640
pendingShutdown: make(map[snowflake.ID]snowflake.ID),
3741
}
3842
}
@@ -150,6 +154,7 @@ func (b *DiscordBot) onMessageCreate(event *events.MessageCreate) {
150154
}
151155

152156
conn := b.client.VoiceManager().CreateConn(*event.GuildID)
157+
conn.SetOpusFrameReceiver(NewDiscordOpusReceiver(b.discordOutEnabled, b.excludedUsers))
153158
go func() {
154159
err := conn.Open(context.TODO(), channelID, false, false)
155160
if err != nil {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package bot
2+
3+
import (
4+
"log"
5+
6+
"VLX_ChatBridge/internal/core/audio"
7+
"github.com/disgoorg/disgo/voice"
8+
"github.com/disgoorg/snowflake/v2"
9+
"gopkg.in/hraban/opus.v2"
10+
"encoding/binary"
11+
"bytes"
12+
)
13+
14+
type DiscordOpusReceiver struct {
15+
decoder *opus.Decoder
16+
configDiscordOut bool
17+
excludedUsers map[string]struct{}
18+
}
19+
20+
func NewDiscordOpusReceiver(discordOutEnabled bool, excludedUsersList []string) *DiscordOpusReceiver {
21+
// Discord sends 48kHz, 2 channels
22+
decoder, err := opus.NewDecoder(48000, 2)
23+
excludedMap := make(map[string]struct{})
24+
for _, id := range excludedUsersList {
25+
excludedMap[id] = struct{}{}
26+
}
27+
28+
if err != nil {
29+
log.Printf("[AudioBridge] Failed to create Opus decoder: %v", err)
30+
return &DiscordOpusReceiver{configDiscordOut: discordOutEnabled, excludedUsers: excludedMap}
31+
}
32+
return &DiscordOpusReceiver{
33+
decoder: decoder,
34+
configDiscordOut: discordOutEnabled,
35+
excludedUsers: excludedMap,
36+
}
37+
}
38+
39+
func (r *DiscordOpusReceiver) ReceiveOpusFrame(userID snowflake.ID, packet *voice.Packet) error {
40+
if !r.configDiscordOut {
41+
return nil
42+
}
43+
44+
if _, excluded := r.excludedUsers[userID.String()]; excluded {
45+
return nil
46+
}
47+
48+
if r.decoder == nil {
49+
return nil
50+
}
51+
52+
// Opus packets from Discord are typically 20ms at 48kHz stereo = 960 samples per channel = 1920 samples total.
53+
// 1920 int16 samples * 2 bytes/sample = 3840 bytes.
54+
// Allocate a slice large enough.
55+
pcm := make([]int16, 1920)
56+
57+
n, err := r.decoder.Decode(packet.Opus, pcm)
58+
if err != nil {
59+
return err
60+
}
61+
62+
// n is the number of samples per channel. For stereo, total samples = n * 2
63+
totalSamples := n * 2
64+
65+
// Convert int16 PCM to byte slice (little endian)
66+
buf := new(bytes.Buffer)
67+
// We can use binary.Write
68+
err = binary.Write(buf, binary.LittleEndian, pcm[:totalSamples])
69+
if err != nil {
70+
return err
71+
}
72+
73+
audio.PCMChannel <- audio.StreamData{
74+
ID: "discord_" + userID.String(),
75+
Data: buf.Bytes(),
76+
}
77+
78+
return nil
79+
}
80+
81+
func (r *DiscordOpusReceiver) CleanupUser(userID snowflake.ID) {
82+
// No user specific state right now.
83+
}
84+
85+
func (r *DiscordOpusReceiver) Close() {
86+
// Cleanup if necessary
87+
}

internal/modules/audiobridge/module.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ func (m *Module) Start() error {
4949
log.Printf("[AudioBridge] Internal audio pipe start error: %v", err)
5050
}
5151

52-
m.bot = bot.NewBot(m.config.Discord.Token, m.config.Discord.Prefix, m.config.Discord.Admins, m.controller)
52+
discordOut := m.config.Discord.DiscordOut
53+
m.bot = bot.NewBot(m.config.Discord.Token, m.config.Discord.Prefix, m.config.Discord.Admins, bool(discordOut), m.config.Discord.ExcludedUsers, m.controller)
5354
if err := m.bot.Connect(); err != nil {
5455
log.Printf("[AudioBridge] Discord bot connect error: %v", err)
5556
}

0 commit comments

Comments
 (0)