git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@1801 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.70
| @@ -17,6 +17,12 @@ Tim Blechmann | |||
| Jackdmp changes log | |||
| --------------------------- | |||
| 2008-01-31 Stephane Letz <letz@grame.fr> | |||
| * Remove checking thread in CoreAudio driver, better device state change recovery strategy: the driver is stopped and restarted. | |||
| * jack_thread_wait implementation. | |||
| * Add jack_thread_wait client example. | |||
| 2008-01-30 Stephane Letz <letz@grame.fr> | |||
| * Latest jack_lsp code from jack SVN. | |||
| @@ -64,7 +64,8 @@ extern "C" | |||
| EXPORT int jack_set_process_callback (jack_client_t *client, | |||
| JackProcessCallback process_callback, | |||
| void *arg); | |||
| EXPORT int jack_set_thread_init_callback (jack_client_t *client, | |||
| EXPORT jack_nframes_t jack_thread_wait(jack_client_t *client, int status); | |||
| EXPORT int jack_set_thread_init_callback (jack_client_t *client, | |||
| JackThreadInitCallback thread_init_callback, | |||
| void *arg); | |||
| EXPORT int jack_set_freewheel_callback (jack_client_t *client, | |||
| @@ -630,6 +631,20 @@ EXPORT int jack_set_process_callback(jack_client_t* ext_client, JackProcessCallb | |||
| } | |||
| } | |||
| EXPORT jack_nframes_t jack_thread_wait(jack_client_t* ext_client, int status) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackLibGlobals::CheckContext(); | |||
| #endif | |||
| JackClient* client = (JackClient*)ext_client; | |||
| if (client == NULL) { | |||
| jack_error("jack_thread_wait called with a NULL client"); | |||
| return -1; | |||
| } else { | |||
| return client->Wait(status); | |||
| } | |||
| } | |||
| EXPORT int jack_set_freewheel_callback(jack_client_t* ext_client, JackFreewheelCallback freewheel_callback, void* arg) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| @@ -298,11 +298,13 @@ int JackClient::Deactivate() | |||
| // RT thread management | |||
| //---------------------- | |||
| /* | |||
| bool JackClient::CallProcessCallback() | |||
| { | |||
| return (fProcess == NULL) ? true : (fProcess(GetEngineControl()->fBufferSize, fProcessArg) == 0); | |||
| } | |||
| */ | |||
| /*! | |||
| \brief Called once when the thread starts. | |||
| */ | |||
| @@ -342,6 +344,7 @@ int JackClient::StartThread() | |||
| /*! | |||
| \brief RT thread. | |||
| */ | |||
| /* | |||
| bool JackClient::Execute() | |||
| { | |||
| // Suspend itself: wait on the input synchro | |||
| @@ -392,6 +395,107 @@ error: | |||
| ShutDown(); | |||
| return false; | |||
| } | |||
| */ | |||
| //// | |||
| bool JackClient::Execute() | |||
| { | |||
| if (WaitFirstSync()) | |||
| ExecuteThread(); | |||
| return false; // Never reached | |||
| } | |||
| inline bool JackClient::WaitFirstSync() | |||
| { | |||
| while (true) { | |||
| // Start first cycle | |||
| WaitSync(); | |||
| if (IsActive()) { | |||
| CallSyncCallback(); | |||
| // Finish first cycle | |||
| if (Wait(CallProcessCallback()) != GetEngineControl()->fBufferSize) | |||
| return false; | |||
| return true; | |||
| } else { | |||
| JackLog("Process called for an inactive client\n"); | |||
| } | |||
| SignalSync(); | |||
| } | |||
| return false; // Never reached | |||
| } | |||
| inline void JackClient::ExecuteThread() | |||
| { | |||
| while (true) { | |||
| if (Wait(CallProcessCallback()) != GetEngineControl()->fBufferSize) | |||
| return; | |||
| } | |||
| } | |||
| inline int JackClient::End() | |||
| { | |||
| JackLog("JackClient::Execute end name = %s\n", GetClientControl()->fName); | |||
| int result; | |||
| // Hum... not sure about this, the following "close" code is called in the RT thread... | |||
| fThread->DropRealTime(); | |||
| GetClientControl()->fActive = false; | |||
| fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); | |||
| fThread->Terminate(); | |||
| return 0; // Never reached | |||
| } | |||
| inline int JackClient::Error() | |||
| { | |||
| jack_error("JackClient::Execute error name = %s", GetClientControl()->fName); | |||
| // Hum... not sure about this, the following "close" code is called in the RT thread... | |||
| fThread->DropRealTime(); | |||
| ShutDown(); | |||
| fThread->Terminate(); | |||
| return 0; // Never reached | |||
| } | |||
| jack_nframes_t JackClient::Wait(int status) | |||
| { | |||
| if (status == 0) | |||
| CallTimebaseCallback(); | |||
| SignalSync(); | |||
| if (status != 0) | |||
| goto end; | |||
| if (!WaitSync()) | |||
| goto error; | |||
| CallSyncCallback(); | |||
| return GetEngineControl()->fBufferSize; | |||
| end: | |||
| return End(); | |||
| error: | |||
| return Error(); | |||
| } | |||
| inline int JackClient::CallProcessCallback() | |||
| { | |||
| return (fProcess != NULL) ? fProcess(GetEngineControl()->fBufferSize, fProcessArg) : 0; | |||
| } | |||
| inline bool JackClient::WaitSync() | |||
| { | |||
| // Suspend itself: wait on the input synchro | |||
| if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable, 0x7FFFFFFF) < 0) { | |||
| jack_error("SuspendRefNum error"); | |||
| return false; | |||
| } else { | |||
| return true; | |||
| } | |||
| } | |||
| inline void JackClient::SignalSync() | |||
| { | |||
| // Resume: signal output clients connected to the running client | |||
| if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) { | |||
| jack_error("ResumeRefNum error"); | |||
| } | |||
| } | |||
| //----------------- | |||
| // Port management | |||
| @@ -90,12 +90,20 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| void SetupDriverSync(bool freewheel); | |||
| bool IsActive(); | |||
| bool CallProcessCallback(); | |||
| void CallSyncCallback(); | |||
| void CallTimebaseCallback(); | |||
| int RequestNewPos(jack_position_t* pos); | |||
| virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value1, int value); | |||
| // Fons Adriaensen thread model | |||
| inline bool WaitFirstSync(); | |||
| inline void ExecuteThread(); | |||
| inline bool WaitSync(); | |||
| inline void SignalSync(); | |||
| inline int CallProcessCallback(); | |||
| inline int End(); | |||
| inline int Error(); | |||
| public: | |||
| @@ -161,6 +169,9 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| virtual int InternalClientHandle(const char* client_name, jack_status_t* status); | |||
| virtual int InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va); | |||
| virtual void InternalClientUnload(int ref, jack_status_t* status); | |||
| // Fons Adriaensen thread model | |||
| virtual jack_nframes_t Wait(int status); | |||
| // JackRunnableInterface interface | |||
| bool Init(); | |||
| @@ -226,5 +226,11 @@ pthread_t JackPosixThread::GetThreadID() | |||
| return fThread; | |||
| } | |||
| void JackPosixThread::Terminate() | |||
| { | |||
| JackLog("JackPosixThread::Terminate\n"); | |||
| pthread_exit(0); | |||
| } | |||
| } // end of namespace | |||
| @@ -62,6 +62,7 @@ class JackPosixThread : public JackThread | |||
| virtual int StartSync(); | |||
| virtual int Kill(); | |||
| virtual int Stop(); | |||
| virtual void Terminate(); | |||
| virtual int AcquireRealTime(); | |||
| virtual int AcquireRealTime(int priority); | |||
| @@ -81,6 +81,7 @@ class JackThread | |||
| virtual int StartSync() = 0; | |||
| virtual int Kill() = 0; | |||
| virtual int Stop() = 0; | |||
| virtual void Terminate() = 0; | |||
| virtual int AcquireRealTime() = 0; | |||
| virtual int AcquireRealTime(int priority) = 0; | |||
| @@ -257,121 +257,65 @@ OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, | |||
| driver->NotifyXRun(GetMicroSeconds()); | |||
| break; | |||
| case kAudioDevicePropertyDeviceIsRunning: { | |||
| UInt32 outSize = sizeof(UInt32); | |||
| driver->fStopTime = CFAbsoluteTimeGetCurrent(); | |||
| OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceIsRunning, &outSize, &driver->fRunning); | |||
| JackLog("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsRunning res = %ld\n", driver->fRunning); | |||
| if (err != noErr) { | |||
| jack_error("Cannot getkAudioDevicePropertyDeviceIsRunning"); | |||
| printError(err); | |||
| } | |||
| break; | |||
| } | |||
| case kAudioDevicePropertyStreamConfiguration: | |||
| JackLog("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyStreamConfiguration \n"); | |||
| //JackLog("GetTotalNumberChannels input = %ld\n", GetTotalNumberChannels(driver->fDeviceID, true)); | |||
| //JackLog("GetTotalNumberChannels output = %ld\n", GetTotalNumberChannels(driver->fDeviceID, false)); | |||
| break; | |||
| case kAudioDevicePropertyNominalSampleRate: { | |||
| OSStatus err; | |||
| UInt32 outSize = sizeof(Float64); | |||
| UInt32 outSize = sizeof(Float64); | |||
| Float64 sampleRate; | |||
| int in_nChannels = 0; | |||
| int out_nChannels = 0; | |||
| char capture_driver_name[256]; | |||
| char playback_driver_name[256]; | |||
| return noErr; // for now | |||
| // Stop and restart | |||
| driver->Stop(); | |||
| driver->RemoveListeners(); | |||
| driver->CloseAUHAL(); | |||
| err = AudioOutputUnitStop(driver->fAUHAL); | |||
| if (err != noErr) | |||
| jack_error("Error calling AudioOutputUnitStop"); | |||
| AudioStreamBasicDescription srcFormat, dstFormat; | |||
| err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); | |||
| OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); | |||
| if (err != noErr) { | |||
| jack_error("Cannot get current sample rate"); | |||
| printError(err); | |||
| return kAudioHardwareUnsupportedOperationError; | |||
| } | |||
| JackLog("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyNominalSampleRate %ld\n", long(sampleRate)); | |||
| if (sampleRate != driver->fEngineControl->fSampleRate) { | |||
| // To get SR change notification | |||
| /* | |||
| driver->fState = false; | |||
| err = AudioDeviceAddPropertyListener(driver->fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, driver); | |||
| if (err != noErr) { | |||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate"); | |||
| printError(err); | |||
| return kAudioHardwareUnsupportedOperationError; | |||
| } | |||
| */ | |||
| //sampleRate = driver->fEngineControl->fSampleRate; | |||
| err = AudioDeviceSetProperty(driver->fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate); | |||
| if (err != noErr) { | |||
| jack_error("Cannot set sample rate = %ld", sampleRate); | |||
| printError(err); | |||
| return kAudioHardwareUnsupportedOperationError; | |||
| } | |||
| JackLog("JackCoreAudioDriver::DeviceNotificationCallback sampleRate %ld\n", driver->fEngineControl->fSampleRate); | |||
| /* | |||
| // Waiting for SR change notification | |||
| int count = 0; | |||
| while (!driver->fState && count++ < 100) { | |||
| usleep(100000); | |||
| JackLog("Wait count = %ld\n", count); | |||
| } | |||
| // Remove SR change notification | |||
| AudioDeviceRemovePropertyListener(driver->fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); | |||
| */ | |||
| } | |||
| /* | |||
| // Update SR for input | |||
| //Float64 sampleRate = driver->fEngineControl->fSampleRate; | |||
| outSize = sizeof(AudioStreamBasicDescription); | |||
| 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; | |||
| //srcFormat.mSampleRate = driver->fEngineControl->fSampleRate; | |||
| 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); | |||
| } | |||
| if (driver->SetupDevices(driver->fCaptureUID, driver->fPlaybackUID, capture_driver_name, playback_driver_name) < 0) | |||
| return -1; | |||
| // 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; | |||
| //dstFormat.mSampleRate = driver->fEngineControl->fSampleRate; | |||
| 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); | |||
| } | |||
| */ | |||
| if (driver->SetupChannels(driver->fCapturing, driver->fPlaying, driver->fInChannels, driver->fOutChannels, in_nChannels, out_nChannels, false) < 0) | |||
| return -1; | |||
| if (driver->SetupBufferSizeAndSampleRate(driver->fEngineControl->fBufferSize, sampleRate) < 0) | |||
| return -1; | |||
| if (driver->OpenAUHAL(driver->fCapturing, | |||
| driver->fPlaying, | |||
| driver->fInChannels, | |||
| driver->fOutChannels, | |||
| in_nChannels, | |||
| out_nChannels, | |||
| driver->fEngineControl->fBufferSize, | |||
| sampleRate, | |||
| false) < 0) | |||
| goto error; | |||
| if (driver->AddListeners() < 0) | |||
| goto error; | |||
| driver->Start(); | |||
| err = AudioOutputUnitStart(driver->fAUHAL); | |||
| if (err != noErr) | |||
| jack_error("Error calling AudioOutputUnitStart"); | |||
| // Send notification to be used in JackPilot or JackRouter plugin | |||
| jack_error("Device restart..."); | |||
| CFStringRef ref = CFStringCreateWithCString(NULL, driver->fEngineControl->fServerName, kCFStringEncodingMacRoman); | |||
| CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(), | |||
| CFSTR("com.grame.jackserver.restart"), | |||
| ref, | |||
| NULL, | |||
| kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions); | |||
| CFRelease(ref); | |||
| return noErr; | |||
| error: | |||
| driver->CloseAUHAL(); | |||
| break; | |||
| } | |||
| } | |||
| @@ -453,7 +397,7 @@ OSStatus JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id, char* name) | |||
| return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name); | |||
| } | |||
| OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, long* channelCount, bool isInput) | |||
| OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput) | |||
| { | |||
| OSStatus err = noErr; | |||
| UInt32 outSize; | |||
| @@ -478,12 +422,11 @@ OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, long* chann | |||
| } | |||
| JackCoreAudioDriver::JackCoreAudioDriver(const char* name, JackEngine* engine, JackSynchro** table) | |||
| : JackAudioDriver(name, engine, table), fJackInputData(NULL), fDriverOutputData(NULL), fState(false), fStopTime(0), fRunning(true) | |||
| : JackAudioDriver(name, engine, table), fJackInputData(NULL), fDriverOutputData(NULL), fState(false) | |||
| { | |||
| #ifdef DEBUG | |||
| //fLogFile = new CALatencyLog("jackmp_latency", ".txt"); | |||
| #endif | |||
| fThread = JackGlobals::MakeThread(this); | |||
| } | |||
| JackCoreAudioDriver::~JackCoreAudioDriver() | |||
| @@ -491,60 +434,14 @@ JackCoreAudioDriver::~JackCoreAudioDriver() | |||
| #ifdef DEBUG | |||
| //delete fLogFile; | |||
| #endif | |||
| fThread->Kill(); | |||
| delete fThread; | |||
| } | |||
| bool JackCoreAudioDriver::Execute() | |||
| { | |||
| while (true) { | |||
| JackLog("Check device running...\n"); | |||
| if (!fRunning && CFAbsoluteTimeGetCurrent() > fStopTime + 3.0) { | |||
| jack_error("Critical error : device not running anymore..."); | |||
| // Send notification to be used in JackPilot or JackRouter plugin | |||
| CFStringRef ref = CFStringCreateWithCString(NULL, fEngineControl->fServerName, kCFStringEncodingMacRoman); | |||
| CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(), | |||
| CFSTR("com.grame.jackserver.stop"), | |||
| ref, | |||
| NULL, | |||
| kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions); | |||
| CFRelease(ref); | |||
| } | |||
| usleep(2000000); | |||
| } | |||
| return false; | |||
| } | |||
| int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| jack_nframes_t samplerate, | |||
| bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| int outchannels, | |||
| bool monitor, | |||
| const char* capture_driver_uid, | |||
| const char* playback_driver_uid, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency) | |||
| int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char* playback_driver_uid, char* capture_driver_name, char* playback_driver_name) | |||
| { | |||
| OSStatus err = noErr; | |||
| ComponentResult err1; | |||
| UInt32 outSize; | |||
| UInt32 enableIO; | |||
| AudioStreamBasicDescription srcFormat, dstFormat; | |||
| Float64 sampleRate; | |||
| long in_nChannels = 0; | |||
| long out_nChannels = 0; | |||
| char capture_driver_name[256]; | |||
| char playback_driver_name[256]; | |||
| capture_driver_name[0] = 0; | |||
| capture_driver_name[0] = 0; | |||
| playback_driver_name[0] = 0; | |||
| JackLog("JackCoreAudioDriver::Open nframes = %ld in = %ld out = %ld capture name = %s playback name = %s\n", | |||
| nframes, inchannels, outchannels, capture_driver_uid, playback_driver_uid); | |||
| // Duplex | |||
| // Duplex | |||
| if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { | |||
| JackLog("JackCoreAudioDriver::Open duplex \n"); | |||
| if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { | |||
| @@ -598,13 +495,15 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| return -1; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| // Generic JackAudioDriver Open | |||
| if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) { | |||
| return -1; | |||
| } | |||
| if (capturing) { | |||
| int JackCoreAudioDriver::SetupChannels(int capturing, int playing, int& inchannels, int& outchannels, int& in_nChannels, int& out_nChannels, bool strict) | |||
| { | |||
| OSStatus err = noErr; | |||
| if (capturing) { | |||
| err = GetTotalChannels(fDeviceID, &in_nChannels, true); | |||
| if (err != noErr) { | |||
| jack_error("Cannot get input channel number"); | |||
| @@ -624,12 +523,14 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (inchannels > in_nChannels) { | |||
| jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels); | |||
| return -1; | |||
| } | |||
| if (strict) | |||
| return -1; | |||
| } | |||
| if (outchannels > out_nChannels) { | |||
| jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels); | |||
| return -1; | |||
| if (strict) | |||
| return -1; | |||
| } | |||
| if (inchannels == 0) { | |||
| @@ -641,10 +542,19 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| JackLog("Setup max out channels = %ld\n", out_nChannels); | |||
| outchannels = out_nChannels; | |||
| } | |||
| return 0; | |||
| } | |||
| // Setting buffer size | |||
| int JackCoreAudioDriver::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate) | |||
| { | |||
| OSStatus err = noErr; | |||
| UInt32 outSize; | |||
| Float64 sampleRate; | |||
| // Setting buffer size | |||
| outSize = sizeof(UInt32); | |||
| err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &fEngineControl->fBufferSize); | |||
| err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &nframes); | |||
| if (err != noErr) { | |||
| jack_error("Cannot set buffer size %ld", nframes); | |||
| printError(err); | |||
| @@ -688,8 +598,25 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| // Remove SR change notification | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); | |||
| } | |||
| return 0; | |||
| } | |||
| // AUHAL | |||
| int JackCoreAudioDriver::OpenAUHAL(int capturing, | |||
| int playing, | |||
| int inchannels, | |||
| int outchannels, | |||
| int in_nChannels, | |||
| int out_nChannels, | |||
| jack_nframes_t nframes, | |||
| jack_nframes_t samplerate, | |||
| bool strict) | |||
| { | |||
| ComponentResult err1; | |||
| UInt32 enableIO; | |||
| AudioStreamBasicDescription srcFormat, dstFormat; | |||
| // AUHAL | |||
| ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; | |||
| Component HALOutput = FindNextComponent(NULL, &cd); | |||
| @@ -697,14 +624,14 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling OpenAComponent"); | |||
| printError(err1); | |||
| goto error; | |||
| return -1; | |||
| } | |||
| err1 = AudioUnitInitialize(fAUHAL); | |||
| if (err1 != noErr) { | |||
| jack_error("Cannot initialize AUHAL unit"); | |||
| printError(err1); | |||
| goto error; | |||
| return -1; | |||
| } | |||
| // Start I/O | |||
| @@ -715,7 +642,8 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); | |||
| printError(err1); | |||
| goto error; | |||
| if (strict) | |||
| return -1; | |||
| } | |||
| } | |||
| @@ -725,7 +653,8 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); | |||
| printError(err1); | |||
| goto error; | |||
| if (strict) | |||
| return -1; | |||
| } | |||
| } | |||
| @@ -734,7 +663,8 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice"); | |||
| printError(err1); | |||
| goto error; | |||
| if (strict) | |||
| return -1; | |||
| } | |||
| // Set buffer size | |||
| @@ -743,7 +673,8 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); | |||
| printError(err1); | |||
| goto error; | |||
| if (strict) | |||
| return -1; | |||
| } | |||
| } | |||
| @@ -752,7 +683,8 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); | |||
| printError(err1); | |||
| goto error; | |||
| if (strict) | |||
| return -1; | |||
| } | |||
| } | |||
| @@ -829,7 +761,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1"); | |||
| printError(err1); | |||
| goto error; | |||
| return -1; | |||
| } | |||
| } else { | |||
| AURenderCallbackStruct output; | |||
| @@ -839,98 +771,174 @@ int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0"); | |||
| printError(err1); | |||
| goto error; | |||
| return -1; | |||
| } | |||
| } | |||
| // Prepare buffers | |||
| if (capturing && inchannels > 0) { | |||
| fJackInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer)); | |||
| if (fJackInputData == 0) { | |||
| jack_error("Cannot allocate memory for input buffers"); | |||
| goto error; | |||
| } | |||
| fJackInputData->mNumberBuffers = inchannels; | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| fJackInputData->mBuffers[i].mNumberChannels = 1; | |||
| fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float); | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| int JackCoreAudioDriver::SetupBuffers(int inchannels, int outchannels) | |||
| { | |||
| // Prepare buffers | |||
| fJackInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer)); | |||
| if (fJackInputData == 0) { | |||
| jack_error("Cannot allocate memory for input buffers"); | |||
| return -1; | |||
| } | |||
| fJackInputData->mNumberBuffers = inchannels; | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| fJackInputData->mBuffers[i].mNumberChannels = 1; | |||
| fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float); | |||
| } | |||
| return 0; | |||
| } | |||
| void JackCoreAudioDriver::DisposeBuffers() | |||
| { | |||
| if (fJackInputData) { | |||
| free(fJackInputData); | |||
| fJackInputData = 0; | |||
| } | |||
| } | |||
| void JackCoreAudioDriver::CloseAUHAL() | |||
| { | |||
| AudioUnitUninitialize(fAUHAL); | |||
| CloseComponent(fAUHAL); | |||
| } | |||
| // Add listeners | |||
| int JackCoreAudioDriver::AddListeners() | |||
| { | |||
| OSStatus err = noErr; | |||
| // Add listeners | |||
| err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this); | |||
| if (err != noErr) { | |||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload"); | |||
| printError(err1); | |||
| goto error; | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); | |||
| if (err != noErr) { | |||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); | |||
| printError(err1); | |||
| goto error; | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this); | |||
| if (err != noErr) { | |||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate"); | |||
| printError(err1); | |||
| goto error; | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this); | |||
| if (err != noErr) { | |||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning"); | |||
| printError(err1); | |||
| goto error; | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this); | |||
| if (err != noErr) { | |||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration"); | |||
| printError(err1); | |||
| goto error; | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this); | |||
| if (err != noErr) { | |||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration"); | |||
| printError(err1); | |||
| goto error; | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| fDriverOutputData = 0; | |||
| return 0; | |||
| } | |||
| void JackCoreAudioDriver::RemoveListeners() | |||
| { | |||
| AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); | |||
| } | |||
| int JackCoreAudioDriver::Open(jack_nframes_t nframes, | |||
| jack_nframes_t samplerate, | |||
| bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| int outchannels, | |||
| bool monitor, | |||
| const char* capture_driver_uid, | |||
| const char* playback_driver_uid, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency) | |||
| { | |||
| int in_nChannels = 0; | |||
| int out_nChannels = 0; | |||
| char capture_driver_name[256]; | |||
| char playback_driver_name[256]; | |||
| // Keep initial state | |||
| fCapturing = capturing; | |||
| fPlaying = playing; | |||
| fInChannels = inchannels; | |||
| fOutChannels = outchannels; | |||
| fMonitor = monitor; | |||
| strcpy(fCaptureUID, capture_driver_uid); | |||
| strcpy(fPlaybackUID, playback_driver_uid); | |||
| fCaptureLatency = capture_latency; | |||
| fPlaybackLatency = playback_latency; | |||
| if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name) < 0) | |||
| return -1; | |||
| // Generic JackAudioDriver Open | |||
| if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) | |||
| return -1; | |||
| if (SetupChannels(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, true) < 0) | |||
| return -1; | |||
| if (SetupBufferSizeAndSampleRate(nframes, samplerate) < 0) | |||
| return -1; | |||
| if (OpenAUHAL(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, nframes, samplerate, true) < 0) | |||
| goto error; | |||
| if (capturing && inchannels > 0) | |||
| if (SetupBuffers(inchannels, outchannels) < 0) | |||
| goto error; | |||
| if (AddListeners() < 0) | |||
| goto error; | |||
| // Core driver may have changed the in/out values | |||
| fCaptureChannels = inchannels; | |||
| fPlaybackChannels = outchannels; | |||
| return noErr; | |||
| error: | |||
| AudioUnitUninitialize(fAUHAL); | |||
| CloseComponent(fAUHAL); | |||
| Close(); | |||
| return -1; | |||
| } | |||
| int JackCoreAudioDriver::Close() | |||
| { | |||
| JackLog("JackCoreAudioDriver::Close\n"); | |||
| Stop(); | |||
| JackAudioDriver::Close(); | |||
| // Possibly (if MeasureCallback has not been called) | |||
| AudioDeviceStop(fDeviceID, MeasureCallback); | |||
| AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); | |||
| AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); | |||
| free(fJackInputData); | |||
| AudioUnitUninitialize(fAUHAL); | |||
| CloseComponent(fAUHAL); | |||
| return 0; | |||
| RemoveListeners(); | |||
| DisposeBuffers(); | |||
| CloseAUHAL(); | |||
| return 0; | |||
| } | |||
| int JackCoreAudioDriver::Attach() | |||
| @@ -978,7 +986,6 @@ int JackCoreAudioDriver::Attach() | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->Rename("system:capture_%d", i + 1); | |||
| port->SetLatency(fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency); | |||
| JackLog("Latency = %ld \n", port->GetLatency()); | |||
| fCapturePortList[i] = port_index; | |||
| } | |||
| @@ -1016,7 +1023,6 @@ int JackCoreAudioDriver::Attach() | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->Rename("system:playback_%d", i + 1); | |||
| port->SetLatency(fEngineControl->fBufferSize + value1 + value2 + fPlaybackLatency); | |||
| JackLog("Latency = %ld \n", port->GetLatency()); | |||
| fPlaybackPortList[i] = port_index; | |||
| // Monitor ports | |||
| @@ -1061,20 +1067,14 @@ int JackCoreAudioDriver::Start() | |||
| return -1; | |||
| } | |||
| // Start checking thread... | |||
| fRunning = true; | |||
| fThread->Start(); | |||
| return 0; | |||
| } | |||
| int JackCoreAudioDriver::Stop() | |||
| { | |||
| JackLog("JackCoreAudioDriver::Stop\n"); | |||
| AudioDeviceStop(fDeviceID, MeasureCallback); | |||
| AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback); | |||
| JackLog("JackCoreAudioDriver::Stop\n"); | |||
| // Kill checking thread... | |||
| fThread->Kill(); | |||
| fRunning = false; | |||
| return (AudioOutputUnitStop(fAUHAL) == noErr) ? 0 : -1; | |||
| } | |||
| @@ -25,7 +25,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #include "JackAudioDriver.h" | |||
| #include "JackTime.h" | |||
| #include "JackThread.h" | |||
| #include "/Developer/Examples/CoreAudio/PublicUtility/CALatencyLog.h" | |||
| @@ -47,7 +46,7 @@ typedef UInt8 CAAudioHardwareDeviceSectionID; | |||
| \todo hardware monitoring | |||
| */ | |||
| class JackCoreAudioDriver : public JackAudioDriver, public JackRunnableInterface | |||
| class JackCoreAudioDriver : public JackAudioDriver | |||
| { | |||
| private: | |||
| @@ -67,9 +66,18 @@ class JackCoreAudioDriver : public JackAudioDriver, public JackRunnableInterfac | |||
| AudioTimeStamp* fCurrentTime; | |||
| bool fState; | |||
| CFAbsoluteTime fStopTime; | |||
| UInt32 fRunning; | |||
| JackThread* fThread; | |||
| /// Intitial state | |||
| int fCapturing; | |||
| int fPlaying; | |||
| int fInChannels; | |||
| int fOutChannels; | |||
| char fCaptureUID[256]; | |||
| char fPlaybackUID[256]; | |||
| bool fMonitor; | |||
| static OSStatus Render(void *inRefCon, | |||
| AudioUnitRenderActionFlags *ioActionFlags, | |||
| @@ -104,7 +112,40 @@ class JackCoreAudioDriver : public JackAudioDriver, public JackRunnableInterfac | |||
| OSStatus GetDefaultInputDevice(AudioDeviceID* id); | |||
| OSStatus GetDefaultOutputDevice(AudioDeviceID* id); | |||
| OSStatus GetDeviceNameFromID(AudioDeviceID id, char* name); | |||
| OSStatus GetTotalChannels(AudioDeviceID device, long* channelCount, bool isInput); | |||
| OSStatus GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput); | |||
| // Setup | |||
| int SetupDevices(const char* capture_driver_uid, | |||
| const char* playback_driver_uid, | |||
| char* capture_driver_name, | |||
| char* playback_driver_name); | |||
| int SetupChannels(int capturing, | |||
| int playing, | |||
| int& inchannels, | |||
| int& outchannels, | |||
| int& in_nChannels, | |||
| int& out_nChannels, | |||
| bool strict); | |||
| int SetupBuffers(int inchannels, int outchannels); | |||
| void DisposeBuffers(); | |||
| int SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate); | |||
| int OpenAUHAL(int capturing, | |||
| int playing, | |||
| int inchannels, | |||
| int outchannels, | |||
| int in_nChannels, | |||
| int out_nChannels, | |||
| jack_nframes_t nframes, | |||
| jack_nframes_t samplerate, | |||
| bool strict); | |||
| void CloseAUHAL(); | |||
| int AddListeners(); | |||
| void RemoveListeners(); | |||
| public: | |||
| @@ -122,8 +163,7 @@ class JackCoreAudioDriver : public JackAudioDriver, public JackRunnableInterfac | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| int Close(); | |||
| int Close(); | |||
| int Attach(); | |||
| @@ -134,8 +174,6 @@ class JackCoreAudioDriver : public JackAudioDriver, public JackRunnableInterfac | |||
| int Write(); | |||
| int SetBufferSize(jack_nframes_t buffer_size); | |||
| bool Execute(); | |||
| }; | |||
| } // end of namespace | |||
| @@ -29,6 +29,7 @@ | |||
| 4B35C6920D4733B9000DE7AE /* PBXTargetDependency */, | |||
| 4B35C6940D4733B9000DE7AE /* PBXTargetDependency */, | |||
| 4B35C6960D4733B9000DE7AE /* PBXTargetDependency */, | |||
| 4B0A29300D5210C4002EFF74 /* PBXTargetDependency */, | |||
| 4B35C6980D4733B9000DE7AE /* PBXTargetDependency */, | |||
| 4B35C69A0D4733B9000DE7AE /* PBXTargetDependency */, | |||
| 4B35C69C0D4733B9000DE7AE /* PBXTargetDependency */, | |||
| @@ -68,6 +69,7 @@ | |||
| 4BE99D630AD7A19100C59091 /* PBXTargetDependency */, | |||
| 4BA693E90CBE5BBA00EAD520 /* PBXTargetDependency */, | |||
| 4BA693EB0CBE5BBA00EAD520 /* PBXTargetDependency */, | |||
| 4B0A28F40D520D11002EFF74 /* PBXTargetDependency */, | |||
| 4BFA99AC0AAAF41D009E916C /* PBXTargetDependency */, | |||
| 4BFA99500AAAED90009E916C /* PBXTargetDependency */, | |||
| 4BFA99520AAAED90009E916C /* PBXTargetDependency */, | |||
| @@ -83,6 +85,8 @@ | |||
| /* End PBXAggregateTarget section */ | |||
| /* Begin PBXBuildFile section */ | |||
| 4B0A28ED0D520852002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; }; | |||
| 4B0A29260D52108E002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; }; | |||
| 4B35C41E0D4731D1000DE7AE /* Jackdmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8D2250834F06A00C94B91 /* Jackdmp.cpp */; }; | |||
| 4B35C4290D4731D1000DE7AE /* JackMachPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B799AD707899652003F3F15 /* JackMachPort.h */; }; | |||
| 4B35C42A0D4731D1000DE7AE /* JackError.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF8D1770834EE4800C94B91 /* JackError.h */; }; | |||
| @@ -596,6 +600,20 @@ | |||
| /* End PBXBuildFile section */ | |||
| /* Begin PBXContainerItemProxy section */ | |||
| 4B0A28F30D520D11002EFF74 /* PBXContainerItemProxy */ = { | |||
| isa = PBXContainerItemProxy; | |||
| containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; | |||
| proxyType = 1; | |||
| remoteGlobalIDString = 4B0A28DC0D52073D002EFF74 /* jack_thread_wait */; | |||
| remoteInfo = jack_thread_wait; | |||
| }; | |||
| 4B0A292F0D5210C4002EFF74 /* PBXContainerItemProxy */ = { | |||
| isa = PBXContainerItemProxy; | |||
| containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; | |||
| proxyType = 1; | |||
| remoteGlobalIDString = 4B0A29230D52108E002EFF74 /* jack_thread_wait 64 bits */; | |||
| remoteInfo = "jack_thread_wait 64 bits"; | |||
| }; | |||
| 4B1C1ABF0CC61597005F551E /* PBXContainerItemProxy */ = { | |||
| isa = PBXContainerItemProxy; | |||
| containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; | |||
| @@ -986,6 +1004,9 @@ | |||
| /* Begin PBXFileReference section */ | |||
| 4B003A6008E2A87A0060EFDC /* JackError.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = JackError.c; path = ../common/JackError.c; sourceTree = SOURCE_ROOT; }; | |||
| 4B003AB008E2B2BA0060EFDC /* ringbuffer.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ringbuffer.c; path = ../common/ringbuffer.c; sourceTree = SOURCE_ROOT; }; | |||
| 4B0A28E60D52073D002EFF74 /* jack_thread_wait */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_thread_wait; sourceTree = BUILT_PRODUCTS_DIR; }; | |||
| 4B0A28EC0D520852002EFF74 /* tw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tw.c; path = "../example-clients/tw.c"; sourceTree = SOURCE_ROOT; }; | |||
| 4B0A292D0D52108E002EFF74 /* jack_thread_wait */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_thread_wait; sourceTree = BUILT_PRODUCTS_DIR; }; | |||
| 4B123D3308B3954300540632 /* JackGlobalsClient.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackGlobalsClient.cpp; path = ../common/JackGlobalsClient.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 4B123D3608B3954A00540632 /* JackGlobalsServer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackGlobalsServer.cpp; path = ../common/JackGlobalsServer.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 4B2C28F908DAD01E00249230 /* JackGlobals.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackGlobals.cpp; path = ../common/JackGlobals.cpp; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1201,6 +1222,20 @@ | |||
| /* End PBXFileReference section */ | |||
| /* Begin PBXFrameworksBuildPhase section */ | |||
| 4B0A28E00D52073D002EFF74 /* Frameworks */ = { | |||
| isa = PBXFrameworksBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| 4B0A29270D52108E002EFF74 /* Frameworks */ = { | |||
| isa = PBXFrameworksBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| 4B35C41F0D4731D1000DE7AE /* Frameworks */ = { | |||
| isa = PBXFrameworksBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| @@ -1680,6 +1715,8 @@ | |||
| 4B35C6290D4731D2000DE7AE /* jack_portaudio.so */, | |||
| 4B35C6340D4731D2000DE7AE /* jack_dummy.so */, | |||
| 4B35C63E0D4731D3000DE7AE /* inprocess.so */, | |||
| 4B0A28E60D52073D002EFF74 /* jack_thread_wait */, | |||
| 4B0A292D0D52108E002EFF74 /* jack_thread_wait */, | |||
| ); | |||
| name = Products; | |||
| sourceTree = "<group>"; | |||
| @@ -1687,6 +1724,7 @@ | |||
| 4B03383E0797E19900686131 /* Simple clients */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 4B0A28EC0D520852002EFF74 /* tw.c */, | |||
| 4B5A1BDC0CD1CD420005BF74 /* midisine.c */, | |||
| 4B5A1BBD0CD1CC110005BF74 /* midiseq.c */, | |||
| 4BA692D60CBE4CC600EAD520 /* ipunload.c */, | |||
| @@ -2031,6 +2069,20 @@ | |||
| /* End PBXGroup section */ | |||
| /* Begin PBXHeadersBuildPhase section */ | |||
| 4B0A28DD0D52073D002EFF74 /* Headers */ = { | |||
| isa = PBXHeadersBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| 4B0A29240D52108E002EFF74 /* Headers */ = { | |||
| isa = PBXHeadersBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| 4B35C41C0D4731D1000DE7AE /* Headers */ = { | |||
| isa = PBXHeadersBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| @@ -2646,6 +2698,44 @@ | |||
| /* End PBXHeadersBuildPhase section */ | |||
| /* Begin PBXNativeTarget section */ | |||
| 4B0A28DC0D52073D002EFF74 /* jack_thread_wait */ = { | |||
| isa = PBXNativeTarget; | |||
| buildConfigurationList = 4B0A28E20D52073D002EFF74 /* Build configuration list for PBXNativeTarget "jack_thread_wait" */; | |||
| buildPhases = ( | |||
| 4B0A28DD0D52073D002EFF74 /* Headers */, | |||
| 4B0A28DE0D52073D002EFF74 /* Sources */, | |||
| 4B0A28E00D52073D002EFF74 /* Frameworks */, | |||
| 4B0A28E10D52073D002EFF74 /* Rez */, | |||
| ); | |||
| buildRules = ( | |||
| ); | |||
| dependencies = ( | |||
| ); | |||
| name = jack_thread_wait; | |||
| productInstallPath = /usr/local/bin; | |||
| productName = testSem; | |||
| productReference = 4B0A28E60D52073D002EFF74 /* jack_thread_wait */; | |||
| productType = "com.apple.product-type.tool"; | |||
| }; | |||
| 4B0A29230D52108E002EFF74 /* jack_thread_wait 64 bits */ = { | |||
| isa = PBXNativeTarget; | |||
| buildConfigurationList = 4B0A29290D52108E002EFF74 /* Build configuration list for PBXNativeTarget "jack_thread_wait 64 bits" */; | |||
| buildPhases = ( | |||
| 4B0A29240D52108E002EFF74 /* Headers */, | |||
| 4B0A29250D52108E002EFF74 /* Sources */, | |||
| 4B0A29270D52108E002EFF74 /* Frameworks */, | |||
| 4B0A29280D52108E002EFF74 /* Rez */, | |||
| ); | |||
| buildRules = ( | |||
| ); | |||
| dependencies = ( | |||
| ); | |||
| name = "jack_thread_wait 64 bits"; | |||
| productInstallPath = /usr/local/bin; | |||
| productName = testSem; | |||
| productReference = 4B0A292D0D52108E002EFF74 /* jack_thread_wait */; | |||
| productType = "com.apple.product-type.tool"; | |||
| }; | |||
| 4B35C41B0D4731D1000DE7AE /* jackdmp framework 64bits */ = { | |||
| isa = PBXNativeTarget; | |||
| buildConfigurationList = 4B35C4210D4731D1000DE7AE /* Build configuration list for PBXNativeTarget "jackdmp framework 64bits" */; | |||
| @@ -3690,6 +3780,7 @@ | |||
| 4BE99D260AD7A04800C59091 /* jack_cpu Universal */, | |||
| 4BA692A60CBE4BC700EAD520 /* jack_load Universal */, | |||
| 4BA692CA0CBE4C9000EAD520 /* jack_unload Universal */, | |||
| 4B0A28DC0D52073D002EFF74 /* jack_thread_wait */, | |||
| 4B699D4F097D421600A18468 /* synchroServer Universal */, | |||
| 4B699D67097D421600A18468 /* synchroClient Universal */, | |||
| 4B699D7F097D421700A18468 /* synchroServerClient Universal */, | |||
| @@ -3717,6 +3808,7 @@ | |||
| 4B35C5B40D4731D2000DE7AE /* jack_cpu 64 bits */, | |||
| 4B35C5C00D4731D2000DE7AE /* jack_load 64 bits */, | |||
| 4B35C5CC0D4731D2000DE7AE /* jack_unload 64 bits */, | |||
| 4B0A29230D52108E002EFF74 /* jack_thread_wait 64 bits */, | |||
| 4B35C5D80D4731D2000DE7AE /* synchroServer 64 bits */, | |||
| 4B35C5EC0D4731D2000DE7AE /* synchroClient 64 bits */, | |||
| 4B35C6000D4731D2000DE7AE /* synchroServerClient 64 bits */, | |||
| @@ -3774,6 +3866,20 @@ | |||
| /* End PBXResourcesBuildPhase section */ | |||
| /* Begin PBXRezBuildPhase section */ | |||
| 4B0A28E10D52073D002EFF74 /* Rez */ = { | |||
| isa = PBXRezBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| 4B0A29280D52108E002EFF74 /* Rez */ = { | |||
| isa = PBXRezBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| 4B35C4200D4731D1000DE7AE /* Rez */ = { | |||
| isa = PBXRezBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| @@ -4085,6 +4191,22 @@ | |||
| /* End PBXRezBuildPhase section */ | |||
| /* Begin PBXSourcesBuildPhase section */ | |||
| 4B0A28DE0D52073D002EFF74 /* Sources */ = { | |||
| isa = PBXSourcesBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| 4B0A28ED0D520852002EFF74 /* tw.c in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| 4B0A29250D52108E002EFF74 /* Sources */ = { | |||
| isa = PBXSourcesBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| 4B0A29260D52108E002EFF74 /* tw.c in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| 4B35C41D0D4731D1000DE7AE /* Sources */ = { | |||
| isa = PBXSourcesBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| @@ -4742,6 +4864,16 @@ | |||
| /* End PBXSourcesBuildPhase section */ | |||
| /* Begin PBXTargetDependency section */ | |||
| 4B0A28F40D520D11002EFF74 /* PBXTargetDependency */ = { | |||
| isa = PBXTargetDependency; | |||
| target = 4B0A28DC0D52073D002EFF74 /* jack_thread_wait */; | |||
| targetProxy = 4B0A28F30D520D11002EFF74 /* PBXContainerItemProxy */; | |||
| }; | |||
| 4B0A29300D5210C4002EFF74 /* PBXTargetDependency */ = { | |||
| isa = PBXTargetDependency; | |||
| target = 4B0A29230D52108E002EFF74 /* jack_thread_wait 64 bits */; | |||
| targetProxy = 4B0A292F0D5210C4002EFF74 /* PBXContainerItemProxy */; | |||
| }; | |||
| 4B1C1AC00CC61597005F551E /* PBXTargetDependency */ = { | |||
| isa = PBXTargetDependency; | |||
| target = 4BE50F8D0B01EE8000C05E63 /* Jackwrapper.framework Universal */; | |||
| @@ -5020,6 +5152,192 @@ | |||
| /* End PBXTargetDependency section */ | |||
| /* Begin XCBuildConfiguration section */ | |||
| 4B0A28E30D52073D002EFF74 /* Development */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ( | |||
| i386, | |||
| ppc, | |||
| ); | |||
| COPY_PHASE_STRIP = NO; | |||
| GCC_DYNAMIC_NO_PIC = NO; | |||
| GCC_ENABLE_FIX_AND_CONTINUE = YES; | |||
| GCC_GENERATE_DEBUGGING_SYMBOLS = YES; | |||
| GCC_OPTIMIZATION_LEVEL = 0; | |||
| HEADER_SEARCH_PATHS = ../common; | |||
| OTHER_CFLAGS = ""; | |||
| OTHER_LDFLAGS = ( | |||
| "-framework", | |||
| Jackmp, | |||
| ); | |||
| OTHER_REZFLAGS = ""; | |||
| PRODUCT_NAME = jack_thread_wait; | |||
| REZ_EXECUTABLE = YES; | |||
| SDKROOT = ""; | |||
| SECTORDER_FLAGS = ""; | |||
| WARNING_CFLAGS = ( | |||
| "-Wmost", | |||
| "-Wno-four-char-constants", | |||
| "-Wno-unknown-pragmas", | |||
| ); | |||
| ZERO_LINK = YES; | |||
| }; | |||
| name = Development; | |||
| }; | |||
| 4B0A28E40D52073D002EFF74 /* Deployment */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ( | |||
| i386, | |||
| ppc, | |||
| ); | |||
| COPY_PHASE_STRIP = YES; | |||
| GCC_ENABLE_FIX_AND_CONTINUE = NO; | |||
| GCC_OPTIMIZATION_LEVEL = 3; | |||
| HEADER_SEARCH_PATHS = ../common; | |||
| MACOSX_DEPLOYMENT_TARGET = 10.4; | |||
| OTHER_CFLAGS = ""; | |||
| OTHER_LDFLAGS = ( | |||
| "-framework", | |||
| Jackmp, | |||
| ); | |||
| OTHER_REZFLAGS = ""; | |||
| PRODUCT_NAME = jack_thread_wait; | |||
| REZ_EXECUTABLE = YES; | |||
| SDKROOT = ""; | |||
| SECTORDER_FLAGS = ""; | |||
| WARNING_CFLAGS = ( | |||
| "-Wmost", | |||
| "-Wno-four-char-constants", | |||
| "-Wno-unknown-pragmas", | |||
| ); | |||
| ZERO_LINK = NO; | |||
| }; | |||
| name = Deployment; | |||
| }; | |||
| 4B0A28E50D52073D002EFF74 /* Default */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ( | |||
| i386, | |||
| ppc, | |||
| ); | |||
| GCC_OPTIMIZATION_LEVEL = 3; | |||
| HEADER_SEARCH_PATHS = ../common; | |||
| OTHER_CFLAGS = ""; | |||
| OTHER_LDFLAGS = ( | |||
| "-framework", | |||
| Jackmp, | |||
| ); | |||
| OTHER_REZFLAGS = ""; | |||
| PRODUCT_NAME = jack_thread_wait; | |||
| REZ_EXECUTABLE = YES; | |||
| SDKROOT = ""; | |||
| SECTORDER_FLAGS = ""; | |||
| WARNING_CFLAGS = ( | |||
| "-Wmost", | |||
| "-Wno-four-char-constants", | |||
| "-Wno-unknown-pragmas", | |||
| ); | |||
| }; | |||
| name = Default; | |||
| }; | |||
| 4B0A292A0D52108E002EFF74 /* Development */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ( | |||
| i386, | |||
| ppc, | |||
| ppc64, | |||
| x86_64, | |||
| ); | |||
| COPY_PHASE_STRIP = NO; | |||
| GCC_DYNAMIC_NO_PIC = NO; | |||
| GCC_ENABLE_FIX_AND_CONTINUE = YES; | |||
| GCC_GENERATE_DEBUGGING_SYMBOLS = YES; | |||
| GCC_OPTIMIZATION_LEVEL = 0; | |||
| HEADER_SEARCH_PATHS = ../common; | |||
| OTHER_CFLAGS = ""; | |||
| OTHER_LDFLAGS = ( | |||
| "-framework", | |||
| Jackmp, | |||
| ); | |||
| OTHER_REZFLAGS = ""; | |||
| PRODUCT_NAME = jack_thread_wait; | |||
| REZ_EXECUTABLE = YES; | |||
| SDKROOT = ""; | |||
| SECTORDER_FLAGS = ""; | |||
| WARNING_CFLAGS = ( | |||
| "-Wmost", | |||
| "-Wno-four-char-constants", | |||
| "-Wno-unknown-pragmas", | |||
| ); | |||
| ZERO_LINK = YES; | |||
| }; | |||
| name = Development; | |||
| }; | |||
| 4B0A292B0D52108E002EFF74 /* Deployment */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ( | |||
| i386, | |||
| ppc, | |||
| ppc64, | |||
| x86_64, | |||
| ); | |||
| COPY_PHASE_STRIP = YES; | |||
| GCC_ENABLE_FIX_AND_CONTINUE = NO; | |||
| GCC_OPTIMIZATION_LEVEL = 3; | |||
| HEADER_SEARCH_PATHS = ../common; | |||
| MACOSX_DEPLOYMENT_TARGET = 10.4; | |||
| OTHER_CFLAGS = ""; | |||
| OTHER_LDFLAGS = ( | |||
| "-framework", | |||
| Jackmp, | |||
| ); | |||
| OTHER_REZFLAGS = ""; | |||
| PRODUCT_NAME = jack_thread_wait; | |||
| REZ_EXECUTABLE = YES; | |||
| SDKROOT = ""; | |||
| SECTORDER_FLAGS = ""; | |||
| WARNING_CFLAGS = ( | |||
| "-Wmost", | |||
| "-Wno-four-char-constants", | |||
| "-Wno-unknown-pragmas", | |||
| ); | |||
| ZERO_LINK = NO; | |||
| }; | |||
| name = Deployment; | |||
| }; | |||
| 4B0A292C0D52108E002EFF74 /* Default */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ( | |||
| i386, | |||
| ppc, | |||
| ppc64, | |||
| x86_64, | |||
| ); | |||
| GCC_OPTIMIZATION_LEVEL = 3; | |||
| HEADER_SEARCH_PATHS = ../common; | |||
| OTHER_CFLAGS = ""; | |||
| OTHER_LDFLAGS = ( | |||
| "-framework", | |||
| Jackmp, | |||
| ); | |||
| OTHER_REZFLAGS = ""; | |||
| PRODUCT_NAME = jack_thread_wait; | |||
| REZ_EXECUTABLE = YES; | |||
| SDKROOT = ""; | |||
| SECTORDER_FLAGS = ""; | |||
| WARNING_CFLAGS = ( | |||
| "-Wmost", | |||
| "-Wno-four-char-constants", | |||
| "-Wno-unknown-pragmas", | |||
| ); | |||
| }; | |||
| name = Default; | |||
| }; | |||
| 4B35C4220D4731D1000DE7AE /* Development */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| @@ -11193,6 +11511,26 @@ | |||
| /* End XCBuildConfiguration section */ | |||
| /* Begin XCConfigurationList section */ | |||
| 4B0A28E20D52073D002EFF74 /* Build configuration list for PBXNativeTarget "jack_thread_wait" */ = { | |||
| isa = XCConfigurationList; | |||
| buildConfigurations = ( | |||
| 4B0A28E30D52073D002EFF74 /* Development */, | |||
| 4B0A28E40D52073D002EFF74 /* Deployment */, | |||
| 4B0A28E50D52073D002EFF74 /* Default */, | |||
| ); | |||
| defaultConfigurationIsVisible = 0; | |||
| defaultConfigurationName = Default; | |||
| }; | |||
| 4B0A29290D52108E002EFF74 /* Build configuration list for PBXNativeTarget "jack_thread_wait 64 bits" */ = { | |||
| isa = XCConfigurationList; | |||
| buildConfigurations = ( | |||
| 4B0A292A0D52108E002EFF74 /* Development */, | |||
| 4B0A292B0D52108E002EFF74 /* Deployment */, | |||
| 4B0A292C0D52108E002EFF74 /* Default */, | |||
| ); | |||
| defaultConfigurationIsVisible = 0; | |||
| defaultConfigurationName = Default; | |||
| }; | |||
| 4B35C4210D4731D1000DE7AE /* Build configuration list for PBXNativeTarget "jackdmp framework 64bits" */ = { | |||
| isa = XCConfigurationList; | |||
| buildConfigurations = ( | |||
| @@ -247,5 +247,12 @@ pthread_t JackWinThread::GetThreadID() | |||
| return fThread; | |||
| } | |||
| void JackWinThread::Terminate() | |||
| { | |||
| TerminateThread(fThread, 0); | |||
| WaitForSingleObject(fThread, INFINITE); | |||
| CloseHandle(fThread); | |||
| } | |||
| } // end of namespace | |||
| @@ -27,8 +27,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| namespace Jack | |||
| { | |||
| typedef DWORD (WINAPI *ThreadCallback)(void *arg); | |||
| typedef DWORD (WINAPI *ThreadCallback)(void *arg); | |||
| /*! | |||
| \brief Windows threads. | |||
| @@ -53,6 +53,7 @@ class JackWinThread : public JackThread | |||
| int StartSync(); | |||
| int Kill(); | |||
| int Stop(); | |||
| void Terminate(); | |||
| int AcquireRealTime(); | |||
| int AcquireRealTime(int priority) ; | |||
| @@ -62,7 +63,7 @@ class JackWinThread : public JackThread | |||
| static int AcquireRealTimeImp(pthread_t thread, int priority); | |||
| static int DropRealTimeImp(pthread_t thread); | |||
| static int StartImp(pthread_t* thread, int priority, int realtime, ThreadCallback start_routine, void* arg); | |||
| static int StartImp(pthread_t* thread, int priority, int realtime, ThreadCallback start_routine, void* arg); | |||
| }; | |||