mirror of
https://github.com/mumble-voip/grumble.git
synced 2025-12-20 06:10:00 -08:00
grumble: Opus support.
This commit is contained in:
parent
dd76f22eb7
commit
a415ae75a9
4 changed files with 89 additions and 27 deletions
26
client.go
26
client.go
|
|
@ -43,6 +43,7 @@ type Client struct {
|
||||||
lastResync int64
|
lastResync int64
|
||||||
crypt *cryptstate.CryptState
|
crypt *cryptstate.CryptState
|
||||||
codecs []int32
|
codecs []int32
|
||||||
|
opus bool
|
||||||
udp bool
|
udp bool
|
||||||
voiceTargets map[uint32]*VoiceTarget
|
voiceTargets map[uint32]*VoiceTarget
|
||||||
|
|
||||||
|
|
@ -170,6 +171,8 @@ func (client *Client) disconnect(kicked bool) {
|
||||||
|
|
||||||
client.Printf("Disconnected")
|
client.Printf("Disconnected")
|
||||||
client.conn.Close()
|
client.conn.Close()
|
||||||
|
|
||||||
|
client.server.updateCodecVersions(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,7 +309,11 @@ func (client *Client) udpRecvLoop() {
|
||||||
case mumbleproto.UDPMessageVoiceCELTAlpha:
|
case mumbleproto.UDPMessageVoiceCELTAlpha:
|
||||||
fallthrough
|
fallthrough
|
||||||
case mumbleproto.UDPMessageVoiceCELTBeta:
|
case mumbleproto.UDPMessageVoiceCELTBeta:
|
||||||
kind := buf[0] & 0xe0
|
if (client.server.Opus) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case mumbleproto.UDPMessageVoiceOpus:
|
||||||
target := buf[0] & 0x1f
|
target := buf[0] & 0x1f
|
||||||
var counter uint8
|
var counter uint8
|
||||||
outbuf := make([]byte, 1024)
|
outbuf := make([]byte, 1024)
|
||||||
|
|
@ -315,17 +322,22 @@ func (client *Client) udpRecvLoop() {
|
||||||
outgoing := packetdatastream.New(outbuf[1 : 1+(len(outbuf)-1)])
|
outgoing := packetdatastream.New(outbuf[1 : 1+(len(outbuf)-1)])
|
||||||
_ = incoming.GetUint32()
|
_ = incoming.GetUint32()
|
||||||
|
|
||||||
for {
|
if kind != mumbleproto.UDPMessageVoiceOpus {
|
||||||
counter = incoming.Next8()
|
for {
|
||||||
incoming.Skip(int(counter & 0x7f))
|
counter = incoming.Next8()
|
||||||
if !((counter&0x80) != 0 && incoming.IsValid()) {
|
incoming.Skip(int(counter & 0x7f))
|
||||||
break
|
if !((counter&0x80) != 0 && incoming.IsValid()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
size := int(incoming.GetUint16())
|
||||||
|
incoming.Skip(size & 0x1fff)
|
||||||
}
|
}
|
||||||
|
|
||||||
outgoing.PutUint32(client.Session)
|
outgoing.PutUint32(client.Session)
|
||||||
outgoing.PutBytes(buf[1 : 1+(len(buf)-1)])
|
outgoing.PutBytes(buf[1 : 1+(len(buf)-1)])
|
||||||
outbuf[0] = kind
|
outbuf[0] = buf[0] & 0xe0 // strip target
|
||||||
|
|
||||||
if target != 0x1f { // VoiceTarget
|
if target != 0x1f { // VoiceTarget
|
||||||
client.server.voicebroadcast <- &VoiceBroadcast{
|
client.server.voicebroadcast <- &VoiceBroadcast{
|
||||||
|
|
|
||||||
|
|
@ -1368,6 +1368,7 @@ func (server *Server) handleUserStatsMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
stats.Version = version
|
stats.Version = version
|
||||||
stats.CeltVersions = target.codecs
|
stats.CeltVersions = target.codecs
|
||||||
|
stats.Opus = proto.Bool(target.opus)
|
||||||
stats.Address = target.tcpaddr.IP
|
stats.Address = target.tcpaddr.IP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ const (
|
||||||
UDPMessagePing
|
UDPMessagePing
|
||||||
UDPMessageVoiceSpeex
|
UDPMessageVoiceSpeex
|
||||||
UDPMessageVoiceCELTBeta
|
UDPMessageVoiceCELTBeta
|
||||||
|
UDPMessageVoiceOpus
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns the numeric value identifying the message type of msg on the wire.
|
// Returns the numeric value identifying the message type of msg on the wire.
|
||||||
|
|
|
||||||
88
server.go
88
server.go
|
|
@ -90,6 +90,7 @@ type Server struct {
|
||||||
AlphaCodec int32
|
AlphaCodec int32
|
||||||
BetaCodec int32
|
BetaCodec int32
|
||||||
PreferAlphaCodec bool
|
PreferAlphaCodec bool
|
||||||
|
Opus bool
|
||||||
|
|
||||||
// Channels
|
// Channels
|
||||||
Channels map[int]*Channel
|
Channels map[int]*Channel
|
||||||
|
|
@ -529,9 +530,7 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
||||||
|
|
||||||
// Add codecs
|
// Add codecs
|
||||||
client.codecs = auth.CeltVersions
|
client.codecs = auth.CeltVersions
|
||||||
if len(client.codecs) == 0 {
|
client.opus = auth.GetOpus()
|
||||||
server.Printf("Client %i connected without CELT codecs.", client.Session)
|
|
||||||
}
|
|
||||||
|
|
||||||
client.state = StateClientAuthenticated
|
client.state = StateClientAuthenticated
|
||||||
server.clientAuthenticated <- client
|
server.clientAuthenticated <- client
|
||||||
|
|
@ -567,9 +566,21 @@ func (server *Server) finishAuthenticate(client *Client) {
|
||||||
// Add the client to the connected list
|
// Add the client to the connected list
|
||||||
server.clients[client.Session] = client
|
server.clients[client.Session] = client
|
||||||
|
|
||||||
|
// Warn clients without CELT support that they might not be able to talk to everyone else.
|
||||||
|
if len(client.codecs) == 0 {
|
||||||
|
client.codecs = []int32{CeltCompatBitstream}
|
||||||
|
server.Printf("Client %i connected without CELT codecs. Faking compat bitstream.", client.Session)
|
||||||
|
if server.Opus && !client.opus {
|
||||||
|
client.sendMessage(&mumbleproto.TextMessage{
|
||||||
|
Session: []uint32{client.Session},
|
||||||
|
Message: proto.String("<strong>WARNING:</strong> Your client doesn't support the CELT codec, you won't be able to talk to or hear most clients. Please make sure your client was built with CELT support."),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// First, check whether we need to tell the other connected
|
// First, check whether we need to tell the other connected
|
||||||
// clients to switch to a codec so the new guy can actually speak.
|
// clients to switch to a codec so the new guy can actually speak.
|
||||||
server.updateCodecVersions()
|
server.updateCodecVersions(client)
|
||||||
|
|
||||||
client.sendChannelList()
|
client.sendChannelList()
|
||||||
|
|
||||||
|
|
@ -669,12 +680,24 @@ func (server *Server) finishAuthenticate(client *Client) {
|
||||||
client.clientReady <- true
|
client.clientReady <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) updateCodecVersions() {
|
func (server *Server) updateCodecVersions(connecting *Client) {
|
||||||
codecusers := map[int32]int{}
|
codecusers := map[int32]int{}
|
||||||
var winner int32
|
var (
|
||||||
var count int
|
winner int32
|
||||||
|
count int
|
||||||
|
users int
|
||||||
|
opus int
|
||||||
|
enableOpus bool
|
||||||
|
txtMsg *mumbleproto.TextMessage = &mumbleproto.TextMessage{
|
||||||
|
Message: proto.String("<strong>WARNING:</strong> Your client doesn't support the Opus codec the server is switching to, you won't be able to talk or hear anyone. Please upgrade to a client with Opus support."),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
for _, client := range server.clients {
|
for _, client := range server.clients {
|
||||||
|
users++
|
||||||
|
if client.opus {
|
||||||
|
opus++
|
||||||
|
}
|
||||||
for _, codec := range client.codecs {
|
for _, codec := range client.codecs {
|
||||||
codecusers[codec] += 1
|
codecusers[codec] += 1
|
||||||
}
|
}
|
||||||
|
|
@ -697,33 +720,58 @@ func (server *Server) updateCodecVersions() {
|
||||||
current = server.BetaCodec
|
current = server.BetaCodec
|
||||||
}
|
}
|
||||||
|
|
||||||
if winner == current {
|
enableOpus = users == opus
|
||||||
|
|
||||||
|
if winner != current {
|
||||||
|
if winner == CeltCompatBitstream {
|
||||||
|
server.PreferAlphaCodec = true
|
||||||
|
} else {
|
||||||
|
server.PreferAlphaCodec = !server.PreferAlphaCodec
|
||||||
|
}
|
||||||
|
|
||||||
|
if server.PreferAlphaCodec {
|
||||||
|
server.AlphaCodec = winner
|
||||||
|
} else {
|
||||||
|
server.BetaCodec = winner
|
||||||
|
}
|
||||||
|
} else if server.Opus == enableOpus {
|
||||||
|
if connecting != nil && !connecting.opus {
|
||||||
|
txtMsg.Session = []uint32{connecting.Session}
|
||||||
|
connecting.sendMessage(txtMsg)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if winner == CeltCompatBitstream {
|
server.Opus = enableOpus
|
||||||
server.PreferAlphaCodec = true
|
|
||||||
} else {
|
|
||||||
server.PreferAlphaCodec = !server.PreferAlphaCodec
|
|
||||||
}
|
|
||||||
|
|
||||||
if server.PreferAlphaCodec {
|
|
||||||
server.AlphaCodec = winner
|
|
||||||
} else {
|
|
||||||
server.BetaCodec = winner
|
|
||||||
}
|
|
||||||
|
|
||||||
err := server.broadcastProtoMessage(&mumbleproto.CodecVersion{
|
err := server.broadcastProtoMessage(&mumbleproto.CodecVersion{
|
||||||
Alpha: proto.Int32(server.AlphaCodec),
|
Alpha: proto.Int32(server.AlphaCodec),
|
||||||
Beta: proto.Int32(server.BetaCodec),
|
Beta: proto.Int32(server.BetaCodec),
|
||||||
PreferAlpha: proto.Bool(server.PreferAlphaCodec),
|
PreferAlpha: proto.Bool(server.PreferAlphaCodec),
|
||||||
|
Opus: proto.Bool(server.Opus),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.Printf("Unable to broadcast.")
|
server.Printf("Unable to broadcast.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
server.Printf("CELT codec switch %#x %#x (PreferAlpha %v)", uint32(server.AlphaCodec), uint32(server.BetaCodec), server.PreferAlphaCodec)
|
if server.Opus {
|
||||||
|
for _, client := range server.clients {
|
||||||
|
if !client.opus && client.state == StateClientReady {
|
||||||
|
txtMsg.Session = []uint32{connecting.Session}
|
||||||
|
err := client.sendMessage(txtMsg)
|
||||||
|
if err != nil {
|
||||||
|
client.Panicf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if connecting != nil && !connecting.opus {
|
||||||
|
txtMsg.Session = []uint32{connecting.Session}
|
||||||
|
connecting.sendMessage(txtMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server.Printf("CELT codec switch %#x %#x (PreferAlpha %v) (Opus %v)", uint32(server.AlphaCodec), uint32(server.BetaCodec), server.PreferAlphaCodec, server.Opus)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue