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)) {
   632     driver_get_descriptor()
   638         return jack_driver_descriptor_construct(
"alsarawmidi", JackDriverSlave, 
"Alternative ALSA raw MIDI backend.", NULL);
   648             if (driver->Open(1, 1, 0, 0, 
false, 
"midi in", 
"midi out", 0, 0) == 0) {
   655             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.