jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
6.0KB

  1. /*
  2. Copyright (C) 2011 Devin Anderson
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include <memory>
  16. #include "JackALSARawMidiOutputPort.h"
  17. using Jack::JackALSARawMidiOutputPort;
  18. JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info,
  19. size_t index,
  20. size_t max_bytes,
  21. size_t max_messages):
  22. JackALSARawMidiPort(info, index)
  23. {
  24. alsa_event = 0;
  25. blocked = false;
  26. read_queue = new JackMidiBufferReadQueue();
  27. std::auto_ptr<JackMidiBufferReadQueue> read_ptr(read_queue);
  28. send_queue = new JackALSARawMidiSendQueue(rawmidi);
  29. std::auto_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
  30. thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
  31. std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
  32. raw_queue = new JackMidiRawOutputWriteQueue(send_queue, max_bytes,
  33. max_messages, max_messages);
  34. thread_ptr.release();
  35. send_ptr.release();
  36. read_ptr.release();
  37. }
  38. JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort()
  39. {
  40. delete raw_queue;
  41. delete read_queue;
  42. delete send_queue;
  43. delete thread_queue;
  44. }
  45. jack_midi_event_t *
  46. JackALSARawMidiOutputPort::DequeueALSAEvent(int read_fd)
  47. {
  48. jack_midi_event_t *event = thread_queue->DequeueEvent();
  49. if (event) {
  50. char c;
  51. ssize_t result = read(read_fd, &c, 1);
  52. if (! result) {
  53. jack_error("JackALSARawMidiOutputPort::DequeueALSAEvent - **BUG** "
  54. "An event was dequeued from the thread queue, but no "
  55. "byte was available for reading from the pipe file "
  56. "descriptor.");
  57. } else if (result < 0) {
  58. jack_error("JackALSARawMidiOutputPort::DequeueALSAEvent - error "
  59. "reading a byte from the pipe file descriptor: %s",
  60. strerror(errno));
  61. }
  62. }
  63. return event;
  64. }
  65. bool
  66. JackALSARawMidiOutputPort::ProcessALSA(int read_fd, jack_nframes_t *frame)
  67. {
  68. unsigned short revents;
  69. if (! ProcessPollEvents(&revents)) {
  70. return false;
  71. }
  72. if (blocked) {
  73. if (! (revents & POLLOUT)) {
  74. *frame = 0;
  75. return true;
  76. }
  77. blocked = false;
  78. }
  79. if (! alsa_event) {
  80. alsa_event = DequeueALSAEvent(read_fd);
  81. }
  82. for (; alsa_event; alsa_event = DequeueALSAEvent(read_fd)) {
  83. switch (raw_queue->EnqueueEvent(alsa_event)) {
  84. case JackMidiWriteQueue::BUFFER_FULL:
  85. // Try to free up some space by processing events early.
  86. raw_queue->Process();
  87. switch (raw_queue->EnqueueEvent(alsa_event)) {
  88. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  89. jack_error("JackALSARawMidiOutputPort::ProcessALSA - **BUG** "
  90. "JackMidiRawOutputWriteQueue::EnqueueEvent "
  91. "returned `BUFFER_FULL`, and then returned "
  92. "`BUFFER_TOO_SMALL` after a Process() call.");
  93. // Fallthrough on purpose
  94. case JackMidiWriteQueue::OK:
  95. continue;
  96. default:
  97. ;
  98. }
  99. goto process_events;
  100. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  101. jack_error("JackALSARawMidiOutputPort::ProcessALSA - The raw "
  102. "output queue couldn't enqueue a %d-byte event. "
  103. "Dropping event.", alsa_event->size);
  104. // Fallthrough on purpose
  105. case JackMidiWriteQueue::OK:
  106. continue;
  107. default:
  108. ;
  109. }
  110. break;
  111. }
  112. process_events:
  113. *frame = raw_queue->Process();
  114. blocked = send_queue->IsBlocked();
  115. if (blocked) {
  116. jack_info("JackALSARawMidiOutputPort::ProcessALSA - MIDI port is "
  117. "blocked");
  118. SetPollEventMask(POLLERR | POLLNVAL | POLLOUT);
  119. *frame = 0;
  120. } else {
  121. SetPollEventMask(POLLERR | POLLNVAL);
  122. }
  123. return true;
  124. }
  125. bool
  126. JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
  127. jack_nframes_t frames, int write_fd)
  128. {
  129. read_queue->ResetMidiBuffer(port_buffer);
  130. for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
  131. event = read_queue->DequeueEvent()) {
  132. if (event->size > thread_queue->GetAvailableSpace()) {
  133. jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
  134. "queue doesn't have enough room to enqueue a %d-byte "
  135. "event. Dropping event.", event->size);
  136. continue;
  137. }
  138. char c = 1;
  139. ssize_t result = write(write_fd, &c, 1);
  140. assert(result <= 1);
  141. if (result < 0) {
  142. jack_error("JackALSARawMidiOutputPort::ProcessJack - error "
  143. "writing a byte to the pipe file descriptor: %s",
  144. strerror(errno));
  145. return false;
  146. }
  147. if (! result) {
  148. // Recoverable.
  149. jack_error("JackALSARawMidiOutputPort::ProcessJack - Couldn't "
  150. "write a byte to the pipe file descriptor. Dropping "
  151. "event.");
  152. } else {
  153. assert(thread_queue->EnqueueEvent(event, frames) ==
  154. JackMidiWriteQueue::OK);
  155. }
  156. }
  157. return true;
  158. }