00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <memory>
00021 #include <new>
00022 #include <stdexcept>
00023
00024 #include <alsa/asoundlib.h>
00025
00026 #include "JackALSARawMidiDriver.h"
00027 #include "JackALSARawMidiUtil.h"
00028 #include "JackEngineControl.h"
00029 #include "JackError.h"
00030 #include "JackMidiUtil.h"
00031 #include "driver_interface.h"
00032
00033 using Jack::JackALSARawMidiDriver;
00034
00035 JackALSARawMidiDriver::JackALSARawMidiDriver(const char *name,
00036 const char *alias,
00037 JackLockedEngine *engine,
00038 JackSynchro *table):
00039 JackMidiDriver(name, alias, engine, table)
00040 {
00041 thread = new JackThread(this);
00042 fds[0] = -1;
00043 fds[1] = -1;
00044 input_ports = 0;
00045 output_ports = 0;
00046 output_port_timeouts = 0;
00047 poll_fds = 0;
00048 }
00049
00050 JackALSARawMidiDriver::~JackALSARawMidiDriver()
00051 {
00052 delete thread;
00053 }
00054
00055 int
00056 JackALSARawMidiDriver::Attach()
00057 {
00058 const char *alias;
00059 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00060 jack_port_id_t index;
00061 jack_nframes_t latency = buffer_size;
00062 jack_latency_range_t latency_range;
00063 const char *name;
00064 JackPort *port;
00065 latency_range.max = latency;
00066 latency_range.min = latency;
00067 for (int i = 0; i < fCaptureChannels; i++) {
00068 JackALSARawMidiInputPort *input_port = input_ports[i];
00069 name = input_port->GetName();
00070 fEngine->PortRegister(fClientControl.fRefNum, name,
00071 JACK_DEFAULT_MIDI_TYPE,
00072 CaptureDriverFlags, buffer_size, &index);
00073 if (index == NO_PORT) {
00074 jack_error("JackALSARawMidiDriver::Attach - cannot register input "
00075 "port with name '%s'.", name);
00076
00077 return -1;
00078 }
00079 alias = input_port->GetAlias();
00080 port = fGraphManager->GetPort(index);
00081 port->SetAlias(alias);
00082 port->SetLatencyRange(JackCaptureLatency, &latency_range);
00083 fCapturePortList[i] = index;
00084
00085 jack_info("JackALSARawMidiDriver::Attach - input port registered "
00086 "(name='%s', alias='%s').", name, alias);
00087 }
00088 if (! fEngineControl->fSyncMode) {
00089 latency += buffer_size;
00090 latency_range.max = latency;
00091 latency_range.min = latency;
00092 }
00093 for (int i = 0; i < fPlaybackChannels; i++) {
00094 JackALSARawMidiOutputPort *output_port = output_ports[i];
00095 name = output_port->GetName();
00096 fEngine->PortRegister(fClientControl.fRefNum, name,
00097 JACK_DEFAULT_MIDI_TYPE,
00098 PlaybackDriverFlags, buffer_size, &index);
00099 if (index == NO_PORT) {
00100 jack_error("JackALSARawMidiDriver::Attach - cannot register "
00101 "output port with name '%s'.", name);
00102
00103 return -1;
00104 }
00105 alias = output_port->GetAlias();
00106 port = fGraphManager->GetPort(index);
00107 port->SetAlias(alias);
00108 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
00109 fPlaybackPortList[i] = index;
00110
00111 jack_info("JackALSARawMidiDriver::Attach - output port registered "
00112 "(name='%s', alias='%s').", name, alias);
00113 }
00114 return 0;
00115 }
00116
00117 int
00118 JackALSARawMidiDriver::Close()
00119 {
00120
00121 int result = JackMidiDriver::Close();
00122
00123 if (input_ports) {
00124 for (int i = 0; i < fCaptureChannels; i++) {
00125 delete input_ports[i];
00126 }
00127 delete[] input_ports;
00128 input_ports = 0;
00129 }
00130 if (output_ports) {
00131 for (int i = 0; i < fPlaybackChannels; i++) {
00132 delete output_ports[i];
00133 }
00134 delete[] output_ports;
00135 output_ports = 0;
00136 }
00137 return result;
00138 }
00139
00140 bool
00141 JackALSARawMidiDriver::Execute()
00142 {
00143 jack_nframes_t timeout_frame = 0;
00144 for (;;) {
00145 struct timespec timeout;
00146 struct timespec *timeout_ptr;
00147 if (! timeout_frame) {
00148 timeout_ptr = 0;
00149 } else {
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 timeout_ptr = &timeout;
00171 jack_time_t next_time = GetTimeFromFrames(timeout_frame);
00172 jack_time_t now = GetMicroSeconds();
00173 if (next_time <= now) {
00174 timeout.tv_sec = 0;
00175 timeout.tv_nsec = 0;
00176 } else {
00177 jack_time_t wait_time = next_time - now;
00178 timeout.tv_sec = wait_time / 1000000;
00179 timeout.tv_nsec = (wait_time % 1000000) * 1000;
00180 }
00181 }
00182 int poll_result = ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
00183
00184
00185
00186
00187 jack_nframes_t current_frame = GetCurrentFrame();
00188
00189 if (poll_result == -1) {
00190 if (errno == EINTR) {
00191 continue;
00192 }
00193 jack_error("JackALSARawMidiDriver::Execute - poll error: %s",
00194 strerror(errno));
00195 break;
00196 }
00197 jack_nframes_t port_timeout;
00198 timeout_frame = 0;
00199 if (! poll_result) {
00200
00201
00202
00203
00204 for (int i = 0; i < fPlaybackChannels; i++) {
00205 port_timeout = output_port_timeouts[i];
00206 if (port_timeout && (port_timeout <= current_frame)) {
00207 if (! output_ports[i]->ProcessPollEvents(false, true,
00208 &port_timeout)) {
00209 jack_error("JackALSARawMidiDriver::Execute - a fatal "
00210 "error occurred while processing ALSA "
00211 "output events.");
00212 goto cleanup;
00213 }
00214 output_port_timeouts[i] = port_timeout;
00215 }
00216 if (port_timeout && ((! timeout_frame) ||
00217 (port_timeout < timeout_frame))) {
00218 timeout_frame = port_timeout;
00219 }
00220 }
00221 continue;
00222 }
00223
00224
00225
00226 unsigned short revents = poll_fds[0].revents;
00227 if (revents) {
00228 if (revents & (~ POLLHUP)) {
00229 jack_error("JackALSARawMidiDriver::Execute - unexpected poll "
00230 "event on pipe file descriptor.");
00231 }
00232 break;
00233 }
00234
00235
00236
00237 for (int i = 0; i < fPlaybackChannels; i++) {
00238 port_timeout = output_port_timeouts[i];
00239 bool timeout = port_timeout && (port_timeout <= current_frame);
00240 if (! output_ports[i]->ProcessPollEvents(true, timeout,
00241 &port_timeout)) {
00242 jack_error("JackALSARawMidiDriver::Execute - a fatal error "
00243 "occurred while processing ALSA output events.");
00244 goto cleanup;
00245 }
00246 output_port_timeouts[i] = port_timeout;
00247 if (port_timeout && ((! timeout_frame) ||
00248 (port_timeout < timeout_frame))) {
00249 timeout_frame = port_timeout;
00250 }
00251 }
00252
00253
00254
00255
00256
00257
00258 for (int i = 0; i < fCaptureChannels; i++) {
00259 if (! input_ports[i]->ProcessPollEvents(current_frame)) {
00260 jack_error("JackALSARawMidiDriver::Execute - a fatal error "
00261 "occurred while processing ALSA input events.");
00262 goto cleanup;
00263 }
00264 }
00265 }
00266 cleanup:
00267 close(fds[0]);
00268 fds[0] = -1;
00269
00270 jack_info("JackALSARawMidiDriver::Execute - ALSA thread exiting.");
00271
00272 return false;
00273 }
00274
00275 void
00276 JackALSARawMidiDriver::
00277 FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
00278 std::vector<snd_rawmidi_info_t *> *out_info_list)
00279 {
00280 size_t length = in_info_list->size();
00281 for (size_t i = 0; i < length; i++) {
00282 snd_rawmidi_info_free(in_info_list->at(i));
00283 }
00284 length = out_info_list->size();
00285 for (size_t i = 0; i < length; i++) {
00286 snd_rawmidi_info_free(out_info_list->at(i));
00287 }
00288 }
00289
00290 void
00291 JackALSARawMidiDriver::
00292 GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
00293 std::vector<snd_rawmidi_info_t *> *info_list)
00294 {
00295 snd_rawmidi_info_set_subdevice(info, 0);
00296 int code = snd_ctl_rawmidi_info(control, info);
00297 if (code) {
00298 if (code != -ENOENT) {
00299 HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
00300 }
00301 return;
00302 }
00303 unsigned int count = snd_rawmidi_info_get_subdevices_count(info);
00304 for (unsigned int i = 0; i < count; i++) {
00305 snd_rawmidi_info_set_subdevice(info, i);
00306 int code = snd_ctl_rawmidi_info(control, info);
00307 if (code) {
00308 HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
00309 continue;
00310 }
00311 snd_rawmidi_info_t *info_copy;
00312 code = snd_rawmidi_info_malloc(&info_copy);
00313 if (code) {
00314 HandleALSAError("GetDeviceInfo", "snd_rawmidi_info_malloc", code);
00315 continue;
00316 }
00317 snd_rawmidi_info_copy(info_copy, info);
00318 try {
00319 info_list->push_back(info_copy);
00320 } catch (std::bad_alloc &e) {
00321 snd_rawmidi_info_free(info_copy);
00322 jack_error("JackALSARawMidiDriver::GetDeviceInfo - "
00323 "std::vector::push_back: %s", e.what());
00324 }
00325 }
00326 }
00327
00328 void
00329 JackALSARawMidiDriver::HandleALSAError(const char *driver_func,
00330 const char *alsa_func, int code)
00331 {
00332 jack_error("JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func,
00333 snd_strerror(code));
00334 }
00335
00336 bool
00337 JackALSARawMidiDriver::Init()
00338 {
00339 set_threaded_log_function();
00340 if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) {
00341 jack_error("JackALSARawMidiDriver::Init - could not acquire realtime "
00342 "scheduling. Continuing anyway.");
00343 }
00344 return true;
00345 }
00346
00347 int
00348 JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
00349 int out_channels, bool monitor,
00350 const char *capture_driver_name,
00351 const char *playback_driver_name,
00352 jack_nframes_t capture_latency,
00353 jack_nframes_t playback_latency)
00354 {
00355 snd_rawmidi_info_t *info;
00356 int code = snd_rawmidi_info_malloc(&info);
00357 if (code) {
00358 HandleALSAError("Open", "snd_rawmidi_info_malloc", code);
00359 return -1;
00360 }
00361 std::vector<snd_rawmidi_info_t *> in_info_list;
00362 std::vector<snd_rawmidi_info_t *> out_info_list;
00363 for (int card = -1;;) {
00364 int code = snd_card_next(&card);
00365 if (code) {
00366 HandleALSAError("Open", "snd_card_next", code);
00367 continue;
00368 }
00369 if (card == -1) {
00370 break;
00371 }
00372 char name[32];
00373 snprintf(name, sizeof(name), "hw:%d", card);
00374 snd_ctl_t *control;
00375 code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK);
00376 if (code) {
00377 HandleALSAError("Open", "snd_ctl_open", code);
00378 continue;
00379 }
00380 for (int device = -1;;) {
00381 code = snd_ctl_rawmidi_next_device(control, &device);
00382 if (code) {
00383 HandleALSAError("Open", "snd_ctl_rawmidi_next_device", code);
00384 continue;
00385 }
00386 if (device == -1) {
00387 break;
00388 }
00389 snd_rawmidi_info_set_device(info, device);
00390 snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
00391 GetDeviceInfo(control, info, &in_info_list);
00392 snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
00393 GetDeviceInfo(control, info, &out_info_list);
00394 }
00395 snd_ctl_close(control);
00396 }
00397 snd_rawmidi_info_free(info);
00398 size_t potential_inputs = in_info_list.size();
00399 size_t potential_outputs = out_info_list.size();
00400 if (! (potential_inputs || potential_outputs)) {
00401 jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
00402 "output ports found.");
00403 FreeDeviceInfo(&in_info_list, &out_info_list);
00404 return -1;
00405 }
00406 size_t num_inputs = 0;
00407 size_t num_outputs = 0;
00408 if (potential_inputs) {
00409 try {
00410 input_ports = new JackALSARawMidiInputPort *[potential_inputs];
00411 } catch (std::exception e) {
00412 jack_error("JackALSARawMidiDriver::Open - while creating input "
00413 "port array: %s", e.what());
00414 FreeDeviceInfo(&in_info_list, &out_info_list);
00415 return -1;
00416 }
00417 }
00418 if (potential_outputs) {
00419 try {
00420 output_ports = new JackALSARawMidiOutputPort *[potential_outputs];
00421 } catch (std::exception e) {
00422 jack_error("JackALSARawMidiDriver::Open - while creating output "
00423 "port array: %s", e.what());
00424 FreeDeviceInfo(&in_info_list, &out_info_list);
00425 goto delete_input_ports;
00426 }
00427 }
00428 for (size_t i = 0; i < potential_inputs; i++) {
00429 snd_rawmidi_info_t *info = in_info_list.at(i);
00430 try {
00431 input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i);
00432 num_inputs++;
00433 } catch (std::exception e) {
00434 jack_error("JackALSARawMidiDriver::Open - while creating new "
00435 "JackALSARawMidiInputPort: %s", e.what());
00436 }
00437 snd_rawmidi_info_free(info);
00438 }
00439 for (size_t i = 0; i < potential_outputs; i++) {
00440 snd_rawmidi_info_t *info = out_info_list.at(i);
00441 try {
00442 output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i);
00443 num_outputs++;
00444 } catch (std::exception e) {
00445 jack_error("JackALSARawMidiDriver::Open - while creating new "
00446 "JackALSARawMidiOutputPort: %s", e.what());
00447 }
00448 snd_rawmidi_info_free(info);
00449 }
00450 if (! (num_inputs || num_outputs)) {
00451 jack_error("JackALSARawMidiDriver::Open - none of the potential "
00452 "inputs or outputs were successfully opened.");
00453 } else if (JackMidiDriver::Open(capturing, playing, num_inputs,
00454 num_outputs, monitor, capture_driver_name,
00455 playback_driver_name, capture_latency,
00456 playback_latency)) {
00457 jack_error("JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
00458 } else {
00459 return 0;
00460 }
00461 if (output_ports) {
00462 for (size_t i = 0; i < num_outputs; i++) {
00463 delete output_ports[i];
00464 }
00465 delete[] output_ports;
00466 output_ports = 0;
00467 }
00468 delete_input_ports:
00469 if (input_ports) {
00470 for (size_t i = 0; i < num_inputs; i++) {
00471 delete input_ports[i];
00472 }
00473 delete[] input_ports;
00474 input_ports = 0;
00475 }
00476 return -1;
00477 }
00478
00479 int
00480 JackALSARawMidiDriver::Read()
00481 {
00482 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00483 for (int i = 0; i < fCaptureChannels; i++) {
00484 if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) {
00485 return -1;
00486 }
00487 }
00488 return 0;
00489 }
00490
00491 int
00492 JackALSARawMidiDriver::Start()
00493 {
00494
00495 jack_info("JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");
00496
00497 JackMidiDriver::Start();
00498 poll_fd_count = 1;
00499 for (int i = 0; i < fCaptureChannels; i++) {
00500 poll_fd_count += input_ports[i]->GetPollDescriptorCount();
00501 }
00502 for (int i = 0; i < fPlaybackChannels; i++) {
00503 poll_fd_count += output_ports[i]->GetPollDescriptorCount();
00504 }
00505 try {
00506 poll_fds = new pollfd[poll_fd_count];
00507 } catch (std::exception e) {
00508 jack_error("JackALSARawMidiDriver::Start - creating poll descriptor "
00509 "structures failed: %s", e.what());
00510 return -1;
00511 }
00512 if (fPlaybackChannels) {
00513 try {
00514 output_port_timeouts = new jack_nframes_t[fPlaybackChannels];
00515 } catch (std::exception e) {
00516 jack_error("JackALSARawMidiDriver::Start - creating array for "
00517 "output port timeout values failed: %s", e.what());
00518 goto free_poll_descriptors;
00519 }
00520 }
00521 struct pollfd *poll_fd_iter;
00522 try {
00523 CreateNonBlockingPipe(fds);
00524 } catch (std::exception e) {
00525 jack_error("JackALSARawMidiDriver::Start - while creating wake pipe: "
00526 "%s", e.what());
00527 goto free_output_port_timeouts;
00528 }
00529 poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
00530 poll_fds[0].fd = fds[0];
00531 poll_fd_iter = poll_fds + 1;
00532 for (int i = 0; i < fCaptureChannels; i++) {
00533 JackALSARawMidiInputPort *input_port = input_ports[i];
00534 input_port->PopulatePollDescriptors(poll_fd_iter);
00535 poll_fd_iter += input_port->GetPollDescriptorCount();
00536 }
00537 for (int i = 0; i < fPlaybackChannels; i++) {
00538 JackALSARawMidiOutputPort *output_port = output_ports[i];
00539 output_port->PopulatePollDescriptors(poll_fd_iter);
00540 poll_fd_iter += output_port->GetPollDescriptorCount();
00541 output_port_timeouts[i] = 0;
00542 }
00543
00544 jack_info("JackALSARawMidiDriver::Start - starting ALSA thread ...");
00545
00546 if (! thread->StartSync()) {
00547
00548 jack_info("JackALSARawMidiDriver::Start - started ALSA thread.");
00549
00550 return 0;
00551 }
00552 jack_error("JackALSARawMidiDriver::Start - failed to start MIDI "
00553 "processing thread.");
00554
00555 DestroyNonBlockingPipe(fds);
00556 fds[1] = -1;
00557 fds[0] = -1;
00558 free_output_port_timeouts:
00559 delete[] output_port_timeouts;
00560 output_port_timeouts = 0;
00561 free_poll_descriptors:
00562 delete[] poll_fds;
00563 poll_fds = 0;
00564 return -1;
00565 }
00566
00567 int
00568 JackALSARawMidiDriver::Stop()
00569 {
00570 jack_info("JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");
00571 JackMidiDriver::Stop();
00572
00573 if (fds[1] != -1) {
00574 close(fds[1]);
00575 fds[1] = -1;
00576 }
00577 int result;
00578 const char *verb;
00579 switch (thread->GetStatus()) {
00580 case JackThread::kIniting:
00581 case JackThread::kStarting:
00582 result = thread->Kill();
00583 verb = "kill";
00584 break;
00585 case JackThread::kRunning:
00586 result = thread->Stop();
00587 verb = "stop";
00588 break;
00589 default:
00590 result = 0;
00591 verb = 0;
00592 }
00593 if (fds[0] != -1) {
00594 close(fds[0]);
00595 fds[0] = -1;
00596 }
00597 if (output_port_timeouts) {
00598 delete[] output_port_timeouts;
00599 output_port_timeouts = 0;
00600 }
00601 if (poll_fds) {
00602 delete[] poll_fds;
00603 poll_fds = 0;
00604 }
00605 if (result) {
00606 jack_error("JackALSARawMidiDriver::Stop - could not %s MIDI "
00607 "processing thread.", verb);
00608 }
00609 return result;
00610 }
00611
00612 int
00613 JackALSARawMidiDriver::Write()
00614 {
00615 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00616 for (int i = 0; i < fPlaybackChannels; i++) {
00617 if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size)) {
00618 return -1;
00619 }
00620 }
00621 return 0;
00622 }
00623
00624 #ifdef __cplusplus
00625 extern "C" {
00626 #endif
00627
00628
00629 static Jack::JackALSARawMidiDriver* driver = NULL;
00630
00631 SERVER_EXPORT jack_driver_desc_t *
00632 driver_get_descriptor()
00633 {
00634
00635
00636
00637
00638 return jack_driver_descriptor_construct("alsarawmidi", JackDriverSlave, "Alternative ALSA raw MIDI backend.", NULL);
00639 }
00640
00641 SERVER_EXPORT Jack::JackDriverClientInterface *
00642 driver_initialize(Jack::JackLockedEngine *engine, Jack::JackSynchro *table,
00643 const JSList *params)
00644 {
00645
00646 if (!driver) {
00647 driver = new Jack::JackALSARawMidiDriver("system_midi", "alsarawmidi", engine, table);
00648 if (driver->Open(1, 1, 0, 0, false, "midi in", "midi out", 0, 0) == 0) {
00649 return driver;
00650 } else {
00651 delete driver;
00652 return NULL;
00653 }
00654 } else {
00655 jack_info("JackALSARawMidiDriver already allocated, cannot be loaded twice");
00656 return NULL;
00657 }
00658 }
00659
00660 #ifdef __cplusplus
00661 }
00662 #endif