+static void* freewheel_thread(void* arg)
+{
+ PortAudioBackend* d = static_cast<PortAudioBackend*>(arg);
+ d->freewheel_process_thread ();
+ pthread_exit (0);
+ return 0;
+}
+
+bool
+PortAudioBackend::start_freewheel_process_thread ()
+{
+ if (pthread_create(&_pthread_freewheel, NULL, freewheel_thread, this)) {
+ DEBUG_AUDIO("Failed to create main audio thread\n");
+ return false;
+ }
+
+ int timeout = 5000;
+ while (!_freewheel_thread_active && --timeout > 0) { Glib::usleep (1000); }
+
+ if (timeout == 0 || !_freewheel_thread_active) {
+ DEBUG_AUDIO("Failed to start freewheel thread\n");
+ return false;
+ }
+ return true;
+}
+
+bool
+PortAudioBackend::stop_freewheel_process_thread ()
+{
+ void *status;
+
+ if (!_freewheel_thread_active) {
+ return true;
+ }
+
+ DEBUG_AUDIO("Signaling freewheel thread to stop\n");
+
+ pthread_mutex_lock (&_freewheel_mutex);
+ pthread_cond_signal (&_freewheel_signal);
+ pthread_mutex_unlock (&_freewheel_mutex);
+
+ if (pthread_join (_pthread_freewheel, &status) != 0) {
+ DEBUG_AUDIO("Failed to stop freewheel thread\n");
+ return false;
+ }
+
+ return true;
+}
+
+void*
+PortAudioBackend::freewheel_process_thread()
+{
+ _freewheel_thread_active = true;
+
+ bool first_run = false;
+
+ pthread_mutex_lock (&_freewheel_mutex);
+
+ while(_run) {
+ // check if we should run,
+ if (_freewheeling != _freewheel) {
+ if (!_freewheeling) {
+ DEBUG_AUDIO("Leaving freewheel\n");
+ _freewheel = false; // first mark as disabled
+ _reinit_thread_callback = true; // hand over _main_thread
+ _freewheel_ack = false; // prepare next handshake
+ _midiio->set_enabled(true);
+ engine.freewheel_callback (_freewheeling);
+ } else {
+ first_run = true;
+ _freewheel = true;
+ }
+ }
+
+ if (!_freewheel || !_freewheel_ack) {
+ // wait for a change, we use a timed wait to
+ // terminate early in case some error sets _run = 0
+ struct timeval tv;
+ struct timespec ts;
+ gettimeofday (&tv, NULL);
+ ts.tv_sec = tv.tv_sec + 3;
+ ts.tv_nsec = 0;
+ DEBUG_AUDIO("Waiting for freewheel change\n");
+ pthread_cond_timedwait (&_freewheel_signal, &_freewheel_mutex, &ts);
+ continue;
+ }
+
+ if (first_run) {
+ // tell the engine we're ready to GO.
+ engine.freewheel_callback (_freewheeling);
+ first_run = false;
+ _main_thread = pthread_self();
+ AudioEngine::thread_init_callback (this);
+ _midiio->set_enabled(false);
+ }
+
+ if (!blocking_process_freewheel()) {
+ break;
+ }
+
+ process_port_connection_changes();
+ }
+
+ pthread_mutex_unlock (&_freewheel_mutex);
+
+ _freewheel_thread_active = false;
+
+ if (_run) {
+ // engine.process_callback() returner error
+ engine.halted_callback("CoreAudio Freehweeling aborted.");
+ }
+ return 0;
+}
+