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"
31 #include "driver_interface.h"
35 JackALSARawMidiDriver::JackALSARawMidiDriver(
const char *name,
37 JackLockedEngine *engine,
39 JackMidiDriver(name, alias, engine, table)
41 thread =
new JackThread(
this);
46 output_port_timeouts = 0;
50 JackALSARawMidiDriver::~JackALSARawMidiDriver()
56 JackALSARawMidiDriver::Attach()
59 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
61 jack_nframes_t latency = buffer_size;
65 latency_range.
max = latency;
66 latency_range.
min = latency;
67 for (
int i = 0; i < fCaptureChannels; i++) {
68 JackALSARawMidiInputPort *input_port = input_ports[i];
69 name = input_port->GetName();
70 fEngine->PortRegister(fClientControl.fRefNum, name,
71 JACK_DEFAULT_MIDI_TYPE,
72 CaptureDriverFlags, buffer_size, &index);
73 if (index == NO_PORT) {
74 jack_error(
"JackALSARawMidiDriver::Attach - cannot register input "
75 "port with name '%s'.", name);
79 alias = input_port->GetAlias();
80 port = fGraphManager->GetPort(index);
81 port->SetAlias(alias);
82 port->SetLatencyRange(JackCaptureLatency, &latency_range);
83 fCapturePortList[i] = index;
85 jack_info(
"JackALSARawMidiDriver::Attach - input port registered "
86 "(name='%s', alias='%s').", name, alias);
88 if (! fEngineControl->fSyncMode) {
89 latency += buffer_size;
90 latency_range.
max = latency;
91 latency_range.
min = latency;
93 for (
int i = 0; i < fPlaybackChannels; i++) {
94 JackALSARawMidiOutputPort *output_port = output_ports[i];
95 name = output_port->GetName();
96 fEngine->PortRegister(fClientControl.fRefNum, name,
97 JACK_DEFAULT_MIDI_TYPE,
98 PlaybackDriverFlags, buffer_size, &index);
99 if (index == NO_PORT) {
100 jack_error(
"JackALSARawMidiDriver::Attach - cannot register "
101 "output port with name '%s'.", name);
105 alias = output_port->GetAlias();
106 port = fGraphManager->GetPort(index);
107 port->SetAlias(alias);
108 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
109 fPlaybackPortList[i] = index;
111 jack_info(
"JackALSARawMidiDriver::Attach - output port registered "
112 "(name='%s', alias='%s').", name, alias);
118 JackALSARawMidiDriver::Close()
121 int result = JackMidiDriver::Close();
124 for (
int i = 0; i < fCaptureChannels; i++) {
125 delete input_ports[i];
127 delete[] input_ports;
131 for (
int i = 0; i < fPlaybackChannels; i++) {
132 delete output_ports[i];
134 delete[] output_ports;
141 JackALSARawMidiDriver::Execute()
143 jack_nframes_t timeout_frame = 0;
145 struct timespec timeout;
146 struct timespec *timeout_ptr;
147 if (! timeout_frame) {
170 timeout_ptr = &timeout;
171 jack_time_t next_time = GetTimeFromFrames(timeout_frame);
172 jack_time_t now = GetMicroSeconds();
173 if (next_time <= now) {
177 jack_time_t wait_time = next_time - now;
178 timeout.tv_sec = wait_time / 1000000;
179 timeout.tv_nsec = (wait_time % 1000000) * 1000;
182 int poll_result = ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
187 jack_nframes_t current_frame = GetCurrentFrame();
189 if (poll_result == -1) {
190 if (errno == EINTR) {
193 jack_error(
"JackALSARawMidiDriver::Execute - poll error: %s",
197 jack_nframes_t port_timeout;
204 for (
int i = 0; i < fPlaybackChannels; i++) {
205 port_timeout = output_port_timeouts[i];
206 if (port_timeout && (port_timeout <= current_frame)) {
207 if (! output_ports[i]->ProcessPollEvents(
false,
true,
209 jack_error(
"JackALSARawMidiDriver::Execute - a fatal "
210 "error occurred while processing ALSA "
214 output_port_timeouts[i] = port_timeout;
216 if (port_timeout && ((! timeout_frame) ||
217 (port_timeout < timeout_frame))) {
218 timeout_frame = port_timeout;
226 unsigned short revents = poll_fds[0].revents;
228 if (revents & (~ POLLHUP)) {
229 jack_error(
"JackALSARawMidiDriver::Execute - unexpected poll "
230 "event on pipe file descriptor.");
237 for (
int i = 0; i < fPlaybackChannels; i++) {
238 port_timeout = output_port_timeouts[i];
239 bool timeout = port_timeout && (port_timeout <= current_frame);
240 if (! output_ports[i]->ProcessPollEvents(
true, timeout,
242 jack_error(
"JackALSARawMidiDriver::Execute - a fatal error "
243 "occurred while processing ALSA output events.");
246 output_port_timeouts[i] = port_timeout;
247 if (port_timeout && ((! timeout_frame) ||
248 (port_timeout < timeout_frame))) {
249 timeout_frame = port_timeout;
258 for (
int i = 0; i < fCaptureChannels; i++) {
259 if (! input_ports[i]->ProcessPollEvents(current_frame)) {
260 jack_error(
"JackALSARawMidiDriver::Execute - a fatal error "
261 "occurred while processing ALSA input events.");
270 jack_info(
"JackALSARawMidiDriver::Execute - ALSA thread exiting.");
276 JackALSARawMidiDriver::
277 FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
278 std::vector<snd_rawmidi_info_t *> *out_info_list)
280 size_t length = in_info_list->size();
281 for (
size_t i = 0; i < length; i++) {
282 snd_rawmidi_info_free(in_info_list->at(i));
284 length = out_info_list->size();
285 for (
size_t i = 0; i < length; i++) {
286 snd_rawmidi_info_free(out_info_list->at(i));
291 JackALSARawMidiDriver::
292 GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
293 std::vector<snd_rawmidi_info_t *> *info_list)
295 snd_rawmidi_info_set_subdevice(info, 0);
296 int code = snd_ctl_rawmidi_info(control, info);
298 if (code != -ENOENT) {
299 HandleALSAError(
"GetDeviceInfo",
"snd_ctl_rawmidi_info", code);
303 unsigned int count = snd_rawmidi_info_get_subdevices_count(info);
304 for (
unsigned int i = 0; i < count; i++) {
305 snd_rawmidi_info_set_subdevice(info, i);
306 int code = snd_ctl_rawmidi_info(control, info);
308 HandleALSAError(
"GetDeviceInfo",
"snd_ctl_rawmidi_info", code);
311 snd_rawmidi_info_t *info_copy;
312 code = snd_rawmidi_info_malloc(&info_copy);
314 HandleALSAError(
"GetDeviceInfo",
"snd_rawmidi_info_malloc", code);
317 snd_rawmidi_info_copy(info_copy, info);
319 info_list->push_back(info_copy);
320 }
catch (std::bad_alloc &e) {
321 snd_rawmidi_info_free(info_copy);
322 jack_error(
"JackALSARawMidiDriver::GetDeviceInfo - "
323 "std::vector::push_back: %s", e.what());
329 JackALSARawMidiDriver::HandleALSAError(
const char *driver_func,
330 const char *alsa_func,
int code)
332 jack_error(
"JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func,
339 set_threaded_log_function();
340 if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) {
341 jack_error(
"JackALSARawMidiDriver::Init - could not acquire realtime "
342 "scheduling. Continuing anyway.");
348 JackALSARawMidiDriver::Open(
bool capturing,
bool playing,
int in_channels,
349 int out_channels,
bool monitor,
350 const char *capture_driver_name,
351 const char *playback_driver_name,
352 jack_nframes_t capture_latency,
353 jack_nframes_t playback_latency)
355 snd_rawmidi_info_t *info;
356 int code = snd_rawmidi_info_malloc(&info);
358 HandleALSAError(
"Open",
"snd_rawmidi_info_malloc", code);
361 std::vector<snd_rawmidi_info_t *> in_info_list;
362 std::vector<snd_rawmidi_info_t *> out_info_list;
363 for (
int card = -1;;) {
364 int code = snd_card_next(&card);
366 HandleALSAError(
"Open",
"snd_card_next", code);
373 snprintf(name,
sizeof(name),
"hw:%d", card);
375 code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK);
377 HandleALSAError(
"Open",
"snd_ctl_open", code);
380 for (
int device = -1;;) {
381 code = snd_ctl_rawmidi_next_device(control, &device);
383 HandleALSAError(
"Open",
"snd_ctl_rawmidi_next_device", code);
389 snd_rawmidi_info_set_device(info, device);
390 snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
391 GetDeviceInfo(control, info, &in_info_list);
392 snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
393 GetDeviceInfo(control, info, &out_info_list);
395 snd_ctl_close(control);
397 snd_rawmidi_info_free(info);
398 size_t potential_inputs = in_info_list.size();
399 size_t potential_outputs = out_info_list.size();
400 if (! (potential_inputs || potential_outputs)) {
401 jack_error(
"JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
402 "output ports found.");
403 FreeDeviceInfo(&in_info_list, &out_info_list);
406 size_t num_inputs = 0;
407 size_t num_outputs = 0;
408 if (potential_inputs) {
410 input_ports =
new JackALSARawMidiInputPort *[potential_inputs];
411 }
catch (std::exception e) {
412 jack_error(
"JackALSARawMidiDriver::Open - while creating input "
413 "port array: %s", e.what());
414 FreeDeviceInfo(&in_info_list, &out_info_list);
418 if (potential_outputs) {
420 output_ports =
new JackALSARawMidiOutputPort *[potential_outputs];
421 }
catch (std::exception e) {
422 jack_error(
"JackALSARawMidiDriver::Open - while creating output "
423 "port array: %s", e.what());
424 FreeDeviceInfo(&in_info_list, &out_info_list);
425 goto delete_input_ports;
428 for (
size_t i = 0; i < potential_inputs; i++) {
429 snd_rawmidi_info_t *info = in_info_list.at(i);
431 input_ports[num_inputs] =
new JackALSARawMidiInputPort(info, i);
433 }
catch (std::exception e) {
434 jack_error(
"JackALSARawMidiDriver::Open - while creating new "
435 "JackALSARawMidiInputPort: %s", e.what());
437 snd_rawmidi_info_free(info);
439 for (
size_t i = 0; i < potential_outputs; i++) {
440 snd_rawmidi_info_t *info = out_info_list.at(i);
442 output_ports[num_outputs] =
new JackALSARawMidiOutputPort(info, i);
444 }
catch (std::exception e) {
445 jack_error(
"JackALSARawMidiDriver::Open - while creating new "
446 "JackALSARawMidiOutputPort: %s", e.what());
448 snd_rawmidi_info_free(info);
450 if (! (num_inputs || num_outputs)) {
451 jack_error(
"JackALSARawMidiDriver::Open - none of the potential "
452 "inputs or outputs were successfully opened.");
453 }
else if (JackMidiDriver::Open(capturing, playing, num_inputs,
454 num_outputs, monitor, capture_driver_name,
455 playback_driver_name, capture_latency,
457 jack_error(
"JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
462 for (
size_t i = 0; i < num_outputs; i++) {
463 delete output_ports[i];
465 delete[] output_ports;
470 for (
size_t i = 0; i < num_inputs; i++) {
471 delete input_ports[i];
473 delete[] input_ports;
480 JackALSARawMidiDriver::Read()
482 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
483 for (
int i = 0; i < fCaptureChannels; i++) {
484 if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) {
492 JackALSARawMidiDriver::Start()
495 jack_info(
"JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");
497 JackMidiDriver::Start();
499 for (
int i = 0; i < fCaptureChannels; i++) {
500 poll_fd_count += input_ports[i]->GetPollDescriptorCount();
502 for (
int i = 0; i < fPlaybackChannels; i++) {
503 poll_fd_count += output_ports[i]->GetPollDescriptorCount();
506 poll_fds =
new pollfd[poll_fd_count];
507 }
catch (std::exception e) {
508 jack_error(
"JackALSARawMidiDriver::Start - creating poll descriptor "
509 "structures failed: %s", e.what());
512 if (fPlaybackChannels) {
514 output_port_timeouts =
new jack_nframes_t[fPlaybackChannels];
515 }
catch (std::exception e) {
516 jack_error(
"JackALSARawMidiDriver::Start - creating array for "
517 "output port timeout values failed: %s", e.what());
518 goto free_poll_descriptors;
521 struct pollfd *poll_fd_iter;
523 CreateNonBlockingPipe(fds);
524 }
catch (std::exception e) {
525 jack_error(
"JackALSARawMidiDriver::Start - while creating wake pipe: "
527 goto free_output_port_timeouts;
529 poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
530 poll_fds[0].fd = fds[0];
531 poll_fd_iter = poll_fds + 1;
532 for (
int i = 0; i < fCaptureChannels; i++) {
533 JackALSARawMidiInputPort *input_port = input_ports[i];
534 input_port->PopulatePollDescriptors(poll_fd_iter);
535 poll_fd_iter += input_port->GetPollDescriptorCount();
537 for (
int i = 0; i < fPlaybackChannels; i++) {
538 JackALSARawMidiOutputPort *output_port = output_ports[i];
539 output_port->PopulatePollDescriptors(poll_fd_iter);
540 poll_fd_iter += output_port->GetPollDescriptorCount();
541 output_port_timeouts[i] = 0;
544 jack_info(
"JackALSARawMidiDriver::Start - starting ALSA thread ...");
546 if (! thread->StartSync()) {
548 jack_info(
"JackALSARawMidiDriver::Start - started ALSA thread.");
552 jack_error(
"JackALSARawMidiDriver::Start - failed to start MIDI "
553 "processing thread.");
555 DestroyNonBlockingPipe(fds);
558 free_output_port_timeouts:
559 delete[] output_port_timeouts;
560 output_port_timeouts = 0;
561 free_poll_descriptors:
568 JackALSARawMidiDriver::Stop()
570 jack_info(
"JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");
571 JackMidiDriver::Stop();
579 switch (thread->GetStatus()) {
580 case JackThread::kIniting:
581 case JackThread::kStarting:
582 result = thread->Kill();
585 case JackThread::kRunning:
586 result = thread->Stop();
597 if (output_port_timeouts) {
598 delete[] output_port_timeouts;
599 output_port_timeouts = 0;
606 jack_error(
"JackALSARawMidiDriver::Stop - could not %s MIDI "
607 "processing thread.", verb);
613 JackALSARawMidiDriver::Write()
615 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
616 for (
int i = 0; i < fPlaybackChannels; i++) {
617 if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size)) {
629 driver_get_descriptor()
635 return jack_driver_descriptor_construct(
"alsarawmidi", JackDriverSlave,
"Alternative ALSA raw MIDI backend.", NULL);
645 if (driver->Open(1, 1, 0, 0,
false,
"midi in",
"midi out", 0, 0)) {
Inter process synchronization using using Mach semaphore.
Locked Engine, access to methods is serialized using a mutex.
SERVER_EXPORT void jack_error(const char *fmt,...)
SERVER_EXPORT void jack_info(const char *fmt,...)
The base interface for drivers clients.