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.

154 lines
5.3KB

  1. #include <memory>
  2. #include "JackALSARawMidiOutputPort.h"
  3. using Jack::JackALSARawMidiOutputPort;
  4. JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info,
  5. size_t index,
  6. size_t max_bytes,
  7. size_t max_messages):
  8. JackALSARawMidiPort(info, index)
  9. {
  10. alsa_event = 0;
  11. blocked = false;
  12. read_queue = new JackMidiBufferReadQueue();
  13. std::auto_ptr<JackMidiBufferReadQueue> read_ptr(read_queue);
  14. send_queue = new JackALSARawMidiSendQueue(rawmidi);
  15. std::auto_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
  16. thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
  17. std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
  18. raw_queue = new JackMidiRawOutputWriteQueue(send_queue, max_bytes,
  19. max_messages, max_messages);
  20. thread_ptr.release();
  21. send_ptr.release();
  22. read_ptr.release();
  23. }
  24. JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort()
  25. {
  26. delete raw_queue;
  27. delete read_queue;
  28. delete send_queue;
  29. delete thread_queue;
  30. }
  31. jack_midi_event_t *
  32. JackALSARawMidiOutputPort::DequeueALSAEvent(int read_fd)
  33. {
  34. jack_midi_event_t *event = thread_queue->DequeueEvent();
  35. if (event) {
  36. char c;
  37. ssize_t result = read(read_fd, &c, 1);
  38. if (! result) {
  39. jack_error("JackALSARawMidiOutputPort::DequeueALSAEvent - **BUG** "
  40. "An event was dequeued from the thread queue, but no "
  41. "byte was available for reading from the pipe file "
  42. "descriptor.");
  43. } else if (result < 0) {
  44. jack_error("JackALSARawMidiOutputPort::DequeueALSAEvent - error "
  45. "reading a byte from the pipe file descriptor: %s",
  46. strerror(errno));
  47. }
  48. }
  49. return event;
  50. }
  51. bool
  52. JackALSARawMidiOutputPort::ProcessALSA(int read_fd, jack_nframes_t *frame)
  53. {
  54. unsigned short revents;
  55. if (! ProcessPollEvents(&revents)) {
  56. return false;
  57. }
  58. if (blocked) {
  59. if (! (revents & POLLOUT)) {
  60. *frame = 0;
  61. return true;
  62. }
  63. blocked = false;
  64. }
  65. if (! alsa_event) {
  66. alsa_event = DequeueALSAEvent(read_fd);
  67. }
  68. for (; alsa_event; alsa_event = DequeueALSAEvent(read_fd)) {
  69. switch (raw_queue->EnqueueEvent(alsa_event)) {
  70. case JackMidiWriteQueue::BUFFER_FULL:
  71. // Try to free up some space by processing events early.
  72. raw_queue->Process();
  73. switch (raw_queue->EnqueueEvent(alsa_event)) {
  74. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  75. jack_error("JackALSARawMidiOutputPort::ProcessALSA - **BUG** "
  76. "JackMidiRawOutputWriteQueue::EnqueueEvent "
  77. "returned `BUFFER_FULL`, and then returned "
  78. "`BUFFER_TOO_SMALL` after a Process() call.");
  79. // Fallthrough on purpose
  80. case JackMidiWriteQueue::OK:
  81. continue;
  82. default:
  83. ;
  84. }
  85. goto process_events;
  86. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  87. jack_error("JackALSARawMidiOutputPort::ProcessALSA - The raw "
  88. "output queue couldn't enqueue a %d-byte event. "
  89. "Dropping event.", alsa_event->size);
  90. // Fallthrough on purpose
  91. case JackMidiWriteQueue::OK:
  92. continue;
  93. default:
  94. ;
  95. }
  96. break;
  97. }
  98. process_events:
  99. *frame = raw_queue->Process();
  100. blocked = send_queue->IsBlocked();
  101. if (blocked) {
  102. jack_info("JackALSARawMidiOutputPort::ProcessALSA - MIDI port is "
  103. "blocked");
  104. SetPollEventMask(POLLERR | POLLNVAL | POLLOUT);
  105. *frame = 0;
  106. } else {
  107. SetPollEventMask(POLLERR | POLLNVAL);
  108. }
  109. return true;
  110. }
  111. bool
  112. JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
  113. jack_nframes_t frames, int write_fd)
  114. {
  115. read_queue->ResetMidiBuffer(port_buffer);
  116. for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
  117. event = read_queue->DequeueEvent()) {
  118. if (event->size > thread_queue->GetAvailableSpace()) {
  119. jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
  120. "queue doesn't have enough room to enqueue a %d-byte "
  121. "event. Dropping event.", event->size);
  122. continue;
  123. }
  124. char c = 1;
  125. ssize_t result = write(write_fd, &c, 1);
  126. assert(result <= 1);
  127. if (result < 0) {
  128. jack_error("JackALSARawMidiOutputPort::ProcessJack - error "
  129. "writing a byte to the pipe file descriptor: %s",
  130. strerror(errno));
  131. return false;
  132. }
  133. if (! result) {
  134. // Recoverable.
  135. jack_error("JackALSARawMidiOutputPort::ProcessJack - Couldn't "
  136. "write a byte to the pipe file descriptor. Dropping "
  137. "event.");
  138. } else {
  139. assert(thread_queue->EnqueueEvent(event, frames) ==
  140. JackMidiWriteQueue::OK);
  141. }
  142. }
  143. return true;
  144. }