Add FFmpegOpusAudio and other voice improvements

Rework FFmpeg player and add FFmpegOpusAudio

I have extracted some of the base FFmpeg source code into its own
base class and reimplemented the PCM and the new Opus variants.

Support avconv probing

Also fix a few things

Update `__all__`

Fix the bugs

Rework probe functions and add factory function

Probing involves subprocess so it has been reworked into an async
factory function.

Add docs + a few tweaks

* Removed unnecessary read() and is_opus() functions from FFmpegAudio
* Clear self._stdout in cleanup()
* Add 20 second process communication timeout to probe functions
* Capped probe function bitrate values at 512

Change AudioPlayer to use more accurate, monotonic time.perf_counter()

Add lazy opus loading

The library now no longer loads libopus on import, only on
opus.Encoder creation or manually.

Fix review nits
This commit is contained in:
Imayhaveborkedit
2019-06-22 02:33:53 -04:00
committed by Rapptz
parent 042a234eac
commit fedf26bf3e
5 changed files with 457 additions and 52 deletions

View File

@@ -68,11 +68,10 @@ class VoiceClient:
Warning
--------
In order to play audio, you must have loaded the opus library
through :func:`opus.load_opus`.
If you don't do this then the library will not be able to
transmit audio.
In order to use PCM based AudioSources, you must have the opus library
installed on your system and loaded through :func:`opus.load_opus`.
Otherwise, your AudioSources must be opus encoded (e.g. using :class:`FFmpegOpusAudio`)
or the library will not be able to transmit audio.
Attributes
-----------
@@ -111,7 +110,7 @@ class VoiceClient:
self.timestamp = 0
self._runner = None
self._player = None
self.encoder = opus.Encoder()
self.encoder = None
warn_nacl = not has_nacl
supported_modes = (
@@ -356,7 +355,9 @@ class VoiceClient:
ClientException
Already playing audio or not connected.
TypeError
source is not a :class:`AudioSource` or after is not a callable.
Source is not a :class:`AudioSource` or after is not a callable.
OpusNotLoaded
Source is not opus encoded and opus is not loaded.
"""
if not self.is_connected():
@@ -368,6 +369,9 @@ class VoiceClient:
if not isinstance(source, AudioSource):
raise TypeError('source must an AudioSource not {0.__class__.__name__}'.format(source))
if not self.encoder and not source.is_opus():
self.encoder = opus.Encoder()
self._player = AudioPlayer(source, self, after=after)
self._player.start()
@@ -444,4 +448,4 @@ class VoiceClient:
except BlockingIOError:
log.warning('A packet has been dropped (seq: %s, timestamp: %s)', self.sequence, self.timestamp)
self.checked_add('timestamp', self.encoder.SAMPLES_PER_FRAME, 4294967295)
self.checked_add('timestamp', opus.Encoder.SAMPLES_PER_FRAME, 4294967295)