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.

625 lines
20KB

  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 "JackEngineControl.h"
  21. #include "JackError.h"
  22. #include "JackMidiUtil.h"
  23. using Jack::JackALSARawMidiDriver;
  24. JackALSARawMidiDriver::JackALSARawMidiDriver(const char *name,
  25. const char *alias,
  26. JackLockedEngine *engine,
  27. JackSynchro *table):
  28. JackMidiDriver(name, alias, engine, table)
  29. {
  30. thread = new JackThread(this);
  31. fCaptureChannels = 0;
  32. fds[0] = -1;
  33. fds[1] = -1;
  34. fPlaybackChannels = 0;
  35. input_ports = 0;
  36. output_ports = 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. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  59. JACK_DEFAULT_MIDI_TYPE,
  60. CaptureDriverFlags, buffer_size);
  61. if (index == NO_PORT) {
  62. jack_error("JackALSARawMidiDriver::Attach - cannot register input "
  63. "port with name '%s'.", name);
  64. // X: 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. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  84. JACK_DEFAULT_MIDI_TYPE,
  85. PlaybackDriverFlags, buffer_size);
  86. if (index == NO_PORT) {
  87. jack_error("JackALSARawMidiDriver::Attach - cannot register "
  88. "output port with name '%s'.", name);
  89. // X: 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. jack_nframes_t process_frame;
  129. unsigned short revents;
  130. struct timespec timeout;
  131. struct timespec *timeout_ptr;
  132. if (! timeout_frame) {
  133. timeout_ptr = 0;
  134. } else {
  135. // We use a relative timeout here. By the time ppoll is called,
  136. // the wait time is larger than it needs to be. Maybe we should
  137. // use a timerfd instead.
  138. //
  139. // Also, ppoll is inefficient in certain cases. We might want to
  140. // consider replacing it with epoll, though I'm uncertain as to
  141. // whether or not it would be more efficient in this case.
  142. timeout_ptr = &timeout;
  143. jack_time_t next_time = GetTimeFromFrames(timeout_frame);
  144. jack_time_t now = GetMicroSeconds();
  145. if (next_time <= now) {
  146. timeout.tv_sec = 0;
  147. timeout.tv_nsec = 0;
  148. } else {
  149. jack_time_t wait_time = next_time - now;
  150. timeout.tv_sec = wait_time / 1000000;
  151. timeout.tv_nsec = (wait_time % 1000000) * 1000;
  152. }
  153. }
  154. if (ppoll(poll_fds, poll_fd_count, timeout_ptr, 0) == -1) {
  155. if (errno == EINTR) {
  156. continue;
  157. }
  158. jack_error("JackALSARawMidiDriver::Execute - poll error: %s",
  159. strerror(errno));
  160. break;
  161. }
  162. if (timeout_frame_ptr) {
  163. jack_info("JackALSARawMidiDriver::Execute - '%d', '%d'",
  164. timeout_frame, GetCurrentFrame());
  165. }
  166. revents = poll_fds[0].revents;
  167. if (revents & POLLHUP) {
  168. // Driver is being stopped.
  169. break;
  170. }
  171. if (revents & (~ POLLIN)) {
  172. jack_error("JackALSARawMidiDriver::Execute - unexpected poll "
  173. "event on pipe file descriptor.");
  174. break;
  175. }
  176. timeout_frame = 0;
  177. for (int i = 0; i < fPlaybackChannels; i++) {
  178. if (! output_ports[i]->ProcessALSA(fds[0], &process_frame)) {
  179. jack_error("JackALSARawMidiDriver::Execute - a fatal error "
  180. "occurred while processing ALSA output events.");
  181. goto cleanup;
  182. }
  183. if (process_frame && ((! timeout_frame) ||
  184. (process_frame < timeout_frame))) {
  185. timeout_frame = process_frame;
  186. }
  187. }
  188. for (int i = 0; i < fCaptureChannels; i++) {
  189. if (! input_ports[i]->ProcessALSA(&process_frame)) {
  190. jack_error("JackALSARawMidiDriver::Execute - a fatal error "
  191. "occurred while processing ALSA input events.");
  192. goto cleanup;
  193. }
  194. if (process_frame && ((! timeout_frame) ||
  195. (process_frame < timeout_frame))) {
  196. timeout_frame = process_frame;
  197. }
  198. }
  199. }
  200. cleanup:
  201. close(fds[0]);
  202. fds[0] = -1;
  203. jack_info("JackALSARawMidiDriver::Execute - ALSA thread exiting.");
  204. return false;
  205. }
  206. void
  207. JackALSARawMidiDriver::
  208. FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
  209. std::vector<snd_rawmidi_info_t *> *out_info_list)
  210. {
  211. size_t length = in_info_list.size();
  212. for (size_t i = 0; i < length; i++) {
  213. snd_rawmidi_info_free(in_info_list.at(i));
  214. }
  215. length = out_info_list.size();
  216. for (size_t i = 0; i < length; i++) {
  217. snd_rawmidi_info_free(out_info_list.at(i));
  218. }
  219. }
  220. void
  221. JackALSARawMidiDriver::
  222. GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
  223. std::vector<snd_rawmidi_info_t *> *info_list)
  224. {
  225. snd_rawmidi_info_set_subdevice(info, 0);
  226. int code = snd_ctl_rawmidi_info(control, info);
  227. if (code) {
  228. if (code != -ENOENT) {
  229. HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
  230. }
  231. return;
  232. }
  233. unsigned int count = snd_rawmidi_info_get_subdevices_count(info);
  234. for (unsigned int i = 0; i < count; i++) {
  235. snd_rawmidi_info_set_subdevice(info, i);
  236. int code = snd_ctl_rawmidi_info(control, info);
  237. if (code) {
  238. HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
  239. continue;
  240. }
  241. snd_rawmidi_info_t *info_copy;
  242. code = snd_rawmidi_info_malloc(&info_copy);
  243. if (code) {
  244. HandleALSAError("GetDeviceInfo", "snd_rawmidi_info_malloc", code);
  245. continue;
  246. }
  247. snd_rawmidi_info_copy(info_copy, info);
  248. try {
  249. info_list->push_back(info_copy);
  250. } catch (std::bad_alloc &e) {
  251. snd_rawmidi_info_free(info_copy);
  252. jack_error("JackALSARawMidiDriver::GetDeviceInfo - "
  253. "std::vector::push_back: %s", e.what());
  254. }
  255. }
  256. }
  257. void
  258. JackALSARawMidiDriver::HandleALSAError(const char *driver_func,
  259. const char *alsa_func, int code)
  260. {
  261. jack_error("JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func,
  262. snd_strerror(code));
  263. }
  264. bool
  265. JackALSARawMidiDriver::Init()
  266. {
  267. set_threaded_log_function();
  268. if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) {
  269. jack_error("JackALSARawMidiDriver::Init - could not acquire realtime "
  270. "scheduling. Continuing anyway.");
  271. }
  272. return true;
  273. }
  274. int
  275. JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
  276. int out_channels, bool monitor,
  277. const char *capture_driver_name,
  278. const char *playback_driver_name,
  279. jack_nframes_t capture_latency,
  280. jack_nframes_t playback_latency)
  281. {
  282. snd_rawmidi_info_t *info;
  283. int code = snd_rawmidi_info_malloc(&info);
  284. if (code) {
  285. HandleALSAError("Open", "snd_rawmidi_info_malloc", code);
  286. return -1;
  287. }
  288. std::vector<snd_rawmidi_info_t *> in_info_list;
  289. std::vector<snd_rawmidi_info_t *> out_info_list;
  290. for (int card = -1;;) {
  291. int code = snd_card_next(&card);
  292. if (code) {
  293. HandleALSAError("Open", "snd_card_next", code);
  294. continue;
  295. }
  296. if (card == -1) {
  297. break;
  298. }
  299. char name[32];
  300. snprintf(name, sizeof(name), "hw:%d", card);
  301. snd_ctl_t *control;
  302. code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK);
  303. if (code) {
  304. HandleALSAError("Open", "snd_ctl_open", code);
  305. continue;
  306. }
  307. for (int device = -1;;) {
  308. code = snd_ctl_rawmidi_next_device(control, &device);
  309. if (code) {
  310. HandleALSAError("Open", "snd_ctl_rawmidi_next_device", code);
  311. continue;
  312. }
  313. if (device == -1) {
  314. break;
  315. }
  316. snd_rawmidi_info_set_device(info, device);
  317. snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
  318. GetDeviceInfo(control, info, &in_info_list);
  319. snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
  320. GetDeviceInfo(control, info, &out_info_list);
  321. }
  322. snd_ctl_close(control);
  323. }
  324. snd_rawmidi_info_free(info);
  325. size_t potential_inputs = in_info_list.size();
  326. size_t potential_outputs = out_info_list.size();
  327. if (! (potential_inputs || potential_outputs)) {
  328. jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
  329. "output ports found.");
  330. FreeDeviceInfo(&in_info_list, &out_info_list);
  331. return -1;
  332. }
  333. if (potential_inputs) {
  334. try {
  335. input_ports = new JackALSARawMidiInputPort *[potential_inputs];
  336. } catch (std::exception e) {
  337. jack_error("JackALSARawMidiDriver::Open - while creating input "
  338. "port array: %s", e.what());
  339. FreeDeviceInfo(&in_info_list, &out_info_list);
  340. return -1;
  341. }
  342. }
  343. if (potential_outputs) {
  344. try {
  345. output_ports = new JackALSARawMidiOutputPort *[potential_outputs];
  346. } catch (std::exception e) {
  347. jack_error("JackALSARawMidiDriver::Open - while creating output "
  348. "port array: %s", e.what());
  349. FreeDeviceInfo(&in_info_list, &out_info_list);
  350. goto delete_input_ports;
  351. }
  352. }
  353. size_t num_inputs = 0;
  354. size_t num_outputs = 0;
  355. for (size_t i = 0; i < potential_inputs; i++) {
  356. snd_rawmidi_info_t *info = in_info_list.at(i);
  357. try {
  358. input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i);
  359. num_inputs++;
  360. } catch (std::exception e) {
  361. jack_error("JackALSARawMidiDriver::Open - while creating new "
  362. "JackALSARawMidiInputPort: %s", e.what());
  363. }
  364. snd_rawmidi_info_free(info);
  365. }
  366. for (size_t i = 0; i < potential_outputs; i++) {
  367. snd_rawmidi_info_t *info = out_info_list.at(i);
  368. try {
  369. output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i);
  370. num_outputs++;
  371. } catch (std::exception e) {
  372. jack_error("JackALSARawMidiDriver::Open - while creating new "
  373. "JackALSARawMidiOutputPort: %s", e.what());
  374. }
  375. snd_rawmidi_info_free(info);
  376. }
  377. if (! (num_inputs || num_outputs)) {
  378. jack_error("JackALSARawMidiDriver::Open - none of the potential "
  379. "inputs or outputs were successfully opened.");
  380. } else if (JackMidiDriver::Open(capturing, playing, num_inputs,
  381. num_outputs, monitor, capture_driver_name,
  382. playback_driver_name, capture_latency,
  383. playback_latency)) {
  384. jack_error("JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
  385. } else {
  386. return 0;
  387. }
  388. if (output_ports) {
  389. for (int i = 0; i < num_outputs; i++) {
  390. delete output_ports[i];
  391. }
  392. delete[] output_ports;
  393. output_ports = 0;
  394. }
  395. delete_input_ports:
  396. if (input_ports) {
  397. for (int i = 0; i < num_inputs; i++) {
  398. delete input_ports[i];
  399. }
  400. delete[] input_ports;
  401. input_ports = 0;
  402. }
  403. return -1;
  404. }
  405. int
  406. JackALSARawMidiDriver::Read()
  407. {
  408. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  409. for (int i = 0; i < fCaptureChannels; i++) {
  410. if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) {
  411. return -1;
  412. }
  413. }
  414. return 0;
  415. }
  416. int
  417. JackALSARawMidiDriver::Start()
  418. {
  419. jack_info("JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");
  420. JackMidiDriver::Start();
  421. poll_fd_count = 1;
  422. for (int i = 0; i < fCaptureChannels; i++) {
  423. poll_fd_count += input_ports[i]->GetPollDescriptorCount();
  424. }
  425. for (int i = 0; i < fPlaybackChannels; i++) {
  426. poll_fd_count += output_ports[i]->GetPollDescriptorCount();
  427. }
  428. try {
  429. poll_fds = new pollfd[poll_fd_count];
  430. } catch (std::bad_alloc e) {
  431. jack_error("JackALSARawMidiDriver::Start - creating poll descriptor "
  432. "structures failed: %s", e.what());
  433. return -1;
  434. }
  435. int flags;
  436. struct pollfd *poll_fd_iter;
  437. if (pipe(fds) == -1) {
  438. jack_error("JackALSARawMidiDriver::Start - while creating wake pipe: "
  439. "%s", strerror(errno));
  440. goto free_poll_descriptors;
  441. }
  442. flags = fcntl(fds[0], F_GETFL);
  443. if (flags == -1) {
  444. jack_error("JackALSARawMidiDriver::Start = while getting flags for "
  445. "read file descriptor: %s", strerror(errno));
  446. goto close_fds;
  447. }
  448. if (fcntl(fds[0], F_SETFL, flags | O_NONBLOCK) == -1) {
  449. jack_error("JackALSARawMidiDriver::Start - while setting non-blocking "
  450. "mode for read file descriptor: %s", strerror(errno));
  451. goto close_fds;
  452. }
  453. flags = fcntl(fds[1], F_GETFL);
  454. if (flags == -1) {
  455. jack_error("JackALSARawMidiDriver::Start = while getting flags for "
  456. "write file descriptor: %s", strerror(errno));
  457. goto close_fds;
  458. }
  459. if (fcntl(fds[1], F_SETFL, flags | O_NONBLOCK) == -1) {
  460. jack_error("JackALSARawMidiDriver::Start - while setting non-blocking "
  461. "mode for write file descriptor: %s", strerror(errno));
  462. goto close_fds;
  463. }
  464. poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
  465. poll_fds[0].fd = fds[0];
  466. poll_fd_iter = poll_fds + 1;
  467. for (int i = 0; i < fCaptureChannels; i++) {
  468. JackALSARawMidiInputPort *input_port = input_ports[i];
  469. input_port->PopulatePollDescriptors(poll_fd_iter);
  470. poll_fd_iter += input_port->GetPollDescriptorCount();
  471. }
  472. for (int i = 0; i < fPlaybackChannels; i++) {
  473. JackALSARawMidiOutputPort *output_port = output_ports[i];
  474. output_port->PopulatePollDescriptors(poll_fd_iter);
  475. poll_fd_iter += output_port->GetPollDescriptorCount();
  476. }
  477. jack_info("JackALSARawMidiDriver::Start - starting ALSA thread ...");
  478. if (! thread->StartSync()) {
  479. jack_info("JackALSARawMidiDriver::Start - started ALSA thread.");
  480. return 0;
  481. }
  482. jack_error("JackALSARawMidiDriver::Start - failed to start MIDI "
  483. "processing thread.");
  484. close_fds:
  485. close(fds[1]);
  486. fds[1] = -1;
  487. close(fds[0]);
  488. fds[0] = -1;
  489. free_poll_descriptors:
  490. delete[] poll_fds;
  491. poll_fds = 0;
  492. return -1;
  493. }
  494. int
  495. JackALSARawMidiDriver::Stop()
  496. {
  497. jack_info("JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");
  498. if (fds[1] != -1) {
  499. close(fds[1]);
  500. fds[1] = -1;
  501. }
  502. int result;
  503. const char *verb;
  504. switch (thread->GetStatus()) {
  505. case JackThread::kIniting:
  506. case JackThread::kStarting:
  507. result = thread->Kill();
  508. verb = "kill";
  509. break;
  510. case JackThread::kRunning:
  511. result = thread->Stop();
  512. verb = "stop";
  513. break;
  514. default:
  515. result = 0;
  516. verb = 0;
  517. }
  518. if (fds[0] != -1) {
  519. close(fds[0]);
  520. fds[0] = -1;
  521. }
  522. if (poll_fds) {
  523. delete[] poll_fds;
  524. poll_fds = 0;
  525. }
  526. if (result) {
  527. jack_error("JackALSARawMidiDriver::Stop - could not %s MIDI "
  528. "processing thread.", verb);
  529. }
  530. return result;
  531. }
  532. int
  533. JackALSARawMidiDriver::Write()
  534. {
  535. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  536. int write_fd = fds[1];
  537. for (int i = 0; i < fPlaybackChannels; i++) {
  538. if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size,
  539. write_fd)) {
  540. return -1;
  541. }
  542. }
  543. return 0;
  544. }
  545. #ifdef __cplusplus
  546. extern "C" {
  547. #endif
  548. SERVER_EXPORT jack_driver_desc_t *
  549. driver_get_descriptor()
  550. {
  551. jack_driver_desc_t *desc =
  552. (jack_driver_desc_t *) malloc(sizeof(jack_driver_desc_t));
  553. if (desc) {
  554. strcpy(desc->desc, "Alternative ALSA raw MIDI backend.");
  555. strcpy(desc->name, "alsarawmidi");
  556. // X: There could be parameters here regarding setting I/O buffer
  557. // sizes. I don't think MIDI drivers can accept parameters right
  558. // now without being set as the main driver.
  559. desc->nparams = 0;
  560. desc->params = 0;
  561. }
  562. return desc;
  563. }
  564. SERVER_EXPORT Jack::JackDriverClientInterface *
  565. driver_initialize(Jack::JackLockedEngine *engine, Jack::JackSynchro *table,
  566. const JSList *params)
  567. {
  568. Jack::JackDriverClientInterface *driver =
  569. new Jack::JackALSARawMidiDriver("system_midi", "alsarawmidi",
  570. engine, table);
  571. if (driver->Open(1, 1, 0, 0, false, "midi in", "midi out", 0, 0)) {
  572. delete driver;
  573. driver = 0;
  574. }
  575. return driver;
  576. }
  577. #ifdef __cplusplus
  578. }
  579. #endif