mirror of
https://github.com/stryan/mumble-discord-bridge.git
synced 2024-11-26 14:45:42 -05:00
use user counting, add discord buffer debuf, intial auto mode
This commit is contained in:
parent
ca1ba1d099
commit
4b8e6eea55
@ -22,7 +22,7 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin
|
||||
}
|
||||
defer dgv.Speaking(false)
|
||||
defer dgv.Close()
|
||||
|
||||
Bridge.Connected = true
|
||||
discord.ShouldReconnectOnError = true
|
||||
|
||||
// MUMBLE Setup
|
||||
@ -79,41 +79,37 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin
|
||||
log.Printf("\nGot %s signal. Terminating Mumble-Bridge\n", sig)
|
||||
case <-die:
|
||||
log.Println("\nGot internal die request. Terminating Mumble-Bridge")
|
||||
close(toMumble)
|
||||
dgv.Disconnect()
|
||||
log.Println("Closing mumble threads")
|
||||
det.Detach()
|
||||
Bridge.Connected = false
|
||||
}
|
||||
}
|
||||
|
||||
func pingMumble(host, port string, c chan int) {
|
||||
m, _ := time.ParseDuration("30s")
|
||||
curr := 0
|
||||
log.Println("Started mumble ping loop")
|
||||
for {
|
||||
time.Sleep(3 * time.Second)
|
||||
resp, err := gumble.Ping(host+":"+port, -1, m)
|
||||
curr = resp.ConnectedUsers
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if resp.ConnectedUsers-1 != curr {
|
||||
curr = resp.ConnectedUsers - 1
|
||||
log.Printf("Now %v users in mumble\n", curr)
|
||||
if curr > 0 {
|
||||
c <- curr
|
||||
if Bridge.Connected {
|
||||
curr = curr - 1
|
||||
}
|
||||
if curr != Bridge.MumbleUserCount {
|
||||
Bridge.MumbleUserCount = curr
|
||||
c <- Bridge.MumbleUserCount
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Println("Mumble ping loop broken")
|
||||
}
|
||||
|
||||
func discordStatusUpdate(dg *discordgo.Session, c chan int) {
|
||||
status := ""
|
||||
curr := 0
|
||||
log.Println("Started discord control loop")
|
||||
for {
|
||||
curr = <-c
|
||||
log.Println("Updating discord status")
|
||||
if curr == 0 {
|
||||
status = ""
|
||||
} else {
|
||||
@ -121,5 +117,28 @@ func discordStatusUpdate(dg *discordgo.Session, c chan int) {
|
||||
}
|
||||
dg.UpdateListeningStatus(status)
|
||||
}
|
||||
log.Println("Discord control loop broken")
|
||||
}
|
||||
|
||||
func AutoBridge(s *discordgo.Session) {
|
||||
log.Println("beginning auto mode")
|
||||
for {
|
||||
select {
|
||||
default:
|
||||
case <-Bridge.AutoChan:
|
||||
log.Println("ending automode")
|
||||
return
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
if !Bridge.Connected && Bridge.MumbleUserCount > 0 && Bridge.DiscordUserCount > 0 {
|
||||
log.Println("users detected in mumble and discord, bridging")
|
||||
die := make(chan bool)
|
||||
Bridge.ActiveConn = die
|
||||
go startBridge(s, BridgeConf.GID, BridgeConf.CID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, die)
|
||||
}
|
||||
log.Printf("DU: %v MU %v\n", Bridge.DiscordUserCount, Bridge.MumbleUserCount)
|
||||
if Bridge.Connected && Bridge.MumbleUserCount == 0 && Bridge.DiscordUserCount <= 1 {
|
||||
log.Println("no one online, killing bridge")
|
||||
Bridge.ActiveConn <- true
|
||||
}
|
||||
}
|
||||
}
|
16
config.go
16
config.go
@ -10,12 +10,22 @@ import (
|
||||
"layeh.com/gumble/gumble"
|
||||
)
|
||||
|
||||
type YammerConfig struct {
|
||||
type BridgeConfig struct {
|
||||
Config *gumble.Config
|
||||
MumbleAddr string
|
||||
MumbleInsecure bool
|
||||
Die chan bool
|
||||
ActiveConns map[string]chan bool
|
||||
Auto bool
|
||||
Command string
|
||||
GID string
|
||||
CID string
|
||||
}
|
||||
|
||||
type BridgeState struct {
|
||||
ActiveConn chan bool
|
||||
Connected bool
|
||||
MumbleUserCount int
|
||||
DiscordUserCount int
|
||||
AutoChan chan bool
|
||||
}
|
||||
|
||||
func lookupEnvOrString(key string, defaultVal string) string {
|
||||
|
27
discord.go
27
discord.go
@ -98,7 +98,6 @@ func discordSendPCM(v *discordgo.VoiceConnection, pcm <-chan []int16, die chan b
|
||||
lastReady = true
|
||||
readyTimeout.Stop()
|
||||
}
|
||||
log.Println("sending packets to mumble")
|
||||
v.OpusSend <- opus
|
||||
} else {
|
||||
if streaming {
|
||||
@ -118,14 +117,12 @@ func discordReceivePCM(v *discordgo.VoiceConnection, die chan bool) {
|
||||
var readyTimeout *time.Timer
|
||||
|
||||
for {
|
||||
log.Println("Start loop")
|
||||
select {
|
||||
case <-die:
|
||||
log.Println("killing discord ReceivePCM")
|
||||
return
|
||||
default:
|
||||
}
|
||||
log.Println("checked for death")
|
||||
if v.Ready == false || v.OpusRecv == nil {
|
||||
if lastReady == true {
|
||||
OnError(fmt.Sprintf("Discordgo not to receive opus packets. %+v : %+v", v.Ready, v.OpusSend), nil)
|
||||
@ -142,16 +139,13 @@ func discordReceivePCM(v *discordgo.VoiceConnection, die chan bool) {
|
||||
readyTimeout.Stop()
|
||||
}
|
||||
|
||||
log.Println("rec1")
|
||||
p, ok := <-v.OpusRecv
|
||||
log.Println("rec2")
|
||||
if !ok {
|
||||
log.Println("Opus not ok")
|
||||
continue
|
||||
}
|
||||
|
||||
discordMutex.Lock()
|
||||
log.Println("got lock one")
|
||||
_, ok = fromDiscordMap[p.SSRC]
|
||||
discordMutex.Unlock()
|
||||
if !ok {
|
||||
@ -169,20 +163,28 @@ func discordReceivePCM(v *discordgo.VoiceConnection, die chan bool) {
|
||||
}
|
||||
|
||||
discordMutex.Lock()
|
||||
log.Println("got lock 2")
|
||||
p.PCM, err = fromDiscordMap[p.SSRC].decoder.Decode(p.Opus, 960, false)
|
||||
discordMutex.Unlock()
|
||||
if err != nil {
|
||||
OnError("Error decoding opus data", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(p.PCM) != 960 {
|
||||
log.Println("Opus size error")
|
||||
continue
|
||||
}
|
||||
discordMutex.Lock()
|
||||
log.Println("got lock 3")
|
||||
fromDiscordMap[p.SSRC].pcm <- p.PCM[0:480]
|
||||
fromDiscordMap[p.SSRC].pcm <- p.PCM[480:960]
|
||||
select {
|
||||
case fromDiscordMap[p.SSRC].pcm <- p.PCM[0:480]:
|
||||
default:
|
||||
log.Println("fromDiscordMap buffer full. Dropping packet")
|
||||
}
|
||||
select {
|
||||
case fromDiscordMap[p.SSRC].pcm <- p.PCM[480:960]:
|
||||
default:
|
||||
log.Println("fromDiscordMap buffer full. Dropping packet")
|
||||
}
|
||||
discordMutex.Unlock()
|
||||
log.Println("finish loop")
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,7 +239,6 @@ func fromDiscordMixer(toMumble chan<- gumble.AudioBuffer, die chan bool) {
|
||||
if sendAudio {
|
||||
select {
|
||||
case toMumble <- outBuf:
|
||||
log.Println("sending to mumble")
|
||||
default:
|
||||
log.Println("toMumble buffer full. Dropping packet")
|
||||
}
|
||||
|
65
handlers.go
65
handlers.go
@ -20,8 +20,8 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
if m.Author.ID == s.State.User.ID {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(m.Content, "!yammer link") {
|
||||
prefix := "!" + BridgeConf.Command
|
||||
if strings.HasPrefix(m.Content, prefix+" link") {
|
||||
|
||||
// Find the channel that the message came from.
|
||||
c, err := s.State.Channel(m.ChannelID)
|
||||
@ -42,14 +42,14 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
if vs.UserID == m.Author.ID {
|
||||
log.Printf("Trying to join GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||
die := make(chan bool)
|
||||
YBConfig.ActiveConns[vs.ChannelID] = die
|
||||
go startBridge(s, g.ID, vs.ChannelID, YBConfig.Config, YBConfig.MumbleAddr, YBConfig.MumbleInsecure, die)
|
||||
Bridge.ActiveConn = die
|
||||
go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, die)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(m.Content, "!yammer unlink") {
|
||||
if strings.HasPrefix(m.Content, prefix+" unlink") {
|
||||
|
||||
// Find the channel that the message came from.
|
||||
c, err := s.State.Channel(m.ChannelID)
|
||||
@ -69,8 +69,8 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
for _, vs := range g.VoiceStates {
|
||||
if vs.UserID == m.Author.ID {
|
||||
log.Printf("Trying to leave GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||
YBConfig.ActiveConns[vs.ChannelID] <- true
|
||||
YBConfig.ActiveConns[vs.ChannelID] = nil
|
||||
Bridge.ActiveConn <- true
|
||||
Bridge.ActiveConn = nil
|
||||
MumbleReset()
|
||||
DiscordReset()
|
||||
return
|
||||
@ -78,7 +78,7 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(m.Content, "!yammer refresh") {
|
||||
if strings.HasPrefix(m.Content, prefix+" refresh") {
|
||||
|
||||
// Find the channel that the message came from.
|
||||
c, err := s.State.Channel(m.ChannelID)
|
||||
@ -98,16 +98,27 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
for _, vs := range g.VoiceStates {
|
||||
if vs.UserID == m.Author.ID {
|
||||
log.Printf("Trying to refresh GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||
YBConfig.ActiveConns[vs.ChannelID] <- true
|
||||
Bridge.ActiveConn <- true
|
||||
MumbleReset()
|
||||
DiscordReset()
|
||||
time.Sleep(5 * time.Second)
|
||||
YBConfig.ActiveConns[vs.ChannelID] = make(chan bool)
|
||||
go startBridge(s, g.ID, vs.ChannelID, YBConfig.Config, YBConfig.MumbleAddr, YBConfig.MumbleInsecure, YBConfig.ActiveConns[vs.ChannelID])
|
||||
Bridge.ActiveConn = make(chan bool)
|
||||
go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, Bridge.ActiveConn)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(m.Content, prefix+" auto") {
|
||||
if BridgeConf.Auto == false {
|
||||
BridgeConf.Auto = true
|
||||
Bridge.AutoChan = make(chan bool)
|
||||
go AutoBridge(s)
|
||||
} else {
|
||||
Bridge.AutoChan <- true
|
||||
BridgeConf.Auto = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
|
||||
@ -123,3 +134,35 @@ func guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func voiceUpdate(s *discordgo.Session, event *discordgo.VoiceStateUpdate) {
|
||||
if event.GuildID == BridgeConf.GID {
|
||||
if event.ChannelID == BridgeConf.CID {
|
||||
log.Println("user joined watched discord channel")
|
||||
Bridge.DiscordUserCount = Bridge.DiscordUserCount + 1
|
||||
}
|
||||
if event.ChannelID == "" {
|
||||
//leave event, trigger recount of active users
|
||||
//TODO when next version of discordgo comes out, switch to PreviousState
|
||||
g, err := s.State.Guild(event.GuildID)
|
||||
if err != nil {
|
||||
// Could not find guild.
|
||||
return
|
||||
}
|
||||
|
||||
// Look for current voice states in watched channel
|
||||
count := 0
|
||||
for _, vs := range g.VoiceStates {
|
||||
if vs.ChannelID == BridgeConf.CID {
|
||||
count = count + 1
|
||||
}
|
||||
}
|
||||
if Bridge.DiscordUserCount > count {
|
||||
log.Println("user left watched discord channel")
|
||||
Bridge.DiscordUserCount = count
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
25
main.go
25
main.go
@ -15,7 +15,8 @@ import (
|
||||
_ "layeh.com/gumble/opus"
|
||||
)
|
||||
|
||||
var YBConfig *YammerConfig
|
||||
var BridgeConf *BridgeConfig
|
||||
var Bridge *BridgeState
|
||||
|
||||
func main() {
|
||||
godotenv.Load()
|
||||
@ -29,7 +30,7 @@ func main() {
|
||||
discordToken := flag.String("discord-token", lookupEnvOrString("DISCORD_TOKEN", ""), "DISCORD_TOKEN, discord bot token")
|
||||
discordGID := flag.String("discord-gid", lookupEnvOrString("DISCORD_GID", ""), "DISCORD_GID, discord gid")
|
||||
discordCID := flag.String("discord-cid", lookupEnvOrString("DISCORD_CID", ""), "DISCORD_CID, discord cid")
|
||||
|
||||
discordCommand := flag.String("discord-command", lookupEnvOrString("DISCORD_COMMAND", "mumble-discord"), "Discord command string, env alt DISCORD_COMMAND, optional, defaults to mumble-discord")
|
||||
flag.Parse()
|
||||
log.Printf("app.config %v\n", getConfig(flag.CommandLine))
|
||||
|
||||
@ -66,6 +67,7 @@ func main() {
|
||||
discord.AddHandler(ready)
|
||||
discord.AddHandler(messageCreate)
|
||||
discord.AddHandler(guildCreate)
|
||||
discord.AddHandler(voiceUpdate)
|
||||
err = discord.Open()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@ -74,19 +76,30 @@ func main() {
|
||||
defer discord.Close()
|
||||
|
||||
log.Println("Discord Bot Connected")
|
||||
log.Printf("Discord bot looking for command !%v", *discordCommand)
|
||||
config := gumble.NewConfig()
|
||||
config.Username = *mumbleUsername
|
||||
config.Password = *mumblePassword
|
||||
config.AudioInterval = time.Millisecond * 10
|
||||
|
||||
YBConfig = &YammerConfig{
|
||||
BridgeConf = &BridgeConfig{
|
||||
Config: config,
|
||||
MumbleAddr: *mumbleAddr + ":" + strconv.Itoa(*mumblePort),
|
||||
MumbleInsecure: *mumbleInsecure,
|
||||
ActiveConns: make(map[string]chan bool),
|
||||
Auto: false,
|
||||
Command: *discordCommand,
|
||||
GID: *discordGID,
|
||||
CID: *discordCID,
|
||||
}
|
||||
|
||||
//go startBridge(discord, *discordGID, *discordCID, config, *mumbleAddr+":"+strconv.Itoa(*mumblePort), *mumbleInsecure, die)
|
||||
Bridge = &BridgeState{
|
||||
ActiveConn: make(chan bool),
|
||||
Connected: false,
|
||||
MumbleUserCount: 0,
|
||||
DiscordUserCount: 0,
|
||||
}
|
||||
userCount := make(chan int)
|
||||
go pingMumble(*mumbleAddr, strconv.Itoa(*mumblePort), userCount)
|
||||
go discordStatusUpdate(discord, userCount)
|
||||
|
||||
sc := make(chan os.Signal, 1)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||
|
Loading…
Reference in New Issue
Block a user