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.

587 lines
18KB

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