int JackPortAudioDriver::Render(const void* inputBuffer, void* outputBuffer, PaStreamCallbackFlags statusFlags) { fInputBuffer = (jack_default_audio_sample_t**)inputBuffer; fOutputBuffer = (jack_default_audio_sample_t**)outputBuffer; if (statusFlags) { if (statusFlags & paOutputUnderflow) jack_error("JackPortAudioDriver::Render paOutputUnderflow"); if (statusFlags & paInputUnderflow) jack_error("JackPortAudioDriver::Render paInputUnderflow"); if (statusFlags & paOutputOverflow) jack_error("JackPortAudioDriver::Render paOutputOverflow"); if (statusFlags & paInputOverflow) jack_error("JackPortAudioDriver::Render paInputOverflow"); if (statusFlags & paPrimingOutput) jack_error("JackPortAudioDriver::Render paOutputUnderflow"); if (statusFlags != paPrimingOutput) { jack_time_t cur_time = GetMicroSeconds(); NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... } } // Setup threaded based log function set_threaded_log_function(); CycleTakeBeginTime(); return (Process() == 0) ? paContinue : paAbort; }
/*! \brief Called once when the thread starts. */ bool JackClient::Init() { /* Execute buffer_size callback. Since StartThread uses fThread.StartSync, we are sure that buffer_size callback is executed before StartThread returns (and then IsActive will be true). So no RT callback can be called at the same time. */ jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", GetEngineControl()->fBufferSize); if (fBufferSize) { fBufferSize(GetEngineControl()->fBufferSize, fBufferSizeArg); } // Init callback InitAux(); // Setup context if (!jack_tls_set(JackGlobals::fRealTimeThread, this)) { jack_error("Failed to set thread realtime key"); } // Setup RT if (GetEngineControl()->fRealTime) { set_threaded_log_function(); SetupRealTime(); } return true; }
int JackPortAudioDriver::Render(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData) { JackPortAudioDriver* driver = (JackPortAudioDriver*)userData; driver->fInputBuffer = (jack_default_audio_sample_t**)inputBuffer; driver->fOutputBuffer = (jack_default_audio_sample_t**)outputBuffer; //MMCSSAcquireRealTime(GetCurrentThread()); if (statusFlags) { if (statusFlags & paOutputUnderflow) jack_error("JackPortAudioDriver::Render paOutputUnderflow"); if (statusFlags & paInputUnderflow) jack_error("JackPortAudioDriver::Render paInputUnderflow"); if (statusFlags & paOutputOverflow) jack_error("JackPortAudioDriver::Render paOutputOverflow"); if (statusFlags & paInputOverflow) jack_error("JackPortAudioDriver::Render paInputOverflow"); if (statusFlags & paPrimingOutput) jack_error("JackPortAudioDriver::Render paOutputUnderflow"); if (statusFlags != paPrimingOutput) { jack_time_t cur_time = GetMicroSeconds(); driver->NotifyXRun(cur_time, float(cur_time - driver->fBeginDateUst)); // Better this value than nothing... } } // Setup threadded based log function set_threaded_log_function(); driver->CycleTakeBeginTime(); return (driver->Process() == 0) ? paContinue : paAbort; }
bool JackNetAdapter::Init() { jack_log("JackNetAdapter::Init"); //init network connection if (!JackNetSlaveInterface::Init()) { jack_error("JackNetSlaveInterface::Init() error..."); return false; } //then set global parameters if (!SetParams()) { jack_error("SetParams error..."); return false; } //set buffers if (fCaptureChannels > 0) { fSoftCaptureBuffer = new sample_t*[fCaptureChannels]; for (int port_index = 0; port_index < fCaptureChannels; port_index++) { fSoftCaptureBuffer[port_index] = new sample_t[fParams.fPeriodSize]; fNetAudioCaptureBuffer->SetBuffer(port_index, fSoftCaptureBuffer[port_index]); } } if (fPlaybackChannels > 0) { fSoftPlaybackBuffer = new sample_t*[fPlaybackChannels]; for (int port_index = 0; port_index < fPlaybackChannels; port_index++) { fSoftPlaybackBuffer[port_index] = new sample_t[fParams.fPeriodSize]; fNetAudioPlaybackBuffer->SetBuffer(port_index, fSoftPlaybackBuffer[port_index]); } } //set audio adapter parameters SetAdaptedBufferSize(fParams.fPeriodSize); SetAdaptedSampleRate(fParams.fSampleRate); // Will do "something" on OSX only... fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) { jack_error("AcquireSelfRealTime error"); } else { set_threaded_log_function(); } //init done, display parameters SessionParamsDisplay(&fParams); return true; }
void JackThreadedDriver::SetRealTime() { if (fDriver->IsRealTime()) { jack_log("JackThreadedDriver::Init real-time"); // Will do "something" on OSX only... GetEngineControl()->fPeriod = GetEngineControl()->fConstraint = GetEngineControl()->fPeriodUsecs * 1000; GetEngineControl()->fComputation = JackTools::ComputationMicroSec(GetEngineControl()->fBufferSize) * 1000; fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); if (fThread.AcquireSelfRealTime(GetEngineControl()->fServerPriority) < 0) { jack_error("AcquireSelfRealTime error"); } else { set_threaded_log_function(); } } else { jack_log("JackThreadedDriver::Init non-realtime"); } }
bool JackWaitThreadedDriver::Execute() { try { // Process a null cycle until NetDriver has started while (!fStarter.fRunning && fThread.GetStatus() == JackThread::kRunning) { fDriver->ProcessNull(); } // Set RT if (fDriver->IsRealTime()) { jack_log("JackWaitThreadedDriver::Init IsRealTime"); // Will do "something" on OSX only... GetEngineControl()->fPeriod = GetEngineControl()->fConstraint = GetEngineControl()->fPeriodUsecs * 1000; fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); if (fThread.AcquireSelfRealTime(GetEngineControl()->fServerPriority) < 0) { jack_error("AcquireSelfRealTime error"); } else { set_threaded_log_function(); } } // Switch to keep running even in case of error while (fThread.GetStatus() == JackThread::kRunning) { fDriver->Process(); } return false; } catch (JackNetException& e) { e.PrintMessage(); jack_info("Driver is restarted"); fThread.DropSelfRealTime(); // Thread in kIniting status again... fThread.SetStatus(JackThread::kIniting); if (Init()) { // Thread in kRunning status again... fThread.SetStatus(JackThread::kRunning); return true; } else { return false; } } }
static void *midi_thread(void *arg) { midi_stream_t *str = arg; alsa_rawmidi_t *midi = str->owner; struct pollfd pfds[MAX_PFDS]; int npfds; jack_time_t wait_nsec = 1000*1000*1000; // 1 sec process_midi_t proc; proc.midi = midi; proc.mode = str->mode; pfds[0].fd = str->wake_pipe[0]; pfds[0].events = POLLIN|POLLERR|POLLNVAL; npfds = 1; if (jack_is_realtime(midi->client)) set_threaded_log_function(); //debug_log("midi_thread(%s): enter", str->name); while (midi->keep_walking) { int poll_timeout; int wait_nanosleep; int r=1, w=1; // read,write pos in pfds int rp=0, wp=0; // read, write pos in ports // sleep //if (wait_nsec != 1000*1000*1000) { // debug_log("midi_thread(%s): ", str->name); // assert (wait_nsec == 1000*1000*1000); //} poll_timeout = wait_nsec / (1000*1000); wait_nanosleep = wait_nsec % (1000*1000); if (wait_nanosleep > NANOSLEEP_RESOLUTION) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = wait_nanosleep; clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); } int res = poll((struct pollfd*)&pfds, npfds, poll_timeout); //debug_log("midi_thread(%s): poll exit: %d", str->name, res); if (!midi->keep_walking) break; if (res < 0) { if (errno == EINTR) continue; error_log("midi_thread(%s) poll failed: %s", str->name, strerror(errno)); break; } // check wakeup pipe if (pfds[0].revents & ~POLLIN) break; if (pfds[0].revents & POLLIN) { char c; read(pfds[0].fd, &c, 1); } // add new ports while (jack_ringbuffer_read_space(str->midi.new_ports) >= sizeof(midi_port_t*) && str->midi.nports < MAX_PORTS) { midi_port_t *port; jack_ringbuffer_read(str->midi.new_ports, (char*)&port, sizeof(port)); str->midi.ports[str->midi.nports++] = port; debug_log("midi_thread(%s): added port %s", str->name, port->name); } // if (res == 0) // continue; // process ports proc.cur_time = 0; //jack_frame_time(midi->client); proc.next_time = NFRAMES_INF; for (rp = 0; rp < str->midi.nports; ++rp) { midi_port_t *port = str->midi.ports[rp]; proc.cur_time = jack_frame_time(midi->client); proc.port = port; proc.rpfds = &pfds[r]; proc.wpfds = &pfds[w]; proc.max_pfds = MAX_PFDS - w; r += port->npfds; if (!(str->process_midi)(&proc)) { port->state = PORT_REMOVED_FROM_MIDI; // this signals to jack thread continue; // this effectively removes port from array } w += port->npfds; if (rp != wp) str->midi.ports[wp] = port; ++wp; } if (str->midi.nports != wp) debug_log("midi_%s: nports %d -> %d", str->name, str->midi.nports, wp); str->midi.nports = wp; if (npfds != w) debug_log("midi_%s: npfds %d -> %d", str->name, npfds, w); npfds = w; /* * Input : ports do not set proc.next_time. * Output: port sets proc.next_time ONLY if it does not have queued data. * So, zero timeout will not cause busy-looping. */ if (proc.next_time < proc.cur_time) { debug_log("%s: late: next_time = %d, cur_time = %d", str->name, (int)proc.next_time, (int)proc.cur_time); wait_nsec = 0; // we are late } else if (proc.next_time != NFRAMES_INF) { jack_time_t wait_frames = proc.next_time - proc.cur_time; jack_nframes_t rate = jack_get_sample_rate(midi->client); wait_nsec = (wait_frames * (1000*1000*1000)) / rate; debug_log("midi_%s: timeout = %d", str->name, (int)wait_frames); } else wait_nsec = 1000*1000*1000; //debug_log("midi_thread(%s): wait_nsec = %lld", str->name, wait_nsec); } return NULL; }