Browse Source

some updates

fixed it
pull/101/head
Dan 7 years ago
parent
commit
f603142898
  1. 31
      disco/voice/client.py
  2. 66
      disco/voice/udp.py

31
disco/voice/client.py

@ -13,14 +13,10 @@ from disco.util.websocket import Websocket
from disco.util.logging import LoggingClass from disco.util.logging import LoggingClass
from disco.gateway.packets import OPCode from disco.gateway.packets import OPCode
from disco.voice.packets import VoiceOPCode from disco.voice.packets import VoiceOPCode
from disco.voice.udp import UDPVoiceClient from disco.voice.udp import AudioCodecs, PayloadTypes, UDPVoiceClient
AudioCodecs = ('opus',)
PayloadTypes = Enum(OPUS=0x78)
SpeakingCodes = Enum( SpeakingCodes = Enum(
NONE=0 NONE=0,
VOICE=1 << 0, VOICE=1 << 0,
SOUNDSHARE=1 << 1 SOUNDSHARE=1 << 1
) )
@ -199,12 +195,14 @@ class VoiceClient(LoggingClass):
for i in range(len(AudioCodecs)): for i in range(len(AudioCodecs)):
codec = AudioCodecs[i] codec = AudioCodecs[i]
codecs.append({ payload_type = PayloadTypes.get(codec)
'name': codec, if payload_type:
'type': 'audio', codecs.append({
'priority': i * 1000, 'name': codec,
'payload_type': PayloadTypes.get(codec.upper()) 'type': 'audio',
}) '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, {
@ -258,10 +256,11 @@ class VoiceClient(LoggingClass):
def on_voice_speaking(self, data): def on_voice_speaking(self, data):
self.audio_ssrcs[data['ssrc']] = data['user_id'] self.audio_ssrcs[data['ssrc']] = data['user_id']
payload = VoiceSpeaking() payload = VoiceSpeaking(
payload.user_id = data['user_id'] user_id=data['user_id'],
payload.speaking = (data['speaking'] & SpeakingCodes.VOICE) == SpeakingCodes.VOICE speaking=(data['speaking'] & SpeakingCodes.VOICE.value),
payload.soundshare = (data['speaking'] & SpeakingCodes.SOUNDSHARE) == SpeakingCodes.SOUNDSHARE soundshare=(data['speaking'] & SpeakingCodes.SOUNDSHARE.value)
)
self.client.gw.events.emit('VoiceSpeaking', payload) self.client.gw.events.emit('VoiceSpeaking', payload)

66
disco/voice/udp.py

@ -12,7 +12,10 @@ except ImportError:
from holster.enum import Enum from holster.enum import Enum
from disco.util.logging import LoggingClass from disco.util.logging import LoggingClass
from disco.voice.client import PayloadTypes
AudioCodecs = ('opus',)
PayloadTypes = Enum(OPUS=0x78)
MAX_UINT32 = 4294967295 MAX_UINT32 = 4294967295
MAX_SEQUENCE = 65535 MAX_SEQUENCE = 65535
@ -43,7 +46,7 @@ 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'])): class VoiceData(namedtuple('VoiceData', ['data', 'user_id', 'rtp', 'codec', 'channel'])):
""" """
Voice Data received from the UDP socket Voice Data received from the UDP socket
Attributes Attributes
@ -54,6 +57,8 @@ class VoiceData(namedtuple('VoiceData', ['data', 'user_id', 'rtp'])):
the id of the user who sent this data the id of the user who sent this data
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):
@ -80,7 +85,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 self._buffer[1] = PayloadTypes.OPUS.value
def increment_timestamp(self, by): def increment_timestamp(self, by):
self.timestamp += by self.timestamp += by
@ -134,18 +139,19 @@ class UDPVoiceClient(LoggingClass):
if len(data) <= 12: if len(data) <= 12:
continue continue
rtp = RTPHeader() first, second, sequence, timestamp, ssrc = struct.unpack_from('>BBHII', data)
rtp.version = data[1] >> 6
rtp.padding = (data[1] >> 5) & 1 rtp = RTPHeader(
rtp.extension = (data[1] >> 4) & 1 version=first >> 6,
rtp.csrc_count = data[1] & 0x0F padding=(first >> 5) & 1,
extension=(first >> 4) & 1,
rtp.marker = data[2] >> 7 csrc_count=first & 0x0F,
rtp.payload_type = data[2] & 0x7F marker=second >> 7,
payload_type=second & 0x7F,
rtp.sequence = struct.unpack('>H', data[2:]) sequence=sequence,
rtp.timestamp = struct.unpack('>I', data[4:]) timestamp=timestamp,
rtp.ssrc = struct.unpack('>I', data[8:]) ssrc=ssrc
)
# Check if rtp version is 2 # Check if rtp version is 2
if rtp.version != 2: if rtp.version != 2:
@ -159,15 +165,18 @@ class UDPVoiceClient(LoggingClass):
nonce = bytearray(24) nonce = bytearray(24)
if self.vc.mode == 'xsalsa20_poly1305_lite': if self.vc.mode == 'xsalsa20_poly1305_lite':
struct.pack_into('>I', nonce, 0, data[-4:]) nonce[:4] = data[-4:]
data = data[-4:] data = data[:-4]
elif self.vc.mode == 'xsalsa20_poly1305_suffx': elif self.vc.mode == 'xsalsa20_poly1305_suffx':
struct.pack_into('>I', nonce, 0, data[-24:]) nonce[:24] = data[-24:]
data = data[-24:] data = data[:-24]
else: else:
struct.pack_into('>I', nonce, 0, data[:12]) nonce[:12] = data[:12]
data = self._secret_box.decrypt(bytes(data[12:]), bytes(nonce)) try:
data = self._secret_box.decrypt(bytes(data[12:]), bytes(nonce))
except:
continue
# RFC3550 Section 5.1 (Padding) # RFC3550 Section 5.1 (Padding)
if rtp.padding: if rtp.padding:
@ -176,14 +185,17 @@ class UDPVoiceClient(LoggingClass):
if rtp.extension: if rtp.extension:
# RFC5285 Section 4.2: One-Byte Header # RFC5285 Section 4.2: One-Byte Header
if all(data[i] == RTP_HEADER_ONE_BYTE[i] for i in range(len(RTP_HEADER_ONE_BYTE))): rtp_extension_header = struct.unpack_from('>BB', data[:2])
fields_amount = struct.unpack_from('>H', data) if rtp_extension_header == RTP_HEADER_ONE_BYTE:
data = data[2:]
fields_amount, = struct.unpack_from('>H', data[:2])
fields = [] fields = []
offset = 4 offset = 4
for i in range(fields_amount): for i in range(fields_amount):
first_byte, = struct.unpack_from('>B', data[offset])
offset += 1 offset += 1
first_byte = data[offset]
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
@ -209,9 +221,9 @@ class UDPVoiceClient(LoggingClass):
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) payload = VoiceData(data=data, user_id=user_id, rtp=rtp, codec=payload_type.name, channel=self.vc.channel)
self.vc.client.gw.events.emit('VoiceReceived', payload) self.vc.client.gw.events.emit('VoiceData', payload)
def send(self, data): def send(self, data):
self.conn.sendto(data, (self.ip, self.port)) self.conn.sendto(data, (self.ip, self.port))

Loading…
Cancel
Save