Browse Source

added more debug logs

pull/101/head
Dan 7 years ago
parent
commit
9fa8d1d427
  1. 35
      disco/voice/client.py
  2. 40
      disco/voice/udp.py

35
disco/voice/client.py

@ -103,7 +103,6 @@ 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):
@ -128,9 +127,15 @@ class VoiceClient(LoggingClass):
self.send(VoiceOPCode.HEARTBEAT, time.time()) self.send(VoiceOPCode.HEARTBEAT, time.time())
gevent.sleep(interval / 1000) gevent.sleep(interval / 1000)
def set_speaking(self, value, delay=0): def set_speaking(self, voice=False, soundshare=False, delay=0):
value = SpeakingCodes.NONE.value
if voice:
value |= SpeakingCodes.VOICE.value
if soundshare:
value |= SpeakingCodes.SOUNDSHARE.value
self.send(VoiceOPCode.SPEAKING, { self.send(VoiceOPCode.SPEAKING, {
'speaking': int(value), 'speaking': value,
'delay': delay, 'delay': delay,
'ssrc': self.ssrc, 'ssrc': self.ssrc,
}) })
@ -157,6 +162,9 @@ class VoiceClient(LoggingClass):
self.video_codec = data['video_codec'] self.video_codec = data['video_codec']
self.transport_id = data['media_session_id'] self.transport_id = data['media_session_id']
# Set the UDP's RTP Audio Header's Payload Type
self.udp.set_audio_codec(data['audio_codec'])
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']) self._heartbeat_task = gevent.spawn(self._heartbeat, data['heartbeat_interval'])
@ -188,16 +196,14 @@ class VoiceClient(LoggingClass):
codecs = [] codecs = []
for i in range(len(AudioCodecs)): # Sending discord our available codecs and rtp payload type for it
codec = AudioCodecs[i] for idx, codec in enumerate(AudioCodecs):
payload_type = PayloadTypes.get(codec) codecs.append({
if payload_type: 'name': codec,
codecs.append({ 'type': 'audio',
'name': codec, 'priority': (idx + 1) * 1000,
'type': 'audio', 'payload_type': PayloadTypes.get(codec).value,
'priority': (i + 1) * 1000, })
'payload_type': payload_type.value
})
self.log.debug('[%s] IP discovery completed (ip = %s, port = %s), sending SELECT_PROTOCOL', self, ip, port) self.log.debug('[%s] IP discovery completed (ip = %s, port = %s), sending SELECT_PROTOCOL', self, ip, port)
self.send(VoiceOPCode.SELECT_PROTOCOL, { self.send(VoiceOPCode.SELECT_PROTOCOL, {
@ -227,6 +233,9 @@ class VoiceClient(LoggingClass):
self.video_codec = sdp['video_codec'] self.video_codec = sdp['video_codec']
self.transport_id = sdp['media_session_id'] self.transport_id = sdp['media_session_id']
# Set the UDP's RTP Audio Header's Payload Type
self.udp.set_audio_codec(sdp['audio_codec'])
# 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'])))

40
disco/voice/udp.py

@ -20,7 +20,8 @@ PayloadTypes = Enum(OPUS=0x78)
MAX_UINT32 = 4294967295 MAX_UINT32 = 4294967295
MAX_SEQUENCE = 65535 MAX_SEQUENCE = 65535
RTP_HEADER_ONE_BYTE = (0xBE, 0xDE) RTP_HEADER_VERSION = 0x80 # Only RTP Version is set here (value of 2 << 6)
RTP_EXTENSION_ONE_BYTE = (0xBE, 0xDE)
RTPHeader = namedtuple('RTPHeader', [ RTPHeader = namedtuple('RTPHeader', [
@ -65,10 +66,17 @@ class UDPVoiceClient(LoggingClass):
self._run_task = None self._run_task = None
self._secret_box = None self._secret_box = None
# Buffer used for encoding/sending frames # RTP Header
self._header = bytearray(12) self._rtp_audio_header = bytearray(12)
self._header[0] = 2 << 6 # Only RTP Version set in the first byte of the header, 0x80 self._rtp_audio_header[0] = RTP_HEADER_VERSION
self._header[1] = PayloadTypes.OPUS.value
def set_audio_codec(self, codec):
ptype = PayloadTypes.get(codec)
if ptype:
self._rtp_audio_header[1] = ptype.value
self.log.debug('[%s] Set UDP\'s Audio Codec to %s, RTP payload type %s', self.vc, ptype.name, ptype.value)
else:
raise Exception('The voice codec, {}, isn\'t supported.'.format(codec))
def increment_timestamp(self, by): def increment_timestamp(self, by):
self.timestamp += by self.timestamp += by
@ -83,9 +91,9 @@ class UDPVoiceClient(LoggingClass):
frame = bytearray(frame) frame = bytearray(frame)
# Pack the rtc header into our buffer # Pack the rtc header into our buffer
struct.pack_into('>H', self._header, 2, sequence or self.sequence) struct.pack_into('>H', self._rtp_audio_header, 2, sequence or self.sequence)
struct.pack_into('>I', self._header, 4, timestamp or self.timestamp) struct.pack_into('>I', self._rtp_audio_header, 4, timestamp or self.timestamp)
struct.pack_into('>i', self._header, 8, self.vc.ssrc) struct.pack_into('>i', self._rtp_audio_header, 8, self.vc.ssrc)
if self.vc.mode == 'xsalsa20_poly1305_lite': if self.vc.mode == 'xsalsa20_poly1305_lite':
# Use an incrementing number as a nonce, only first 4 bytes of the nonce is padded on # Use an incrementing number as a nonce, only first 4 bytes of the nonce is padded on
@ -103,20 +111,20 @@ class UDPVoiceClient(LoggingClass):
elif self.vc.mode == 'xsalsa20_poly1305': elif self.vc.mode == 'xsalsa20_poly1305':
# Nonce is the header # Nonce is the header
nonce = bytearray(24) nonce = bytearray(24)
nonce[:12] = self._header nonce[:12] = self._rtp_audio_header
nonce_padding = None nonce_padding = None
else: else:
raise Exception('The voice mode, {}, isn\'t supported.'.format(self.vc.mode)) raise Exception('The voice mode, {}, isn\'t supported.'.format(self.vc.mode))
# Encrypt the payload with the nonce # Encrypt the payload with the nonce
raw = self._secret_box.encrypt(bytes(frame), bytes(nonce)).ciphertext payload = self._secret_box.encrypt(bytes(frame), bytes(nonce)).ciphertext
# Pad the payload with the nonce, if applicable # Pad the payload with the nonce, if applicable
if nonce_padding: if nonce_padding:
raw += nonce_padding payload += nonce_padding
# Send the header (sans nonce padding) plus the payload # Send the header (sans nonce padding) plus the payload
self.send(self._header + raw) self.send(self._rtp_audio_header + payload)
# Increment our sequence counter # Increment our sequence counter
self.sequence += 1 self.sequence += 1
@ -133,6 +141,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:
self.log.debug('[%s] [VoiceData] Received voice data under 13 bytes', self.vc)
continue continue
first, second, sequence, timestamp, ssrc = struct.unpack_from('>BBHII', data) first, second, sequence, timestamp, ssrc = struct.unpack_from('>BBHII', data)
@ -151,12 +160,14 @@ class UDPVoiceClient(LoggingClass):
# Check if rtp version is 2 # Check if rtp version is 2
if rtp.version != 2: if rtp.version != 2:
self.log.debug('[%s] [VoiceData] Received an invalid RTP packet version, %s', self.vc, rtp.version)
continue continue
payload_type = PayloadTypes.get(rtp.payload_type) payload_type = PayloadTypes.get(rtp.payload_type)
# Unsupported payload type received # Unsupported payload type received
if not payload_type: if not payload_type:
self.log.debug('[%s] [VoiceData] Received unsupported payload type, %s', self.vc, rtp.payload_type)
continue continue
nonce = bytearray(24) nonce = bytearray(24)
@ -169,11 +180,13 @@ class UDPVoiceClient(LoggingClass):
elif self.vc.mode == 'xsalsa20_poly1305': elif self.vc.mode == 'xsalsa20_poly1305':
nonce[:12] = data[:12] nonce[:12] = data[:12]
else: else:
self.log.debug('[%s] [VoiceData] Unsupported Encryption Mode, %s', self.vc, self.vc.mode)
continue continue
try: try:
data = self._secret_box.decrypt(bytes(data[12:]), bytes(nonce)) data = self._secret_box.decrypt(bytes(data[12:]), bytes(nonce))
except Exception: except Exception:
self.log.debug('[%s] [VoiceData] Failed to decode data from ssrc %s', self.vc, rtp.ssrc)
continue continue
# RFC3550 Section 5.1 (Padding) # RFC3550 Section 5.1 (Padding)
@ -184,7 +197,7 @@ class UDPVoiceClient(LoggingClass):
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) rtp_extension_header = struct.unpack_from('>BB', data)
if rtp_extension_header == RTP_HEADER_ONE_BYTE: if rtp_extension_header == RTP_EXTENSION_ONE_BYTE:
data = data[2:] data = data[2:]
fields_amount, = struct.unpack_from('>H', data) fields_amount, = struct.unpack_from('>H', data)
@ -217,6 +230,7 @@ class UDPVoiceClient(LoggingClass):
# 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:
self.log.debug('[%s] [VoiceData] Received RTP data with the marker set, skipping', self.vc)
continue continue
payload = VoiceData( payload = VoiceData(

Loading…
Cancel
Save