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.

654 lines
22KB

  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 <new>
  17. #include <stdexcept>
  18. #include <alsa/asoundlib.h>
  19. #include "JackALSARawMidiDriver.h"
  20. #include "JackALSARawMidiUtil.h"
  21. #include "JackEngineControl.h"
  22. #include "JackError.h"
  23. #include "JackMidiUtil.h"
  24. using Jack::JackALSARawMidiDriver;
  25. JackALSARawMidiDriver::JackALSARawMidiDriver(const char *name,
  26. const char *alias,
  27. JackLockedEngine *engine,
  28. JackSynchro *table):
  29. JackMidiDriver(name, alias, engine, table)
  30. {
  31. thread = new JackThread(this);
  32. fds[0] = -1;
  33. fds[1] = -1;
  34. input_ports = 0;
  35. output_ports = 0;
  36. output_port_timeouts = 0;
  37. poll_fds = 0;
  38. }
  39. JackALSARawMidiDriver::~JackALSARawMidiDriver()
  40. {
  41. delete thread;
  42. }
  43. int
  44. JackALSARawMidiDriver::Attach()
  45. {
  46. const char *alias;
  47. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  48. jack_port_id_t index;
  49. jack_nframes_t latency = buffer_size;
  50. jack_latency_range_t latency_range;
  51. const char *name;
  52. JackPort *port;
  53. latency_range.max = latency;
  54. latency_range.min = latency;
  55. for (int i = 0; i < fCaptureChannels; i++) {
  56. JackALSARawMidiInputPort *input_port = input_ports[i];
  57. name = input_port->GetName();
  58. fEngine->PortRegister(fClientControl.fRefNum, name,
  59. JACK_DEFAULT_MIDI_TYPE,
  60. CaptureDriverFlags, buffer_size, &index);
  61. if (index == NO_PORT) {
  62. jack_error("JackALSARawMidiDriver::Attach - cannot register input "
  63. "port with name '%s'.", name);
  64. // XX: Do we need to deallocate ports?
  65. return -1;
  66. }
  67. alias = input_port->GetAlias();
  68. port = fGraphManager->GetPort(index);
  69. port->SetAlias(alias);
  70. port->SetLatencyRange(JackCaptureLatency, &latency_range);
  71. fCapturePortList[i] = index;
  72. jack_info("JackALSARawMidiDriver::Attach - input port registered "
  73. "(name='%s', alias='%s').", name, alias);
  74. }
  75. if (! fEngineControl->fSyncMode) {
  76. latency += buffer_size;
  77. latency_range.max = latency;
  78. latency_range.min = latency;
  79. }
  80. for (int i = 0; i < fPlaybackChannels; i++) {
  81. JackALSARawMidiOutputPort *output_port = output_ports[i];
  82. name = output_port->GetName();
  83. fEngine->PortRegister(fClientControl.fRefNum, name,
  84. JACK_DEFAULT_MIDI_TYPE,
  85. PlaybackDriverFlags, buffer_size, &index);
  86. if (index == NO_PORT) {
  87. jack_error("JackALSARawMidiDriver::Attach - cannot register "
  88. "output port with name '%s'.", name);
  89. // XX: Do we need to deallocate ports?
  90. return -1;
  91. }
  92. alias = output_port->GetAlias();
  93. port = fGraphManager->GetPort(index);
  94. port->SetAlias(alias);
  95. port->SetLatencyRange(JackPlaybackLatency, &latency_range);
  96. fPlaybackPortList[i] = index;
  97. jack_info("JackALSARawMidiDriver::Attach - output port registered "
  98. "(name='%s', alias='%s').", name, alias);
  99. }
  100. return 0;
  101. }
  102. int
  103. JackALSARawMidiDriver::Close()
  104. {
  105. // Generic MIDI driver close
  106. int result = JackMidiDriver::Close();
  107. if (input_ports) {
  108. for (int i = 0; i < fCaptureChannels; i++) {
  109. delete input_ports[i];
  110. }
  111. delete[] input_ports;
  112. input_ports = 0;
  113. }
  114. if (output_ports) {
  115. for (int i = 0; i < fPlaybackChannels; i++) {
  116. delete output_ports[i];
  117. }
  118. delete[] output_ports;
  119. output_ports = 0;
  120. }
  121. return result;
  122. }
  123. bool
  124. JackALSARawMidiDriver::Execute()
  125. {
  126. jack_nframes_t timeout_frame = 0;
  127. for (;;) {
  128. struct timespec timeout;
  129. struct timespec *timeout_ptr;
  130. if (! timeout_frame) {
  131. timeout_ptr = 0;
  132. } else {
  133. // The timeout value is relative to the time that
  134. // 'GetMicroSeconds()' is called, not the time that 'poll()' is
  135. // called. This means that the amount of time that passes between
  136. // 'GetMicroSeconds()' and 'ppoll()' is time that will be lost
  137. // while waiting for 'poll() to timeout.
  138. //
  139. // I tried to replace the timeout with a 'timerfd' with absolute
  140. // times, but, strangely, it actually slowed things down, and made
  141. // the code a lot more complicated.
  142. //
  143. // I wonder about using the 'epoll' interface instead of 'ppoll()'.
  144. // The problem with the 'epoll' interface is that the timeout
  145. // resolution of 'epoll_wait()' is set in milliseconds. We need
  146. // microsecond resolution. Without microsecond resolution, we
  147. // impose the same jitter as USB MIDI.
  148. //
  149. // Another problem is that 'ppoll()' returns later than the wait
  150. // time. The problem can be minimized with high precision timers.
  151. timeout_ptr = &timeout;
  152. jack_time_t next_time = GetTimeFromFrames(timeout_frame);
  153. jack_time_t now = GetMicroSeconds();
  154. if (next_time <= now) {
  155. timeout.tv_sec = 0;
  156. timeout.tv_nsec = 0;
  157. } else {
  158. jack_time_t wait_time = next_time - now;
  159. timeout.tv_sec = wait_time / 1000000;
  160. timeout.tv_nsec = (wait_time % 1000000) * 1000;
  161. }
  162. }
  163. int poll_result = ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
  164. // Getting the current frame value here allows us to use it for
  165. // incoming MIDI bytes. This makes sense, as the data has already
  166. // arrived at this point.
  167. jack_nframes_t current_frame = GetCurrentFrame();
  168. if (poll_result == -1) {
  169. if (errno == EINTR) {
  170. continue;
  171. }
  172. jack_error("JackALSARawMidiDriver::Execute - poll error: %s",
  173. strerror(errno));
  174. break;
  175. }
  176. jack_nframes_t port_timeout;
  177. timeout_frame = 0;
  178. if (! poll_result) {
  179. // No I/O events occurred. So, only handle timeout events on
  180. // output ports.
  181. for (int i = 0; i < fPlaybackChannels; i++) {
  182. port_timeout = output_port_timeouts[i];
  183. if (port_timeout && (port_timeout <= current_frame)) {
  184. if (! output_ports[i]->ProcessPollEvents(false, true,
  185. &port_timeout)) {
  186. jack_error("JackALSARawMidiDriver::Execute - a fatal "
  187. "error occurred while processing ALSA "
  188. "output events.");
  189. goto cleanup;
  190. }
  191. output_port_timeouts[i] = port_timeout;
  192. }
  193. if (port_timeout && ((! timeout_frame) ||
  194. (port_timeout < timeout_frame))) {
  195. timeout_frame = port_timeout;
  196. }
  197. }
  198. continue;
  199. }
  200. // See if it's time to shutdown.
  201. unsigned short revents = poll_fds[0].revents;
  202. if (revents) {
  203. if (revents & (~ POLLHUP)) {
  204. jack_error("JackALSARawMidiDriver::Execute - unexpected poll "
  205. "event on pipe file descriptor.");
  206. }
  207. break;
  208. }
  209. // Handle I/O events *and* timeout events on output ports.
  210. for (int i = 0; i < fPlaybackChannels; i++) {
  211. port_timeout = output_port_timeouts[i];
  212. bool timeout = port_timeout && (port_timeout <= current_frame);
  213. if (! output_ports[i]->ProcessPollEvents(true, timeout,
  214. &port_timeout)) {
  215. jack_error("JackALSARawMidiDriver::Execute - a fatal error "
  216. "occurred while processing ALSA output events.");
  217. goto cleanup;
  218. }
  219. output_port_timeouts[i] = port_timeout;
  220. if (port_timeout && ((! timeout_frame) ||
  221. (port_timeout < timeout_frame))) {
  222. timeout_frame = port_timeout;
  223. }
  224. }
  225. // Handle I/O events on input ports. We handle these last because we
  226. // already computed the arrival time above, and will impose a delay on
  227. // the events by 'period-size' frames anyway, which gives us a bit of
  228. // borrowed time.
  229. for (int i = 0; i < fCaptureChannels; i++) {
  230. if (! input_ports[i]->ProcessPollEvents(current_frame)) {
  231. jack_error("JackALSARawMidiDriver::Execute - a fatal error "
  232. "occurred while processing ALSA input events.");
  233. goto cleanup;
  234. }
  235. }
  236. }
  237. cleanup:
  238. close(fds[0]);
  239. fds[0] = -1;
  240. jack_info("JackALSARawMidiDriver::Execute - ALSA thread exiting.");
  241. return false;
  242. }
  243. void
  244. JackALSARawMidiDriver::
  245. FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
  246. std::vector<snd_rawmidi_info_t *> *out_info_list)
  247. {
  248. size_t length = in_info_list->size();
  249. for (size_t i = 0; i < length; i++) {
  250. snd_rawmidi_info_free(in_info_list->at(i));
  251. }
  252. length = out_info_list->size();
  253. for (size_t i = 0; i < length; i++) {
  254. snd_rawmidi_info_free(out_info_list->at(i));
  255. }
  256. }
  257. void
  258. JackALSARawMidiDriver::
  259. GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
  260. std::vector<snd_rawmidi_info_t *> *info_list)
  261. {
  262. snd_rawmidi_info_set_subdevice(info, 0);
  263. int code = snd_ctl_rawmidi_info(control, info);
  264. if (code) {
  265. if (code != -ENOENT) {
  266. HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
  267. }
  268. return;
  269. }
  270. unsigned int count = snd_rawmidi_info_get_subdevices_count(info);
  271. for (unsigned int i = 0; i < count; i++) {
  272. snd_rawmidi_info_set_subdevice(info, i);
  273. int code = snd_ctl_rawmidi_info(control, info);
  274. if (code) {
  275. HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
  276. continue;
  277. }
  278. snd_rawmidi_info_t *info_copy;
  279. code = snd_rawmidi_info_malloc(&info_copy);
  280. if (code) {
  281. HandleALSAError("GetDeviceInfo", "snd_rawmidi_info_malloc", code);
  282. continue;
  283. }
  284. snd_rawmidi_info_copy(info_copy, info);
  285. try {
  286. info_list->push_back(info_copy);
  287. } catch (std::bad_alloc &e) {
  288. snd_rawmidi_info_free(info_copy);
  289. jack_error("JackALSARawMidiDriver::GetDeviceInfo - "
  290. "std::vector::push_back: %s", e.what());
  291. }
  292. }
  293. }
  294. void
  295. JackALSARawMidiDriver::HandleALSAError(const char *driver_func,
  296. const char *alsa_func, int code)
  297. {
  298. jack_error("JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func,
  299. snd_strerror(code));
  300. }
  301. bool
  302. JackALSARawMidiDriver::Init()
  303. {
  304. set_threaded_log_function();
  305. if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) {
  306. jack_error("JackALSARawMidiDriver::Init - could not acquire realtime "
  307. "scheduling. Continuing anyway.");
  308. }
  309. return true;
  310. }
  311. int
  312. JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
  313. int out_channels, bool monitor,
  314. const char *capture_driver_name,
  315. const char *playback_driver_name,
  316. jack_nframes_t capture_latency,
  317. jack_nframes_t playback_latency)
  318. {
  319. snd_rawmidi_info_t *info;
  320. int code = snd_rawmidi_info_malloc(&info);
  321. if (code) {
  322. HandleALSAError("Open", "snd_rawmidi_info_malloc", code);
  323. return -1;
  324. }
  325. std::vector<snd_rawmidi_info_t *> in_info_list;
  326. std::vector<snd_rawmidi_info_t *> out_info_list;
  327. for (int card = -1;;) {
  328. int code = snd_card_next(&card);
  329. if (code) {
  330. HandleALSAError("Open", "snd_card_next", code);
  331. continue;
  332. }
  333. if (card == -1) {
  334. break;
  335. }
  336. char name[32];
  337. snprintf(name, sizeof(name), "hw:%d", card);
  338. snd_ctl_t *control;
  339. code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK);
  340. if (code) {
  341. HandleALSAError("Open", "snd_ctl_open", code);
  342. continue;
  343. }
  344. for (int device = -1;;) {
  345. code = snd_ctl_rawmidi_next_device(control, &device);
  346. if (code) {
  347. HandleALSAError("Open", "snd_ctl_rawmidi_next_device", code);
  348. continue;
  349. }
  350. if (device == -1) {
  351. break;
  352. }
  353. snd_rawmidi_info_set_device(info, device);
  354. snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
  355. GetDeviceInfo(control, info, &in_info_list);
  356. snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
  357. GetDeviceInfo(control, info, &out_info_list);
  358. }
  359. snd_ctl_close(control);
  360. }
  361. snd_rawmidi_info_free(info);
  362. size_t potential_inputs = in_info_list.size();
  363. size_t potential_outputs = out_info_list.size();
  364. if (! (potential_inputs || potential_outputs)) {
  365. jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
  366. "output ports found.");
  367. FreeDeviceInfo(&in_info_list, &out_info_list);
  368. return -1;
  369. }
  370. size_t num_inputs = 0;
  371. size_t num_outputs = 0;
  372. if (potential_inputs) {
  373. try {
  374. input_ports = new JackALSARawMidiInputPort *[potential_inputs];
  375. } catch (std::exception e) {
  376. jack_error("JackALSARawMidiDriver::Open - while creating input "
  377. "port array: %s", e.what());
  378. FreeDeviceInfo(&in_info_list, &out_info_list);
  379. return -1;
  380. }
  381. }
  382. if (potential_outputs) {
  383. try {
  384. output_ports = new JackALSARawMidiOutputPort *[potential_outputs];
  385. } catch (std::exception e) {
  386. jack_error("JackALSARawMidiDriver::Open - while creating output "
  387. "port array: %s", e.what());
  388. FreeDeviceInfo(&in_info_list, &out_info_list);
  389. goto delete_input_ports;
  390. }
  391. }
  392. for (size_t i = 0; i < potential_inputs; i++) {
  393. snd_rawmidi_info_t *info = in_info_list.at(i);
  394. try {
  395. input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i);
  396. num_inputs++;
  397. } catch (std::exception e) {
  398. jack_error("JackALSARawMidiDriver::Open - while creating new "
  399. "JackALSARawMidiInputPort: %s", e.what());
  400. }
  401. snd_rawmidi_info_free(info);
  402. }
  403. for (size_t i = 0; i < potential_outputs; i++) {
  404. snd_rawmidi_info_t *info = out_info_list.at(i);
  405. try {
  406. output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i);
  407. num_outputs++;
  408. } catch (std::exception e) {
  409. jack_error("JackALSARawMidiDriver::Open - while creating new "
  410. "JackALSARawMidiOutputPort: %s", e.what());
  411. }
  412. snd_rawmidi_info_free(info);
  413. }
  414. if (! (num_inputs || num_outputs)) {
  415. jack_error("JackALSARawMidiDriver::Open - none of the potential "
  416. "inputs or outputs were successfully opened.");
  417. } else if (JackMidiDriver::Open(capturing, playing, num_inputs,
  418. num_outputs, monitor, capture_driver_name,
  419. playback_driver_name, capture_latency,
  420. playback_latency)) {
  421. jack_error("JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
  422. } else {
  423. return 0;
  424. }
  425. if (output_ports) {
  426. for (size_t i = 0; i < num_outputs; i++) {
  427. delete output_ports[i];
  428. }
  429. delete[] output_ports;
  430. output_ports = 0;
  431. }
  432. delete_input_ports:
  433. if (input_ports) {
  434. for (size_t i = 0; i < num_inputs; i++) {
  435. delete input_ports[i];
  436. }
  437. delete[] input_ports;
  438. input_ports = 0;
  439. }
  440. return -1;
  441. }
  442. int
  443. JackALSARawMidiDriver::Read()
  444. {
  445. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  446. for (int i = 0; i < fCaptureChannels; i++) {
  447. if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) {
  448. return -1;
  449. }
  450. }
  451. return 0;
  452. }
  453. int
  454. JackALSARawMidiDriver::Start()
  455. {
  456. jack_info("JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");
  457. JackMidiDriver::Start();
  458. poll_fd_count = 1;
  459. for (int i = 0; i < fCaptureChannels; i++) {
  460. poll_fd_count += input_ports[i]->GetPollDescriptorCount();
  461. }
  462. for (int i = 0; i < fPlaybackChannels; i++) {
  463. poll_fd_count += output_ports[i]->GetPollDescriptorCount();
  464. }
  465. try {
  466. poll_fds = new pollfd[poll_fd_count];
  467. } catch (std::exception e) {
  468. jack_error("JackALSARawMidiDriver::Start - creating poll descriptor "
  469. "structures failed: %s", e.what());
  470. return -1;
  471. }
  472. if (fPlaybackChannels) {
  473. try {
  474. output_port_timeouts = new jack_nframes_t[fPlaybackChannels];
  475. } catch (std::exception e) {
  476. jack_error("JackALSARawMidiDriver::Start - creating array for "
  477. "output port timeout values failed: %s", e.what());
  478. goto free_poll_descriptors;
  479. }
  480. }
  481. struct pollfd *poll_fd_iter;
  482. try {
  483. CreateNonBlockingPipe(fds);
  484. } catch (std::exception e) {
  485. jack_error("JackALSARawMidiDriver::Start - while creating wake pipe: "
  486. "%s", e.what());
  487. goto free_output_port_timeouts;
  488. }
  489. poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
  490. poll_fds[0].fd = fds[0];
  491. poll_fd_iter = poll_fds + 1;
  492. for (int i = 0; i < fCaptureChannels; i++) {
  493. JackALSARawMidiInputPort *input_port = input_ports[i];
  494. input_port->PopulatePollDescriptors(poll_fd_iter);
  495. poll_fd_iter += input_port->GetPollDescriptorCount();
  496. }
  497. for (int i = 0; i < fPlaybackChannels; i++) {
  498. JackALSARawMidiOutputPort *output_port = output_ports[i];
  499. output_port->PopulatePollDescriptors(poll_fd_iter);
  500. poll_fd_iter += output_port->GetPollDescriptorCount();
  501. output_port_timeouts[i] = 0;
  502. }
  503. jack_info("JackALSARawMidiDriver::Start - starting ALSA thread ...");
  504. if (! thread->StartSync()) {
  505. jack_info("JackALSARawMidiDriver::Start - started ALSA thread.");
  506. return 0;
  507. }
  508. jack_error("JackALSARawMidiDriver::Start - failed to start MIDI "
  509. "processing thread.");
  510. DestroyNonBlockingPipe(fds);
  511. fds[1] = -1;
  512. fds[0] = -1;
  513. free_output_port_timeouts:
  514. delete[] output_port_timeouts;
  515. output_port_timeouts = 0;
  516. free_poll_descriptors:
  517. delete[] poll_fds;
  518. poll_fds = 0;
  519. return -1;
  520. }
  521. int
  522. JackALSARawMidiDriver::Stop()
  523. {
  524. jack_info("JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");
  525. JackMidiDriver::Stop();
  526. if (fds[1] != -1) {
  527. close(fds[1]);
  528. fds[1] = -1;
  529. }
  530. int result;
  531. const char *verb;
  532. switch (thread->GetStatus()) {
  533. case JackThread::kIniting:
  534. case JackThread::kStarting:
  535. result = thread->Kill();
  536. verb = "kill";
  537. break;
  538. case JackThread::kRunning:
  539. result = thread->Stop();
  540. verb = "stop";
  541. break;
  542. default:
  543. result = 0;
  544. verb = 0;
  545. }
  546. if (fds[0] != -1) {
  547. close(fds[0]);
  548. fds[0] = -1;
  549. }
  550. if (output_port_timeouts) {
  551. delete[] output_port_timeouts;
  552. output_port_timeouts = 0;
  553. }
  554. if (poll_fds) {
  555. delete[] poll_fds;
  556. poll_fds = 0;
  557. }
  558. if (result) {
  559. jack_error("JackALSARawMidiDriver::Stop - could not %s MIDI "
  560. "processing thread.", verb);
  561. }
  562. return result;
  563. }
  564. int
  565. JackALSARawMidiDriver::Write()
  566. {
  567. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  568. for (int i = 0; i < fPlaybackChannels; i++) {
  569. if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size)) {
  570. return -1;
  571. }
  572. }
  573. return 0;
  574. }
  575. #ifdef __cplusplus
  576. extern "C" {
  577. #endif
  578. SERVER_EXPORT jack_driver_desc_t *
  579. driver_get_descriptor()
  580. {
  581. // X: There could be parameters here regarding setting I/O buffer
  582. // sizes. I don't think MIDI drivers can accept parameters right
  583. // now without being set as the main driver.
  584. return jack_driver_descriptor_construct("alsarawmidi", JackDriverSlave, "Alternative ALSA raw MIDI backend.", NULL);
  585. }
  586. SERVER_EXPORT Jack::JackDriverClientInterface *
  587. driver_initialize(Jack::JackLockedEngine *engine, Jack::JackSynchro *table,
  588. const JSList *params)
  589. {
  590. Jack::JackDriverClientInterface *driver =
  591. new Jack::JackALSARawMidiDriver("system_midi", "alsarawmidi",
  592. engine, table);
  593. if (driver->Open(1, 1, 0, 0, false, "midi in", "midi out", 0, 0)) {
  594. delete driver;
  595. driver = 0;
  596. }
  597. return driver;
  598. }
  599. #ifdef __cplusplus
  600. }
  601. #endif