+++ /dev/null
-/************************************************************************
-
- IMPORTANT NOTE : this file contains two clearly delimited sections :
- the ARCHITECTURE section (in two parts) and the USER section. Each section
- is governed by its own copyright and license. Please check individually
- each section for license and copyright information.
-*************************************************************************/
-
-#ifndef __coreaudio_dsp__
-#define __coreaudio_dsp__
-
-/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
-
-/************************************************************************
- FAUST Architecture File
- Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
- ---------------------------------------------------------------------
- This Architecture section is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 3 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; If not, see <http://www.gnu.org/licenses/>.
-
- EXCEPTION : As a special exception, you may create a larger work
- that contains this FAUST architecture section and distribute
- that work under terms of your choice, so long as this FAUST
- architecture section is not modified.
-
-
- ************************************************************************
- ************************************************************************/
-
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <vector>
-#include <iostream>
-#include <libgen.h>
-
-#include <AudioToolbox/AudioConverter.h>
-#include <CoreAudio/CoreAudio.h>
-#include <AudioUnit/AudioUnit.h>
-#include <CoreServices/CoreServices.h>
-
-#include "audio.h"
-#include "dsp.h"
-
-using namespace std;
-
-/******************************************************************************
-*******************************************************************************
-
- COREAUDIO INTERFACE
-
-*******************************************************************************
-*******************************************************************************/
-
-//----------------------------------------------------------------------------
-// number of physical input and output channels of the CA device
-//----------------------------------------------------------------------------
-
-int gDevNumInChans;
-int gDevNumOutChans;
-
-//----------------------------------------------------------------------------
-// tables of noninterleaved input and output channels for FAUST
-//----------------------------------------------------------------------------
-
-float* gInChannel[256];
-float* gOutChannel[256];
-
-#define OPEN_ERR -1
-#define NO_ERR 0
-
-#define WAIT_COUNTER 60
-
-typedef UInt8 CAAudioHardwareDeviceSectionID;
-#define kAudioDeviceSectionInput ((CAAudioHardwareDeviceSectionID)0x01)
-#define kAudioDeviceSectionOutput ((CAAudioHardwareDeviceSectionID)0x00)
-#define kAudioDeviceSectionGlobal ((CAAudioHardwareDeviceSectionID)0x00)
-#define kAudioDeviceSectionWildcard ((CAAudioHardwareDeviceSectionID)0xFF)
-
-dsp * gDsp;
-
-class TCoreAudioRenderer
-{
- private:
- AudioBufferList* fInputData;
- AudioDeviceID fDeviceID;
- AudioUnit fAUHAL;
- AudioObjectID fPluginID; // Used for aggregate device
- bool fState;
-
- OSStatus GetDefaultDevice(int inChan, int outChan, int samplerate, AudioDeviceID* id);
-
- OSStatus CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, int samplerate, AudioDeviceID* outAggregateDevice);
- OSStatus CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, int samplerate, AudioDeviceID* outAggregateDevice);
- OSStatus DestroyAggregateDevice();
-
- OSStatus GetDeviceNameFromID(AudioDeviceID id, char* name);
-
- int SetupSampleRateAux(AudioDeviceID inDevice, int samplerate);
-
- static OSStatus Render(void *inRefCon,
- AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp,
- UInt32 inBusNumber,
- UInt32 inNumberFrames,
- AudioBufferList *ioData);
-
-
- static OSStatus SRNotificationCallback(AudioDeviceID inDevice,
- UInt32 inChannel,
- Boolean isInput,
- AudioDevicePropertyID inPropertyID,
- void* inClientData);
-
- public:
-
- TCoreAudioRenderer()
- :fInputData(0),fDeviceID(0),fAUHAL(0),fPluginID(0),fState(false)
- {}
- virtual ~TCoreAudioRenderer()
- {}
-
- long OpenDefault(long inChan, long outChan, long bufferSize, long sampleRate);
- long Close();
-
- long Start();
- long Stop();
-
-};
-
-typedef TCoreAudioRenderer * TCoreAudioRendererPtr;
-
-static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
-{
- cout << "- - - - - - - - - - - - - - - - - - - -" << endl;
- cout << " Sample Rate: " << inDesc->mSampleRate << endl;
- cout << " Format ID:%.*s\n" << sizeof(inDesc->mFormatID) << (char*)&inDesc->mFormatID << endl;
- cout << " Format Flags " << inDesc->mFormatFlags << endl;
- cout << " Bytes per Packet: " << inDesc->mBytesPerPacket << endl;
- cout << " Frames per Packet: " << inDesc->mFramesPerPacket << endl;
- cout << " Bytes per Frame: " << inDesc->mBytesPerFrame << endl;
- cout << " Channels per Frame: "<< inDesc->mChannelsPerFrame << endl;
- cout << " Bits per Channel: " << inDesc->mBitsPerChannel << endl;
- cout << "- - - - - - - - - - - - - - - - - - - -" << endl;
-}
-
-static void printError(OSStatus err)
-{
- switch (err) {
- case kAudioHardwareNoError:
- printf("error code : kAudioHardwareNoError\n");
- break;
- case kAudioConverterErr_FormatNotSupported:
- printf("error code : kAudioConverterErr_FormatNotSupported\n");
- break;
- case kAudioConverterErr_OperationNotSupported:
- printf("error code : kAudioConverterErr_OperationNotSupported\n");
- break;
- case kAudioConverterErr_PropertyNotSupported:
- printf("error code : kAudioConverterErr_PropertyNotSupported\n");
- break;
- case kAudioConverterErr_InvalidInputSize:
- printf("error code : kAudioConverterErr_InvalidInputSize\n");
- break;
- case kAudioConverterErr_InvalidOutputSize:
- printf("error code : kAudioConverterErr_InvalidOutputSize\n");
- break;
- case kAudioConverterErr_UnspecifiedError:
- printf("error code : kAudioConverterErr_UnspecifiedError\n");
- break;
- case kAudioConverterErr_BadPropertySizeError:
- printf("error code : kAudioConverterErr_BadPropertySizeError\n");
- break;
- case kAudioConverterErr_RequiresPacketDescriptionsError:
- printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
- break;
- case kAudioConverterErr_InputSampleRateOutOfRange:
- printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
- break;
- case kAudioConverterErr_OutputSampleRateOutOfRange:
- printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
- break;
- case kAudioHardwareNotRunningError:
- printf("error code : kAudioHardwareNotRunningError\n");
- break;
- case kAudioHardwareUnknownPropertyError:
- printf("error code : kAudioHardwareUnknownPropertyError\n");
- break;
- case kAudioHardwareIllegalOperationError:
- printf("error code : kAudioHardwareIllegalOperationError\n");
- break;
- case kAudioHardwareBadDeviceError:
- printf("error code : kAudioHardwareBadDeviceError\n");
- break;
- case kAudioHardwareBadStreamError:
- printf("error code : kAudioHardwareBadStreamError\n");
- break;
- case kAudioDeviceUnsupportedFormatError:
- printf("error code : kAudioDeviceUnsupportedFormatError\n");
- break;
- case kAudioDevicePermissionsError:
- printf("error code : kAudioDevicePermissionsError\n");
- break;
- default:
- printf("error code : unknown\n");
- break;
- }
-}
-
-OSStatus TCoreAudioRenderer::Render(void *inRefCon,
- AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp,
- UInt32,
- UInt32 inNumberFrames,
- AudioBufferList *ioData)
-{
- TCoreAudioRendererPtr renderer = (TCoreAudioRendererPtr)inRefCon;
- AudioUnitRender(renderer->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, renderer->fInputData);
- for (int i = 0; i < gDevNumInChans; i++) {
- gInChannel[i] = (float*)renderer->fInputData->mBuffers[i].mData;
- }
- for (int i = 0; i < gDevNumOutChans; i++) {
- gOutChannel[i] = (float*)ioData->mBuffers[i].mData;
- }
- gDsp->compute((int)inNumberFrames, gInChannel, gOutChannel);
- return 0;
-}
-
-static CFStringRef GetDeviceName(AudioDeviceID id)
-{
- UInt32 size = sizeof(CFStringRef);
- CFStringRef UIname;
- OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
- return (err == noErr) ? UIname : NULL;
-}
-
-OSStatus TCoreAudioRenderer::GetDeviceNameFromID(AudioDeviceID id, char* name)
-{
- UInt32 size = 256;
- return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
-}
-
-OSStatus TCoreAudioRenderer::GetDefaultDevice(int inChan, int outChan, int samplerate, AudioDeviceID* id)
-{
- UInt32 theSize = sizeof(UInt32);
- AudioDeviceID inDefault;
- AudioDeviceID outDefault;
- OSStatus res;
-
- if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
- &theSize, &inDefault)) != noErr)
- return res;
-
- if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
- &theSize, &outDefault)) != noErr)
- return res;
-
- // Duplex mode
- if (inChan > 0 && outChan > 0) {
- // Get the device only if default input and output are the same
- if (inDefault == outDefault) {
- *id = inDefault;
- return noErr;
- } else {
- printf("GetDefaultDevice : input = %ld and output = %ld are not the same, create aggregate device...\n", inDefault, outDefault);
- if (CreateAggregateDevice(inDefault, outDefault, samplerate, id) != noErr)
- return kAudioHardwareBadDeviceError;
- }
- } else if (inChan > 0) {
- *id = inDefault;
- return noErr;
- } else if (outChan > 0) {
- *id = outDefault;
- return noErr;
- } else {
- return kAudioHardwareBadDeviceError;
- }
-
- return noErr;
-}
-
-OSStatus TCoreAudioRenderer::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, int samplerate, AudioDeviceID* outAggregateDevice)
-{
- OSStatus err = noErr;
- AudioObjectID sub_device[32];
- UInt32 outSize = sizeof(sub_device);
-
- err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
- vector<AudioDeviceID> captureDeviceIDArray;
-
- if (err != noErr) {
- printf("Input device does not have subdevices\n");
- captureDeviceIDArray.push_back(captureDeviceID);
- } else {
- int num_devices = outSize / sizeof(AudioObjectID);
- printf("Input device has %d subdevices\n", num_devices);
- for (int i = 0; i < num_devices; i++) {
- captureDeviceIDArray.push_back(sub_device[i]);
- }
- }
-
- err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
- vector<AudioDeviceID> playbackDeviceIDArray;
-
- if (err != noErr) {
- printf("Output device does not have subdevices\n");
- playbackDeviceIDArray.push_back(playbackDeviceID);
- } else {
- int num_devices = outSize / sizeof(AudioObjectID);
- printf("Output device has %d subdevices\n", num_devices);
- for (int i = 0; i < num_devices; i++) {
- playbackDeviceIDArray.push_back(sub_device[i]);
- }
- }
-
- return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice);
-}
-
-
-OSStatus TCoreAudioRenderer::SRNotificationCallback(AudioDeviceID inDevice,
- UInt32 /*inChannel*/,
- Boolean /*isInput*/,
- AudioDevicePropertyID inPropertyID,
- void* inClientData)
-{
- TCoreAudioRenderer* driver = (TCoreAudioRenderer*)inClientData;
-
- switch (inPropertyID) {
-
- case kAudioDevicePropertyNominalSampleRate: {
- printf("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate\n");
- driver->fState = true;
- // Check new sample rate
- Float64 sampleRate;
- UInt32 outSize = sizeof(Float64);
- OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
- if (err != noErr) {
- printf("Cannot get current sample rate\n");
- printError(err);
- } else {
- printf("SRNotificationCallback : checked sample rate = %f\n", sampleRate);
- }
- break;
- }
- }
-
- return noErr;
-}
-
-int TCoreAudioRenderer::SetupSampleRateAux(AudioDeviceID inDevice, int samplerate)
-{
- OSStatus err = noErr;
- UInt32 outSize;
- Float64 sampleRate;
-
- // Get sample rate
- outSize = sizeof(Float64);
- err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
- if (err != noErr) {
- printf("Cannot get current sample rate\n");
- printError(err);
- return -1;
- } else {
- printf("Current sample rate = %f\n", sampleRate);
- }
-
- // If needed, set new sample rate
- if (samplerate != (int)sampleRate) {
- sampleRate = (Float64)samplerate;
-
- // To get SR change notification
- err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
- if (err != noErr) {
- printf("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate\n");
- printError(err);
- return -1;
- }
- err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
- if (err != noErr) {
- printf("Cannot set sample rate = %d\n", samplerate);
- printError(err);
- return -1;
- }
-
- // Waiting for SR change notification
- int count = 0;
- while (!fState && count++ < WAIT_COUNTER) {
- usleep(100000);
- printf("Wait count = %d\n", count);
- }
-
- // Check new sample rate
- outSize = sizeof(Float64);
- err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
- if (err != noErr) {
- printf("Cannot get current sample rate\n");
- printError(err);
- } else {
- printf("Checked sample rate = %f\n", sampleRate);
- }
-
- // Remove SR change notification
- AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
- }
-
- return 0;
-}
-
-OSStatus TCoreAudioRenderer::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, int samplerate, AudioDeviceID* outAggregateDevice)
-{
- OSStatus osErr = noErr;
- UInt32 outSize;
- Boolean outWritable;
-
- bool fClockDriftCompensate = true;
-
- // Prepare sub-devices for clock drift compensation
- // Workaround for bug in the HAL : until 10.6.2
- AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- UInt32 theQualifierDataSize = sizeof(AudioObjectID);
- AudioClassID inClass = kAudioSubDeviceClassID;
- void* theQualifierData = &inClass;
- UInt32 subDevicesNum = 0;
-
- //---------------------------------------------------------------------------
- // Setup SR of both devices otherwise creating AD may fail...
- //---------------------------------------------------------------------------
- UInt32 keptclockdomain = 0;
- UInt32 clockdomain = 0;
- outSize = sizeof(UInt32);
- bool need_clock_drift_compensation = false;
-
- for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
- if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : cannot set SR of input device\n");
- } else {
- // Check clock domain
- osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
- if (osErr != 0) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : kAudioDevicePropertyClockDomain error\n");
- printError(osErr);
- } else {
- keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
- printf("TCoreAudioRenderer::CreateAggregateDevice : input clockdomain = %d\n", clockdomain);
- if (clockdomain != 0 && clockdomain != keptclockdomain) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...\n");
- need_clock_drift_compensation = true;
- }
- }
- }
- }
-
- for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
- if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : cannot set SR of output device\n");
- } else {
- // Check clock domain
- osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
- if (osErr != 0) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : kAudioDevicePropertyClockDomain error\n");
- printError(osErr);
- } else {
- keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
- printf("TCoreAudioRenderer::CreateAggregateDevice : output clockdomain = %d", clockdomain);
- if (clockdomain != 0 && clockdomain != keptclockdomain) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...\n");
- need_clock_drift_compensation = true;
- }
- }
- }
- }
-
- // If no valid clock domain was found, then assume we have to compensate...
- if (keptclockdomain == 0) {
- need_clock_drift_compensation = true;
- }
-
- //---------------------------------------------------------------------------
- // Start to create a new aggregate by getting the base audio hardware plugin
- //---------------------------------------------------------------------------
-
- char device_name[256];
- for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
- GetDeviceNameFromID(captureDeviceID[i], device_name);
- printf("Separated input = '%s' \n", device_name);
- }
-
- for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
- GetDeviceNameFromID(playbackDeviceID[i], device_name);
- printf("Separated output = '%s' \n", device_name);
- }
-
- osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error\n");
- printError(osErr);
- return osErr;
- }
-
- AudioValueTranslation pluginAVT;
-
- CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
-
- pluginAVT.mInputData = &inBundleRef;
- pluginAVT.mInputDataSize = sizeof(inBundleRef);
- pluginAVT.mOutputData = &fPluginID;
- pluginAVT.mOutputDataSize = sizeof(fPluginID);
-
- osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error\n");
- printError(osErr);
- return osErr;
- }
-
- //-------------------------------------------------
- // Create a CFDictionary for our aggregate device
- //-------------------------------------------------
-
- CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-
- CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
- CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
-
- // add the name of the device to the dictionary
- CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
-
- // add our choice of UID for the aggregate device to the dictionary
- CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
-
- // add a "private aggregate key" to the dictionary
- int value = 1;
- CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
-
- SInt32 system;
- Gestalt(gestaltSystemVersion, &system);
-
- printf("TCoreAudioRenderer::CreateAggregateDevice : system version = %x limit = %x\n", system, 0x00001054);
-
- // Starting with 10.5.4 systems, the AD can be internal... (better)
- if (system < 0x00001054) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : public aggregate device....\n");
- } else {
- printf("TCoreAudioRenderer::CreateAggregateDevice : private aggregate device....\n");
- CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
- }
-
- // Prepare sub-devices for clock drift compensation
- CFMutableArrayRef subDevicesArrayClock = NULL;
-
- /*
- if (fClockDriftCompensate) {
- if (need_clock_drift_compensation) {
- jack_info("Clock drift compensation activated...");
- subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
- for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
- CFStringRef UID = GetDeviceName(captureDeviceID[i]);
- if (UID) {
- CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
- CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
- //CFRelease(UID);
- CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
- }
- }
-
- for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
- CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
- if (UID) {
- CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
- CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
- //CFRelease(UID);
- CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
- }
- }
-
- // add sub-device clock array for the aggregate device to the dictionary
- CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
- } else {
- jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
- }
- }
- */
-
- //-------------------------------------------------
- // Create a CFMutableArray for our sub-device list
- //-------------------------------------------------
-
- // we need to append the UID for each device to a CFMutableArray, so create one here
- CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
- vector<CFStringRef> captureDeviceUID;
- for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
- CFStringRef ref = GetDeviceName(captureDeviceID[i]);
- if (ref == NULL)
- return -1;
- captureDeviceUID.push_back(ref);
- // input sub-devices in this example, so append the sub-device's UID to the CFArray
- CFArrayAppendValue(subDevicesArray, ref);
- }
-
- vector<CFStringRef> playbackDeviceUID;
- for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
- CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
- if (ref == NULL)
- return -1;
- playbackDeviceUID.push_back(ref);
- // output sub-devices in this example, so append the sub-device's UID to the CFArray
- CFArrayAppendValue(subDevicesArray, ref);
- }
-
- //-----------------------------------------------------------------------
- // Feed the dictionary to the plugin, to create a blank aggregate device
- //-----------------------------------------------------------------------
-
- AudioObjectPropertyAddress pluginAOPA;
- pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
- pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
- pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
- UInt32 outDataSize;
-
- osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : AudioObjectGetPropertyDataSize error\n");
- printError(osErr);
- goto error;
- }
-
- osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : AudioObjectGetPropertyData error\n");
- printError(osErr);
- goto error;
- }
-
- // pause for a bit to make sure that everything completed correctly
- // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
-
- //-------------------------
- // Set the sub-device list
- //-------------------------
-
- pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
- pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
- pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
- outDataSize = sizeof(CFMutableArrayRef);
- osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error\n");
- printError(osErr);
- goto error;
- }
-
- // pause again to give the changes time to take effect
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
-
- //-----------------------
- // Set the master device
- //-----------------------
-
- // set the master device manually (this is the device which will act as the master clock for the aggregate device)
- // pass in the UID of the device you want to use
- pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
- pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
- pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
- outDataSize = sizeof(CFStringRef);
- osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]); // First apture is master...
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice : AudioObjectSetPropertyData for master device error\n");
- printError(osErr);
- goto error;
- }
-
- // pause again to give the changes time to take effect
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
-
- // Prepare sub-devices for clock drift compensation
- // Workaround for bug in the HAL : until 10.6.2
-
- if (fClockDriftCompensate) {
- if (need_clock_drift_compensation) {
- printf("Clock drift compensation activated...\n");
-
- // Get the property data size
- osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error\n");
- printError(osErr);
- }
-
- // Calculate the number of object IDs
- subDevicesNum = outSize / sizeof(AudioObjectID);
- printf("TCoreAudioRenderer::CreateAggregateDevice clock drift compensation, number of sub-devices = %d\n", subDevicesNum);
- AudioObjectID subDevices[subDevicesNum];
- outSize = sizeof(subDevices);
-
- osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error\n");
- printError(osErr);
- }
-
- // Set kAudioSubDevicePropertyDriftCompensation property...
- for (UInt32 index = 0; index < subDevicesNum; ++index) {
- UInt32 theDriftCompensationValue = 1;
- osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error\n");
- printError(osErr);
- }
- }
- } else {
- printf("Clock drift compensation was asked but is not needed (devices use the same clock domain)\n");
- }
- }
-
- // pause again to give the changes time to take effect
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
-
- //----------
- // Clean up
- //----------
-
- // release the private AD key
- CFRelease(AggregateDeviceNumberRef);
-
- // release the CF objects we have created - we don't need them any more
- CFRelease(aggDeviceDict);
- CFRelease(subDevicesArray);
-
- if (subDevicesArrayClock)
- CFRelease(subDevicesArrayClock);
-
- // release the device UID
- for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
- CFRelease(captureDeviceUID[i]);
- }
-
- for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
- CFRelease(playbackDeviceUID[i]);
- }
-
- printf("New aggregate device %d\n", *outAggregateDevice);
- return noErr;
-
-error:
- DestroyAggregateDevice();
- return -1;
-}
-
-OSStatus TCoreAudioRenderer::DestroyAggregateDevice()
-{
- OSStatus osErr = noErr;
- AudioObjectPropertyAddress pluginAOPA;
- pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
- pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
- pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
- UInt32 outDataSize;
-
- if (fPluginID > 0) {
-
- osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error\n");
- printError(osErr);
- return osErr;
- }
-
- osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::DestroyAggregateDevice : AudioObjectGetPropertyData error\n");
- printError(osErr);
- return osErr;
- }
-
- }
-
- return noErr;
-}
-
-
-long TCoreAudioRenderer::OpenDefault(long inChan, long outChan, long bufferSize, long samplerate)
-{
- OSStatus err = noErr;
- ComponentResult err1;
- UInt32 outSize;
- UInt32 enableIO;
- Boolean isWritable;
- AudioStreamBasicDescription srcFormat, dstFormat, sampleRate;
- long in_nChannels, out_nChannels;
-
- printf("OpenDefault inChan = %ld outChan = %ld bufferSize = %ld samplerate = %ld\n", inChan, outChan, bufferSize, samplerate);
-
- SInt32 major;
- SInt32 minor;
- Gestalt(gestaltSystemVersionMajor, &major);
- Gestalt(gestaltSystemVersionMinor, &minor);
-
- // Starting with 10.6 systems, the HAL notification thread is created internally
- if (major == 10 && minor >= 6) {
- CFRunLoopRef theRunLoop = NULL;
- AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
- if (osErr != noErr) {
- printf("TCoreAudioRenderer::Open kAudioHardwarePropertyRunLoop error\n");
- printError(osErr);
- }
- }
-
- if (GetDefaultDevice(inChan, outChan, samplerate,&fDeviceID) != noErr) {
- printf("Cannot open default device\n");
- return OPEN_ERR;
- }
-
- // Setting buffer size
- outSize = sizeof(UInt32);
- err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &bufferSize);
- if (err != noErr) {
- printf("Cannot set buffer size %ld\n", bufferSize);
- printError(err);
- return OPEN_ERR;
- }
-
- // Setting sample rate
- outSize = sizeof(AudioStreamBasicDescription);
- err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &outSize, &sampleRate);
- if (err != noErr) {
- printf("Cannot get current sample rate\n");
- printError(err);
- return OPEN_ERR;
- }
-
- if (samplerate != long(sampleRate.mSampleRate)) {
- sampleRate.mSampleRate = (Float64)(samplerate);
- err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyStreamFormat, outSize, &sampleRate);
- if (err != noErr) {
- printf("Cannot set sample rate = %ld\n", samplerate);
- printError(err);
- return OPEN_ERR;
- }
- }
-
- // AUHAL
- ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
- Component HALOutput = FindNextComponent(NULL, &cd);
-
- err1 = OpenAComponent(HALOutput, &fAUHAL);
- if (err1 != noErr) {
- printf("Error calling OpenAComponent\n");
- printError(err1);
- goto error;
- }
-
- err1 = AudioUnitInitialize(fAUHAL);
- if (err1 != noErr) {
- printf("Cannot initialize AUHAL unit\n");
- printError(err1);
- goto error;
- }
-
- enableIO = 1;
- err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
- printError(err1);
- goto error;
- }
-
- enableIO = 1;
- err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
- printError(err1);
- goto error;
- }
-
- err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice\n");
- printError(err1);
- goto error;
- }
-
- err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&bufferSize, sizeof(UInt32));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
- printError(err1);
- goto error;
- }
-
- err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&bufferSize, sizeof(UInt32));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
- printError(err1);
- goto error;
- }
-
- err1 = AudioUnitGetPropertyInfo(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Input, 1, &outSize, &isWritable);
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap-INFO 1\n");
- printError(err1);
- }
-
- in_nChannels = (err1 == noErr) ? outSize / sizeof(SInt32) : 0;
- printf("in_nChannels = %ld\n", in_nChannels);
-
- err1 = AudioUnitGetPropertyInfo(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, &outSize, &isWritable);
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap-INFO 0\n");
- printError(err1);
- }
-
- out_nChannels = (err1 == noErr) ? outSize / sizeof(SInt32) : 0;
- printf("out_nChannels = %ld\n", out_nChannels);
-
- /*
- Just ignore this case : seems to work without any further change...
-
- if (outChan > out_nChannels) {
- printf("This device hasn't required output channels\n");
- goto error;
- }
- if (inChan > in_nChannels) {
- printf("This device hasn't required input channels\n");
- goto error;
- }
- */
-
- if (outChan < out_nChannels) {
- SInt32 chanArr[out_nChannels];
- for (int i = 0; i < out_nChannels; i++) {
- chanArr[i] = -1;
- }
- for (int i = 0; i < outChan; i++) {
- chanArr[i] = i;
- }
- err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0\n");
- printError(err1);
- }
- }
-
- if (inChan < in_nChannels) {
- SInt32 chanArr[in_nChannels];
- for (int i = 0; i < in_nChannels; i++) {
- chanArr[i] = -1;
- }
- for (int i = 0; i < inChan; i++) {
- chanArr[i] = i;
- }
- AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1\n");
- printError(err1);
- }
- }
-
- if (inChan > 0) {
- outSize = sizeof(AudioStreamBasicDescription);
- err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize);
- if (err1 != noErr) {
- printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
- printError(err1);
- }
- PrintStreamDesc(&srcFormat);
-
- srcFormat.mSampleRate = samplerate;
- srcFormat.mFormatID = kAudioFormatLinearPCM;
- srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
- srcFormat.mBytesPerPacket = sizeof(float);
- srcFormat.mFramesPerPacket = 1;
- srcFormat.mBytesPerFrame = sizeof(float);
- srcFormat.mChannelsPerFrame = inChan;
- srcFormat.mBitsPerChannel = 32;
-
- PrintStreamDesc(&srcFormat);
-
- err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
- printError(err1);
- }
- }
-
- if (outChan > 0) {
- outSize = sizeof(AudioStreamBasicDescription);
- err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize);
- if (err1 != noErr) {
- printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
- printError(err1);
- }
- PrintStreamDesc(&dstFormat);
-
- dstFormat.mSampleRate = samplerate;
- dstFormat.mFormatID = kAudioFormatLinearPCM;
- dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
- dstFormat.mBytesPerPacket = sizeof(float);
- dstFormat.mFramesPerPacket = 1;
- dstFormat.mBytesPerFrame = sizeof(float);
- dstFormat.mChannelsPerFrame = outChan;
- dstFormat.mBitsPerChannel = 32;
-
- PrintStreamDesc(&dstFormat);
-
- err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
- printError(err1);
- }
- }
-
- if (inChan > 0 && outChan == 0) {
- AURenderCallbackStruct output;
- output.inputProc = Render;
- output.inputProcRefCon = this;
- err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
- printError(err1);
- goto error;
- }
- } else {
- AURenderCallbackStruct output;
- output.inputProc = Render;
- output.inputProcRefCon = this;
- err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
- if (err1 != noErr) {
- printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
- printError(err1);
- goto error;
- }
- }
-
- fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inChan * sizeof(AudioBuffer));
- if (fInputData == 0) {
- printf("Cannot allocate memory for input buffers\n");
- goto error;
- }
- fInputData->mNumberBuffers = inChan;
-
- // Prepare buffers
- for (int i = 0; i < inChan; i++) {
- fInputData->mBuffers[i].mNumberChannels = 1;
- fInputData->mBuffers[i].mData = malloc(bufferSize * sizeof(float));
- fInputData->mBuffers[i].mDataByteSize = bufferSize * sizeof(float);
- }
-
- return NO_ERR;
-
-error:
- AudioUnitUninitialize(fAUHAL);
- CloseComponent(fAUHAL);
- return OPEN_ERR;
-}
-
-long TCoreAudioRenderer::Close()
-{
- for (int i = 0; i < gDevNumInChans; i++) {
- free(fInputData->mBuffers[i].mData);
- }
- free(fInputData);
- AudioUnitUninitialize(fAUHAL);
- CloseComponent(fAUHAL);
- DestroyAggregateDevice();
- return NO_ERR;
-}
-
-long TCoreAudioRenderer::Start()
-{
- OSStatus err = AudioOutputUnitStart(fAUHAL);
-
- if (err != noErr) {
- printf("Error while opening device : device open error \n");
- return OPEN_ERR;
- } else {
- return NO_ERR;
- }
-}
-
-long TCoreAudioRenderer::Stop()
-{
- OSStatus err = AudioOutputUnitStop(fAUHAL);
-
- if (err != noErr) {
- printf("Error while closing device : device close error \n");
- return OPEN_ERR;
- } else {
- return NO_ERR;
- }
-}
-
-
-
-/******************************************************************************
-*******************************************************************************
-
- CORE AUDIO INTERFACE
-
-*******************************************************************************
-*******************************************************************************/
-class coreaudio : public audio {
-
- TCoreAudioRenderer audio_device;
- long fSampleRate, fFramesPerBuf;
-
- public:
- coreaudio(long srate, long fpb) : fSampleRate(srate), fFramesPerBuf(fpb) {}
- virtual ~coreaudio() {}
-
- virtual bool init(const char* /*name*/, dsp* DSP) {
- gDsp = DSP;
- DSP->init (fSampleRate);
- gDevNumInChans = DSP->getNumInputs();
- gDevNumOutChans = DSP->getNumOutputs();
- if (audio_device.OpenDefault(gDevNumInChans, gDevNumOutChans, fFramesPerBuf, fSampleRate) < 0) {
- printf("Cannot open CoreAudio device\n");
- return false;
- }
- return true;
- }
-
- virtual bool start() {
- if (audio_device.Start() < 0) {
- printf("Cannot start CoreAudio device\n");
- return false;
- }
- return true;
- }
-
- virtual void stop() {
- audio_device.Stop();
- audio_device.Close();
- }
-
-};
-
-#endif
-
-/********************END ARCHITECTURE SECTION (part 2/2)****************/
-
-