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 fEngine->PortSetDeviceMetadata(fClientControl.fRefNum, index,
84 input_port->GetDeviceName());
85 fCapturePortList[i] = index;
87 jack_info(
"JackALSARawMidiDriver::Attach - input port registered "
88 "(name='%s', alias='%s').", name, alias);
90 if (! fEngineControl->fSyncMode) {
91 latency += buffer_size;
92 latency_range.
max = latency;
93 latency_range.
min = latency;
95 for (
int i = 0; i < fPlaybackChannels; i++) {
96 JackALSARawMidiOutputPort *output_port = output_ports[i];
97 name = output_port->GetName();
98 fEngine->PortRegister(fClientControl.fRefNum, name,
99 JACK_DEFAULT_MIDI_TYPE,
100 PlaybackDriverFlags, buffer_size, &index);
101 if (index == NO_PORT) {
102 jack_error(
"JackALSARawMidiDriver::Attach - cannot register "
103 "output port with name '%s'.", name);
107 alias = output_port->GetAlias();
108 port = fGraphManager->GetPort(index);
109 port->SetAlias(alias);
110 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
111 fEngine->PortSetDeviceMetadata(fClientControl.fRefNum, index,
112 output_port->GetDeviceName());
113 fPlaybackPortList[i] = index;
115 jack_info(
"JackALSARawMidiDriver::Attach - output port registered "
116 "(name='%s', alias='%s').", name, alias);
122 JackALSARawMidiDriver::Close()
125 int result = JackMidiDriver::Close();
128 for (
int i = 0; i < fCaptureChannels; i++) {
129 delete input_ports[i];
131 delete[] input_ports;
135 for (
int i = 0; i < fPlaybackChannels; i++) {
136 delete output_ports[i];
138 delete[] output_ports;
145 JackALSARawMidiDriver::Execute()
147 jack_nframes_t timeout_frame = 0;
149 struct timespec timeout;
150 struct timespec *timeout_ptr;
151 if (! timeout_frame) {
174 timeout_ptr = &timeout;
175 jack_time_t next_time = GetTimeFromFrames(timeout_frame);
176 jack_time_t now = GetMicroSeconds();
177 if (next_time <= now) {
181 jack_time_t wait_time = next_time - now;
182 timeout.tv_sec = wait_time / 1000000;
183 timeout.tv_nsec = (wait_time % 1000000) * 1000;
186 int poll_result = ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
191 jack_nframes_t current_frame = GetCurrentFrame();
193 if (poll_result == -1) {
194 if (errno == EINTR) {
197 jack_error(
"JackALSARawMidiDriver::Execute - poll error: %s",
201 jack_nframes_t port_timeout;
208 for (
int i = 0; i < fPlaybackChannels; i++) {
209 port_timeout = output_port_timeouts[i];
210 if (port_timeout && (port_timeout <= current_frame)) {
211 if (! output_ports[i]->ProcessPollEvents(
false,
true,
213 jack_error(
"JackALSARawMidiDriver::Execute - a fatal "
214 "error occurred while processing ALSA "
218 output_port_timeouts[i] = port_timeout;
220 if (port_timeout && ((! timeout_frame) ||
221 (port_timeout < timeout_frame))) {
222 timeout_frame = port_timeout;
230 unsigned short revents = poll_fds[0].revents;
232 if (revents & (~ POLLHUP)) {
233 jack_error(
"JackALSARawMidiDriver::Execute - unexpected poll "
234 "event on pipe file descriptor.");
241 for (
int i = 0; i < fPlaybackChannels; i++) {
242 port_timeout = output_port_timeouts[i];
243 bool timeout = port_timeout && (port_timeout <= current_frame);
244 if (! output_ports[i]->ProcessPollEvents(
true, timeout,
246 jack_error(
"JackALSARawMidiDriver::Execute - a fatal error "
247 "occurred while processing ALSA output events.");
250 output_port_timeouts[i] = port_timeout;
251 if (port_timeout && ((! timeout_frame) ||
252 (port_timeout < timeout_frame))) {
253 timeout_frame = port_timeout;
262 for (
int i = 0; i < fCaptureChannels; i++) {
263 if (! input_ports[i]->ProcessPollEvents(current_frame)) {
264 jack_error(
"JackALSARawMidiDriver::Execute - a fatal error "
265 "occurred while processing ALSA input events.");
274 jack_info(
"JackALSARawMidiDriver::Execute - ALSA thread exiting.");
280 JackALSARawMidiDriver::
281 FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
282 std::vector<snd_rawmidi_info_t *> *out_info_list)
284 size_t length = in_info_list->size();
285 for (
size_t i = 0; i < length; i++) {
286 snd_rawmidi_info_free(in_info_list->at(i));
288 length = out_info_list->size();
289 for (
size_t i = 0; i < length; i++) {
290 snd_rawmidi_info_free(out_info_list->at(i));
295 JackALSARawMidiDriver::
296 GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
297 std::vector<snd_rawmidi_info_t *> *info_list)
299 snd_rawmidi_info_set_subdevice(info, 0);
300 int code = snd_ctl_rawmidi_info(control, info);
302 if (code != -ENOENT) {
303 HandleALSAError(
"GetDeviceInfo",
"snd_ctl_rawmidi_info", code);
307 unsigned int count = snd_rawmidi_info_get_subdevices_count(info);
308 for (
unsigned int i = 0; i < count; i++) {
309 snd_rawmidi_info_set_subdevice(info, i);
310 int code = snd_ctl_rawmidi_info(control, info);
312 HandleALSAError(
"GetDeviceInfo",
"snd_ctl_rawmidi_info", code);
315 snd_rawmidi_info_t *info_copy;
316 code = snd_rawmidi_info_malloc(&info_copy);
318 HandleALSAError(
"GetDeviceInfo",
"snd_rawmidi_info_malloc", code);
321 snd_rawmidi_info_copy(info_copy, info);
323 info_list->push_back(info_copy);
324 }
catch (std::bad_alloc &e) {
325 snd_rawmidi_info_free(info_copy);
326 jack_error(
"JackALSARawMidiDriver::GetDeviceInfo - "
327 "std::vector::push_back: %s", e.what());
333 JackALSARawMidiDriver::HandleALSAError(
const char *driver_func,
334 const char *alsa_func,
int code)
336 jack_error(
"JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func,
343 set_threaded_log_function();
344 if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) {
345 jack_error(
"JackALSARawMidiDriver::Init - could not acquire realtime "
346 "scheduling. Continuing anyway.");
352 JackALSARawMidiDriver::Open(
bool capturing,
bool playing,
int in_channels,
353 int out_channels,
bool monitor,
354 const char *capture_driver_name,
355 const char *playback_driver_name,
356 jack_nframes_t capture_latency,
357 jack_nframes_t playback_latency)
359 snd_rawmidi_info_t *info;
360 int code = snd_rawmidi_info_malloc(&info);
362 HandleALSAError(
"Open",
"snd_rawmidi_info_malloc", code);
365 std::vector<snd_rawmidi_info_t *> in_info_list;
366 std::vector<snd_rawmidi_info_t *> out_info_list;
367 for (
int card = -1;;) {
368 int code = snd_card_next(&card);
370 HandleALSAError(
"Open",
"snd_card_next", code);
377 snprintf(name,
sizeof(name),
"hw:%d", card);
379 code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK);
381 HandleALSAError(
"Open",
"snd_ctl_open", code);
384 for (
int device = -1;;) {
385 code = snd_ctl_rawmidi_next_device(control, &device);
387 HandleALSAError(
"Open",
"snd_ctl_rawmidi_next_device", code);
393 snd_rawmidi_info_set_device(info, device);
394 snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
395 GetDeviceInfo(control, info, &in_info_list);
396 snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
397 GetDeviceInfo(control, info, &out_info_list);
399 snd_ctl_close(control);
401 snd_rawmidi_info_free(info);
402 size_t potential_inputs = in_info_list.size();
403 size_t potential_outputs = out_info_list.size();
404 if (! (potential_inputs || potential_outputs)) {
405 jack_error(
"JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
406 "output ports found.");
407 FreeDeviceInfo(&in_info_list, &out_info_list);
410 size_t num_inputs = 0;
411 size_t num_outputs = 0;
412 const char *client_name = fClientControl.fName;
413 if (potential_inputs) {
415 input_ports =
new JackALSARawMidiInputPort *[potential_inputs];
416 }
catch (std::exception& e) {
417 jack_error(
"JackALSARawMidiDriver::Open - while creating input "
418 "port array: %s", e.what());
419 FreeDeviceInfo(&in_info_list, &out_info_list);
423 if (potential_outputs) {
425 output_ports =
new JackALSARawMidiOutputPort *[potential_outputs];
426 }
catch (std::exception& e) {
427 jack_error(
"JackALSARawMidiDriver::Open - while creating output "
428 "port array: %s", e.what());
429 FreeDeviceInfo(&in_info_list, &out_info_list);
430 goto delete_input_ports;
433 for (
size_t i = 0; i < potential_inputs; i++) {
434 snd_rawmidi_info_t *info = in_info_list.at(i);
436 input_ports[num_inputs] =
new JackALSARawMidiInputPort(client_name, info, i);
438 }
catch (std::exception& e) {
439 jack_error(
"JackALSARawMidiDriver::Open - while creating new "
440 "JackALSARawMidiInputPort: %s", e.what());
442 snd_rawmidi_info_free(info);
444 for (
size_t i = 0; i < potential_outputs; i++) {
445 snd_rawmidi_info_t *info = out_info_list.at(i);
447 output_ports[num_outputs] =
new JackALSARawMidiOutputPort(client_name, info, i);
449 }
catch (std::exception& e) {
450 jack_error(
"JackALSARawMidiDriver::Open - while creating new "
451 "JackALSARawMidiOutputPort: %s", e.what());
453 snd_rawmidi_info_free(info);
455 if (! (num_inputs || num_outputs)) {
456 jack_error(
"JackALSARawMidiDriver::Open - none of the potential "
457 "inputs or outputs were successfully opened.");
458 }
else if (JackMidiDriver::Open(capturing, playing, num_inputs,
459 num_outputs, monitor, capture_driver_name,
460 playback_driver_name, capture_latency,
462 jack_error(
"JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
467 for (
size_t i = 0; i < num_outputs; i++) {
468 delete output_ports[i];
470 delete[] output_ports;
475 for (
size_t i = 0; i < num_inputs; i++) {
476 delete input_ports[i];
478 delete[] input_ports;
485 JackALSARawMidiDriver::Read()
487 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
488 for (
int i = 0; i < fCaptureChannels; i++) {
489 if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) {
497 JackALSARawMidiDriver::Start()
500 jack_info(
"JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");
502 JackMidiDriver::Start();
504 for (
int i = 0; i < fCaptureChannels; i++) {
505 poll_fd_count += input_ports[i]->GetPollDescriptorCount();
507 for (
int i = 0; i < fPlaybackChannels; i++) {
508 poll_fd_count += output_ports[i]->GetPollDescriptorCount();
511 poll_fds =
new pollfd[poll_fd_count];
512 }
catch (std::exception& e) {
513 jack_error(
"JackALSARawMidiDriver::Start - creating poll descriptor "
514 "structures failed: %s", e.what());
517 if (fPlaybackChannels) {
519 output_port_timeouts =
new jack_nframes_t[fPlaybackChannels];
520 }
catch (std::exception& e) {
521 jack_error(
"JackALSARawMidiDriver::Start - creating array for "
522 "output port timeout values failed: %s", e.what());
523 goto free_poll_descriptors;
526 struct pollfd *poll_fd_iter;
528 CreateNonBlockingPipe(fds);
529 }
catch (std::exception& e) {
530 jack_error(
"JackALSARawMidiDriver::Start - while creating wake pipe: "
532 goto free_output_port_timeouts;
534 poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
535 poll_fds[0].fd = fds[0];
536 poll_fd_iter = poll_fds + 1;
537 for (
int i = 0; i < fCaptureChannels; i++) {
538 JackALSARawMidiInputPort *input_port = input_ports[i];
539 input_port->PopulatePollDescriptors(poll_fd_iter);
540 poll_fd_iter += input_port->GetPollDescriptorCount();
542 for (
int i = 0; i < fPlaybackChannels; i++) {
543 JackALSARawMidiOutputPort *output_port = output_ports[i];
544 output_port->PopulatePollDescriptors(poll_fd_iter);
545 poll_fd_iter += output_port->GetPollDescriptorCount();
546 output_port_timeouts[i] = 0;
549 jack_info(
"JackALSARawMidiDriver::Start - starting ALSA thread ...");
551 if (! thread->StartSync()) {
553 jack_info(
"JackALSARawMidiDriver::Start - started ALSA thread.");
557 jack_error(
"JackALSARawMidiDriver::Start - failed to start MIDI "
558 "processing thread.");
560 DestroyNonBlockingPipe(fds);
563 free_output_port_timeouts:
564 delete[] output_port_timeouts;
565 output_port_timeouts = 0;
566 free_poll_descriptors:
573 JackALSARawMidiDriver::Stop()
575 jack_info(
"JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");
576 JackMidiDriver::Stop();
584 switch (thread->GetStatus()) {
585 case JackThread::kIniting:
586 case JackThread::kStarting:
587 result = thread->Kill();
590 case JackThread::kRunning:
591 result = thread->Stop();
602 if (output_port_timeouts) {
603 delete[] output_port_timeouts;
604 output_port_timeouts = 0;
611 jack_error(
"JackALSARawMidiDriver::Stop - could not %s MIDI "
612 "processing thread.", verb);
618 JackALSARawMidiDriver::Write()
620 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
621 for (
int i = 0; i < fPlaybackChannels; i++) {
622 if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size)) {
637 driver_get_descriptor()
643 return jack_driver_descriptor_construct(
"alsarawmidi", JackDriverSlave,
"Alternative ALSA raw MIDI backend.", NULL);
653 if (driver->Open(1, 1, 0, 0,
false,
"midi in",
"midi out", 0, 0) == 0) {
660 jack_info(
"JackALSARawMidiDriver already allocated, cannot be loaded twice");
Locked Engine, access to methods is serialized using a mutex.
Inter process synchronization using POSIX semaphore.
SERVER_EXPORT void jack_error(const char *fmt,...)
SERVER_EXPORT void jack_info(const char *fmt,...)
The base interface for drivers clients.