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

@ -38,6 +38,8 @@ c_int_ptr = ctypes.POINTER(ctypes.c_int)
c_int16_ptr = ctypes.POINTER(ctypes.c_int16)
c_float_ptr = ctypes.POINTER(ctypes.c_float)
_lib = None
class EncoderStruct(ctypes.Structure):
pass
@ -100,25 +102,29 @@ def libopus_loader(name):
return lib
try:
if sys.platform == 'win32':
_basedir = os.path.dirname(os.path.abspath(__file__))
_bitness = 'x64' if sys.maxsize > 2**32 else 'x86'
_filename = os.path.join(_basedir, 'bin', 'libopus-0.{}.dll'.format(_bitness))
_lib = libopus_loader(_filename)
else:
_lib = libopus_loader(ctypes.util.find_library('opus'))
except Exception:
_lib = None
def _load_default():
global _lib
try:
if sys.platform == 'win32':
_basedir = os.path.dirname(os.path.abspath(__file__))
_bitness = 'x64' if sys.maxsize > 2**32 else 'x86'
_filename = os.path.join(_basedir, 'bin', 'libopus-0.{}.dll'.format(_bitness))
_lib = libopus_loader(_filename)
else:
_lib = libopus_loader(ctypes.util.find_library('opus'))
except Exception:
_lib = None
return _lib is not None
def load_opus(name):
"""Loads the libopus shared library for use with voice.
If this function is not called then the library uses the function
:func:`ctypes.util.find_library` and then loads that one
if available.
:func:`ctypes.util.find_library` and then loads that one if available.
Not loading a library leads to voice not working.
Not loading a library and attempting to use PCM based AudioSources will
lead to voice not working.
This function propagates the exceptions thrown.
@ -221,7 +227,8 @@ class Encoder:
self.application = application
if not is_loaded():
raise OpusNotLoaded()
if not _load_default():
raise OpusNotLoaded()
self._state = self._create_state()
self.set_bitrate(128)