MacOS: Empty result for all_speakers/all_microphones
See original GitHub issueSymptom:
% ptpython
>>> sys.version
'3.10.8 (main, Oct 21 2022, 22:22:30) [Clang 14.0.0 (clang-1400.0.29.202)]'
>>> import soundcard as sc
>>> sc.all_speakers()
[]
>>> sc.all_microphones()
[]
>>> sc.default_speaker()
<Speaker HyperX Cloud Alpha Wireless (0 channels)>
>>> sc.default_microphone()
<Microphone HyperX Cloud Alpha Wireless (0 channels)>
Note all_speakers()
and all_microphones()
return empty lists instead of the expected data. The other strangeness is that it says the default speaker and microphone have “0” channels.
I have Python 3.10.8 installed on MacOS Ventura using Homebrew. To rule out environment problems, I’ve checked env
for any weird variables, cleared out my site-packages
directory and reinstalled soundcard and all its dependencies, but the problem persists.
Just the other day, all of this was working as expected, but after doing a complete reinstall of Python and soundcard, this no longer works.
As a proof that my CoreAudio native libraries are working, the program SwitchAudio (installed by brew install switchaudio-osx
; source code at https://github.com/deweller/switchaudio-osx ) returns the following output showing all my devices:
% SwitchAudioSource -a -f json
{"name": "HyperX Cloud Alpha Wireless", "type": "input", "id": "51", "uid": ""}
{"name": "MacBook Pro Microphone", "type": "input", "id": "148", "uid": ""}
{"name": "Loopback Audio", "type": "input", "id": "153", "uid": ""}
{"name": "HyperX Cloud Alpha Wireless", "type": "output", "id": "51", "uid": ""}
{"name": "MacBook Pro Speakers", "type": "output", "id": "141", "uid": ""}
{"name": "Loopback Audio", "type": "output", "id": "153", "uid": ""}
Technically, I could drop the soundcard dependency, call switchaudio-osx via the CLI, parse the resulting JSON, and get what I need. But I wanted to report this issue in the soundcard lib.
Looking at the definition of all_speakers()
for CoreAudio in soundcard/coreaudio.py:
def all_speakers():
"""A list of all connected speakers."""
device_ids = _CoreAudio.get_property(
_cac.kAudioObjectSystemObject,
_cac.kAudioHardwarePropertyDevices,
"AudioObjectID")
return [_Speaker(id=d) for d in device_ids
if _Speaker(id=d).channels > 0]
See how it only creates a Speaker object if channels > 0 ? Well, the default speaker and default microphone are showing up as channels = 0, for some reason, so maybe all of my devices are showing up as channels = 0 using the API…
Based on the native code here (which we know works, because switchaudio-osx works on my system), it looks like the soundcard CFFI code is probably correctly enumerating all the devices. Unfortunately, switchaudio doesn’t implement channel detection, so I can’t vouch for the correctness of this code in soundcard/coreaudio.py:
@property
def channels(self):
bufferlist = _CoreAudio.get_property(
self._id,
_cac.kAudioDevicePropertyStreamConfiguration,
'AudioBufferList', scope=_cac.kAudioObjectPropertyScopeOutput)
if bufferlist and bufferlist[0].mNumberBuffers > 0:
return bufferlist[0].mBuffers[0].mNumberChannels
else:
return 0
Looks like it gets to the return 0
there at the end, which is the source of all the problems… unfortunately I don’t know why this happens, or how to fix it.
Issue Analytics
- State:
- Created 10 months ago
- Comments:11 (4 by maintainers)
I have a few other Macs floating around that I’ll test on when I get a chance, but it may not be soon.
Maybe, but I tried it both with iTerm2 and the native Mac Terminal app, and neither one pops up a security prompt asking me to permit microphone access or anything like that. They don’t appear as options in Privacy to even enable microphone access, because they don’t seem to need it.
The only possible update it could have been is between Ventura 13.0.0 and Ventura 13.0.1. I’m not 100% sure I had tested this both before and after the 13.0.1 upgrade, as I wasn’t paying attention to specifically when I installed the update vs. when I was messing with python-soundcard.
I wasn’t able to get this working in Rust, but that’s mainly due to my own incompetence with figuring out how to do raw memory allocation in Rust. The furthest I got was some program crashes. I can’t put any more time into it unfortunately.
@bastibe @allquixotic There is another similar package https://github.com/kyleneideck/BackgroundMusic#recording-system-audio that enables system audio recording. Maybe worth checking it out if not done already.