// ---------------------------------------------------------------------------- void AudioCoreDriver::deinitialize() // ---------------------------------------------------------------------------- { if (!mIsInitialized) return; stopPlayback(); AudioDeviceDestroyIOProcID(mDeviceID, mEmulationPlaybackProcID); AudioDeviceDestroyIOProcID(mDeviceID, mPreRenderedBufferPlaybackProcID); #if USE_NEW_API OSStatus err; AudioObjectPropertyAddress prop5 = { kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster }; err = AudioObjectRemovePropertyListener(mDeviceID, &prop5, streamFormatChanged, (void*)this); if (err != kAudioHardwareNoError) printf("AudioObjectRemovePropertyListener(streamFormatChanged) failed\n"); AudioObjectPropertyAddress prop6 = { kAudioDeviceProcessorOverload, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster }; err = AudioObjectRemovePropertyListener(mDeviceID, &prop6, overloadDetected, (void*)this); if (err != kAudioHardwareNoError) printf("AudioObjectRemovePropertyListener(overloadDetected) failed\n"); AudioObjectPropertyAddress prop7 = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster }; err = AudioObjectRemovePropertyListener(mDeviceID, &prop7, deviceChanged, (void*)this); if (err != kAudioHardwareNoError) printf("AudioObjectRemovePropertyListener(deviceChanged) failed\n"); #else AudioDeviceRemovePropertyListener(mDeviceID, 0, false, kAudioDevicePropertyStreamFormat, streamFormatChanged); AudioDeviceRemovePropertyListener(mDeviceID, 0, false, kAudioDeviceProcessorOverload, overloadDetected); AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDefaultOutputDevice, deviceChanged); #endif delete[] mSampleBuffer1; mSampleBuffer1 = NULL; delete[] mSampleBuffer2; mSampleBuffer2 = NULL; mSampleBuffer = NULL; mRetSampleBuffer = NULL; delete[] mSpectrumBuffer; mSpectrumBuffer = NULL; mIsInitialized = false; }
/** free all memory allocated by a driver instance */ static void coreaudio_driver_delete(coreaudio_driver_t * driver) { AudioDeviceRemovePropertyListener(driver->device_id, 0, true, kAudioDeviceProcessorOverload, notification); free(driver->input_list); AudioUnitUninitialize(driver->au_hal); CloseComponent(driver->au_hal); free(driver); }
void CoreAudioDevice::RemovePropertyListener(UInt32 inChannel, CoreAudioDeviceSection inSection, AudioHardwarePropertyID inPropertyID, AudioDevicePropertyListenerProc inListenerProc) { if (AudioDeviceRemovePropertyListener(deviceID, inChannel, inSection, inPropertyID, inListenerProc) !=0) { //fprintf(stderr,"Error while Removing device notifications listener. Exiting."); //exit(0); } }
static int ca_free (void) { if (device_id) { AudioDeviceStop(device_id, ca_buffer_callback); AudioDeviceRemovePropertyListener(device_id, 0, 0, kAudioDevicePropertyStreamFormat, ca_fmtchanged); AudioDeviceRemoveIOProc(device_id, ca_buffer_callback); } return 0; }
void CCoreAudioSoundManager::Stop() { if (!m_OutputUnit.IsRunning()) return; m_OutputUnit.Stop(); AudioDeviceRemovePropertyListener(m_OutputDevice.GetId(), 0, false, kAudioDevicePropertyHogMode, PropertyChangeCallback); // No longer need to know if the device is hogged // TODO: Clean up leftover event(s) CLog::Log(LOGDEBUG, "CCoreAudioSoundManager::Stop: SoundManager has been stopped."); }
/** create a new driver instance */ static jack_driver_t *coreaudio_driver_new(char* name, jack_client_t* client, jack_nframes_t nframes, jack_nframes_t samplerate, int capturing, int playing, int inchannels, int outchannels, char* capture_driver_uid, char* playback_driver_uid, jack_nframes_t capture_latency, jack_nframes_t playback_latency) { coreaudio_driver_t *driver; OSStatus err = noErr; ComponentResult err1; UInt32 outSize; UInt32 enableIO; AudioStreamBasicDescription srcFormat, dstFormat; Float64 sampleRate; int in_nChannels = 0; int out_nChannels = 0; int i; driver = (coreaudio_driver_t *) calloc(1, sizeof(coreaudio_driver_t)); jack_driver_init((jack_driver_t *) driver); if (!jack_power_of_two(nframes)) { jack_error("CA: -p must be a power of two."); goto error; } driver->state = 0; driver->frames_per_cycle = nframes; driver->frame_rate = samplerate; driver->capturing = capturing; driver->playing = playing; driver->xrun_detected = 0; driver->null_cycle = 0; driver->attach = (JackDriverAttachFunction) coreaudio_driver_attach; driver->detach = (JackDriverDetachFunction) coreaudio_driver_detach; driver->read = (JackDriverReadFunction) coreaudio_driver_read; driver->write = (JackDriverReadFunction) coreaudio_driver_write; driver->null_cycle = (JackDriverNullCycleFunction) coreaudio_driver_null_cycle; driver->bufsize = (JackDriverBufSizeFunction) coreaudio_driver_bufsize; driver->start = (JackDriverStartFunction) coreaudio_driver_audio_start; driver->stop = (JackDriverStopFunction) coreaudio_driver_audio_stop; driver->capture_frame_latency = capture_latency; driver->playback_frame_latency = playback_latency; // Duplex if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { JCALog("Open duplex \n"); if (get_device_id_from_uid(playback_driver_uid, &driver->device_id) != noErr) { if (get_default_device(&driver->device_id) != noErr) { jack_error("Cannot open default device"); goto error; } } if (get_device_name_from_id(driver->device_id, driver->capture_driver_name) != noErr || get_device_name_from_id(driver->device_id, driver->playback_driver_name) != noErr) { jack_error("Cannot get device name from device ID"); goto error; } // Capture only } else if (strcmp(capture_driver_uid, "") != 0) { JCALog("Open capture only \n"); if (get_device_id_from_uid(capture_driver_uid, &driver->device_id) != noErr) { if (get_default_input_device(&driver->device_id) != noErr) { jack_error("Cannot open default device"); goto error; } } if (get_device_name_from_id(driver->device_id, driver->capture_driver_name) != noErr) { jack_error("Cannot get device name from device ID"); goto error; } // Playback only } else if (playback_driver_uid != NULL) { JCALog("Open playback only \n"); if (get_device_id_from_uid(playback_driver_uid, &driver->device_id) != noErr) { if (get_default_output_device(&driver->device_id) != noErr) { jack_error("Cannot open default device"); goto error; } } if (get_device_name_from_id(driver->device_id, driver->playback_driver_name) != noErr) { jack_error("Cannot get device name from device ID"); goto error; } // Use default driver in duplex mode } else { JCALog("Open default driver \n"); if (get_default_device(&driver->device_id) != noErr) { jack_error("Cannot open default device"); goto error; } if (get_device_name_from_id(driver->device_id, driver->capture_driver_name) != noErr || get_device_name_from_id(driver->device_id, driver->playback_driver_name) != noErr) { jack_error("Cannot get device name from device ID"); goto error; } } driver->client = client; driver->period_usecs = (((float) driver->frames_per_cycle) / driver->frame_rate) * 1000000.0f; if (capturing) { err = get_total_channels(driver->device_id, &in_nChannels, true); if (err != noErr) { jack_error("Cannot get input channel number"); printError(err); goto error; } } if (playing) { err = get_total_channels(driver->device_id, &out_nChannels, false); if (err != noErr) { jack_error("Cannot get output channel number"); printError(err); goto error; } } if (inchannels > in_nChannels) { jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels); goto error; } if (outchannels > out_nChannels) { jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels); goto error; } if (inchannels == 0) { JCALog("Setup max in channels = %ld\n", in_nChannels); inchannels = in_nChannels; } if (outchannels == 0) { JCALog("Setup max out channels = %ld\n", out_nChannels); outchannels = out_nChannels; } // Setting buffer size outSize = sizeof(UInt32); err = AudioDeviceSetProperty(driver->device_id, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &nframes); if (err != noErr) { jack_error("Cannot set buffer size %ld", nframes); printError(err); goto error; } // Set sample rate outSize = sizeof(Float64); err = AudioDeviceGetProperty(driver->device_id, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); if (err != noErr) { jack_error("Cannot get current sample rate"); printError(err); goto error; } if (samplerate != (jack_nframes_t)sampleRate) { sampleRate = (Float64)samplerate; // To get SR change notification err = AudioDeviceAddPropertyListener(driver->device_id, 0, true, kAudioDevicePropertyNominalSampleRate, sr_notification, driver); if (err != noErr) { jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate"); printError(err); return -1; } err = AudioDeviceSetProperty(driver->device_id, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate); if (err != noErr) { jack_error("Cannot set sample rate = %ld", samplerate); printError(err); return -1; } // Waiting for SR change notification int count = 0; while (!driver->state && count++ < 100) { usleep(100000); JCALog("Wait count = %ld\n", count); } // Remove SR change notification AudioDeviceRemovePropertyListener(driver->device_id, 0, true, kAudioDevicePropertyNominalSampleRate, sr_notification); } // AUHAL ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; Component HALOutput = FindNextComponent(NULL, &cd); err1 = OpenAComponent(HALOutput, &driver->au_hal); if (err1 != noErr) { jack_error("Error calling OpenAComponent"); printError(err1); goto error; } err1 = AudioUnitInitialize(driver->au_hal); if (err1 != noErr) { jack_error("Cannot initialize AUHAL unit"); printError(err1); goto error; } // Start I/O enableIO = 1; if (capturing && inchannels > 0) { JCALog("Setup AUHAL input\n"); err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); printError(err1); goto error; } } if (playing && outchannels > 0) { JCALog("Setup AUHAL output\n"); err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); printError(err1); goto error; } } // Setup up choosen device, in both input and output cases err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &driver->device_id, sizeof(AudioDeviceID)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice"); printError(err1); goto error; } // Set buffer size if (capturing && inchannels > 0) { err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&nframes, sizeof(UInt32)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); printError(err1); goto error; } } if (playing && outchannels > 0) { err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&nframes, sizeof(UInt32)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); printError(err1); goto error; } } // Setup channel map if (capturing && inchannels > 0 && inchannels < in_nChannels) { SInt32 chanArr[in_nChannels]; for (i = 0; i < in_nChannels; i++) { chanArr[i] = -1; } for (i = 0; i < inchannels; i++) { chanArr[i] = i; } AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1"); printError(err1); } } if (playing && outchannels > 0 && outchannels < out_nChannels) { SInt32 chanArr[out_nChannels]; for (i = 0; i < out_nChannels; i++) { chanArr[i] = -1; } for (i = 0; i < outchannels; i++) { chanArr[i] = i; } err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0"); printError(err1); } } // Setup stream converters srcFormat.mSampleRate = samplerate; srcFormat.mFormatID = kAudioFormatLinearPCM; srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; srcFormat.mBytesPerPacket = sizeof(float); srcFormat.mFramesPerPacket = 1; srcFormat.mBytesPerFrame = sizeof(float); srcFormat.mChannelsPerFrame = outchannels; srcFormat.mBitsPerChannel = 32; err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); printError(err1); } dstFormat.mSampleRate = samplerate; dstFormat.mFormatID = kAudioFormatLinearPCM; dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; dstFormat.mBytesPerPacket = sizeof(float); dstFormat.mFramesPerPacket = 1; dstFormat.mBytesPerFrame = sizeof(float); dstFormat.mChannelsPerFrame = inchannels; dstFormat.mBitsPerChannel = 32; err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); printError(err1); } // Setup callbacks if (inchannels > 0 && outchannels == 0) { AURenderCallbackStruct output; output.inputProc = render_input; output.inputProcRefCon = driver; err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1"); printError(err1); goto error; } } else { AURenderCallbackStruct output; output.inputProc = render; output.inputProcRefCon = driver; err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0"); printError(err1); goto error; } } if (capturing && inchannels > 0) { driver->input_list = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer)); if (driver->input_list == 0) goto error; driver->input_list->mNumberBuffers = inchannels; // Prepare buffers for (i = 0; i < driver->capture_nchannels; i++) { driver->input_list->mBuffers[i].mNumberChannels = 1; driver->input_list->mBuffers[i].mDataByteSize = nframes * sizeof(float); } } err = AudioDeviceAddPropertyListener(driver->device_id, 0, true, kAudioDeviceProcessorOverload, notification, driver); if (err != noErr) { jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload"); goto error; } err = AudioDeviceAddPropertyListener(driver->device_id, 0, true, kAudioDevicePropertyNominalSampleRate, notification, driver); if (err != noErr) { jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate"); goto error; } driver->playback_nchannels = outchannels; driver->capture_nchannels = inchannels; return ((jack_driver_t *) driver); error: AudioUnitUninitialize(driver->au_hal); CloseComponent(driver->au_hal); jack_error("Cannot open the coreaudio driver"); free(driver); return NULL; }
/* sets the value of the given property and waits for the change to be acknowledged, and returns the final value, which is not guaranteed by this function to be the same as the desired value. Obviously, this function can only be used for data whose input and output are the same size and format, and their size and format are known in advance.*/ PaError AudioDeviceSetPropertyNowAndWaitForChange( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData, void *outPropertyData ) { OSStatus macErr; int unixErr; MutexAndBool mab; UInt32 outPropertyDataSize = inPropertyDataSize; /* First, see if it already has that value. If so, return. */ macErr = AudioDeviceGetProperty( inDevice, inChannel, isInput, inPropertyID, &outPropertyDataSize, outPropertyData ); if( macErr ) goto failMac2; if( inPropertyDataSize!=outPropertyDataSize ) return paInternalError; if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) ) return paNoError; /* setup and lock mutex */ mab.once = FALSE; unixErr = pthread_mutex_init( &mab.mutex, NULL ); if( unixErr ) goto failUnix2; unixErr = pthread_mutex_lock( &mab.mutex ); if( unixErr ) goto failUnix; /* add property listener */ macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc, &mab ); if( macErr ) goto failMac; /* set property */ macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel, isInput, inPropertyID, inPropertyDataSize, inPropertyData ); if( macErr ) { /* we couldn't set the property, so we'll just unlock the mutex and move on. */ pthread_mutex_unlock( &mab.mutex ); } /* wait for property to change */ unixErr = pthread_mutex_lock( &mab.mutex ); if( unixErr ) goto failUnix; /* now read the property back out */ macErr = AudioDeviceGetProperty( inDevice, inChannel, isInput, inPropertyID, &outPropertyDataSize, outPropertyData ); if( macErr ) goto failMac; /* cleanup */ AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); unixErr = pthread_mutex_unlock( &mab.mutex ); if( unixErr ) goto failUnix2; unixErr = pthread_mutex_destroy( &mab.mutex ); if( unixErr ) goto failUnix2; return paNoError; failUnix: pthread_mutex_destroy( &mab.mutex ); AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); failUnix2: DBUG( ("Error #%d while setting a device property: %s\n", unixErr, strerror( unixErr ) ) ); return paUnanticipatedHostError; failMac: pthread_mutex_destroy( &mab.mutex ); AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); failMac2: return ERR( macErr ); }