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.

599 lines
19KB

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