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.

148 lines
5.5KB

  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. jack_nframes_t
  52. JackALSARawMidiOutputPort::ProcessALSA(int read_fd)
  53. {
  54. unsigned short revents = ProcessPollEvents();
  55. if (blocked) {
  56. if (! (revents & POLLOUT)) {
  57. return 0;
  58. }
  59. blocked = false;
  60. }
  61. if (! alsa_event) {
  62. alsa_event = DequeueALSAEvent(read_fd);
  63. }
  64. for (; alsa_event; alsa_event = DequeueALSAEvent(read_fd)) {
  65. switch (raw_queue->EnqueueEvent(alsa_event)) {
  66. case JackMidiWriteQueue::BUFFER_FULL:
  67. // Try to free up some space by processing events early.
  68. raw_queue->Process();
  69. switch (raw_queue->EnqueueEvent(alsa_event)) {
  70. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  71. jack_error("JackALSARawMidiOutputPort::ProcessALSA - **BUG** "
  72. "JackMidiRawOutputWriteQueue::EnqueueEvent "
  73. "returned `BUFFER_FULL`, and then returned "
  74. "`BUFFER_TOO_SMALL` after a Process() call.");
  75. // Fallthrough on purpose
  76. case JackMidiWriteQueue::OK:
  77. continue;
  78. default:
  79. ;
  80. }
  81. goto process_events;
  82. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  83. jack_error("JackALSARawMidiOutputPort::ProcessALSA - The raw "
  84. "output queue couldn't enqueue a %d-byte event. "
  85. "Dropping event.", alsa_event->size);
  86. // Fallthrough on purpose
  87. case JackMidiWriteQueue::OK:
  88. continue;
  89. default:
  90. ;
  91. }
  92. break;
  93. }
  94. process_events:
  95. jack_nframes_t next_frame = raw_queue->Process();
  96. blocked = send_queue->IsBlocked();
  97. if (blocked) {
  98. jack_info("JackALSARawMidiOutputPort::ProcessALSA - MIDI port is "
  99. "blocked");
  100. SetPollEventMask(POLLERR | POLLNVAL | POLLOUT);
  101. return 0;
  102. }
  103. SetPollEventMask(POLLERR | POLLNVAL);
  104. return next_frame;
  105. }
  106. void
  107. JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
  108. jack_nframes_t frames, int write_fd)
  109. {
  110. read_queue->ResetMidiBuffer(port_buffer);
  111. for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
  112. event = read_queue->DequeueEvent()) {
  113. if (event->size > thread_queue->GetAvailableSpace()) {
  114. jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
  115. "queue doesn't have enough room to enqueue a %d-byte "
  116. "event. Dropping event.", event->size);
  117. continue;
  118. }
  119. char c = 1;
  120. ssize_t result = write(write_fd, &c, 1);
  121. assert(result <= 1);
  122. if (! result) {
  123. jack_error("JackALSARawMidiOutputPort::ProcessJack - Couldn't "
  124. "write a byte to the pipe file descriptor. Dropping "
  125. "event.");
  126. } else if (result < 0) {
  127. jack_error("JackALSARawMidiOutputPort::ProcessJack - error "
  128. "writing a byte to the pipe file descriptor: %s",
  129. strerror(errno));
  130. } else if (thread_queue->EnqueueEvent(event->time + frames,
  131. event->size, event->buffer) !=
  132. JackMidiWriteQueue::OK) {
  133. jack_error("JackALSARawMidiOutputPort::ProcessJack - **BUG** The "
  134. "thread queue said it had enough space to enqueue a "
  135. "%d-byte event, but failed to enqueue the event.");
  136. }
  137. }
  138. }