diff --git a/ChangeLog b/ChangeLog index 30884412..d7dae1d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,10 @@ Kjetil S.Matheussen Jackdmp changes log --------------------------- +2007-12-05 Stephane Letz + + * Correct sample_rate management in JackCoreAudioDriver::Open. Better handling in sample_rate change listener. + 2007-12-04 Stephane Letz * Add a sample_rate change listener in CoreAudio driver. diff --git a/macosx/JackCoreAudioDriver.cpp b/macosx/JackCoreAudioDriver.cpp index ad17d361..578c5fa7 100644 --- a/macosx/JackCoreAudioDriver.cpp +++ b/macosx/JackCoreAudioDriver.cpp @@ -193,7 +193,7 @@ OSStatus JackCoreAudioDriver::Render(void *inRefCon, UInt32 inNumberFrames, AudioBufferList *ioData) { - JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inRefCon; + JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inRefCon; driver->fLastWaitUst = GetMicroSeconds(); // Take callback date here memcpy(&driver->fActionFags, ioActionFlags, sizeof(AudioUnitRenderActionFlags)); memcpy(&driver->fCurrentTime, inTimeStamp, sizeof(AudioTimeStamp)); @@ -243,6 +243,26 @@ OSStatus JackCoreAudioDriver::MeasureCallback(AudioDeviceID inDevice, return noErr; } +OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + void* inClientData) +{ + JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData; + + switch (inPropertyID) { + + case kAudioDevicePropertyNominalSampleRate: { + JackLog("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate \n"); + driver->fState = true; + break; + } + } + + return noErr; +} + OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, @@ -250,6 +270,7 @@ OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, void* inClientData) { JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData; + switch (inPropertyID) { case kAudioDeviceProcessorOverload: @@ -263,6 +284,7 @@ OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, case kAudioDevicePropertyNominalSampleRate: { UInt32 outSize = sizeof(Float64); Float64 sampleRate; + AudioStreamBasicDescription srcFormat, dstFormat; OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); if (err != noErr) { jack_error("Cannot get current sample rate"); @@ -270,9 +292,32 @@ OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, return kAudioHardwareUnsupportedOperationError; } JackLog("JackCoreAudioDriver::NotificationCallback kAudioDevicePropertyNominalSampleRate %ld\n", long(sampleRate)); - if (jack_nframes_t(sampleRate) != driver->fEngineControl->fSampleRate) { - AudioUnitUninitialize(driver->fAUHAL); - jack_error("Critical error: new %ld sample rate, coreaudio driver is stopped", long(sampleRate)); + outSize = sizeof(AudioStreamBasicDescription); + + // Update SR for input + err = AudioUnitGetProperty(driver->fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, &outSize); + if (err != noErr) { + jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); + printError(err); + } + srcFormat.mSampleRate = sampleRate; + err = AudioUnitSetProperty(driver->fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, outSize); + if (err != noErr) { + jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); + printError(err); + } + + // Update SR for output + err = AudioUnitGetProperty(driver->fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, &outSize); + if (err != noErr) { + jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); + printError(err); + } + dstFormat.mSampleRate = sampleRate; + err = AudioUnitSetProperty(driver->fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, outSize); + if (err != noErr) { + jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); + printError(err); } break; } @@ -400,7 +445,7 @@ OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, long* chann } JackCoreAudioDriver::JackCoreAudioDriver(const char* name, JackEngine* engine, JackSynchro** table) - : JackAudioDriver(name, engine, table), fJackInputData(NULL), fDriverOutputData(NULL) + : JackAudioDriver(name, engine, table), fJackInputData(NULL), fDriverOutputData(NULL), fState(false) { #ifdef DEBUG //fLogFile = new CALatencyLog("jackmp_latency", ".txt"); @@ -437,8 +482,6 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, long out_nChannels = 0; char capture_driver_name[256]; char playback_driver_name[256]; - float iousage; - capture_driver_name[0] = 0; playback_driver_name[0] = 0; @@ -446,7 +489,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, nframes, inchannels, outchannels, capture_driver_uid, playback_driver_uid); // Duplex - if (capture_driver_uid != NULL && playback_driver_uid != NULL) { + if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { JackLog("JackCoreAudioDriver::Open duplex \n"); if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { if (GetDefaultDevice(&fDeviceID) != noErr) { @@ -459,8 +502,8 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, return -1; } - // Capture only - } else if (capture_driver_uid != NULL) { + // Capture only + } else if (strcmp(capture_driver_uid, "") != 0) { JackLog("JackCoreAudioDriver::Open capture only \n"); if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) { if (GetDefaultInputDevice(&fDeviceID) != noErr) { @@ -473,8 +516,8 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, return -1; } - // Playback only - } else if (playback_driver_uid != NULL) { + // Playback only + } else if (strcmp(playback_driver_uid, "") != 0) { JackLog("JackCoreAudioDriver::Open playback only \n"); if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { if (GetDefaultOutputDevice(&fDeviceID) != noErr) { @@ -487,7 +530,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, return -1; } - // Use default driver in duplex mode + // Use default driver in duplex mode } else { JackLog("JackCoreAudioDriver::Open default driver \n"); if (GetDefaultDevice(&fDeviceID) != noErr) { @@ -552,7 +595,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, return -1; } - // Set sample rate + // Get sample rate outSize = sizeof(Float64); err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); if (err != noErr) { @@ -561,16 +604,35 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, return -1; } + // If needed, set new sample rate if (samplerate != (jack_nframes_t)sampleRate) { sampleRate = (Float64)samplerate; + + // To get SR change notification + err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this); + if (err != noErr) { + jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate"); + printError(err); + return -1; + } err = AudioDeviceSetProperty(fDeviceID, 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 (!fState && count++ < 100) { + usleep(100000); + JackLog("Wait count = %ld\n", count); + } + + // Remove SR change notification + AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); } - + // AUHAL ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; Component HALOutput = FindNextComponent(NULL, &cd); @@ -621,7 +683,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, // Set buffer size if (capturing && inchannels > 0) { - err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*) & nframes, sizeof(UInt32)); + err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&nframes, sizeof(UInt32)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); printError(err1); @@ -630,7 +692,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, } if (playing && outchannels > 0) { - err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*) & nframes, sizeof(UInt32)); + err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&nframes, sizeof(UInt32)); if (err1 != noErr) { jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); printError(err1); @@ -670,40 +732,40 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, } // Setup stream converters - if (capturing && inchannels > 0) { - 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(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription)); - if (err1 != noErr) { - jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); - printError(err1); - } - } - - if (playing && outchannels > 0) { - 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(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription)); - if (err1 != noErr) { - jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); - printError(err1); - } - } + JackLog("Setup AUHAL input stream converter SR = %ld\n", samplerate); + 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(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription)); + if (err1 != noErr) { + jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); + printError(err1); + goto error; + } + JackLog("Setup AUHAL output stream converter SR = %ld\n", samplerate); + 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(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription)); + if (err1 != noErr) { + jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); + printError(err1); + goto error; + } + // Setup callbacks if (inchannels > 0 && outchannels == 0) { AURenderCallbackStruct output; @@ -762,7 +824,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, printError(err1); goto error; } - + fDriverOutputData = 0; #if IO_CPU @@ -778,7 +840,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, // Core driver may have changed the in/out values fCaptureChannels = inchannels; fPlaybackChannels = outchannels; - return 0; + return noErr; error: AudioUnitUninitialize(fAUHAL); diff --git a/macosx/JackCoreAudioDriver.h b/macosx/JackCoreAudioDriver.h index b59424ac..9cbea223 100644 --- a/macosx/JackCoreAudioDriver.h +++ b/macosx/JackCoreAudioDriver.h @@ -53,9 +53,10 @@ class JackCoreAudioDriver : public JackAudioDriver { private: -#ifdef DEBUG + + #ifdef DEBUG //CALatencyLog* fLogFile; -#endif + #endif AudioUnit fAUHAL; @@ -66,6 +67,8 @@ class JackCoreAudioDriver : public JackAudioDriver AudioUnitRenderActionFlags fActionFags; AudioTimeStamp fCurrentTime; + + bool fState; static OSStatus Render(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, @@ -87,7 +90,14 @@ class JackCoreAudioDriver : public JackAudioDriver Boolean isInput, AudioDevicePropertyID inPropertyID, void* inClientData); - + + + static OSStatus SRNotificationCallback(AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + void* inClientData); + OSStatus GetDeviceIDFromUID(const char* UID, AudioDeviceID* id); OSStatus GetDefaultDevice(AudioDeviceID* id); OSStatus GetDefaultInputDevice(AudioDeviceID* id);