use user counting, add discord buffer debuf, intial auto mode

This commit is contained in:
stryan 2021-01-03 15:32:59 -05:00
parent ca1ba1d099
commit 4b8e6eea55
5 changed files with 133 additions and 47 deletions

View File

@ -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
}
}
}

View File

@ -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 {

View File

@ -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")
}

View File

@ -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
View File

@ -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)