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.

609 lines
22KB

  1. /*
  2. Copyright (C) 2014 Cédric Schieli
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. */
  15. #include "JackCompilerDeps.h"
  16. #include "driver_interface.h"
  17. #include "JackEngineControl.h"
  18. #include "JackLockedEngine.h"
  19. #include "JackWaitCallbackDriver.h"
  20. #include "JackProxyDriver.h"
  21. using namespace std;
  22. namespace Jack
  23. {
  24. JackProxyDriver::JackProxyDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
  25. const char* upstream, const char* promiscuous,
  26. char* client_name, bool auto_connect, bool auto_save)
  27. : JackRestarterDriver(name, alias, engine, table)
  28. {
  29. jack_log("JackProxyDriver::JackProxyDriver upstream %s", upstream);
  30. assert(strlen(upstream) < JACK_CLIENT_NAME_SIZE);
  31. strcpy(fUpstream, upstream);
  32. assert(strlen(client_name) < JACK_CLIENT_NAME_SIZE);
  33. strcpy(fClientName, client_name);
  34. if (promiscuous) {
  35. fPromiscuous = strdup(promiscuous);
  36. }
  37. fAutoConnect = auto_connect;
  38. fAutoSave = auto_save;
  39. }
  40. JackProxyDriver::~JackProxyDriver()
  41. {
  42. if (fHandle) {
  43. UnloadJackModule(fHandle);
  44. }
  45. }
  46. int JackProxyDriver::LoadClientLib()
  47. {
  48. // Already loaded
  49. if (fHandle) {
  50. return 0;
  51. }
  52. fHandle = LoadJackModule(JACK_PROXY_CLIENT_LIB);
  53. if (!fHandle) {
  54. return -1;
  55. }
  56. LoadSymbols();
  57. return 0;
  58. }
  59. //open, close, attach and detach------------------------------------------------------
  60. int JackProxyDriver::Open(jack_nframes_t buffer_size,
  61. jack_nframes_t samplerate,
  62. bool capturing,
  63. bool playing,
  64. int inchannels,
  65. int outchannels,
  66. bool monitor,
  67. const char* capture_driver_name,
  68. const char* playback_driver_name,
  69. jack_nframes_t capture_latency,
  70. jack_nframes_t playback_latency)
  71. {
  72. fDetectPlaybackChannels = (outchannels == -1);
  73. fDetectCaptureChannels = (inchannels == -1);
  74. if (LoadClientLib() != 0) {
  75. jack_error("Cannot dynamically load client library !");
  76. return -1;
  77. }
  78. return JackWaiterDriver::Open(buffer_size, samplerate,
  79. capturing, playing,
  80. inchannels, outchannels,
  81. monitor,
  82. capture_driver_name, playback_driver_name,
  83. capture_latency, playback_latency);
  84. }
  85. int JackProxyDriver::Close()
  86. {
  87. FreePorts();
  88. return JackWaiterDriver::Close();
  89. }
  90. // Attach and Detach are defined as empty methods: port allocation is done when driver actually start (that is in Init)
  91. int JackProxyDriver::Attach()
  92. {
  93. return 0;
  94. }
  95. int JackProxyDriver::Detach()
  96. {
  97. return 0;
  98. }
  99. //init and restart--------------------------------------------------------------------
  100. /*
  101. JackProxyDriver is wrapped in a JackWaitCallbackDriver decorator that behaves
  102. as a "dummy driver, until Initialize method returns.
  103. */
  104. bool JackProxyDriver::Initialize()
  105. {
  106. jack_log("JackProxyDriver::Initialize");
  107. // save existing local connections if needed
  108. if (fAutoSave) {
  109. SaveConnections(0);
  110. }
  111. // new loading, but existing client, restart the driver
  112. if (fClient) {
  113. jack_info("JackProxyDriver restarting...");
  114. jack_client_close(fClient);
  115. }
  116. FreePorts();
  117. // display some additional infos
  118. jack_info("JackProxyDriver started in %s mode.",
  119. (fEngineControl->fSyncMode) ? "sync" : "async");
  120. do {
  121. jack_status_t status;
  122. char *old = NULL;
  123. if (fPromiscuous) {
  124. // as we are fiddling with the environment variable content, save it
  125. const char* tmp = getenv("JACK_PROMISCUOUS_SERVER");
  126. if (tmp) {
  127. old = strdup(tmp);
  128. }
  129. // temporary enable promiscuous mode
  130. if (setenv("JACK_PROMISCUOUS_SERVER", fPromiscuous, 1) < 0) {
  131. free(old);
  132. jack_error("Error allocating memory.");
  133. return false;
  134. }
  135. }
  136. jack_info("JackProxyDriver connecting to %s", fUpstream);
  137. fClient = jack_client_open(fClientName, static_cast<jack_options_t>(JackNoStartServer|JackServerName), &status, fUpstream);
  138. if (fPromiscuous) {
  139. // restore previous environment variable content
  140. if (old) {
  141. if (setenv("JACK_PROMISCUOUS_SERVER", old, 1) < 0) {
  142. free(old);
  143. jack_error("Error allocating memory.");
  144. return false;
  145. }
  146. free(old);
  147. } else {
  148. unsetenv("JACK_PROMISCUOUS_SERVER");
  149. }
  150. }
  151. // the connection failed, try again later
  152. if (!fClient) {
  153. JackSleep(1000000);
  154. }
  155. } while (!fClient);
  156. jack_info("JackProxyDriver connected to %s", fUpstream);
  157. // we are connected, let's register some callbacks
  158. jack_on_shutdown(fClient, shutdown_callback, this);
  159. if (jack_set_process_callback(fClient, process_callback, this) != 0) {
  160. jack_error("Cannot set process callback.");
  161. return false;
  162. }
  163. if (jack_set_buffer_size_callback(fClient, bufsize_callback, this) != 0) {
  164. jack_error("Cannot set buffer size callback.");
  165. return false;
  166. }
  167. if (jack_set_sample_rate_callback(fClient, srate_callback, this) != 0) {
  168. jack_error("Cannot set sample rate callback.");
  169. return false;
  170. }
  171. if (jack_set_port_connect_callback(fClient, connect_callback, this) != 0) {
  172. jack_error("Cannot set port connect callback.");
  173. return false;
  174. }
  175. // detect upstream physical playback ports if needed
  176. if (fDetectPlaybackChannels) {
  177. fPlaybackChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
  178. }
  179. // detect upstream physical capture ports if needed
  180. if (fDetectCaptureChannels) {
  181. fCaptureChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
  182. }
  183. if (AllocPorts() != 0) {
  184. jack_error("Can't allocate ports.");
  185. return false;
  186. }
  187. bufsize_callback(jack_get_buffer_size(fClient));
  188. srate_callback(jack_get_sample_rate(fClient));
  189. // restore local connections if needed
  190. if (fAutoSave) {
  191. LoadConnections(0);
  192. }
  193. // everything is ready, start upstream processing
  194. if (jack_activate(fClient) != 0) {
  195. jack_error("Cannot activate jack client.");
  196. return false;
  197. }
  198. // connect upstream ports if needed
  199. if (fAutoConnect) {
  200. ConnectPorts();
  201. }
  202. return true;
  203. }
  204. int JackProxyDriver::Stop()
  205. {
  206. if (fClient && (jack_deactivate(fClient) != 0)) {
  207. jack_error("Cannot deactivate jack client.");
  208. return -1;
  209. }
  210. return 0;
  211. }
  212. //client callbacks---------------------------------------------------------------------------
  213. int JackProxyDriver::process_callback(jack_nframes_t nframes, void* arg)
  214. {
  215. assert(static_cast<JackProxyDriver*>(arg));
  216. return static_cast<JackProxyDriver*>(arg)->Process();
  217. }
  218. int JackProxyDriver::bufsize_callback(jack_nframes_t nframes, void* arg)
  219. {
  220. assert(static_cast<JackProxyDriver*>(arg));
  221. return static_cast<JackProxyDriver*>(arg)->bufsize_callback(nframes);
  222. }
  223. int JackProxyDriver::bufsize_callback(jack_nframes_t nframes)
  224. {
  225. if (JackTimedDriver::SetBufferSize(nframes) == 0) {
  226. return -1;
  227. }
  228. JackDriver::NotifyBufferSize(nframes);
  229. return 0;
  230. }
  231. int JackProxyDriver::srate_callback(jack_nframes_t nframes, void* arg)
  232. {
  233. assert(static_cast<JackProxyDriver*>(arg));
  234. return static_cast<JackProxyDriver*>(arg)->srate_callback(nframes);
  235. }
  236. int JackProxyDriver::srate_callback(jack_nframes_t nframes)
  237. {
  238. if (JackTimedDriver::SetSampleRate(nframes) == 0) {
  239. return -1;
  240. }
  241. JackDriver::NotifySampleRate(nframes);
  242. return 0;
  243. }
  244. void JackProxyDriver::connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
  245. {
  246. assert(static_cast<JackProxyDriver*>(arg));
  247. static_cast<JackProxyDriver*>(arg)->connect_callback(a, b, connect);
  248. }
  249. void JackProxyDriver::connect_callback(jack_port_id_t a, jack_port_id_t b, int connect)
  250. {
  251. jack_port_t* port;
  252. int i;
  253. // skip port if not our own
  254. port = jack_port_by_id(fClient, a);
  255. if (!jack_port_is_mine(fClient, port)) {
  256. port = jack_port_by_id(fClient, b);
  257. if (!jack_port_is_mine(fClient, port)) {
  258. return;
  259. }
  260. }
  261. for (i = 0; i < fCaptureChannels; i++) {
  262. if (fUpstreamPlaybackPorts[i] == port) {
  263. fUpstreamPlaybackPortConnected[i] = connect;
  264. }
  265. }
  266. for (i = 0; i < fPlaybackChannels; i++) {
  267. if (fUpstreamCapturePorts[i] == port) {
  268. fUpstreamCapturePortConnected[i] = connect;
  269. }
  270. }
  271. }
  272. void JackProxyDriver::shutdown_callback(void* arg)
  273. {
  274. assert(static_cast<JackProxyDriver*>(arg));
  275. static_cast<JackProxyDriver*>(arg)->RestartWait();
  276. }
  277. //jack ports and buffers--------------------------------------------------------------
  278. int JackProxyDriver::CountIO(const char* type, int flags)
  279. {
  280. int count = 0;
  281. const char** ports = jack_get_ports(fClient, NULL, type, flags);
  282. if (ports != NULL) {
  283. while (ports[count]) { count++; }
  284. jack_free(ports);
  285. }
  286. return count;
  287. }
  288. int JackProxyDriver::AllocPorts()
  289. {
  290. jack_log("JackProxyDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
  291. char proxy[REAL_JACK_PORT_NAME_SIZE];
  292. int i;
  293. fUpstreamPlaybackPorts = new jack_port_t* [fCaptureChannels];
  294. fUpstreamPlaybackPortConnected = new int [fCaptureChannels];
  295. for (i = 0; i < fCaptureChannels; i++) {
  296. snprintf(proxy, sizeof(proxy), "%s:to_client_%d", fClientName, i + 1);
  297. fUpstreamPlaybackPorts[i] = jack_port_register(fClient, proxy, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
  298. if (fUpstreamPlaybackPorts[i] == NULL) {
  299. jack_error("driver: cannot register upstream port %s", proxy);
  300. return -1;
  301. }
  302. fUpstreamPlaybackPortConnected[i] = 0;
  303. }
  304. fUpstreamCapturePorts = new jack_port_t* [fPlaybackChannels];
  305. fUpstreamCapturePortConnected = new int [fPlaybackChannels];
  306. for (i = 0; i < fPlaybackChannels; i++) {
  307. snprintf(proxy, sizeof(proxy), "%s:from_client_%d", fClientName, i + 1);
  308. fUpstreamCapturePorts[i] = jack_port_register(fClient, proxy, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
  309. if (fUpstreamCapturePorts[i] == NULL) {
  310. jack_error("driver: cannot register upstream port %s", proxy);
  311. return -1;
  312. }
  313. fUpstreamCapturePortConnected[i] = 0;
  314. }
  315. // local ports are registered here
  316. return JackAudioDriver::Attach();
  317. }
  318. int JackProxyDriver::FreePorts()
  319. {
  320. jack_log("JackProxyDriver::FreePorts");
  321. int i;
  322. for (i = 0; i < fCaptureChannels; i++) {
  323. if (fCapturePortList[i] > 0) {
  324. fEngine->PortUnRegister(fClientControl.fRefNum, fCapturePortList[i]);
  325. fCapturePortList[i] = 0;
  326. }
  327. if (fUpstreamPlaybackPorts && fUpstreamPlaybackPorts[i]) {
  328. fUpstreamPlaybackPorts[i] = NULL;
  329. }
  330. }
  331. for (i = 0; i < fPlaybackChannels; i++) {
  332. if (fPlaybackPortList[i] > 0) {
  333. fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackPortList[i]);
  334. fPlaybackPortList[i] = 0;
  335. }
  336. if (fUpstreamCapturePorts && fUpstreamCapturePorts[i]) {
  337. fUpstreamCapturePorts[i] = NULL;
  338. }
  339. }
  340. delete[] fUpstreamPlaybackPorts;
  341. delete[] fUpstreamPlaybackPortConnected;
  342. delete[] fUpstreamCapturePorts;
  343. delete[] fUpstreamCapturePortConnected;
  344. fUpstreamPlaybackPorts = NULL;
  345. fUpstreamPlaybackPortConnected = NULL;
  346. fUpstreamCapturePorts = NULL;
  347. fUpstreamCapturePortConnected = NULL;
  348. return 0;
  349. }
  350. void JackProxyDriver::ConnectPorts()
  351. {
  352. jack_log("JackProxyDriver::ConnectPorts");
  353. const char** ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
  354. if (ports != NULL) {
  355. for (int i = 0; i < fCaptureChannels && ports[i]; i++) {
  356. jack_connect(fClient, ports[i], jack_port_name(fUpstreamPlaybackPorts[i]));
  357. }
  358. jack_free(ports);
  359. }
  360. ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
  361. if (ports != NULL) {
  362. for (int i = 0; i < fPlaybackChannels && ports[i]; i++) {
  363. jack_connect(fClient, jack_port_name(fUpstreamCapturePorts[i]), ports[i]);
  364. }
  365. jack_free(ports);
  366. }
  367. }
  368. //driver processes--------------------------------------------------------------------
  369. int JackProxyDriver::Read()
  370. {
  371. // take the time at the beginning of the cycle
  372. JackDriver::CycleTakeBeginTime();
  373. int i;
  374. void *from, *to;
  375. size_t buflen = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize;
  376. for (i = 0; i < fCaptureChannels; i++) {
  377. if (fUpstreamPlaybackPortConnected[i]) {
  378. from = jack_port_get_buffer(fUpstreamPlaybackPorts[i], fEngineControl->fBufferSize);
  379. to = GetInputBuffer(i);
  380. memcpy(to, from, buflen);
  381. }
  382. }
  383. return 0;
  384. }
  385. int JackProxyDriver::Write()
  386. {
  387. int i;
  388. void *from, *to;
  389. size_t buflen = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize;
  390. for (i = 0; i < fPlaybackChannels; i++) {
  391. if (fUpstreamCapturePortConnected[i]) {
  392. to = jack_port_get_buffer(fUpstreamCapturePorts[i], fEngineControl->fBufferSize);
  393. from = GetOutputBuffer(i);
  394. memcpy(to, from, buflen);
  395. }
  396. }
  397. return 0;
  398. }
  399. //driver loader-----------------------------------------------------------------------
  400. #ifdef __cplusplus
  401. extern "C"
  402. {
  403. #endif
  404. SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
  405. {
  406. jack_driver_desc_t * desc;
  407. jack_driver_desc_filler_t filler;
  408. jack_driver_param_value_t value;
  409. desc = jack_driver_descriptor_construct("proxy", JackDriverMaster, "proxy backend", &filler);
  410. strcpy(value.str, DEFAULT_UPSTREAM);
  411. jack_driver_descriptor_add_parameter(desc, &filler, "upstream", 'u', JackDriverParamString, &value, NULL, "Name of the upstream jack server", NULL);
  412. strcpy(value.str, "");
  413. jack_driver_descriptor_add_parameter(desc, &filler, "promiscuous", 'p', JackDriverParamString, &value, NULL, "Promiscuous group", NULL);
  414. value.i = -1;
  415. jack_driver_descriptor_add_parameter(desc, &filler, "input-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", "Number of audio input ports. If -1, audio physical input from the master");
  416. jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'P', JackDriverParamInt, &value, NULL, "Number of audio output ports", "Number of audio output ports. If -1, audio physical output from the master");
  417. strcpy(value.str, "proxy");
  418. jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
  419. value.i = false;
  420. jack_driver_descriptor_add_parameter(desc, &filler, "use-username", 'U', JackDriverParamBool, &value, NULL, "Use current username as client name", NULL);
  421. value.i = false;
  422. jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect proxy to upstream system ports", NULL);
  423. value.i = false;
  424. jack_driver_descriptor_add_parameter(desc, &filler, "auto-save", 's', JackDriverParamBool, &value, NULL, "Save/restore connection state when restarting", NULL);
  425. return desc;
  426. }
  427. SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
  428. {
  429. char upstream[JACK_CLIENT_NAME_SIZE + 1];
  430. char promiscuous[JACK_CLIENT_NAME_SIZE + 1] = {0};
  431. char client_name[JACK_CLIENT_NAME_SIZE + 1];
  432. jack_nframes_t period_size = 1024; // to be used while waiting for master period_size
  433. jack_nframes_t sample_rate = 48000; // to be used while waiting for master sample_rate
  434. int capture_ports = -1;
  435. int playback_ports = -1;
  436. const JSList* node;
  437. const jack_driver_param_t* param;
  438. bool auto_connect = false;
  439. bool auto_save = false;
  440. bool use_promiscuous = false;
  441. // Possibly use env variable for upstream name
  442. const char* default_upstream = getenv("JACK_PROXY_UPSTREAM");
  443. strcpy(upstream, (default_upstream) ? default_upstream : DEFAULT_UPSTREAM);
  444. // Possibly use env variable for upstream promiscuous
  445. const char* default_promiscuous = getenv("JACK_PROXY_PROMISCUOUS");
  446. strcpy(promiscuous, (default_promiscuous) ? default_promiscuous : "");
  447. // Possibly use env variable for client name
  448. const char* default_client_name = getenv("JACK_PROXY_CLIENT_NAME");
  449. strcpy(client_name, (default_client_name) ? default_client_name : DEFAULT_CLIENT_NAME);
  450. #ifdef WIN32
  451. const char* username = getenv("USERNAME");
  452. #else
  453. const char* username = getenv("LOGNAME");
  454. #endif
  455. for (node = params; node; node = jack_slist_next(node)) {
  456. param = (const jack_driver_param_t*) node->data;
  457. switch (param->character)
  458. {
  459. case 'u' :
  460. assert(strlen(param->value.str) < JACK_CLIENT_NAME_SIZE);
  461. strcpy(upstream, param->value.str);
  462. break;
  463. case 'p':
  464. assert(strlen(param->value.str) < JACK_CLIENT_NAME_SIZE);
  465. use_promiscuous = true;
  466. strcpy(promiscuous, param->value.str);
  467. break;
  468. case 'C':
  469. capture_ports = param->value.i;
  470. break;
  471. case 'P':
  472. playback_ports = param->value.i;
  473. break;
  474. case 'n' :
  475. assert(strlen(param->value.str) < JACK_CLIENT_NAME_SIZE);
  476. strncpy(client_name, param->value.str, JACK_CLIENT_NAME_SIZE);
  477. break;
  478. case 'U' :
  479. if (username && *username) {
  480. assert(strlen(username) < JACK_CLIENT_NAME_SIZE);
  481. strncpy(client_name, username, JACK_CLIENT_NAME_SIZE);
  482. }
  483. case 'c':
  484. auto_connect = true;
  485. break;
  486. case 's':
  487. auto_save = true;
  488. break;
  489. }
  490. }
  491. try {
  492. Jack::JackDriverClientInterface* driver = new Jack::JackWaitCallbackDriver(
  493. new Jack::JackProxyDriver("system", "proxy_pcm", engine, table, upstream, use_promiscuous ? promiscuous : NULL, client_name, auto_connect, auto_save));
  494. if (driver->Open(period_size, sample_rate, 1, 1, capture_ports, playback_ports, false, "capture_", "playback_", 0, 0) == 0) {
  495. return driver;
  496. } else {
  497. delete driver;
  498. return NULL;
  499. }
  500. } catch (...) {
  501. return NULL;
  502. }
  503. }
  504. #ifdef __cplusplus
  505. }
  506. #endif
  507. }