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.

603 lines
19KB

  1. #include <memory>
  2. #include <new>
  3. #include <stdexcept>
  4. #include <alsa/asoundlib.h>
  5. #include "JackALSARawMidiDriver.h"
  6. #include "JackEngineControl.h"
  7. #include "JackError.h"
  8. #include "JackMidiUtil.h"
  9. using Jack::JackALSARawMidiDriver;
  10. JackALSARawMidiDriver::JackALSARawMidiDriver(const char *name,
  11. const char *alias,
  12. JackLockedEngine *engine,
  13. JackSynchro *table):
  14. JackMidiDriver(name, alias, engine, table)
  15. {
  16. thread = new JackThread(this);
  17. fCaptureChannels = 0;
  18. fds[0] = -1;
  19. fds[1] = -1;
  20. fPlaybackChannels = 0;
  21. input_ports = 0;
  22. output_ports = 0;
  23. poll_fds = 0;
  24. }
  25. JackALSARawMidiDriver::~JackALSARawMidiDriver()
  26. {
  27. Stop();
  28. delete thread;
  29. Close();
  30. }
  31. int
  32. JackALSARawMidiDriver::Attach()
  33. {
  34. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  35. jack_port_id_t index;
  36. jack_nframes_t latency = buffer_size;
  37. jack_latency_range_t latency_range;
  38. const char *name;
  39. JackPort *port;
  40. latency_range.max = latency;
  41. latency_range.min = latency;
  42. for (int i = 0; i < fCaptureChannels; i++) {
  43. JackALSARawMidiInputPort *input_port = input_ports[i];
  44. name = input_port->GetName();
  45. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  46. JACK_DEFAULT_MIDI_TYPE,
  47. CaptureDriverFlags, buffer_size);
  48. if (index == NO_PORT) {
  49. jack_error("JackALSARawMidiDriver::Attach - cannot register input "
  50. "port with name '%s'.", name);
  51. // X: Do we need to deallocate ports?
  52. return -1;
  53. }
  54. port = fGraphManager->GetPort(index);
  55. port->SetAlias(input_port->GetAlias());
  56. port->SetLatencyRange(JackCaptureLatency, &latency_range);
  57. fCapturePortList[i] = index;
  58. }
  59. if (! fEngineControl->fSyncMode) {
  60. latency += buffer_size;
  61. latency_range.max = latency;
  62. latency_range.min = latency;
  63. }
  64. for (int i = 0; i < fPlaybackChannels; i++) {
  65. JackALSARawMidiOutputPort *output_port = output_ports[i];
  66. name = output_port->GetName();
  67. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  68. JACK_DEFAULT_MIDI_TYPE,
  69. PlaybackDriverFlags, buffer_size);
  70. if (index == NO_PORT) {
  71. jack_error("JackALSARawMidiDriver::Attach - cannot register "
  72. "output port with name '%s'.", name);
  73. // X: Do we need to deallocate ports?
  74. return -1;
  75. }
  76. port = fGraphManager->GetPort(index);
  77. port->SetAlias(output_port->GetAlias());
  78. port->SetLatencyRange(JackPlaybackLatency, &latency_range);
  79. fPlaybackPortList[i] = index;
  80. }
  81. return 0;
  82. }
  83. int
  84. JackALSARawMidiDriver::Close()
  85. {
  86. if (input_ports) {
  87. for (int i = 0; i < fCaptureChannels; i++) {
  88. delete input_ports[i];
  89. }
  90. delete[] input_ports;
  91. input_ports = 0;
  92. }
  93. if (output_ports) {
  94. for (int i = 0; i < fPlaybackChannels; i++) {
  95. delete output_ports[i];
  96. }
  97. delete[] output_ports;
  98. output_ports = 0;
  99. }
  100. return 0;
  101. }
  102. bool
  103. JackALSARawMidiDriver::Execute()
  104. {
  105. jack_nframes_t timeout_frame = 0;
  106. for (;;) {
  107. jack_nframes_t process_frame;
  108. jack_time_t wait_time;
  109. jack_time_t *wait_time_ptr;
  110. unsigned short revents;
  111. if (! timeout_frame) {
  112. wait_time_ptr = 0;
  113. } else {
  114. jack_time_t next_time = GetTimeFromFrames(timeout_frame);
  115. jack_time_t now = GetMicroSeconds();
  116. wait_time = next_time <= now ? 0 : next_time - now;
  117. wait_time_ptr = &wait_time;
  118. }
  119. if (Poll(wait_time_ptr) == -1) {
  120. if (errno == EINTR) {
  121. continue;
  122. }
  123. jack_error("JackALSARawMidiDriver::Execute - poll error: %s",
  124. strerror(errno));
  125. break;
  126. }
  127. revents = poll_fds[0].revents;
  128. if (revents & POLLHUP) {
  129. // Driver is being stopped.
  130. break;
  131. }
  132. if (revents & (~ POLLIN)) {
  133. jack_error("JackALSARawMidiDriver::Execute - unexpected poll "
  134. "event on pipe file descriptor.");
  135. break;
  136. }
  137. timeout_frame = 0;
  138. for (int i = 0; i < fCaptureChannels; i++) {
  139. if (! input_ports[i]->ProcessALSA(&process_frame)) {
  140. jack_error("JackALSARawMidiDriver::Execute - a fatal error "
  141. "occurred while processing ALSA input events.");
  142. goto cleanup;
  143. }
  144. if (process_frame && ((! timeout_frame) ||
  145. (process_frame < timeout_frame))) {
  146. timeout_frame = process_frame;
  147. }
  148. }
  149. for (int i = 0; i < fPlaybackChannels; i++) {
  150. if (! output_ports[i]->ProcessALSA(fds[0], &process_frame)) {
  151. jack_error("JackALSARawMidiDriver::Execute - a fatal error "
  152. "occurred while processing ALSA output events.");
  153. goto cleanup;
  154. }
  155. if (process_frame && ((! timeout_frame) ||
  156. (process_frame < timeout_frame))) {
  157. timeout_frame = process_frame;
  158. }
  159. }
  160. }
  161. cleanup:
  162. close(fds[0]);
  163. fds[0] = -1;
  164. jack_info("JackALSARawMidiDriver::Execute - ALSA thread exiting.");
  165. return false;
  166. }
  167. void
  168. JackALSARawMidiDriver::
  169. GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
  170. std::vector<snd_rawmidi_info_t *> *info_list)
  171. {
  172. snd_rawmidi_info_set_subdevice(info, 0);
  173. int code = snd_ctl_rawmidi_info(control, info);
  174. if (code) {
  175. if (code != -ENOENT) {
  176. HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
  177. }
  178. return;
  179. }
  180. unsigned int count = snd_rawmidi_info_get_subdevices_count(info);
  181. for (unsigned int i = 0; i < count; i++) {
  182. snd_rawmidi_info_set_subdevice(info, i);
  183. int code = snd_ctl_rawmidi_info(control, info);
  184. if (code) {
  185. HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
  186. continue;
  187. }
  188. snd_rawmidi_info_t *info_copy;
  189. code = snd_rawmidi_info_malloc(&info_copy);
  190. if (code) {
  191. HandleALSAError("GetDeviceInfo", "snd_rawmidi_info_malloc", code);
  192. continue;
  193. }
  194. snd_rawmidi_info_copy(info_copy, info);
  195. try {
  196. info_list->push_back(info_copy);
  197. } catch (std::bad_alloc &e) {
  198. snd_rawmidi_info_free(info_copy);
  199. jack_error("JackALSARawMidiDriver::GetDeviceInfo - "
  200. "std::vector::push_back: %s", e.what());
  201. }
  202. }
  203. }
  204. void
  205. JackALSARawMidiDriver::HandleALSAError(const char *driver_func,
  206. const char *alsa_func, int code)
  207. {
  208. jack_error("JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func,
  209. snd_strerror(code));
  210. }
  211. bool
  212. JackALSARawMidiDriver::Init()
  213. {
  214. set_threaded_log_function();
  215. if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) {
  216. jack_error("JackALSARawMidiDriver::Init - could not acquire realtime "
  217. "scheduling. Continuing anyway.");
  218. }
  219. return true;
  220. }
  221. int
  222. JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
  223. int out_channels, bool monitor,
  224. const char *capture_driver_name,
  225. const char *playback_driver_name,
  226. jack_nframes_t capture_latency,
  227. jack_nframes_t playback_latency)
  228. {
  229. snd_rawmidi_info_t *info;
  230. int code = snd_rawmidi_info_malloc(&info);
  231. if (code) {
  232. HandleALSAError("Open", "snd_rawmidi_info_malloc", code);
  233. return -1;
  234. }
  235. std::vector<snd_rawmidi_info_t *> in_info_list;
  236. std::vector<snd_rawmidi_info_t *> out_info_list;
  237. for (int card = -1;;) {
  238. int code = snd_card_next(&card);
  239. if (code) {
  240. HandleALSAError("Open", "snd_card_next", code);
  241. continue;
  242. }
  243. if (card == -1) {
  244. break;
  245. }
  246. char name[32];
  247. snprintf(name, sizeof(name), "hw:%d", card);
  248. snd_ctl_t *control;
  249. code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK);
  250. if (code) {
  251. HandleALSAError("Open", "snd_ctl_open", code);
  252. continue;
  253. }
  254. for (int device = -1;;) {
  255. code = snd_ctl_rawmidi_next_device(control, &device);
  256. if (code) {
  257. HandleALSAError("Open", "snd_ctl_rawmidi_next_device", code);
  258. continue;
  259. }
  260. if (device == -1) {
  261. break;
  262. }
  263. snd_rawmidi_info_set_device(info, device);
  264. snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
  265. GetDeviceInfo(control, info, &in_info_list);
  266. snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
  267. GetDeviceInfo(control, info, &out_info_list);
  268. }
  269. snd_ctl_close(control);
  270. }
  271. snd_rawmidi_info_free(info);
  272. size_t potential_inputs = in_info_list.size();
  273. size_t potential_outputs = out_info_list.size();
  274. if (! (potential_inputs || potential_outputs)) {
  275. jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
  276. "output ports found.");
  277. return -1;
  278. }
  279. // XXX: Can't use auto_ptr here. These are arrays, and require the
  280. // delete[] operator.
  281. std::auto_ptr<JackALSARawMidiInputPort *> input_ptr;
  282. if (potential_inputs) {
  283. input_ports = new JackALSARawMidiInputPort *[potential_inputs];
  284. input_ptr.reset(input_ports);
  285. }
  286. std::auto_ptr<JackALSARawMidiOutputPort *> output_ptr;
  287. if (potential_outputs) {
  288. output_ports = new JackALSARawMidiOutputPort *[potential_outputs];
  289. output_ptr.reset(output_ports);
  290. }
  291. size_t num_inputs = 0;
  292. size_t num_outputs = 0;
  293. for (size_t i = 0; i < potential_inputs; i++) {
  294. snd_rawmidi_info_t *info = in_info_list.at(i);
  295. try {
  296. input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i);
  297. jack_info("JackALSARawMidiDriver::Open - Input port: card=%d, "
  298. "device=%d, subdevice=%d, id=%s, name=%s, subdevice "
  299. "name=%s",
  300. snd_rawmidi_info_get_card(info),
  301. snd_rawmidi_info_get_device(info),
  302. snd_rawmidi_info_get_subdevice(info),
  303. snd_rawmidi_info_get_id(info),
  304. snd_rawmidi_info_get_name(info),
  305. snd_rawmidi_info_get_subdevice_name(info));
  306. num_inputs++;
  307. } catch (std::exception e) {
  308. jack_error("JackALSARawMidiDriver::Open - while creating new "
  309. "JackALSARawMidiInputPort: %s", e.what());
  310. }
  311. snd_rawmidi_info_free(info);
  312. }
  313. for (size_t i = 0; i < potential_outputs; i++) {
  314. snd_rawmidi_info_t *info = out_info_list.at(i);
  315. try {
  316. output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i);
  317. jack_info("JackALSARawMidiDriver::Open - Output port: card=%d, "
  318. "device=%d, subdevice=%d, id=%s, name=%s, subdevice "
  319. "name=%s",
  320. snd_rawmidi_info_get_card(info),
  321. snd_rawmidi_info_get_device(info),
  322. snd_rawmidi_info_get_subdevice(info),
  323. snd_rawmidi_info_get_id(info),
  324. snd_rawmidi_info_get_name(info),
  325. snd_rawmidi_info_get_subdevice_name(info));
  326. num_outputs++;
  327. } catch (std::exception e) {
  328. jack_error("JackALSARawMidiDriver::Open - while creating new "
  329. "JackALSARawMidiOutputPort: %s", e.what());
  330. }
  331. snd_rawmidi_info_free(info);
  332. }
  333. if (num_inputs || num_outputs) {
  334. if (! JackMidiDriver::Open(capturing, playing, num_inputs, num_outputs,
  335. monitor, capture_driver_name,
  336. playback_driver_name, capture_latency,
  337. playback_latency)) {
  338. if (potential_inputs) {
  339. input_ptr.release();
  340. }
  341. if (potential_outputs) {
  342. output_ptr.release();
  343. }
  344. return 0;
  345. }
  346. jack_error("JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
  347. } else {
  348. jack_error("JackALSARawMidiDriver::Open - none of the potential "
  349. "inputs or outputs were successfully opened.");
  350. }
  351. Close();
  352. return -1;
  353. }
  354. #ifdef HAVE_PPOLL
  355. int
  356. JackALSARawMidiDriver::Poll(const jack_time_t *wait_time)
  357. {
  358. struct timespec timeout;
  359. struct timespec *timeout_ptr;
  360. if (! wait_time) {
  361. timeout_ptr = 0;
  362. } else {
  363. timeout.tv_sec = (*wait_time) / 1000000;
  364. timeout.tv_nsec = ((*wait_time) % 1000000) * 1000;
  365. timeout_ptr = &timeout;
  366. }
  367. return ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
  368. }
  369. #else
  370. int
  371. JackALSARawMidiDriver::Poll(const jack_time_t *wait_time)
  372. {
  373. int result = poll(poll_fds, poll_fd_count,
  374. ! wait_time ? -1 : (int) ((*wait_time) / 1000));
  375. if ((! result) && wait_time) {
  376. jack_time_t time_left = (*wait_time) % 1000;
  377. if (time_left) {
  378. // Cheap hack.
  379. usleep(time_left);
  380. result = poll(poll_fds, poll_fd_count, 0);
  381. }
  382. }
  383. return result;
  384. }
  385. #endif
  386. int
  387. JackALSARawMidiDriver::Read()
  388. {
  389. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  390. for (int i = 0; i < fCaptureChannels; i++) {
  391. if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) {
  392. return -1;
  393. }
  394. }
  395. return 0;
  396. }
  397. int
  398. JackALSARawMidiDriver::Start()
  399. {
  400. jack_info("JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");
  401. JackMidiDriver::Start();
  402. poll_fd_count = 1;
  403. for (int i = 0; i < fCaptureChannels; i++) {
  404. poll_fd_count += input_ports[i]->GetPollDescriptorCount();
  405. }
  406. for (int i = 0; i < fPlaybackChannels; i++) {
  407. poll_fd_count += output_ports[i]->GetPollDescriptorCount();
  408. }
  409. try {
  410. poll_fds = new pollfd[poll_fd_count];
  411. } catch (std::bad_alloc e) {
  412. jack_error("JackALSARawMidiDriver::Start - creating poll descriptor "
  413. "structures failed: %s", e.what());
  414. return -1;
  415. }
  416. int flags;
  417. struct pollfd *poll_fd_iter;
  418. if (pipe(fds) == -1) {
  419. jack_error("JackALSARawMidiDriver::Start - while creating wake pipe: "
  420. "%s", strerror(errno));
  421. goto free_poll_descriptors;
  422. }
  423. flags = fcntl(fds[0], F_GETFL);
  424. if (flags == -1) {
  425. jack_error("JackALSARawMidiDriver::Start = while getting flags for "
  426. "read file descriptor: %s", strerror(errno));
  427. goto close_fds;
  428. }
  429. if (fcntl(fds[0], F_SETFL, flags | O_NONBLOCK) == -1) {
  430. jack_error("JackALSARawMidiDriver::Start - while setting non-blocking "
  431. "mode for read file descriptor: %s", strerror(errno));
  432. goto close_fds;
  433. }
  434. flags = fcntl(fds[1], F_GETFL);
  435. if (flags == -1) {
  436. jack_error("JackALSARawMidiDriver::Start = while getting flags for "
  437. "write file descriptor: %s", strerror(errno));
  438. goto close_fds;
  439. }
  440. if (fcntl(fds[1], F_SETFL, flags | O_NONBLOCK) == -1) {
  441. jack_error("JackALSARawMidiDriver::Start - while setting non-blocking "
  442. "mode for write file descriptor: %s", strerror(errno));
  443. goto close_fds;
  444. }
  445. poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
  446. poll_fds[0].fd = fds[0];
  447. poll_fd_iter = poll_fds + 1;
  448. for (int i = 0; i < fCaptureChannels; i++) {
  449. JackALSARawMidiInputPort *input_port = input_ports[i];
  450. input_port->PopulatePollDescriptors(poll_fd_iter);
  451. poll_fd_iter += input_port->GetPollDescriptorCount();
  452. }
  453. for (int i = 0; i < fPlaybackChannels; i++) {
  454. JackALSARawMidiOutputPort *output_port = output_ports[i];
  455. output_port->PopulatePollDescriptors(poll_fd_iter);
  456. poll_fd_iter += output_port->GetPollDescriptorCount();
  457. }
  458. jack_info("JackALSARawMidiDriver::Start - starting ALSA thread ...");
  459. if (! thread->StartSync()) {
  460. jack_info("JackALSARawMidiDriver::Start - started ALSA thread.");
  461. return 0;
  462. }
  463. jack_error("JackALSARawMidiDriver::Start - failed to start MIDI "
  464. "processing thread.");
  465. close_fds:
  466. close(fds[1]);
  467. fds[1] = -1;
  468. close(fds[0]);
  469. fds[0] = -1;
  470. free_poll_descriptors:
  471. delete[] poll_fds;
  472. poll_fds = 0;
  473. return -1;
  474. }
  475. int
  476. JackALSARawMidiDriver::Stop()
  477. {
  478. jack_info("JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");
  479. if (fds[1] != -1) {
  480. close(fds[1]);
  481. fds[1] = -1;
  482. }
  483. int result;
  484. const char *verb;
  485. switch (thread->GetStatus()) {
  486. case JackThread::kIniting:
  487. case JackThread::kStarting:
  488. result = thread->Kill();
  489. verb = "kill";
  490. break;
  491. case JackThread::kRunning:
  492. result = thread->Stop();
  493. verb = "stop";
  494. break;
  495. default:
  496. result = 0;
  497. verb = 0;
  498. }
  499. if (fds[0] != -1) {
  500. close(fds[0]);
  501. fds[0] = -1;
  502. }
  503. if (poll_fds) {
  504. delete[] poll_fds;
  505. poll_fds = 0;
  506. }
  507. if (result) {
  508. jack_error("JackALSARawMidiDriver::Stop - could not %s MIDI "
  509. "processing thread.", verb);
  510. }
  511. return result;
  512. }
  513. int
  514. JackALSARawMidiDriver::Write()
  515. {
  516. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  517. int write_fd = fds[1];
  518. for (int i = 0; i < fPlaybackChannels; i++) {
  519. if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size,
  520. write_fd)) {
  521. return -1;
  522. }
  523. }
  524. return 0;
  525. }
  526. #ifdef __cplusplus
  527. extern "C" {
  528. #endif
  529. SERVER_EXPORT jack_driver_desc_t *
  530. driver_get_descriptor()
  531. {
  532. jack_driver_desc_t *desc =
  533. (jack_driver_desc_t *) malloc(sizeof(jack_driver_desc_t));
  534. if (desc) {
  535. strcpy(desc->desc, "Alternative ALSA raw MIDI backend.");
  536. strcpy(desc->name, "alsarawmidi");
  537. // X: There could be parameters here regarding setting I/O buffer
  538. // sizes. I don't think MIDI drivers can accept parameters right
  539. // now without being set as the main driver.
  540. desc->nparams = 0;
  541. desc->params = 0;
  542. }
  543. return desc;
  544. }
  545. SERVER_EXPORT Jack::JackDriverClientInterface *
  546. driver_initialize(Jack::JackLockedEngine *engine, Jack::JackSynchro *table,
  547. const JSList *params)
  548. {
  549. Jack::JackDriverClientInterface *driver =
  550. new Jack::JackALSARawMidiDriver("system_midi", "alsarawmidi",
  551. engine, table);
  552. if (driver->Open(1, 1, 0, 0, false, "midi in", "midi out", 0, 0)) {
  553. delete driver;
  554. driver = 0;
  555. }
  556. return driver;
  557. }
  558. #ifdef __cplusplus
  559. }
  560. #endif