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.

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