Obtenha buffers de áudio do dispositivo de saída do macOS em tempo real

Dec 14 2020

Estou tentando tocar no dispositivo de áudio de saída selecionado no macOS, então basicamente tenho um ouvinte de passagem que pode monitorar o fluxo de áudio que está sendo emitido sem afetá-lo.

Quero copiar esses dados para um buffer de anel em tempo real para que possa operar separadamente.

A combinação de documentos da Apple e respostas (desatualizadas?) SO são confusas quanto a se eu preciso escrever uma extensão de kernel hacky, se posso utilizar o CoreAudio para isso ou preciso fazer a interface com o HAL?

Eu gostaria de trabalhar na Swift, se possível.

Muito Obrigado

(ps. Eu estava olhando para isso e isso )

Respostas

3 RhythmicFistman Dec 14 2020 at 23:07

Não sei sobre as extensões do kernel - o uso de certificados de assinatura especiais do tipo "ligue para nós" ou a necessidade de desligar o SIP desencoraja a exploração casual.

No entanto, você pode usar uma combinação de plug-ins CoreAudio e HAL AudioServer para fazer o que quiser, e você não precisa nem mesmo escrever o plug-in, existem várias versões de código aberto para escolher.

O CoreAudio não oferece uma maneira de gravar de (ou "tocar") dispositivos de saída - você só pode gravar de dispositivos de entrada, então a maneira de contornar isso é criar um dispositivo de "passagem" virtual (AudioServerPlugin), não associado a qualquer hardware, que copia a saída para a entrada e, em seguida, define esse dispositivo de passagem como saída padrão e grava de sua entrada. Eu fiz isso usando Plugins AudioServer de código aberto como BackgroundMusic e BlackHole [TODO: add more].

Para tocar / gravar do dispositivo resultante, você pode simplesmente adicionar um AudioDeviceIOProcretorno de chamada a ele ou definir o dispositivo como o kAudioOutputUnitProperty_CurrentDevicede umkAudioUnitSubType_HALOutput AudioUnit

Existem dois problemas com a abordagem de dispositivo de passagem virtual acima:

  1. você não consegue mais ouvir a saída, porque está sendo consumida pelo dispositivo de passagem
  2. alterar o dispositivo de saída padrão mudará seu dispositivo e a torneira ficará em silêncio.

Se 1. for um problema, então um simples é criar um dispositivo de saída múltipla contendo o dispositivo de passagem e um dispositivo de saída real (veja a imagem) e definir isso como o dispositivo de saída padrão. Os controles de volume param de funcionar, mas você ainda pode alterar o volume do dispositivo de saída real Audio MIDI Setup.app.

Para 2. você pode adicionar um ouvinte ao dispositivo de saída padrão e atualizar o dispositivo de múltiplas saídas acima quando ele mudar.

Você pode fazer a maioria dos itens acima rapidamente, embora para armazenamento de ringbuffer a partir dos callbacks de entrega de buffer, você terá que usar C ou alguma outra linguagem que possa respeitar as regras de áudio em tempo real (sem travas, sem alocação de memória, etc). Você poderia tentar AVAudioEnginefazer a torneira, mas alterar o dispositivo de entrada do IIRC é um vale de lágrimas .