diff --git a/buildconfig/stubs/pygame/mixer.pyi b/buildconfig/stubs/pygame/mixer.pyi index d7da6fe50e..4d1cafc830 100644 --- a/buildconfig/stubs/pygame/mixer.pyi +++ b/buildconfig/stubs/pygame/mixer.pyi @@ -28,6 +28,7 @@ def pre_init( ) -> None: ... def quit() -> None: ... def get_init() -> Tuple[int, int, int]: ... +def get_driver() -> str: ... def stop() -> None: ... def pause() -> None: ... def unpause() -> None: ... diff --git a/docs/reST/ref/mixer.rst b/docs/reST/ref/mixer.rst index 1eaa4b8a20..6ce5e14442 100644 --- a/docs/reST/ref/mixer.rst +++ b/docs/reST/ref/mixer.rst @@ -165,6 +165,18 @@ The following file formats are supported .. ## pygame.mixer.get_init ## +.. function:: get_driver + + | :sl:`get the name of the current audio backend driver` + | :sg:`get_driver() -> str` + + Pygame chooses one of many available audio backend drivers when it is + initialized. This returns the internal name used for the backend. This + function is intended to be used for getting diagnostic/debugging information. + This can be controlled with ``SDL_AUDIODRIVER`` environment variable. + + .. versionadded:: 2.5.0 + .. function:: stop | :sl:`stop playback of all sound channels` diff --git a/src_c/doc/mixer_doc.h b/src_c/doc/mixer_doc.h index 782dde2cd4..381ba09e9c 100644 --- a/src_c/doc/mixer_doc.h +++ b/src_c/doc/mixer_doc.h @@ -4,6 +4,7 @@ #define DOC_MIXER_PREINIT "pre_init(frequency=44100, size=-16, channels=2, buffer=512, devicename=None, allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE) -> None\npreset the mixer init arguments" #define DOC_MIXER_QUIT "quit() -> None\nuninitialize the mixer" #define DOC_MIXER_GETINIT "get_init() -> (frequency, format, channels)\ntest if the mixer is initialized" +#define DOC_MIXER_GETDRIVER "get_driver() -> str\nget the name of the current audio backend driver" #define DOC_MIXER_STOP "stop() -> None\nstop playback of all sound channels" #define DOC_MIXER_PAUSE "pause() -> None\ntemporarily stop playback of all sound channels" #define DOC_MIXER_UNPAUSE "unpause() -> None\nresume paused playback of sound channels" diff --git a/src_c/mixer.c b/src_c/mixer.c index 51097bbab8..f2f4ecb1f7 100644 --- a/src_c/mixer.c +++ b/src_c/mixer.c @@ -582,6 +582,18 @@ pg_mixer_get_init(PyObject *self, PyObject *_null) return Py_BuildValue("(iii)", freq, realform, channels); } +static PyObject * +pg_mixer_get_driver(PyObject *self, PyObject *_null) +{ + const char *name = NULL; + MIXER_INIT_CHECK(); + name = SDL_GetCurrentAudioDriver(); + if (!name) { + name = "unknown"; + } + return PyUnicode_FromString(name); +} + static PyObject * pre_init(PyObject *self, PyObject *args, PyObject *keywds) { @@ -1941,6 +1953,8 @@ static PyMethodDef _mixer_methods[] = { {"quit", (PyCFunction)mixer_quit, METH_NOARGS, DOC_MIXER_QUIT}, {"get_init", (PyCFunction)pg_mixer_get_init, METH_NOARGS, DOC_MIXER_GETINIT}, + {"get_driver", (PyCFunction)pg_mixer_get_driver, METH_NOARGS, + DOC_MIXER_GETDRIVER}, {"pre_init", (PyCFunction)pre_init, METH_VARARGS | METH_KEYWORDS, DOC_MIXER_PREINIT}, {"get_num_channels", (PyCFunction)get_num_channels, METH_NOARGS, diff --git a/src_py/_debug.py b/src_py/_debug.py index 24b0445a9c..32347101e0 100644 --- a/src_py/_debug.py +++ b/src_py/_debug.py @@ -1,11 +1,14 @@ """Debug functionality that allows for more useful issue reporting """ +import platform import sys import traceback import importlib from typing import Tuple, Optional, Callable +from pygame.version import ver + ImportResult = Tuple[str, bool, Optional[Callable]] @@ -53,6 +56,24 @@ def attempt_import(module, function_name, output_str=""): return (output_str, success, i) +def _get_platform_info(): + """ + Internal helper to get platform information + """ + ret = f"Platform:\t\t{platform.platform()}\n" + ret += f"System:\t\t\t{platform.system()}\n" + ret += f"System Version:\t\t{platform.version()}\n" + ret += f"Processor:\t\t{platform.processor()}\n" + ret += ( + f"Architecture:\t\tBits: {platform.architecture()[0]}\t" + f"Linkage: {platform.architecture()[1]}\n\n" + ) + + ret += f"Python:\t\t\t{platform.python_implementation()} {sys.version}\n" + ret += f"pygame version:\t\t{ver}\n" + return ret + + def print_debug_info(filename=None): """Gets debug information for reporting bugs. Prints to console if filename is not specified, otherwise writes to that file @@ -69,7 +90,14 @@ def default_return(linked=True): # pylint: disable=unused-argument return (-1, -1, -1) - from pygame.display import get_driver, get_init as display_init + from pygame.display import ( + get_driver as get_display_driver, + get_init as display_init, + ) + from pygame.mixer import ( + get_driver as get_mixer_driver, + get_init as mixer_init, + ) from pygame.base import get_sdl_version debug_str, *mixer = attempt_import( @@ -100,33 +128,7 @@ def default_return(linked=True): else: ft_version = freetype[1] - from pygame.version import ver - - import platform - - debug_str += f"Platform:\t\t{platform.platform()}\n" - - debug_str += f"System:\t\t\t{platform.system()}\n" - - debug_str += f"System Version:\t\t{platform.version()}\n" - - debug_str += f"Processor:\t\t{platform.processor()}\n" - - debug_str += ( - f"Architecture:\t\tBits: {platform.architecture()[0]}\t" - f"Linkage: {platform.architecture()[1]}\n" - ) - - if display_init(): - debug_str += f"Driver:\t\t\t{get_driver()}\n\n" - else: - debug_str += "Driver:\t\t\tDisplay Not Initialized\n\n" - - debug_str += f"Python:\t\t\t{platform.python_implementation()}\n" - - debug_str += f"pygame version:\t\t{ver}\n" - - debug_str += f"python version:\t\t{str_from_tuple(sys.version_info[0:3])}\n\n" + debug_str += _get_platform_info() debug_str += ( f"SDL versions:\t\tLinked: {str_from_tuple(get_sdl_version())}\t" @@ -150,9 +152,19 @@ def default_return(linked=True): debug_str += ( f"Freetype versions:\tLinked: {str_from_tuple(ft_version())}\t" - f"Compiled: {str_from_tuple(ft_version(linked = False))}" + f"Compiled: {str_from_tuple(ft_version(linked = False))}\n\n" ) + if display_init(): + debug_str += f"Display Driver:\t\t{get_display_driver()}\n" + else: + debug_str += "Display Driver:\t\tDisplay Not Initialized\n" + + if mixer_init(): + debug_str += f"Mixer Driver:\t\t{get_mixer_driver()}" + else: + debug_str += "Mixer Driver:\t\tMixer Not Initialized" + if filename is None: print(debug_str) diff --git a/test/mixer_test.py b/test/mixer_test.py index 76e9390d23..2707285c6d 100644 --- a/test/mixer_test.py +++ b/test/mixer_test.py @@ -48,6 +48,48 @@ def tearDown(self): mixer.quit() mixer.pre_init(0, 0, 0, 0) + def test_get_driver(self): + mixer.init() + drivers = [ + pygame.NULL_VIDEODRIVER, + "pipewire", + "pulseaudio", + "alsa", + "jack", + "sndio", + "netbsd", + "dsp", + "qsa", + "audio", + "arts", + "esd", + "nacl", + "nas", + "wasapi", + "directsound", + "winmm", + "paud", + "haiku", + "coreaudio", + "disk", + "fusionsound", + "AAudio", + "openslES", + "android", + "ps2", + "psp", + "vita", + "n3ds", + "emscripten", + "DART", + ] + driver = mixer.get_driver() + self.assertIn(driver, drivers) + + mixer.quit() + with self.assertRaises(pygame.error): + mixer.get_driver() + def test_init__keyword_args(self): # note: this test used to loop over all CONFIGS, but it's very slow.. mixer.init(**CONFIG)