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