| @@ -63,13 +63,16 @@ namespace Jack { | |||
| jack_midi_data_t *buffer) = 0; | |||
| /** | |||
| * A wrapper method for the `EnqueueEvent` method above. | |||
| * A wrapper method for the `EnqueueEvent` method above. The optional | |||
| * 'frame_offset' argument is an amount of frames to add to the event's | |||
| * time. | |||
| */ | |||
| inline EnqueueResult | |||
| EnqueueEvent(jack_midi_event_t *event) | |||
| EnqueueEvent(jack_midi_event_t *event, jack_nframes_t frame_offset=0) | |||
| { | |||
| return EnqueueEvent(event->time, event->size, event->buffer); | |||
| return EnqueueEvent(event->time + frame_offset, event->size, | |||
| event->buffer); | |||
| } | |||
| }; | |||
| @@ -134,32 +134,44 @@ JackALSARawMidiDriver::Execute() | |||
| } | |||
| revents = poll_fds[0].revents; | |||
| if (revents & POLLHUP) { | |||
| close(fds[0]); | |||
| fds[0] = -1; | |||
| // Driver is being stopped. | |||
| break; | |||
| } | |||
| if (revents & (~(POLLHUP | POLLIN))) { | |||
| if (revents & (~ POLLIN)) { | |||
| jack_error("JackALSARawMidiDriver::Execute - unexpected poll " | |||
| "event on pipe file descriptor."); | |||
| break; | |||
| } | |||
| handle_ports: | |||
| timeout_frame = 0; | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| process_frame = input_ports[i]->ProcessALSA(); | |||
| if (! input_ports[i]->ProcessALSA(&process_frame)) { | |||
| jack_error("JackALSARawMidiDriver::Execute - a fatal error " | |||
| "occurred while processing ALSA input events."); | |||
| goto cleanup; | |||
| } | |||
| if (process_frame && ((! timeout_frame) || | |||
| (process_frame < timeout_frame))) { | |||
| timeout_frame = process_frame; | |||
| } | |||
| } | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| process_frame = output_ports[i]->ProcessALSA(fds[0]); | |||
| if (! output_ports[i]->ProcessALSA(fds[0], &process_frame)) { | |||
| jack_error("JackALSARawMidiDriver::Execute - a fatal error " | |||
| "occurred while processing ALSA output events."); | |||
| goto cleanup; | |||
| } | |||
| if (process_frame && ((! timeout_frame) || | |||
| (process_frame < timeout_frame))) { | |||
| timeout_frame = process_frame; | |||
| } | |||
| } | |||
| } | |||
| cleanup: | |||
| close(fds[0]); | |||
| fds[0] = -1; | |||
| jack_info("JackALSARawMidiDriver::Execute - ALSA thread exiting."); | |||
| return false; | |||
| } | |||
| @@ -402,7 +414,9 @@ JackALSARawMidiDriver::Read() | |||
| { | |||
| jack_nframes_t buffer_size = fEngineControl->fBufferSize; | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size); | |||
| if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) { | |||
| return -1; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -539,8 +553,10 @@ JackALSARawMidiDriver::Write() | |||
| jack_nframes_t buffer_size = fEngineControl->fBufferSize; | |||
| int write_fd = fds[1]; | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size, | |||
| write_fd); | |||
| if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size, | |||
| write_fd)) { | |||
| return -1; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -69,30 +69,33 @@ JackALSARawMidiInputPort::EnqueueALSAEvent() | |||
| return (next_time < alsa_time) ? next_time : alsa_time; | |||
| } | |||
| jack_nframes_t | |||
| JackALSARawMidiInputPort::ProcessALSA() | |||
| bool | |||
| JackALSARawMidiInputPort::ProcessALSA(jack_nframes_t *frame) | |||
| { | |||
| unsigned short revents = ProcessPollEvents(); | |||
| jack_nframes_t frame; | |||
| unsigned short revents; | |||
| if (! ProcessPollEvents(&revents)) { | |||
| return false; | |||
| } | |||
| if (alsa_event) { | |||
| frame = EnqueueALSAEvent(); | |||
| if (frame) { | |||
| return frame; | |||
| *frame = EnqueueALSAEvent(); | |||
| if (*frame) { | |||
| return true; | |||
| } | |||
| } | |||
| if (revents & POLLIN) { | |||
| for (alsa_event = receive_queue->DequeueEvent(); alsa_event; | |||
| alsa_event = receive_queue->DequeueEvent()) { | |||
| frame = EnqueueALSAEvent(); | |||
| if (frame) { | |||
| return frame; | |||
| *frame = EnqueueALSAEvent(); | |||
| if (*frame) { | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| return raw_queue->Process(); | |||
| *frame = raw_queue->Process(); | |||
| return true; | |||
| } | |||
| void | |||
| bool | |||
| JackALSARawMidiInputPort::ProcessJack(JackMidiBuffer *port_buffer, | |||
| jack_nframes_t frames) | |||
| { | |||
| @@ -119,4 +122,5 @@ JackALSARawMidiInputPort::ProcessJack(JackMidiBuffer *port_buffer, | |||
| } | |||
| break; | |||
| } | |||
| return true; | |||
| } | |||
| @@ -30,10 +30,10 @@ namespace Jack { | |||
| size_t max_messages=1024); | |||
| ~JackALSARawMidiInputPort(); | |||
| jack_nframes_t | |||
| ProcessALSA(); | |||
| bool | |||
| ProcessALSA(jack_nframes_t *frame); | |||
| void | |||
| bool | |||
| ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames); | |||
| }; | |||
| @@ -54,13 +54,17 @@ JackALSARawMidiOutputPort::DequeueALSAEvent(int read_fd) | |||
| return event; | |||
| } | |||
| jack_nframes_t | |||
| JackALSARawMidiOutputPort::ProcessALSA(int read_fd) | |||
| bool | |||
| JackALSARawMidiOutputPort::ProcessALSA(int read_fd, jack_nframes_t *frame) | |||
| { | |||
| unsigned short revents = ProcessPollEvents(); | |||
| unsigned short revents; | |||
| if (! ProcessPollEvents(&revents)) { | |||
| return false; | |||
| } | |||
| if (blocked) { | |||
| if (! (revents & POLLOUT)) { | |||
| return 0; | |||
| *frame = 0; | |||
| return true; | |||
| } | |||
| blocked = false; | |||
| } | |||
| @@ -98,7 +102,7 @@ JackALSARawMidiOutputPort::ProcessALSA(int read_fd) | |||
| break; | |||
| } | |||
| process_events: | |||
| jack_nframes_t next_frame = raw_queue->Process(); | |||
| *frame = raw_queue->Process(); | |||
| blocked = send_queue->IsBlocked(); | |||
| if (blocked) { | |||
| @@ -106,13 +110,14 @@ JackALSARawMidiOutputPort::ProcessALSA(int read_fd) | |||
| "blocked"); | |||
| SetPollEventMask(POLLERR | POLLNVAL | POLLOUT); | |||
| return 0; | |||
| *frame = 0; | |||
| } else { | |||
| SetPollEventMask(POLLERR | POLLNVAL); | |||
| } | |||
| SetPollEventMask(POLLERR | POLLNVAL); | |||
| return next_frame; | |||
| return true; | |||
| } | |||
| void | |||
| bool | |||
| JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer, | |||
| jack_nframes_t frames, int write_fd) | |||
| { | |||
| @@ -128,20 +133,21 @@ JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer, | |||
| char c = 1; | |||
| ssize_t result = write(write_fd, &c, 1); | |||
| assert(result <= 1); | |||
| if (result < 0) { | |||
| jack_error("JackALSARawMidiOutputPort::ProcessJack - error " | |||
| "writing a byte to the pipe file descriptor: %s", | |||
| strerror(errno)); | |||
| return false; | |||
| } | |||
| if (! result) { | |||
| // Recoverable. | |||
| jack_error("JackALSARawMidiOutputPort::ProcessJack - Couldn't " | |||
| "write a byte to the pipe file descriptor. Dropping " | |||
| "event."); | |||
| } else if (result < 0) { | |||
| jack_error("JackALSARawMidiOutputPort::ProcessJack - error " | |||
| "writing a byte to the pipe file descriptor: %s", | |||
| strerror(errno)); | |||
| } else if (thread_queue->EnqueueEvent(event->time + frames, | |||
| event->size, event->buffer) != | |||
| JackMidiWriteQueue::OK) { | |||
| jack_error("JackALSARawMidiOutputPort::ProcessJack - **BUG** The " | |||
| "thread queue said it had enough space to enqueue a " | |||
| "%d-byte event, but failed to enqueue the event."); | |||
| } else { | |||
| assert(thread_queue->EnqueueEvent(event, frames) == | |||
| JackMidiWriteQueue::OK); | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| @@ -30,10 +30,10 @@ namespace Jack { | |||
| size_t max_messages=1024); | |||
| ~JackALSARawMidiOutputPort(); | |||
| jack_nframes_t | |||
| ProcessALSA(int read_fd); | |||
| bool | |||
| ProcessALSA(int read_fd, jack_nframes_t *frame); | |||
| void | |||
| bool | |||
| ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames, | |||
| int write_fd); | |||
| @@ -126,27 +126,28 @@ JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd) | |||
| return result; | |||
| } | |||
| int | |||
| JackALSARawMidiPort::ProcessPollEvents() | |||
| bool | |||
| JackALSARawMidiPort::ProcessPollEvents(unsigned short *revents) | |||
| { | |||
| unsigned short revents = 0; | |||
| int code = snd_rawmidi_poll_descriptors_revents(rawmidi, poll_fds, num_fds, | |||
| &revents); | |||
| revents); | |||
| if (code) { | |||
| jack_error("JackALSARawMidiPort::ProcessPollEvents - " | |||
| "snd_rawmidi_poll_descriptors_revents: %s", | |||
| snd_strerror(code)); | |||
| return 0; | |||
| return false; | |||
| } | |||
| if (revents & POLLNVAL) { | |||
| if ((*revents) & POLLNVAL) { | |||
| jack_error("JackALSARawMidiPort::ProcessPollEvents - the file " | |||
| "descriptor is invalid."); | |||
| return false; | |||
| } | |||
| if (revents & POLLERR) { | |||
| if ((*revents) & POLLERR) { | |||
| jack_error("JackALSARawMidiPort::ProcessPollEvents - an error has " | |||
| "occurred on the device or stream."); | |||
| return false; | |||
| } | |||
| return revents; | |||
| return true; | |||
| } | |||
| void | |||
| @@ -21,8 +21,8 @@ namespace Jack { | |||
| snd_rawmidi_t *rawmidi; | |||
| int | |||
| ProcessPollEvents(); | |||
| bool | |||
| ProcessPollEvents(unsigned short *revents); | |||
| void | |||
| SetPollEventMask(unsigned short events); | |||