Browse Source

some style updates

replaced the speaking when joining with an actual client_connect event
pull/101/head
Dan 7 years ago
parent
commit
2989a2cec6
  1. 2
      disco/gateway/packets.py
  2. 20
      disco/voice/client.py
  3. 2
      disco/voice/packets.py
  4. 45
      disco/voice/udp.py

2
disco/gateway/packets.py

@ -16,5 +16,5 @@ OPCode = Enum(
INVALID_SESSION=9,
HELLO=10,
HEARTBEAT_ACK=11,
GUILD_SYNC=12
GUILD_SYNC=12,
)

20
disco/voice/client.py

@ -33,6 +33,7 @@ VoiceState = Enum(
VOICE_CONNECTED=8,
)
class VoiceSpeaking(namedtuple('VoiceSpeaking', ['user_id', 'speaking', 'soundshare'])):
"""
Voice Speaking Event
@ -46,6 +47,7 @@ class VoiceSpeaking(namedtuple('VoiceSpeaking', ['user_id', 'speaking', 'soundsh
if they are using soundshare
"""
class VoiceException(Exception):
def __init__(self, msg, client):
self.voice_client = client
@ -108,7 +110,7 @@ class VoiceClient(LoggingClass):
self._heartbeat_task = None
# SSRCs
self.audio_ssrcs = {}
def __repr__(self):
@ -146,7 +148,7 @@ class VoiceClient(LoggingClass):
'op': op.value,
'd': data,
}), self.encoder.OPCODE)
def on_voice_client_connect(self, data):
self.audio_ssrcs[data['audio_ssrc']] = data['user_id']
# ignore data['voice_ssrc'] for now
@ -164,7 +166,7 @@ class VoiceClient(LoggingClass):
def on_voice_hello(self, data):
self.log.info('[%s] Recieved Voice HELLO payload, starting heartbeater', self)
self._heartbeat_task = gevent.spawn(self._heartbeat, data['heartbeat_interval'] * 0.75)
self._heartbeat_task = gevent.spawn(self._heartbeat, data['heartbeat_interval'])
self.set_state(VoiceState.AUTHENTICATED)
def on_voice_ready(self, data):
@ -190,7 +192,7 @@ class VoiceClient(LoggingClass):
self.log.error('Failed to discover our IP, perhaps a NAT or firewall is fucking us')
self.disconnect()
return
codecs = []
for i in range(len(AudioCodecs)):
@ -214,6 +216,11 @@ class VoiceClient(LoggingClass):
},
'codecs': codecs
})
self.send(VoiceOPCode.CLIENT_CONNECT, {
'audio_ssrc': self.ssrc,
'video_ssrc': 0,
'rtx_ssrc': 0
})
def on_voice_resumed(self, data):
self.log.info('[%s] Recieved resumed', self)
@ -230,11 +237,6 @@ class VoiceClient(LoggingClass):
# Create a secret box for encryption/decryption
self.udp.setup_encryption(bytes(bytearray(sdp['secret_key'])))
# Toggle speaking state so clients learn of our SSRC
self.set_speaking(True)
self.set_speaking(False)
gevent.sleep(0.25)
self.set_state(VoiceState.CONNECTED)
def on_voice_server_update(self, data):

2
disco/voice/packets.py

@ -13,5 +13,5 @@ VoiceOPCode = Enum(
RESUMED=9,
CLIENT_CONNECT=12,
CLIENT_DISCONNECT=13,
CODECS=14
CODECS=14,
)

45
disco/voice/udp.py

@ -22,6 +22,7 @@ MAX_SEQUENCE = 65535
RTP_HEADER_ONE_BYTE = (0xBE, 0xDE)
class RTPHeader(namedtuple('RTPHeader', ['version', 'padding', 'extension', 'csrc_count', 'marker', 'payload_type', 'sequence', 'timestamp', 'ssrc'])):
"""
RTP Packet's Header information
@ -46,7 +47,8 @@ class RTPHeader(namedtuple('RTPHeader', ['version', 'padding', 'extension', 'csr
RTP packet's SSRC, the person talking
"""
class VoiceData(namedtuple('VoiceData', ['data', 'user_id', 'rtp', 'codec', 'channel'])):
class VoiceData(namedtuple('VoiceData', ['data', 'user_id', 'payload_type', 'channel', 'rtp'])):
"""
Voice Data received from the UDP socket
Attributes
@ -55,12 +57,14 @@ class VoiceData(namedtuple('VoiceData', ['data', 'user_id', 'rtp', 'codec', 'cha
the decrypted data
user_id: snowflake
the id of the user who sent this data
payload_type : string
the payload's type, currently only 'opus' supported
channel : object??
rtp : RTPHeader
the rtp packet's header data
codec : string
the codec this packet is using
"""
class UDPVoiceClient(LoggingClass):
def __init__(self, vc):
super(UDPVoiceClient, self).__init__()
@ -84,7 +88,7 @@ class UDPVoiceClient(LoggingClass):
# Buffer used for encoding/sending frames
self._buffer = bytearray(24)
self._buffer[0] = 2 << 6 # Only RTP Version set in the first byte of the header, 0x80
self._buffer[0] = 2 << 6 # Only RTP Version set in the first byte of the header, 0x80
self._buffer[1] = PayloadTypes.OPUS.value
def increment_timestamp(self, by):
@ -138,7 +142,7 @@ class UDPVoiceClient(LoggingClass):
# Data cannot be less than the bare minimum, just ignore
if len(data) <= 12:
continue
first, second, sequence, timestamp, ssrc = struct.unpack_from('>BBHII', data)
rtp = RTPHeader(
@ -156,7 +160,7 @@ class UDPVoiceClient(LoggingClass):
# Check if rtp version is 2
if rtp.version != 2:
continue
payload_type = PayloadTypes.get(rtp.payload_type)
# Unsupported payload type received
@ -175,17 +179,17 @@ class UDPVoiceClient(LoggingClass):
try:
data = self._secret_box.decrypt(bytes(data[12:]), bytes(nonce))
except:
except Exception:
continue
# RFC3550 Section 5.1 (Padding)
if rtp.padding:
padding_amount = data[:-1]
data = data[-padding_amount:]
if rtp.extension:
# RFC5285 Section 4.2: One-Byte Header
rtp_extension_header = struct.unpack_from('>BB', data[:2])
rtp_extension_header = struct.unpack_from('>BB', data)
if rtp_extension_header == RTP_HEADER_ONE_BYTE:
data = data[2:]
@ -196,32 +200,39 @@ class UDPVoiceClient(LoggingClass):
for i in range(fields_amount):
first_byte, = struct.unpack_from('>B', data[offset])
offset += 1
rtp_extension_identifer = first_byte & 0xF
rtp_extension_len = ((first_byte >> 4) & 0xF) + 1
# Ignore data if identifer == 15, so skip if this is set as 0
if rtp_extension_identifer:
fields.append(data[offset:offset + rtp_extension_len])
offset += rtp_extension_len
# skip padding
while data[offset] == 0:
offset += 1
if len(fields):
data = b''.join(fields + [data[offset:]])
fields.append(data[offset:])
data = b''.join(fields)
else:
data = data[offset:]
# RFC3550 Section 5.3: Profile-Specific Modifications to the RTP Header
# clients send it sometimes, definitely on fresh connects to a server, dunno what to do here
# clients send it sometimes, definitely on fresh connects to a server, dunno what to do here
if rtp.marker:
continue
user_id = self.vc.audio_ssrcs.get(rtp.ssrc, None)
payload = VoiceData(data=data, user_id=user_id, rtp=rtp, codec=payload_type.name, channel=self.vc.channel)
payload = VoiceData(
data=data,
payload_type=payload_type.name,
user_id=user_id,
channel=self.vc.channel,
rtp=rtp
)
self.vc.client.gw.events.emit('VoiceData', payload)

Loading…
Cancel
Save