bastibe / SoundCard

A Pure-Python Real-Time Audio Library

Home Page:https://soundcard.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Runtime error when attempting to initialize player in "exclusive_mode"

jmw182 opened this issue · comments

Hi,

I am attempting to generate real-time audio with low latency on a Windows 10 system with python 3.7. If I try to set the exclusive_mode argument to speaker.player() to True, mediafoundation.py throws an error at line 92: RuntimeError: invalid argument

Here is a snippet of code that generates the error for me:

speaker = soundcard.default_speaker()
with speaker.player(samplerate=48000, blocksize=1200, exclusive_mode=True) as audioplayer:
    pass

The values of samplerate and blocksize (and channels, which I left as default) do not seem to matter here, the error always happens when I set exclusive_mode=True.

Here is the full error when I run the above snippet in an interactive session:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python\Anaconda3\lib\site-packages\soundcard\mediafoundation.py", line 435, in player
    return _Player(self._audio_client(), samplerate, channels, blocksize, False, exclusive_mode)
  File "C:\Python\Anaconda3\lib\site-packages\soundcard\mediafoundation.py", line 542, in __init__
    _com.check_error(hr)
  File "C:\Python\Anaconda3\lib\site-packages\soundcard\mediafoundation.py", line 92, in check_error
    raise RuntimeError("invalid argument")
RuntimeError: invalid argument

My PC has Realtek audio:

>>> print(speaker)
<Speaker Speakers (Realtek(R) Audio) (2 channels)>

Thanks! Overall this library seems very helpful and a bit easier to use than pyaudio.

I suspect that the error is Windows' way of telling you that you can't open this device in exclusive mode. Perhaps because some other process is using it, or because exclusive mode is not available for every kind of sound card?

Hm I have the same error with different devices. With the python sounddevice library and other applications I can activate the exclusive mode.

In that case this might be a bug. I'd be grateful for any help in debugging this, as I don't currently have a lot of time to devote to open source at the moment.

Thanks for the response @bastibe and thanks for commenting about your error @fmorillo. I had some time to take a look at this tonight and made some progress. In _AudioClient.__init__, the streamflag 0x00100000 is incompatible with exclusive_mode (See MS docs here).

Moving the streamflag definition into the if exclusive_mode/else block to only use that flag for shared mode may fix this issue. Now my code snippet from the OP still returns an error, but instead of "invalid argument" it returns "unsupported format" which seems like another rabbit hole for another day. Still, this seems like progress.

Some relevant documentation for the "unsupported format" error:
https://docs.microsoft.com/en-us/windows/win32/coreaudio/device-formats
https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient-isformatsupported
https://docs.microsoft.com/en-us/windows/win32/coreaudio/exclusive-mode-streams
https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatextensible?redirectedfrom=MSDN
https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient-initialize

Brilliant! Thank you for investigating this!

So we might be restricted to a pre-set sample rate if we open a device in exclusive mode. Or perhaps we have to change the device's sample rate, as opposed to the AudioClient's.

I pushed a relevant commit (5060713) to my fork, but I'm not sure if there's any point in making a pull request since I do not actually have exclusive mode working.

You can create the pull request at any time if you want to ask for help, just mark is as work-in-progress. I'm afraid I can't help much at the moment, sorry.