mirror of
https://github.com/stryan/mumble-discord-bridge.git
synced 2024-11-23 05:45:41 -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.Speaking(false)
|
||||||
defer dgv.Close()
|
defer dgv.Close()
|
||||||
|
Bridge.Connected = true
|
||||||
discord.ShouldReconnectOnError = true
|
discord.ShouldReconnectOnError = true
|
||||||
|
|
||||||
// MUMBLE Setup
|
// 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)
|
log.Printf("\nGot %s signal. Terminating Mumble-Bridge\n", sig)
|
||||||
case <-die:
|
case <-die:
|
||||||
log.Println("\nGot internal die request. Terminating Mumble-Bridge")
|
log.Println("\nGot internal die request. Terminating Mumble-Bridge")
|
||||||
close(toMumble)
|
|
||||||
dgv.Disconnect()
|
dgv.Disconnect()
|
||||||
log.Println("Closing mumble threads")
|
|
||||||
det.Detach()
|
det.Detach()
|
||||||
|
Bridge.Connected = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pingMumble(host, port string, c chan int) {
|
func pingMumble(host, port string, c chan int) {
|
||||||
m, _ := time.ParseDuration("30s")
|
m, _ := time.ParseDuration("30s")
|
||||||
curr := 0
|
curr := 0
|
||||||
log.Println("Started mumble ping loop")
|
|
||||||
for {
|
for {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
resp, err := gumble.Ping(host+":"+port, -1, m)
|
resp, err := gumble.Ping(host+":"+port, -1, m)
|
||||||
|
curr = resp.ConnectedUsers
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if resp.ConnectedUsers-1 != curr {
|
if Bridge.Connected {
|
||||||
curr = resp.ConnectedUsers - 1
|
curr = curr - 1
|
||||||
log.Printf("Now %v users in mumble\n", curr)
|
}
|
||||||
if curr > 0 {
|
if curr != Bridge.MumbleUserCount {
|
||||||
c <- curr
|
Bridge.MumbleUserCount = curr
|
||||||
|
c <- Bridge.MumbleUserCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Println("Mumble ping loop broken")
|
|
||||||
}
|
|
||||||
|
|
||||||
func discordStatusUpdate(dg *discordgo.Session, c chan int) {
|
func discordStatusUpdate(dg *discordgo.Session, c chan int) {
|
||||||
status := ""
|
status := ""
|
||||||
curr := 0
|
curr := 0
|
||||||
log.Println("Started discord control loop")
|
|
||||||
for {
|
for {
|
||||||
curr = <-c
|
curr = <-c
|
||||||
log.Println("Updating discord status")
|
|
||||||
if curr == 0 {
|
if curr == 0 {
|
||||||
status = ""
|
status = ""
|
||||||
} else {
|
} else {
|
||||||
@ -121,5 +117,28 @@ func discordStatusUpdate(dg *discordgo.Session, c chan int) {
|
|||||||
}
|
}
|
||||||
dg.UpdateListeningStatus(status)
|
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"
|
"layeh.com/gumble/gumble"
|
||||||
)
|
)
|
||||||
|
|
||||||
type YammerConfig struct {
|
type BridgeConfig struct {
|
||||||
Config *gumble.Config
|
Config *gumble.Config
|
||||||
MumbleAddr string
|
MumbleAddr string
|
||||||
MumbleInsecure bool
|
MumbleInsecure bool
|
||||||
Die chan bool
|
Auto bool
|
||||||
ActiveConns map[string]chan 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 {
|
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
|
lastReady = true
|
||||||
readyTimeout.Stop()
|
readyTimeout.Stop()
|
||||||
}
|
}
|
||||||
log.Println("sending packets to mumble")
|
|
||||||
v.OpusSend <- opus
|
v.OpusSend <- opus
|
||||||
} else {
|
} else {
|
||||||
if streaming {
|
if streaming {
|
||||||
@ -118,14 +117,12 @@ func discordReceivePCM(v *discordgo.VoiceConnection, die chan bool) {
|
|||||||
var readyTimeout *time.Timer
|
var readyTimeout *time.Timer
|
||||||
|
|
||||||
for {
|
for {
|
||||||
log.Println("Start loop")
|
|
||||||
select {
|
select {
|
||||||
case <-die:
|
case <-die:
|
||||||
log.Println("killing discord ReceivePCM")
|
log.Println("killing discord ReceivePCM")
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
log.Println("checked for death")
|
|
||||||
if v.Ready == false || v.OpusRecv == nil {
|
if v.Ready == false || v.OpusRecv == nil {
|
||||||
if lastReady == true {
|
if lastReady == true {
|
||||||
OnError(fmt.Sprintf("Discordgo not to receive opus packets. %+v : %+v", v.Ready, v.OpusSend), nil)
|
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()
|
readyTimeout.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("rec1")
|
|
||||||
p, ok := <-v.OpusRecv
|
p, ok := <-v.OpusRecv
|
||||||
log.Println("rec2")
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Println("Opus not ok")
|
log.Println("Opus not ok")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
discordMutex.Lock()
|
discordMutex.Lock()
|
||||||
log.Println("got lock one")
|
|
||||||
_, ok = fromDiscordMap[p.SSRC]
|
_, ok = fromDiscordMap[p.SSRC]
|
||||||
discordMutex.Unlock()
|
discordMutex.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -169,20 +163,28 @@ func discordReceivePCM(v *discordgo.VoiceConnection, die chan bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
discordMutex.Lock()
|
discordMutex.Lock()
|
||||||
log.Println("got lock 2")
|
|
||||||
p.PCM, err = fromDiscordMap[p.SSRC].decoder.Decode(p.Opus, 960, false)
|
p.PCM, err = fromDiscordMap[p.SSRC].decoder.Decode(p.Opus, 960, false)
|
||||||
discordMutex.Unlock()
|
discordMutex.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
OnError("Error decoding opus data", err)
|
OnError("Error decoding opus data", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if len(p.PCM) != 960 {
|
||||||
|
log.Println("Opus size error")
|
||||||
|
continue
|
||||||
|
}
|
||||||
discordMutex.Lock()
|
discordMutex.Lock()
|
||||||
log.Println("got lock 3")
|
select {
|
||||||
fromDiscordMap[p.SSRC].pcm <- p.PCM[0:480]
|
case fromDiscordMap[p.SSRC].pcm <- p.PCM[0:480]:
|
||||||
fromDiscordMap[p.SSRC].pcm <- p.PCM[480:960]
|
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()
|
discordMutex.Unlock()
|
||||||
log.Println("finish loop")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +239,6 @@ func fromDiscordMixer(toMumble chan<- gumble.AudioBuffer, die chan bool) {
|
|||||||
if sendAudio {
|
if sendAudio {
|
||||||
select {
|
select {
|
||||||
case toMumble <- outBuf:
|
case toMumble <- outBuf:
|
||||||
log.Println("sending to mumble")
|
|
||||||
default:
|
default:
|
||||||
log.Println("toMumble buffer full. Dropping packet")
|
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 {
|
if m.Author.ID == s.State.User.ID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
prefix := "!" + BridgeConf.Command
|
||||||
if strings.HasPrefix(m.Content, "!yammer link") {
|
if strings.HasPrefix(m.Content, prefix+" link") {
|
||||||
|
|
||||||
// Find the channel that the message came from.
|
// Find the channel that the message came from.
|
||||||
c, err := s.State.Channel(m.ChannelID)
|
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 {
|
if vs.UserID == m.Author.ID {
|
||||||
log.Printf("Trying to join GID %v and VID %v\n", g.ID, vs.ChannelID)
|
log.Printf("Trying to join GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||||
die := make(chan bool)
|
die := make(chan bool)
|
||||||
YBConfig.ActiveConns[vs.ChannelID] = die
|
Bridge.ActiveConn = die
|
||||||
go startBridge(s, g.ID, vs.ChannelID, YBConfig.Config, YBConfig.MumbleAddr, YBConfig.MumbleInsecure, die)
|
go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, die)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(m.Content, "!yammer unlink") {
|
if strings.HasPrefix(m.Content, prefix+" unlink") {
|
||||||
|
|
||||||
// Find the channel that the message came from.
|
// Find the channel that the message came from.
|
||||||
c, err := s.State.Channel(m.ChannelID)
|
c, err := s.State.Channel(m.ChannelID)
|
||||||
@ -69,8 +69,8 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|||||||
for _, vs := range g.VoiceStates {
|
for _, vs := range g.VoiceStates {
|
||||||
if vs.UserID == m.Author.ID {
|
if vs.UserID == m.Author.ID {
|
||||||
log.Printf("Trying to leave GID %v and VID %v\n", g.ID, vs.ChannelID)
|
log.Printf("Trying to leave GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||||
YBConfig.ActiveConns[vs.ChannelID] <- true
|
Bridge.ActiveConn <- true
|
||||||
YBConfig.ActiveConns[vs.ChannelID] = nil
|
Bridge.ActiveConn = nil
|
||||||
MumbleReset()
|
MumbleReset()
|
||||||
DiscordReset()
|
DiscordReset()
|
||||||
return
|
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.
|
// Find the channel that the message came from.
|
||||||
c, err := s.State.Channel(m.ChannelID)
|
c, err := s.State.Channel(m.ChannelID)
|
||||||
@ -98,16 +98,27 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|||||||
for _, vs := range g.VoiceStates {
|
for _, vs := range g.VoiceStates {
|
||||||
if vs.UserID == m.Author.ID {
|
if vs.UserID == m.Author.ID {
|
||||||
log.Printf("Trying to refresh GID %v and VID %v\n", g.ID, vs.ChannelID)
|
log.Printf("Trying to refresh GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||||
YBConfig.ActiveConns[vs.ChannelID] <- true
|
Bridge.ActiveConn <- true
|
||||||
MumbleReset()
|
MumbleReset()
|
||||||
DiscordReset()
|
DiscordReset()
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
YBConfig.ActiveConns[vs.ChannelID] = make(chan bool)
|
Bridge.ActiveConn = make(chan bool)
|
||||||
go startBridge(s, g.ID, vs.ChannelID, YBConfig.Config, YBConfig.MumbleAddr, YBConfig.MumbleInsecure, YBConfig.ActiveConns[vs.ChannelID])
|
go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, Bridge.ActiveConn)
|
||||||
return
|
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) {
|
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"
|
_ "layeh.com/gumble/opus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var YBConfig *YammerConfig
|
var BridgeConf *BridgeConfig
|
||||||
|
var Bridge *BridgeState
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
godotenv.Load()
|
godotenv.Load()
|
||||||
@ -29,7 +30,7 @@ func main() {
|
|||||||
discordToken := flag.String("discord-token", lookupEnvOrString("DISCORD_TOKEN", ""), "DISCORD_TOKEN, discord bot token")
|
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")
|
discordGID := flag.String("discord-gid", lookupEnvOrString("DISCORD_GID", ""), "DISCORD_GID, discord gid")
|
||||||
discordCID := flag.String("discord-cid", lookupEnvOrString("DISCORD_CID", ""), "DISCORD_CID, discord cid")
|
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()
|
flag.Parse()
|
||||||
log.Printf("app.config %v\n", getConfig(flag.CommandLine))
|
log.Printf("app.config %v\n", getConfig(flag.CommandLine))
|
||||||
|
|
||||||
@ -66,6 +67,7 @@ func main() {
|
|||||||
discord.AddHandler(ready)
|
discord.AddHandler(ready)
|
||||||
discord.AddHandler(messageCreate)
|
discord.AddHandler(messageCreate)
|
||||||
discord.AddHandler(guildCreate)
|
discord.AddHandler(guildCreate)
|
||||||
|
discord.AddHandler(voiceUpdate)
|
||||||
err = discord.Open()
|
err = discord.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@ -74,19 +76,30 @@ func main() {
|
|||||||
defer discord.Close()
|
defer discord.Close()
|
||||||
|
|
||||||
log.Println("Discord Bot Connected")
|
log.Println("Discord Bot Connected")
|
||||||
|
log.Printf("Discord bot looking for command !%v", *discordCommand)
|
||||||
config := gumble.NewConfig()
|
config := gumble.NewConfig()
|
||||||
config.Username = *mumbleUsername
|
config.Username = *mumbleUsername
|
||||||
config.Password = *mumblePassword
|
config.Password = *mumblePassword
|
||||||
config.AudioInterval = time.Millisecond * 10
|
config.AudioInterval = time.Millisecond * 10
|
||||||
|
|
||||||
YBConfig = &YammerConfig{
|
BridgeConf = &BridgeConfig{
|
||||||
Config: config,
|
Config: config,
|
||||||
MumbleAddr: *mumbleAddr + ":" + strconv.Itoa(*mumblePort),
|
MumbleAddr: *mumbleAddr + ":" + strconv.Itoa(*mumblePort),
|
||||||
MumbleInsecure: *mumbleInsecure,
|
MumbleInsecure: *mumbleInsecure,
|
||||||
ActiveConns: make(map[string]chan bool),
|
Auto: false,
|
||||||
|
Command: *discordCommand,
|
||||||
|
GID: *discordGID,
|
||||||
|
CID: *discordCID,
|
||||||
}
|
}
|
||||||
|
Bridge = &BridgeState{
|
||||||
//go startBridge(discord, *discordGID, *discordCID, config, *mumbleAddr+":"+strconv.Itoa(*mumblePort), *mumbleInsecure, die)
|
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)
|
sc := make(chan os.Signal, 1)
|
||||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||||
|
Loading…
Reference in New Issue
Block a user