Working multi-server voice support.

This commit is contained in:
Rapptz
2016-04-29 05:48:48 -04:00
parent 5fa715c350
commit d9c780b8a8
4 changed files with 97 additions and 65 deletions

View File

@ -90,10 +90,10 @@ class Client:
-----------
user : Optional[:class:`User`]
Represents the connected client. None if not logged in.
voice : Optional[:class:`VoiceClient`]
Represents the current voice connection. None if you are not connected
to a voice channel. To connect to voice use :meth:`join_voice_channel`.
To query the voice connection state use :meth:`is_voice_connected`.
voice_clients : iterable of :class:`VoiceClient`
Represents a list of voice connections. To connect to voice use
:meth:`join_voice_channel`. To query the voice connection state use
:meth:`is_voice_connected`.
servers : iterable of :class:`Server`
The servers that the connected client is a member of.
private_channels : iterable of :class:`PrivateChannel`
@ -114,7 +114,6 @@ class Client:
def __init__(self, *, loop=None, **options):
self.ws = None
self.token = None
self.voice = None
self.loop = asyncio.get_event_loop() if loop is None else loop
self._listeners = []
self.cache_auth = options.get('cache_auth', True)
@ -227,14 +226,14 @@ class Client:
raise InvalidArgument('Destination must be Channel, PrivateChannel, User, or Object')
def __getattr__(self, name):
if name in ('user', 'servers', 'private_channels', 'messages'):
if name in ('user', 'servers', 'private_channels', 'messages', 'voice_clients'):
return getattr(self.connection, name)
else:
msg = "'{}' object has no attribute '{}'"
raise AttributeError(msg.format(self.__class__, name))
def __setattr__(self, name, value):
if name in ('user', 'servers', 'private_channels', 'messages'):
if name in ('user', 'servers', 'private_channels', 'messages', 'voice_clients'):
return setattr(self.connection, name, value)
else:
object.__setattr__(self, name, value)
@ -418,13 +417,13 @@ class Client:
if self.is_closed:
return
if self.is_voice_connected():
yield from self.voice.disconnect()
self.voice = None
if self.ws is not None and self.ws.open:
yield from self.ws.close()
for voice in list(self.voice_clients):
yield from voice.disconnect()
self.connection._remove_voice_client(voice.server.id)
yield from self.session.close()
self._closed.set()
self._is_ready.clear()
@ -2415,15 +2414,17 @@ class Client:
:class:`VoiceClient`
A voice client that is fully connected to the voice server.
"""
if self.is_voice_connected():
raise ClientException('Already connected to a voice channel')
if isinstance(channel, Object):
channel = self.get_channel(channel.id)
if getattr(channel, 'type', ChannelType.text) != ChannelType.voice:
raise InvalidArgument('Channel passed must be a voice channel')
server = channel.server
if self.is_voice_connected(server):
raise ClientException('Already connected to a voice channel in this server')
log.info('attempting to join voice channel {0.name}'.format(channel))
def session_id_found(data):
@ -2435,14 +2436,10 @@ class Client:
voice_data_future = self.ws.wait_for('VOICE_SERVER_UPDATE', lambda d: True)
# request joining
yield from self.ws.voice_state(channel.server.id, channel.id)
yield from self.ws.voice_state(server.id, channel.id)
session_id_data = yield from asyncio.wait_for(session_id_future, timeout=10.0, loop=self.loop)
data = yield from asyncio.wait_for(voice_data_future, timeout=10.0, loop=self.loop)
# todo: multivoice
if self.is_voice_connected():
self.voice.channel = self.get_channel(session_id_data.get('channel_id'))
kwargs = {
'user': self.user,
'channel': channel,
@ -2452,10 +2449,36 @@ class Client:
'main_ws': self.ws
}
self.voice = VoiceClient(**kwargs)
yield from self.voice.connect()
return self.voice
voice = VoiceClient(**kwargs)
yield from voice.connect()
self.connection._add_voice_client(server.id, voice)
return voice
def is_voice_connected(self):
"""bool : Indicates if we are currently connected to a voice channel."""
return self.voice is not None and self.voice.is_connected()
def is_voice_connected(self, server):
"""Indicates if we are currently connected to a voice channel in the
specified server.
Parameters
-----------
server : :class:`Server`
The server to query if we're connected to it.
"""
voice = self.voice_client_in(server)
return voice is not None
def voice_client_in(self, server):
"""Returns the voice client associated with a server.
If no voice client is found then ``None`` is returned.
Parameters
-----------
server : :class:`Server`
The server to query if we have a voice client for.
Returns
--------
:class:`VoiceClient`
The voice client associated with the server.
"""
return self.connection._get_voice_client(server.id)