Tag Archives: apple

CoreAudio Taps for Dummies

I’ve finally spent some time on implementing CoreAudio taps in SoundPusher 1.5. These let you listen in on (“tap”) the output that is generated by certain processes or sent to certain devices.

So far, SoundPusher has done this with a loopback device that reflects any output it receives back into an input stream that looks to the system like a (6-channel) microphone. This has required increasingly more permissions from the system to access microphone input (since the OS doesn’t know what the SoundPusher Audio device records), and results in a big orange blob in the menu bar to warn the user that they’re being recorded.

Apple has started to provide APIs for recording system audio through audio “taps”, and if they’re good enough for Rogue Amoeba than maybe they’re good enough for me as well.

Unfortunately, Apple’s developer documentation is terrible as usual even though the actual C headers contain some more information. So this is mostly what I’ve figured out.

Taps work by attaching them to an aggregate device using the kAudioAggregateDeviceTapListKey in the dictionary provided to AudioHardwareCreateAggregateDevice(). See https://github.com/q-p/SoundPusher/blob/v1.5.1/SoundPusher/AudioTap.mm#L52 for an example.

The aggregate device with the tap (and nothing else — initially I put the device I was tapping into the aggregate device as well but that only confused matters) will then provide an input stream that contains the tapped data. This is similar to reading from a (virtual) microphone, so I didn’t have to change the rest of the code much. Starting to read from such a tap requires a TCC / privacy authorization and results in a less obnoxious purple dot compared to the orange microphone blob. There doesn’t seem to be a way to query this authorization status as is possible for the microphone access using [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio], so if the user denies this request all you will get is silence (and you cannot inform them about the authorization status since you don’t know).

Do note that if the device you’re tapping also contains input streams (like my SoundPusher Audio loopback device did), then you will in addition still need microphone access to tap that device. I have tried all sorts of ways to disable the input streams to avoid the microphone permissions when tapping a device with inputs, but no such luck. That’s why I have removed all input (and therefore loopback) support from SoundPusher Audio.

Why is this dummy device then needed at all? Because I need 5.1 channels of input data, and unless the user has a real 6 channel audio device, there won’t be anything good to tap. The system can provide a mono or stereo mix-down when tapping, but if you want something more specific than that, then you need a real (fake) device to prescribe the shape and format you want tapped…

2021 MacBook Pro (14-inch) Impressions

While working from home for most of 2020 and 2021 I’ve been using my 12-core (24-thread) Mac Pro for my usual C++ development. For the eventual return to the office (which is still a rather big question mark), I didn’t want returning there and working from a laptop to be such a huge step down, so of course I ordered one of the shiny new 2021 MacBook Pros. I went for the 14-inch for portability, as I’m mostly using it in clamshell-mode at my desk, and only occasionally when traveling (remember that?).

As I’m only really stressing the CPU, the 10-core “Pro” version with the small GPU is totally adequate, and the 32GB were enough memory to load all those cores when compiling. The extra memory bandwidth of the “Max” doesn’t help much when only loading the CPU.

The display is very nice (more dimming zones than the Pro Display XDR), but I hardly notice ProMotion (up to 120Hz refresh rate).

For some benchmarks, I compiled our largely C++ work project (using a different build system to Xcode — which seems to have trouble parallelizing large builds) on all cores (including hyper-threads on the Mac Pro):

  • 2019 Mac Pro (12-core, 24-thread; 96GB): 4m54secs
  • 2021 MacBook Pro (8+2-core, 32GB, 14-inch): 3m50secs
  • 2021 MacBook Pro (8+2-core, 32GB, 14-inch) low-power mode: 4m32secs

So that’s roughly 28% faster on the laptop. The fans become audible after ~2min on full load, but they aren’t as annoying as the ones on my previous 2018 i9 Intel MacBook Pro which spun up at the slightest provocation. The new MBP’s fans sound more like low-level white noise. With low-power mode enabled (which throttles the CPU), the fans do come on as well, but only spin at a barely audible level; resulting in a slow-down of 15% compared to normal operation (and still being faster than the Mac Pro).