24 #include <alsa/asoundlib.h>
26 #include "JackALSARawMidiDriver.h"
27 #include "JackALSARawMidiUtil.h"
28 #include "JackEngineControl.h"
29 #include "JackError.h"
30 #include "JackMidiUtil.h"
34 JackALSARawMidiDriver::JackALSARawMidiDriver(
const char *name,
36 JackLockedEngine *engine,
38 JackMidiDriver(name, alias, engine, table)
40 thread =
new JackThread(
this);
45 output_port_timeouts = 0;
49 JackALSARawMidiDriver::~JackALSARawMidiDriver()
55 JackALSARawMidiDriver::Attach()
58 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
60 jack_nframes_t latency = buffer_size;
64 latency_range.
max = latency;
65 latency_range.
min = latency;
66 for (
int i = 0; i < fCaptureChannels; i++) {
67 JackALSARawMidiInputPort *input_port = input_ports[i];
68 name = input_port->GetName();
69 fEngine->PortRegister(fClientControl.fRefNum, name,
70 JACK_DEFAULT_MIDI_TYPE,
71 CaptureDriverFlags, buffer_size, &index);
72 if (index == NO_PORT) {
73 jack_error(
"JackALSARawMidiDriver::Attach - cannot register input "
74 "port with name '%s'.", name);
78 alias = input_port->GetAlias();
79 port = fGraphManager->GetPort(index);
80 port->SetAlias(alias);
81 port->SetLatencyRange(JackCaptureLatency, &latency_range);
82 fCapturePortList[i] = index;
84 jack_info(
"JackALSARawMidiDriver::Attach - input port registered "
85 "(name='%s', alias='%s').", name, alias);
87 if (! fEngineControl->fSyncMode) {
88 latency += buffer_size;
89 latency_range.
max = latency;
90 latency_range.
min = latency;
92 for (
int i = 0; i < fPlaybackChannels; i++) {
93 JackALSARawMidiOutputPort *output_port = output_ports[i];
94 name = output_port->GetName();
95 fEngine->PortRegister(fClientControl.fRefNum, name,
96 JACK_DEFAULT_MIDI_TYPE,
97 PlaybackDriverFlags, buffer_size, &index);
98 if (index == NO_PORT) {
99 jack_error(
"JackALSARawMidiDriver::Attach - cannot register "
100 "output port with name '%s'.", name);
104 alias = output_port->GetAlias();
105 port = fGraphManager->GetPort(index);
106 port->SetAlias(alias);
107 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
108 fPlaybackPortList[i] = index;
110 jack_info(
"JackALSARawMidiDriver::Attach - output port registered "
111 "(name='%s', alias='%s').", name, alias);
117 JackALSARawMidiDriver::Close()
120 int result = JackMidiDriver::Close();
123 for (
int i = 0; i < fCaptureChannels; i++) {
124 delete input_ports[i];
126 delete[] input_ports;
130 for (
int i = 0; i < fPlaybackChannels; i++) {
131 delete output_ports[i];
133 delete[] output_ports;
140 JackALSARawMidiDriver::Execute()
142 jack_nframes_t timeout_frame = 0;
144 struct timespec timeout;
145 struct timespec *timeout_ptr;
146 if (! timeout_frame) {
169 timeout_ptr = &timeout;
170 jack_time_t next_time = GetTimeFromFrames(timeout_frame);
171 jack_time_t now = GetMicroSeconds();
172 if (next_time <= now) {
176 jack_time_t wait_time = next_time - now;
177 timeout.tv_sec = wait_time / 1000000;
178 timeout.tv_nsec = (wait_time % 1000000) * 1000;
181 int poll_result = ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
186 jack_nframes_t current_frame = GetCurrentFrame();
188 if (poll_result == -1) {
189 if (errno == EINTR) {
192 jack_error(
"JackALSARawMidiDriver::Execute - poll error: %s",
196 jack_nframes_t port_timeout;
203 for (
int i = 0; i < fPlaybackChannels; i++) {
204 port_timeout = output_port_timeouts[i];
205 if (port_timeout && (port_timeout <= current_frame)) {
206 if (! output_ports[i]->ProcessPollEvents(
false,
true,
208 jack_error(
"JackALSARawMidiDriver::Execute - a fatal "
209 "error occurred while processing ALSA "
213 output_port_timeouts[i] = port_timeout;
215 if (port_timeout && ((! timeout_frame) ||
216 (port_timeout < timeout_frame))) {
217 timeout_frame = port_timeout;
225 unsigned short revents = poll_fds[0].revents;
227 if (revents & (~ POLLHUP)) {
228 jack_error(
"JackALSARawMidiDriver::Execute - unexpected poll "
229 "event on pipe file descriptor.");
236 for (
int i = 0; i < fPlaybackChannels; i++) {
237 port_timeout = output_port_timeouts[i];
238 bool timeout = port_timeout && (port_timeout <= current_frame);
239 if (! output_ports[i]->ProcessPollEvents(
true, timeout,
241 jack_error(
"JackALSARawMidiDriver::Execute - a fatal error "
242 "occurred while processing ALSA output events.");
245 output_port_timeouts[i] = port_timeout;
246 if (port_timeout && ((! timeout_frame) ||
247 (port_timeout < timeout_frame))) {
248 timeout_frame = port_timeout;
257 for (
int i = 0; i < fCaptureChannels; i++) {
258 if (! input_ports[i]->ProcessPollEvents(current_frame)) {
259 jack_error(
"JackALSARawMidiDriver::Execute - a fatal error "
260 "occurred while processing ALSA input events.");
269 jack_info(
"JackALSARawMidiDriver::Execute - ALSA thread exiting.");
275 JackALSARawMidiDriver::
276 FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
277 std::vector<snd_rawmidi_info_t *> *out_info_list)
279 size_t length = in_info_list->size();
280 for (
size_t i = 0; i < length; i++) {
281 snd_rawmidi_info_free(in_info_list->at(i));
283 length = out_info_list->size();
284 for (
size_t i = 0; i < length; i++) {
285 snd_rawmidi_info_free(out_info_list->at(i));
290 JackALSARawMidiDriver::
291 GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
292 std::vector<snd_rawmidi_info_t *> *info_list)
294 snd_rawmidi_info_set_subdevice(info, 0);
295 int code = snd_ctl_rawmidi_info(control, info);
297 if (code != -ENOENT) {
298 HandleALSAError(
"GetDeviceInfo",
"snd_ctl_rawmidi_info", code);
302 unsigned int count = snd_rawmidi_info_get_subdevices_count(info);
303 for (
unsigned int i = 0; i < count; i++) {
304 snd_rawmidi_info_set_subdevice(info, i);
305 int code = snd_ctl_rawmidi_info(control, info);
307 HandleALSAError(
"GetDeviceInfo",
"snd_ctl_rawmidi_info", code);
310 snd_rawmidi_info_t *info_copy;
311 code = snd_rawmidi_info_malloc(&info_copy);
313 HandleALSAError(
"GetDeviceInfo",
"snd_rawmidi_info_malloc", code);
316 snd_rawmidi_info_copy(info_copy, info);
318 info_list->push_back(info_copy);
319 }
catch (std::bad_alloc &e) {
320 snd_rawmidi_info_free(info_copy);
321 jack_error(
"JackALSARawMidiDriver::GetDeviceInfo - "
322 "std::vector::push_back: %s", e.what());
328 JackALSARawMidiDriver::HandleALSAError(
const char *driver_func,
329 const char *alsa_func,
int code)
331 jack_error(
"JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func,
338 set_threaded_log_function();
339 if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) {
340 jack_error(
"JackALSARawMidiDriver::Init - could not acquire realtime "
341 "scheduling. Continuing anyway.");
347 JackALSARawMidiDriver::Open(
bool capturing,
bool playing,
int in_channels,
348 int out_channels,
bool monitor,
349 const char *capture_driver_name,
350 const char *playback_driver_name,
351 jack_nframes_t capture_latency,
352 jack_nframes_t playback_latency)
354 snd_rawmidi_info_t *info;
355 int code = snd_rawmidi_info_malloc(&info);
357 HandleALSAError(
"Open",
"snd_rawmidi_info_malloc", code);
360 std::vector<snd_rawmidi_info_t *> in_info_list;
361 std::vector<snd_rawmidi_info_t *> out_info_list;
362 for (
int card = -1;;) {
363 int code = snd_card_next(&card);
365 HandleALSAError(
"Open",
"snd_card_next", code);
372 snprintf(name,
sizeof(name),
"hw:%d", card);
374 code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK);
376 HandleALSAError(
"Open",
"snd_ctl_open", code);
379 for (
int device = -1;;) {
380 code = snd_ctl_rawmidi_next_device(control, &device);
382 HandleALSAError(
"Open",
"snd_ctl_rawmidi_next_device", code);
388 snd_rawmidi_info_set_device(info, device);
389 snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
390 GetDeviceInfo(control, info, &in_info_list);
391 snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
392 GetDeviceInfo(control, info, &out_info_list);
394 snd_ctl_close(control);
396 snd_rawmidi_info_free(info);
397 size_t potential_inputs = in_info_list.size();
398 size_t potential_outputs = out_info_list.size();
399 if (! (potential_inputs || potential_outputs)) {
400 jack_error(
"JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
401 "output ports found.");
402 FreeDeviceInfo(&in_info_list, &out_info_list);
405 size_t num_inputs = 0;
406 size_t num_outputs = 0;
407 if (potential_inputs) {
409 input_ports =
new JackALSARawMidiInputPort *[potential_inputs];
410 }
catch (std::exception e) {
411 jack_error(
"JackALSARawMidiDriver::Open - while creating input "
412 "port array: %s", e.what());
413 FreeDeviceInfo(&in_info_list, &out_info_list);
417 if (potential_outputs) {
419 output_ports =
new JackALSARawMidiOutputPort *[potential_outputs];
420 }
catch (std::exception e) {
421 jack_error(
"JackALSARawMidiDriver::Open - while creating output "
422 "port array: %s", e.what());
423 FreeDeviceInfo(&in_info_list, &out_info_list);
424 goto delete_input_ports;
427 for (
size_t i = 0; i < potential_inputs; i++) {
428 snd_rawmidi_info_t *info = in_info_list.at(i);
430 input_ports[num_inputs] =
new JackALSARawMidiInputPort(info, i);
432 }
catch (std::exception e) {
433 jack_error(
"JackALSARawMidiDriver::Open - while creating new "
434 "JackALSARawMidiInputPort: %s", e.what());
436 snd_rawmidi_info_free(info);
438 for (
size_t i = 0; i < potential_outputs; i++) {
439 snd_rawmidi_info_t *info = out_info_list.at(i);
441 output_ports[num_outputs] =
new JackALSARawMidiOutputPort(info, i);
443 }
catch (std::exception e) {
444 jack_error(
"JackALSARawMidiDriver::Open - while creating new "
445 "JackALSARawMidiOutputPort: %s", e.what());
447 snd_rawmidi_info_free(info);
449 if (! (num_inputs || num_outputs)) {
450 jack_error(
"JackALSARawMidiDriver::Open - none of the potential "
451 "inputs or outputs were successfully opened.");
452 }
else if (JackMidiDriver::Open(capturing, playing, num_inputs,
453 num_outputs, monitor, capture_driver_name,
454 playback_driver_name, capture_latency,
456 jack_error(
"JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
461 for (
size_t i = 0; i < num_outputs; i++) {
462 delete output_ports[i];
464 delete[] output_ports;
469 for (
size_t i = 0; i < num_inputs; i++) {
470 delete input_ports[i];
472 delete[] input_ports;
479 JackALSARawMidiDriver::Read()
481 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
482 for (
int i = 0; i < fCaptureChannels; i++) {
483 if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) {
491 JackALSARawMidiDriver::Start()
494 jack_info(
"JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");
496 JackMidiDriver::Start();
498 for (
int i = 0; i < fCaptureChannels; i++) {
499 poll_fd_count += input_ports[i]->GetPollDescriptorCount();
501 for (
int i = 0; i < fPlaybackChannels; i++) {
502 poll_fd_count += output_ports[i]->GetPollDescriptorCount();
505 poll_fds =
new pollfd[poll_fd_count];
506 }
catch (std::exception e) {
507 jack_error(
"JackALSARawMidiDriver::Start - creating poll descriptor "
508 "structures failed: %s", e.what());
511 if (fPlaybackChannels) {
513 output_port_timeouts =
new jack_nframes_t[fPlaybackChannels];
514 }
catch (std::exception e) {
515 jack_error(
"JackALSARawMidiDriver::Start - creating array for "
516 "output port timeout values failed: %s", e.what());
517 goto free_poll_descriptors;
520 struct pollfd *poll_fd_iter;
522 CreateNonBlockingPipe(fds);
523 }
catch (std::exception e) {
524 jack_error(
"JackALSARawMidiDriver::Start - while creating wake pipe: "
526 goto free_output_port_timeouts;
528 poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
529 poll_fds[0].fd = fds[0];
530 poll_fd_iter = poll_fds + 1;
531 for (
int i = 0; i < fCaptureChannels; i++) {
532 JackALSARawMidiInputPort *input_port = input_ports[i];
533 input_port->PopulatePollDescriptors(poll_fd_iter);
534 poll_fd_iter += input_port->GetPollDescriptorCount();
536 for (
int i = 0; i < fPlaybackChannels; i++) {
537 JackALSARawMidiOutputPort *output_port = output_ports[i];
538 output_port->PopulatePollDescriptors(poll_fd_iter);
539 poll_fd_iter += output_port->GetPollDescriptorCount();
540 output_port_timeouts[i] = 0;
543 jack_info(
"JackALSARawMidiDriver::Start - starting ALSA thread ...");
545 if (! thread->StartSync()) {
547 jack_info(
"JackALSARawMidiDriver::Start - started ALSA thread.");
551 jack_error(
"JackALSARawMidiDriver::Start - failed to start MIDI "
552 "processing thread.");
554 DestroyNonBlockingPipe(fds);
557 free_output_port_timeouts:
558 delete[] output_port_timeouts;
559 output_port_timeouts = 0;
560 free_poll_descriptors:
567 JackALSARawMidiDriver::Stop()
569 jack_info(
"JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");
570 JackMidiDriver::Stop();
578 switch (thread->GetStatus()) {
579 case JackThread::kIniting:
580 case JackThread::kStarting:
581 result = thread->Kill();
584 case JackThread::kRunning:
585 result = thread->Stop();
596 if (output_port_timeouts) {
597 delete[] output_port_timeouts;
598 output_port_timeouts = 0;
605 jack_error(
"JackALSARawMidiDriver::Stop - could not %s MIDI "
606 "processing thread.", verb);
612 JackALSARawMidiDriver::Write()
614 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
615 for (
int i = 0; i < fPlaybackChannels; i++) {
616 if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size)) {
628 driver_get_descriptor()
634 return jack_driver_descriptor_construct(
"alsarawmidi", JackDriverSlave,
"Alternative ALSA raw MIDI backend.", NULL);
644 if (driver->Open(1, 1, 0, 0,
false,
"midi in",
"midi out", 0, 0)) {