bastibe / SoundCard

A Pure-Python Real-Time Audio Library
https://soundcard.readthedocs.io
BSD 3-Clause "New" or "Revised" License
680 stars 69 forks source link

[Bug] default_speaker() returns the wrong bluetooth speaker #122

Open shawnc722 opened 3 years ago

shawnc722 commented 3 years ago

I use two bluetooth devices with my computer: a speaker and headphones. When I call default_speaker() while either are connected (and set to default automatically by windows), it returns the headphones - even if they aren't connected. Trying to play through the returned speaker object throws an error, so it's clearly not just the wrong name. The really weird part is it sometimes works flawlessly, letting me switch between speakers, headphones, and analog out without any trouble. I haven't figured out what's causing the difference in behavior, but I wanted to note what I've found in case someone else runs into the same thing. Thanks for making this library, it's been really useful for me so far. I'll make sure to update this if I figure out anything more.

bastibe commented 3 years ago

Is Windows showing the disconnected headphones as its default speaker as well?

Perhaps Windows only changes the default once some app tries to play audio, but technically we query it before playing? That would be unfortunate.

shawnc722 commented 3 years ago

Windows shows the correct default speaker, and doesn’t list the disconnected one as an option. Weirdly, calling all_speakers() returns the correct list - no Bluetooth headphones if they’re disconnected, even if default_speaker() still returns them.

bastibe commented 3 years ago

The default device is fetched from Windows in mediafoundation.py:274 using the function GetDefaultAudioEndpoint. Perhaps the documentation on the eRole parameter is outdated, and we should be using eEmultimedia instead of eConsole?

Does it work correctly if you change the third parameter from 0 to 1?

shawnc722 commented 3 years ago

I’ll test this within a few days and find out.

shawnc722 commented 3 years ago

Tried to reproduce the error, not having any luck even on a fresh restart. Nothing about my code has changed and I haven't updated python or any packages. I tested the change you mentioned anyway, and nothing changed - everything works great. I'm using your library in a background service I keep running all the time, so I'll keep an eye on it and try to do more testing if/when the problem shows up again. One thing I did note (not related to your suggestion) was that if both bluetooth devices are connected, soundcard reports the default speaker as the headphones even if I've manually changed it to the speaker. Windows shows the speaker as default, sound is coming from the speaker, but soundcard still reports that the headphones are default. If I turn off the headphones, soundcard immediately recognizes the speaker as the default. This behavior happens in the original version of soundcard and the modified one using eEmultimedia. It's not nearly as disruptive as the original problem, but maybe it's related? I'm pretty out of my depth here lol. Thanks for your suggestion, and hopefully I'll be able to reproduce the error soon.

bastibe commented 3 years ago

This sounds like a bug in WASAPI. But it's probably instead some subtle issue in soundcard's use of WASAPI. I have honestly no idea what is going on, though. That said, Bluetooth audio support on Windows has always been a bit flakey in my experience, and your experiences with the issue half-solving itself on reboot seems to confirm that.

I will say that there are probably more robust ways of "just" playing audio on the default device than using soundcard. If I remember correctly, the WASAPI has a few functions for playing something without selecting an audio device first. But soundcard is specifically about playing/recording from a particular sound card, and thus does not use the simple APIs. Which conversely apparently leads to these connection/disconnection issues.

Sorry I can't be of much help, there.

But please do let me know if you find out more about this behavior.

shawnc722 commented 3 years ago

Thanks, knowing to check into WASAPI narrows it down for me and hopefully I’ll be able to find the issue. I’m actually using soundcard to monitor loopback and run an rgb lighting visualizer cross platform, so I don’t think those simpler APIs are the solution in my case. Soundcard is working really well for my application anyway, but because I keep it running all the time and switch between Linux and windows (both with multiple output devices) I’m doing pretty thorough testing almost by accident lol. I’ll update if I learn anything about the WASAPI behaviour, and thanks again for all your work on this project.