From 33e3ea70a4b4f412c1640d84875032def1df7309 Mon Sep 17 00:00:00 2001 From: Tyler Stiene Date: Wed, 4 Nov 2020 01:12:43 -0500 Subject: [PATCH] reliability improvements die on mumble disconnect drop packets if channel is full --- Makefile | 2 +- discord.go | 25 +++++---- example/docker-compose.yml | 13 +++++ example/docker-compose.yml.example | 13 ----- main.go | 82 ++++++++++++++++++------------ mumble.go | 6 ++- 6 files changed, 84 insertions(+), 57 deletions(-) create mode 100644 example/docker-compose.yml delete mode 100644 example/docker-compose.yml.example diff --git a/Makefile b/Makefile index 1d65f2b..88c1f6d 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ mumble-discord-bridge: $(GOFILES) go build -o $@ $(GOFILES) docker-latest: - docker build . + docker build -t stieneee/mumble-discord-bridge:latest . docker push stieneee/mumble-bridge-latest clean: diff --git a/discord.go b/discord.go index c609ee6..de30943 100644 --- a/discord.go +++ b/discord.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "os" + "log" "sync" "time" @@ -28,9 +28,9 @@ var OnError = func(str string, err error) { prefix := "dgVoice: " + str if err != nil { - os.Stderr.WriteString(prefix + ": " + err.Error()) + log.Println(prefix + ": " + err.Error()) } else { - os.Stderr.WriteString(prefix) + log.Println(prefix) } } @@ -47,7 +47,7 @@ func discordSendPCM(v *discordgo.VoiceConnection, pcm <-chan []int16) { opusEncoder, err := gopus.NewEncoder(frameRate, channels, gopus.Audio) if err != nil { OnError("NewEncoder Error", err) - return + panic(err) } ticker := time.NewTicker(20 * time.Millisecond) @@ -68,12 +68,12 @@ func discordSendPCM(v *discordgo.VoiceConnection, pcm <-chan []int16) { opus, err := opusEncoder.Encode(append(r1, r2...), frameSize, maxBytes) if err != nil { OnError("Encoding Error", err) - return + continue } if v.Ready == false || v.OpusSend == nil { OnError(fmt.Sprintf("Discordgo not ready for opus packets. %+v : %+v", v.Ready, v.OpusSend), nil) - return + continue } v.OpusSend <- opus @@ -94,13 +94,13 @@ func discordReceivePCM(v *discordgo.VoiceConnection) { for { if v.Ready == false || v.OpusRecv == nil { OnError(fmt.Sprintf("Discordgo not to receive opus packets. %+v : %+v", v.Ready, v.OpusSend), nil) - return + continue } p, ok := <-v.OpusRecv if !ok { - fmt.Println("Opus not ok") - return + log.Println("Opus not ok") + continue } discordMutex.Lock() @@ -178,7 +178,12 @@ func fromDiscordMixer(toMumble chan<- gumble.AudioBuffer) { } if sendAudio { - toMumble <- outBuf + select { + case toMumble <- outBuf: + default: + log.Println("toMumble buffer full. Dropping packet") + } + } } } diff --git a/example/docker-compose.yml b/example/docker-compose.yml new file mode 100644 index 0000000..f5e548f --- /dev/null +++ b/example/docker-compose.yml @@ -0,0 +1,13 @@ +version: "3" + +services: + mumble-discord-bridge: + image: stieneee/mumble-discord-bridge + restart: unless-stopped + environment: + - MUMBLE_ADDRESS=example.com" + - MUMBLE_USERNAME=discord-bridge + - MUMBLE_PASSWORD=password + - DISCORD_TOKEN=token + - DISCORD_GID=gid + - DISCORD_CID=cid \ No newline at end of file diff --git a/example/docker-compose.yml.example b/example/docker-compose.yml.example deleted file mode 100644 index 8b5369b..0000000 --- a/example/docker-compose.yml.example +++ /dev/null @@ -1,13 +0,0 @@ -version: "3.8" - -services: - mumble-discord-bridge: - image: stieneee/mumble-discord-bridge - restart: always - environment: - - MUMBLE_ADDRESS= - - MUMBLE_USERNAME= - - MUMBLE_PASSWORD= - - DISCORD_TOKEN= - - DISCORD_GID= - - DISCORD_CID= \ No newline at end of file diff --git a/main.go b/main.go index 21ba51a..cb6032c 100644 --- a/main.go +++ b/main.go @@ -86,6 +86,35 @@ func main() { log.Fatalln("missing discord cid") } + // DISCORD Setup + + discord, err := discordgo.New("Bot " + *discordToken) + if err != nil { + log.Println(err) + return + } + + // Open Websocket + discord.LogLevel = 2 + err = discord.Open() + if err != nil { + log.Println(err) + return + } + defer discord.Close() + + log.Println("Discord Bot Connected") + + dgv, err := discord.ChannelVoiceJoin(*discordGID, *discordCID, false, false) + if err != nil { + log.Println(err) + return + } + defer dgv.Speaking(false) + defer dgv.Close() + + discord.ShouldReconnectOnError = true + // MUMBLE Setup config := gumble.NewConfig() @@ -100,41 +129,21 @@ func main() { log.Println(err) return } + defer mumble.Disconnect() // Shared Channels // Shared channels pass PCM information in 10ms chunks [480]int16 var toMumble = mumble.AudioOutgoing() var toDiscord = make(chan []int16, 100) - - go m.fromMumbleMixer(toDiscord) - - config.AudioListeners.Attach(m) + var die = make(chan bool) log.Println("Mumble Connected") - // DISCORD Setup - - discord, err := discordgo.New("Bot " + *discordToken) - if err != nil { - log.Println(err) - return - } - - // Open Websocket - err = discord.Open() - if err != nil { - log.Println(err) - return - } - - log.Println("Discord Bot Connected") - - dgv, err := discord.ChannelVoiceJoin(*discordGID, *discordCID, false, false) - if err != nil { - log.Println(err) - return - } - + // Start Passing Between + // Mumble + go m.fromMumbleMixer(toDiscord) + config.AudioListeners.Attach(m) + //Discord go discordReceivePCM(dgv) go fromDiscordMixer(toMumble) go discordSendPCM(dgv, toDiscord) @@ -143,12 +152,21 @@ func main() { c := make(chan os.Signal) signal.Notify(c, os.Interrupt) + go func() { + ticker := time.NewTicker(500 * time.Millisecond) + for { + <-ticker.C + if mumble.State() != 2 { + log.Println("Lost mumble connection " + strconv.Itoa(int(mumble.State()))) + die <- true + } + } + }() + select { case sig := <-c: - log.Printf("\nGot %s signal. Ending Mumble-Bridge\n", sig) - mumble.Disconnect() - dgv.Speaking(false) - dgv.Close() - discord.Close() + log.Printf("\nGot %s signal. Terminating Mumble-Bridge\n", sig) + case <-die: + log.Println("\nGot internal die request. Terminating Mumble-Bridge") } } diff --git a/mumble.go b/mumble.go index fb4e917..2909c36 100644 --- a/mumble.go +++ b/mumble.go @@ -86,7 +86,11 @@ func (m MumbleDuplex) fromMumbleMixer(toDiscord chan []int16) { } if sendAudio { - toDiscord <- outBuf + select { + case toDiscord <- outBuf: + default: + log.Println("toDiscord buffer full. Dropping packet") + } } } }