+ if (_use_blocking_api) {
+ if (!start_blocking_process_thread()) {
+ return ProcessThreadStartError;
+ }
+ } else {
+ if (_pcmio->start_stream() != paNoError) {
+ DEBUG_AUDIO("Unable to start stream\n");
+ return AudioDeviceOpenError;
+ }
+
+ if (!start_freewheel_process_thread()) {
+ DEBUG_AUDIO("Unable to start freewheel thread\n");
+ stop();
+ return ProcessThreadStartError;
+ }
+
+ /* wait for backend to become active */
+ int timeout = 5000;
+ while (!_active && --timeout > 0) { Glib::usleep (1000); }
+
+ if (timeout == 0 || !_active) {
+ PBD::error << _("PortAudio:: failed to start device.") << endmsg;
+ stop ();
+ return ProcessThreadStartError;
+ }
+ }
+
+ return NoError;
+}
+
+int
+PortAudioBackend::portaudio_callback(const void* input,
+ void* output,
+ unsigned long sample_count,
+ const PaStreamCallbackTimeInfo* time_info,
+ PaStreamCallbackFlags status_flags,
+ void* user_data)
+{
+ PortAudioBackend* pa_backend = static_cast<PortAudioBackend*>(user_data);
+
+ if (!pa_backend->process_callback((const float*)input,
+ (float*)output,
+ sample_count,
+ time_info,
+ status_flags)) {
+ return paAbort;
+ }
+
+ return paContinue;
+}
+
+bool
+PortAudioBackend::process_callback(const float* input,
+ float* output,
+ uint32_t sample_count,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags)
+{
+ _active = true;
+
+ _dsp_calc.set_start_timestamp_us (PBD::get_microseconds());
+
+ if (_run && _freewheel && !_freewheel_ack) {
+ // acknowledge freewheeling; hand-over thread ID
+ pthread_mutex_lock (&_freewheel_mutex);
+ if (_freewheel) {
+ DEBUG_AUDIO("Setting _freewheel_ack = true;\n");
+ _freewheel_ack = true;
+ }
+ DEBUG_AUDIO("Signalling freewheel thread\n");
+ pthread_cond_signal (&_freewheel_signal);
+ pthread_mutex_unlock (&_freewheel_mutex);
+ }
+
+ if (statusFlags & paInputUnderflow ||
+ statusFlags & paInputOverflow ||
+ statusFlags & paOutputUnderflow ||
+ statusFlags & paOutputOverflow ) {
+ DEBUG_AUDIO("PortAudio: Xrun\n");
+ engine.Xrun();
+ return true;
+ }
+
+ if (!_run || _freewheel) {
+ memset(output, 0, sample_count * sizeof(float) * _system_outputs.size());
+ return true;
+ }
+
+ bool in_main_thread = pthread_equal(_main_thread, pthread_self());
+
+ if (_reinit_thread_callback || !in_main_thread) {
+ _reinit_thread_callback = false;
+ _main_thread = pthread_self();
+ AudioEngine::thread_init_callback (this);
+ }
+
+ process_port_connection_changes();
+
+ return blocking_process_main (input, output);
+}
+
+bool
+PortAudioBackend::start_blocking_process_thread ()
+{
+ if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, -20, 100000,
+ &_main_blocking_thread, blocking_thread_func, this))