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, INVALID_SESSION=9,
HELLO=10, HELLO=10,
HEARTBEAT_ACK=11, HEARTBEAT_ACK=11,
GUILD_SYNC=12 GUILD_SYNC=12,
) )

20
disco/voice/client.py

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

2
disco/voice/packets.py

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

Loading…
Cancel
Save