Uzyskaj bufory audio urządzenia wyjściowego macOS w czasie rzeczywistym

Dec 14 2020

Próbuję dotknąć aktualnie wybranego wyjściowego urządzenia audio w systemie MacOS, więc w zasadzie mam odbiornik tranzytowy, który może monitorować aktualnie odtwarzany strumień audio bez wpływu na to.

Chcę skopiować te dane do bufora pierścieniowego w czasie rzeczywistym, aby móc na nim oddzielnie operować.

Połączenie dokumentacji Apple i (nieaktualnych?) Odpowiedzi SO jest mylące, czy muszę napisać hacky rozszerzenie jądra, czy mogę wykorzystać do tego CoreAudio, czy też muszę połączyć się z HAL?

Jeśli to możliwe, chciałbym pracować w Swift.

Wielkie dzięki

(ps. Patrzyłem na to i to )

Odpowiedzi

3 RhythmicFistman Dec 14 2020 at 23:07

Nie wiem o rozszerzeniach jądra - używanie przez nie specjalnych certyfikatów podpisujących „zadzwoń do nas” czy konieczność wyłączenia SIP zniechęca do swobodnych eksploracji.

Możesz jednak użyć kombinacji wtyczek CoreAudio i HAL AudioServer, aby robić to, co chcesz, i nie musisz nawet samodzielnie pisać wtyczki, do wyboru jest kilka wersji open source.

CoreAudio nie daje możliwości nagrywania z urządzeń wyjściowych (lub „stukania”) - można nagrywać tylko z urządzeń wejściowych, więc sposobem obejścia tego problemu jest utworzenie wirtualnego urządzenia „przechodzącego” (AudioServerPlugin), a nie skojarzony z dowolnym sprzętem, który kopiuje dane wyjściowe na wejście, a następnie ustawia to urządzenie tranzytowe jako domyślne wyjście i zapisuje z jego wejścia. Zrobiłem to za pomocą wtyczek AudioServer typu open source, takich jak BackgroundMusic i BlackHole [TODO: dodaj więcej].

Aby dotknąć / nagrać z powstałego urządzenia, możesz po prostu dodać AudioDeviceIOProcdo niego oddzwonienie lub ustawić urządzenie jako kAudioOutputUnitProperty_CurrentDeviceplikkAudioUnitSubType_HALOutput AudioUnit

Istnieją dwa problemy z powyższym podejściem do wirtualnego przejścia przez urządzenie:

  1. nie słychać już dźwięku, ponieważ jest on pochłaniany przez urządzenie przelotowe
  2. Zmiana domyślnego urządzenia wyjściowego spowoduje odłączenie urządzenia, a kran ucichnie.

Jeśli 1. stanowi problem, prostym sposobem jest utworzenie urządzenia z wieloma wyjściami zawierającego urządzenie przejściowe i rzeczywiste urządzenie wyjściowe (patrz zrzut ekranu) i ustawienie go jako domyślnego urządzenia wyjściowego. Regulacja głośności przestaje działać, ale nadal można zmienić głośność rzeczywistego urządzenia wyjściowego w Audio MIDI Setup.app.

W przypadku 2. można dodać odbiornik do domyślnego urządzenia wyjściowego i zaktualizować powyższe urządzenie z wieloma wyjściami po zmianie.

Większość powyższych czynności możesz wykonać szybko, chociaż w celu przechowywania bufora pierścieniowego z wywołań zwrotnych dostarczania bufora będziesz musiał użyć C lub innego języka, który może respektować reguły dźwięku w czasie rzeczywistym (bez blokad, bez alokacji pamięci itp.). Mógłbyś może spróbować AVAudioEnginestuknąć, ale zmiana urządzenia wejściowego IIRC to prawdziwa dolina łez .