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.

1222 lines
38KB

  1. /*
  2. Copyright (C) 2004-2008 Grame
  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 <iostream>
  16. #include <fstream>
  17. #include <set>
  18. #include <assert.h>
  19. #include <ctype.h>
  20. #include "JackSystemDeps.h"
  21. #include "JackLockedEngine.h"
  22. #include "JackExternalClient.h"
  23. #include "JackInternalClient.h"
  24. #include "JackEngineControl.h"
  25. #include "JackClientControl.h"
  26. #include "JackServerGlobals.h"
  27. #include "JackGlobals.h"
  28. #include "JackChannel.h"
  29. #include "JackError.h"
  30. namespace Jack
  31. {
  32. JackEngine::JackEngine(JackGraphManager* manager,
  33. JackSynchro* table,
  34. JackEngineControl* control,
  35. char self_connect_mode)
  36. : JackLockAble(control->fServerName),
  37. fSignal(control->fServerName)
  38. {
  39. fGraphManager = manager;
  40. fSynchroTable = table;
  41. fEngineControl = control;
  42. fSelfConnectMode = self_connect_mode;
  43. for (int i = 0; i < CLIENT_NUM; i++) {
  44. fClientTable[i] = NULL;
  45. }
  46. fLastSwitchUsecs = 0;
  47. fSessionPendingReplies = 0;
  48. fSessionTransaction = NULL;
  49. fSessionResult = NULL;
  50. }
  51. JackEngine::~JackEngine()
  52. {}
  53. int JackEngine::Open()
  54. {
  55. jack_log("JackEngine::Open");
  56. // Open audio thread => request thread communication channel
  57. if (fChannel.Open(fEngineControl->fServerName) < 0) {
  58. jack_error("Cannot connect to server");
  59. return -1;
  60. } else {
  61. return 0;
  62. }
  63. }
  64. int JackEngine::Close()
  65. {
  66. jack_log("JackEngine::Close");
  67. fChannel.Close();
  68. // Close remaining clients (RT is stopped)
  69. for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
  70. if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) {
  71. jack_log("JackEngine::Close loadable client = %s", loadable_client->GetClientControl()->fName);
  72. loadable_client->Close();
  73. fClientTable[i] = NULL;
  74. delete loadable_client;
  75. } else if (JackExternalClient* external_client = dynamic_cast<JackExternalClient*>(fClientTable[i])) {
  76. jack_log("JackEngine::Close external client = %s", external_client->GetClientControl()->fName);
  77. external_client->Close();
  78. fClientTable[i] = NULL;
  79. delete external_client;
  80. }
  81. }
  82. return 0;
  83. }
  84. void JackEngine::NotifyQuit()
  85. {
  86. fChannel.NotifyQuit();
  87. }
  88. //-----------------------------
  89. // Client ressource management
  90. //-----------------------------
  91. int JackEngine::AllocateRefnum()
  92. {
  93. for (int i = 0; i < CLIENT_NUM; i++) {
  94. if (!fClientTable[i]) {
  95. jack_log("JackEngine::AllocateRefNum ref = %ld", i);
  96. return i;
  97. }
  98. }
  99. return -1;
  100. }
  101. void JackEngine::ReleaseRefnum(int refnum)
  102. {
  103. fClientTable[refnum] = NULL;
  104. if (fEngineControl->fTemporary) {
  105. int i;
  106. for (i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
  107. if (fClientTable[i]) {
  108. break;
  109. }
  110. }
  111. if (i == CLIENT_NUM) {
  112. // Last client and temporay case: quit the server
  113. jack_log("JackEngine::ReleaseRefnum server quit");
  114. fEngineControl->fTemporary = false;
  115. throw JackTemporaryException();
  116. }
  117. }
  118. }
  119. //------------------
  120. // Graph management
  121. //------------------
  122. void JackEngine::ProcessNext(jack_time_t cur_cycle_begin)
  123. {
  124. fLastSwitchUsecs = cur_cycle_begin;
  125. if (fGraphManager->RunNextGraph()) { // True if the graph actually switched to a new state
  126. fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0);
  127. }
  128. fSignal.Signal(); // Signal for threads waiting for next cycle
  129. }
  130. void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin)
  131. {
  132. if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) { // Signal XRun only for the first failing cycle
  133. CheckXRun(cur_cycle_begin);
  134. }
  135. fGraphManager->RunCurrentGraph();
  136. }
  137. bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end)
  138. {
  139. bool res = true;
  140. // Cycle begin
  141. fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end);
  142. // Graph
  143. if (fGraphManager->IsFinishedGraph()) {
  144. ProcessNext(cur_cycle_begin);
  145. res = true;
  146. } else {
  147. jack_log("Process: graph not finished!");
  148. if (cur_cycle_begin > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
  149. jack_log("Process: switch to next state delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
  150. ProcessNext(cur_cycle_begin);
  151. res = true;
  152. } else {
  153. jack_log("Process: waiting to switch delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
  154. ProcessCurrent(cur_cycle_begin);
  155. res = false;
  156. }
  157. }
  158. // Cycle end
  159. fEngineControl->CycleEnd(fClientTable);
  160. return res;
  161. }
  162. /*
  163. Client that finish *after* the callback date are considered late even if their output buffers may have been
  164. correctly mixed in the time window: callbackUsecs <==> Read <==> Write.
  165. */
  166. static const char* State2String(jack_client_state_t state)
  167. {
  168. switch (state) {
  169. case NotTriggered:
  170. return "NotTriggered";
  171. case Triggered:
  172. return "Triggered";
  173. case Running:
  174. return "Running";
  175. case Finished:
  176. return "Finished";
  177. default:
  178. return "";
  179. }
  180. }
  181. void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions de fin
  182. {
  183. for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
  184. JackClientInterface* client = fClientTable[i];
  185. if (client && client->GetClientControl()->fActive) {
  186. JackClientTiming* timing = fGraphManager->GetClientTiming(i);
  187. jack_client_state_t status = timing->fStatus;
  188. jack_time_t finished_date = timing->fFinishedAt;
  189. if (status != NotTriggered && status != Finished) {
  190. jack_error("JackEngine::XRun: client = %s was not finished, state = %s", client->GetClientControl()->fName, State2String(status));
  191. fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients
  192. }
  193. if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
  194. jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
  195. fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients
  196. }
  197. }
  198. }
  199. }
  200. int JackEngine::ComputeTotalLatencies()
  201. {
  202. std::vector<jack_int_t> sorted;
  203. std::vector<jack_int_t>::iterator it;
  204. std::vector<jack_int_t>::reverse_iterator rit;
  205. fGraphManager->TopologicalSort(sorted);
  206. /* iterate over all clients in graph order, and emit
  207. * capture latency callback.
  208. */
  209. for (it = sorted.begin(); it != sorted.end(); it++) {
  210. NotifyClient(*it, kLatencyCallback, true, "", 0, 0);
  211. }
  212. /* now issue playback latency callbacks in reverse graph order.
  213. */
  214. for (rit = sorted.rbegin(); rit != sorted.rend(); rit++) {
  215. NotifyClient(*rit, kLatencyCallback, true, "", 1, 0);
  216. }
  217. return 0;
  218. }
  219. //--------------
  220. // Metadata API
  221. //--------------
  222. int JackEngine::PropertyChangeNotify(jack_uuid_t subject, const char* key, jack_property_change_t change)
  223. {
  224. jack_log("JackEngine::PropertyChangeNotify: subject = %x key = %s change = %x", subject, key, change);
  225. for (int i = 0; i < CLIENT_NUM; i++) {
  226. JackClientInterface* client = fClientTable[i];
  227. if (client) {
  228. char buf[JACK_UUID_STRING_SIZE];
  229. jack_uuid_unparse(subject, buf);
  230. client->ClientNotify(i, buf, kPropertyChangeCallback, false, key, change, 0);
  231. }
  232. }
  233. return 0;
  234. }
  235. //---------------
  236. // Notifications
  237. //---------------
  238. int JackEngine::ClientNotify(JackClientInterface* client, int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
  239. {
  240. // Check if notification is needed
  241. if (!client->GetClientControl()->fCallback[notify]) {
  242. jack_log("JackEngine::ClientNotify: no callback for notification = %ld", notify);
  243. return 0;
  244. }
  245. int res1;
  246. // External client
  247. if (dynamic_cast<JackExternalClient*>(client)) {
  248. res1 = client->ClientNotify(refnum, name, notify, sync, message, value1, value2);
  249. // Important for internal client : unlock before calling the notification callbacks
  250. } else {
  251. bool res2 = Unlock();
  252. res1 = client->ClientNotify(refnum, name, notify, sync, message, value1, value2);
  253. if (res2) {
  254. Lock();
  255. }
  256. }
  257. if (res1 < 0) {
  258. jack_error("ClientNotify fails name = %s notification = %ld val1 = %ld val2 = %ld", name, notify, value1, value2);
  259. }
  260. return res1;
  261. }
  262. void JackEngine::NotifyClient(int refnum, int event, int sync, const char* message, int value1, int value2)
  263. {
  264. JackClientInterface* client = fClientTable[refnum];
  265. if (client) {
  266. ClientNotify(client, refnum, client->GetClientControl()->fName, event, sync, message, value1, value2);
  267. }
  268. }
  269. void JackEngine::NotifyClients(int event, int sync, const char* message, int value1, int value2)
  270. {
  271. for (int i = 0; i < CLIENT_NUM; i++) {
  272. NotifyClient(i, event, sync, message, value1, value2);
  273. }
  274. }
  275. int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* new_name, int refnum)
  276. {
  277. jack_log("JackEngine::NotifyAddClient: name = %s", new_name);
  278. // Notify existing clients of the new client and new client of existing clients.
  279. for (int i = 0; i < CLIENT_NUM; i++) {
  280. JackClientInterface* old_client = fClientTable[i];
  281. if (old_client && old_client != new_client) {
  282. char* old_name = old_client->GetClientControl()->fName;
  283. if (ClientNotify(old_client, refnum, new_name, kAddClient, false, "", 0, 0) < 0) {
  284. jack_error("NotifyAddClient old_client fails name = %s", old_name);
  285. // Not considered as a failure...
  286. }
  287. if (ClientNotify(new_client, i, old_name, kAddClient, true, "", 0, 0) < 0) {
  288. jack_error("NotifyAddClient new_client fails name = %s", new_name);
  289. return -1;
  290. }
  291. }
  292. }
  293. return 0;
  294. }
  295. void JackEngine::NotifyRemoveClient(const char* name, int refnum)
  296. {
  297. // Notify existing clients (including the one beeing suppressed) of the removed client
  298. for (int i = 0; i < CLIENT_NUM; i++) {
  299. JackClientInterface* client = fClientTable[i];
  300. if (client) {
  301. ClientNotify(client, refnum, name, kRemoveClient, false, "", 0, 0);
  302. }
  303. }
  304. }
  305. // Coming from the driver
  306. void JackEngine::NotifyDriverXRun()
  307. {
  308. // Use the audio thread => request thread communication channel
  309. fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);
  310. }
  311. void JackEngine::NotifyClientXRun(int refnum)
  312. {
  313. if (refnum == ALL_CLIENTS) {
  314. NotifyClients(kXRunCallback, false, "", 0, 0);
  315. } else {
  316. NotifyClient(refnum, kXRunCallback, false, "", 0, 0);
  317. }
  318. }
  319. void JackEngine::NotifyGraphReorder()
  320. {
  321. ComputeTotalLatencies();
  322. NotifyClients(kGraphOrderCallback, false, "", 0, 0);
  323. }
  324. void JackEngine::NotifyBufferSize(jack_nframes_t buffer_size)
  325. {
  326. NotifyClients(kBufferSizeCallback, true, "", buffer_size, 0);
  327. }
  328. void JackEngine::NotifySampleRate(jack_nframes_t sample_rate)
  329. {
  330. NotifyClients(kSampleRateCallback, true, "", sample_rate, 0);
  331. }
  332. void JackEngine::NotifyFailure(int code, const char* reason)
  333. {
  334. NotifyClients(kShutDownCallback, false, reason, code, 0);
  335. }
  336. void JackEngine::NotifyFreewheel(bool onoff)
  337. {
  338. if (onoff) {
  339. // Save RT state
  340. fEngineControl->fSavedRealTime = fEngineControl->fRealTime;
  341. fEngineControl->fRealTime = false;
  342. } else {
  343. // Restore RT state
  344. fEngineControl->fRealTime = fEngineControl->fSavedRealTime;
  345. fEngineControl->fSavedRealTime = false;
  346. }
  347. NotifyClients((onoff ? kStartFreewheelCallback : kStopFreewheelCallback), true, "", 0, 0);
  348. }
  349. void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
  350. {
  351. NotifyClients((onoff ? kPortRegistrationOnCallback : kPortRegistrationOffCallback), false, "", port_index, 0);
  352. }
  353. void JackEngine::NotifyPortRename(jack_port_id_t port, const char* old_name)
  354. {
  355. NotifyClients(kPortRenameCallback, false, old_name, port, 0);
  356. }
  357. void JackEngine::NotifyPortConnect(jack_port_id_t src, jack_port_id_t dst, bool onoff)
  358. {
  359. NotifyClients((onoff ? kPortConnectCallback : kPortDisconnectCallback), false, "", src, dst);
  360. }
  361. void JackEngine::NotifyActivate(int refnum)
  362. {
  363. NotifyClient(refnum, kActivateClient, true, "", 0, 0);
  364. }
  365. //----------------------------
  366. // Loadable client management
  367. //----------------------------
  368. int JackEngine::GetInternalClientName(int refnum, char* name_res)
  369. {
  370. JackClientInterface* client = fClientTable[refnum];
  371. assert(client);
  372. strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE);
  373. return 0;
  374. }
  375. int JackEngine::InternalClientHandle(const char* client_name, int* status, int* int_ref)
  376. {
  377. // Clear status
  378. *status = 0;
  379. for (int i = 0; i < CLIENT_NUM; i++) {
  380. JackClientInterface* client = fClientTable[i];
  381. if (client && dynamic_cast<JackLoadableInternalClient*>(client) && (strcmp(client->GetClientControl()->fName, client_name) == 0)) {
  382. jack_log("InternalClientHandle found client name = %s ref = %ld", client_name, i);
  383. *int_ref = i;
  384. return 0;
  385. }
  386. }
  387. *status |= (JackNoSuchClient | JackFailure);
  388. return -1;
  389. }
  390. int JackEngine::InternalClientUnload(int refnum, int* status)
  391. {
  392. JackClientInterface* client = fClientTable[refnum];
  393. if (client) {
  394. int res = client->Close();
  395. delete client;
  396. *status = 0;
  397. return res;
  398. } else {
  399. *status = (JackNoSuchClient | JackFailure);
  400. return -1;
  401. }
  402. }
  403. //-------------------
  404. // Client management
  405. //-------------------
  406. int JackEngine::ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status)
  407. {
  408. // Clear status
  409. *status = 0;
  410. strcpy(name_res, name);
  411. jack_log("Check protocol client = %ld server = %ld", protocol, JACK_PROTOCOL_VERSION);
  412. if (protocol != JACK_PROTOCOL_VERSION) {
  413. *status |= (JackFailure | JackVersionError);
  414. jack_error("JACK protocol mismatch (%d vs %d)", protocol, JACK_PROTOCOL_VERSION);
  415. return -1;
  416. }
  417. std::map<int,std::string>::iterator res = fReservationMap.find(uuid);
  418. if (res != fReservationMap.end()) {
  419. strncpy(name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE);
  420. } else if (ClientCheckName(name)) {
  421. *status |= JackNameNotUnique;
  422. if (options & JackUseExactName) {
  423. jack_error("cannot create new client; %s already exists", name);
  424. *status |= JackFailure;
  425. return -1;
  426. }
  427. if (GenerateUniqueName(name_res)) {
  428. *status |= JackFailure;
  429. return -1;
  430. }
  431. }
  432. return 0;
  433. }
  434. bool JackEngine::GenerateUniqueName(char* name)
  435. {
  436. int tens, ones;
  437. int length = strlen(name);
  438. if (length > JACK_CLIENT_NAME_SIZE - 4) {
  439. jack_error("%s exists and is too long to make unique", name);
  440. return true; /* failure */
  441. }
  442. /* generate a unique name by appending "-01".."-99" */
  443. name[length++] = '-';
  444. tens = length++;
  445. ones = length++;
  446. name[tens] = '0';
  447. name[ones] = '1';
  448. name[length] = '\0';
  449. while (ClientCheckName(name)) {
  450. if (name[ones] == '9') {
  451. if (name[tens] == '9') {
  452. jack_error("client %s has 99 extra instances already", name);
  453. return true; /* give up */
  454. }
  455. name[tens]++;
  456. name[ones] = '0';
  457. } else {
  458. name[ones]++;
  459. }
  460. }
  461. return false;
  462. }
  463. bool JackEngine::ClientCheckName(const char* name)
  464. {
  465. for (int i = 0; i < CLIENT_NUM; i++) {
  466. JackClientInterface* client = fClientTable[i];
  467. if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) {
  468. return true;
  469. }
  470. }
  471. for (std::map<int,std::string>::iterator i = fReservationMap.begin(); i != fReservationMap.end(); i++) {
  472. if (i->second == name) {
  473. return true;
  474. }
  475. }
  476. return false;
  477. }
  478. void JackEngine::EnsureUUID(int uuid)
  479. {
  480. if (uuid == 0)
  481. return;
  482. for (int i = 0; i < CLIENT_NUM; i++) {
  483. JackClientInterface* client = fClientTable[i];
  484. if (client && (client->GetClientControl()->fSessionID == uuid)) {
  485. client->GetClientControl()->fSessionID = 0;
  486. }
  487. }
  488. }
  489. int JackEngine::GetClientPID(const char* name)
  490. {
  491. for (int i = 0; i < CLIENT_NUM; i++) {
  492. JackClientInterface* client = fClientTable[i];
  493. if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) {
  494. return client->GetClientControl()->fPID;
  495. }
  496. }
  497. return 0;
  498. }
  499. int JackEngine::GetClientRefNum(const char* name)
  500. {
  501. for (int i = 0; i < CLIENT_NUM; i++) {
  502. JackClientInterface* client = fClientTable[i];
  503. if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) {
  504. return client->GetClientControl()->fRefNum;
  505. }
  506. }
  507. return -1;
  508. }
  509. // Used for external clients
  510. int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
  511. {
  512. char real_name[JACK_CLIENT_NAME_SIZE + 1];
  513. if (uuid < 0) {
  514. uuid = jack_client_uuid_generate();
  515. strncpy(real_name, name, JACK_CLIENT_NAME_SIZE);
  516. } else {
  517. std::map<int, std::string>::iterator res = fReservationMap.find(uuid);
  518. if (res != fReservationMap.end()) {
  519. strncpy(real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE);
  520. fReservationMap.erase(uuid);
  521. } else {
  522. strncpy(real_name, name, JACK_CLIENT_NAME_SIZE);
  523. }
  524. EnsureUUID(uuid);
  525. }
  526. jack_log("JackEngine::ClientExternalOpen: uuid = %d, name = %s", uuid, real_name);
  527. int refnum = AllocateRefnum();
  528. if (refnum < 0) {
  529. jack_error("No more refnum available");
  530. return -1;
  531. }
  532. JackExternalClient* client = new JackExternalClient();
  533. if (!fSynchroTable[refnum].Allocate(real_name, fEngineControl->fServerName, 0)) {
  534. jack_error("Cannot allocate synchro");
  535. goto error;
  536. }
  537. if (client->Open(real_name, pid, refnum, uuid, shared_client) < 0) {
  538. jack_error("Cannot open client");
  539. goto error;
  540. }
  541. if (!fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
  542. // Failure if RT thread is not running (problem with the driver...)
  543. jack_error("Driver is not running");
  544. goto error;
  545. }
  546. fClientTable[refnum] = client;
  547. if (NotifyAddClient(client, real_name, refnum) < 0) {
  548. jack_error("Cannot notify add client");
  549. goto error;
  550. }
  551. fGraphManager->InitRefNum(refnum);
  552. fEngineControl->ResetRollingUsecs();
  553. *shared_engine = fEngineControl->GetShmIndex();
  554. *shared_graph_manager = fGraphManager->GetShmIndex();
  555. *ref = refnum;
  556. return 0;
  557. error:
  558. // Cleanup...
  559. fSynchroTable[refnum].Destroy();
  560. fClientTable[refnum] = 0;
  561. client->Close();
  562. delete client;
  563. return -1;
  564. }
  565. // Used for server driver clients
  566. int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait)
  567. {
  568. jack_log("JackEngine::ClientInternalOpen: name = %s", name);
  569. int refnum = AllocateRefnum();
  570. if (refnum < 0) {
  571. jack_error("No more refnum available");
  572. goto error;
  573. }
  574. if (!fSynchroTable[refnum].Allocate(name, fEngineControl->fServerName, 0)) {
  575. jack_error("Cannot allocate synchro");
  576. goto error;
  577. }
  578. if (wait && !fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
  579. // Failure if RT thread is not running (problem with the driver...)
  580. jack_error("Driver is not running");
  581. goto error;
  582. }
  583. fClientTable[refnum] = client;
  584. if (NotifyAddClient(client, name, refnum) < 0) {
  585. jack_error("Cannot notify add client");
  586. goto error;
  587. }
  588. fGraphManager->InitRefNum(refnum);
  589. fEngineControl->ResetRollingUsecs();
  590. *shared_engine = fEngineControl;
  591. *shared_manager = fGraphManager;
  592. *ref = refnum;
  593. return 0;
  594. error:
  595. // Cleanup...
  596. fSynchroTable[refnum].Destroy();
  597. fClientTable[refnum] = 0;
  598. return -1;
  599. }
  600. // Used for external clients
  601. int JackEngine::ClientExternalClose(int refnum)
  602. {
  603. jack_log("JackEngine::ClientExternalClose ref = %ld", refnum);
  604. JackClientInterface* client = fClientTable[refnum];
  605. assert(client);
  606. int res = ClientCloseAux(refnum, true);
  607. client->Close();
  608. delete client;
  609. return res;
  610. }
  611. // Used for server internal clients or drivers when the RT thread is stopped
  612. int JackEngine::ClientInternalClose(int refnum, bool wait)
  613. {
  614. jack_log("JackEngine::ClientInternalClose ref = %ld", refnum);
  615. return ClientCloseAux(refnum, wait);
  616. }
  617. int JackEngine::ClientCloseAux(int refnum, bool wait)
  618. {
  619. jack_log("JackEngine::ClientCloseAux ref = %ld", refnum);
  620. JackClientInterface* client = fClientTable[refnum];
  621. fEngineControl->fTransport.ResetTimebase(refnum);
  622. // Unregister all ports ==> notifications are sent
  623. jack_int_t ports[PORT_NUM_FOR_CLIENT];
  624. int i;
  625. fGraphManager->GetInputPorts(refnum, ports);
  626. for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY); i++) {
  627. PortUnRegister(refnum, ports[i]);
  628. }
  629. fGraphManager->GetOutputPorts(refnum, ports);
  630. for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY); i++) {
  631. PortUnRegister(refnum, ports[i]);
  632. }
  633. // Remove the client from the table
  634. ReleaseRefnum(refnum);
  635. // Remove all ports
  636. fGraphManager->RemoveAllPorts(refnum);
  637. // Wait until next cycle to be sure client is not used anymore
  638. if (wait) {
  639. if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure
  640. jack_error("JackEngine::ClientCloseAux wait error ref = %ld", refnum);
  641. }
  642. }
  643. // Notify running clients
  644. NotifyRemoveClient(client->GetClientControl()->fName, refnum);
  645. // Cleanup...
  646. fSynchroTable[refnum].Destroy();
  647. fEngineControl->ResetRollingUsecs();
  648. return 0;
  649. }
  650. int JackEngine::ClientActivate(int refnum, bool is_real_time)
  651. {
  652. JackClientInterface* client = fClientTable[refnum];
  653. jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
  654. if (is_real_time) {
  655. fGraphManager->Activate(refnum);
  656. }
  657. // Wait for graph state change to be effective
  658. if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
  659. jack_error("JackEngine::ClientActivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
  660. return -1;
  661. } else {
  662. jack_int_t input_ports[PORT_NUM_FOR_CLIENT];
  663. jack_int_t output_ports[PORT_NUM_FOR_CLIENT];
  664. fGraphManager->GetInputPorts(refnum, input_ports);
  665. fGraphManager->GetOutputPorts(refnum, output_ports);
  666. // Notify client
  667. NotifyActivate(refnum);
  668. // Then issue port registration notification
  669. for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
  670. NotifyPortRegistation(input_ports[i], true);
  671. }
  672. for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
  673. NotifyPortRegistation(output_ports[i], true);
  674. }
  675. return 0;
  676. }
  677. }
  678. // May be called without client
  679. int JackEngine::ClientDeactivate(int refnum)
  680. {
  681. JackClientInterface* client = fClientTable[refnum];
  682. jack_log("JackEngine::ClientDeactivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
  683. jack_int_t input_ports[PORT_NUM_FOR_CLIENT];
  684. jack_int_t output_ports[PORT_NUM_FOR_CLIENT];
  685. fGraphManager->GetInputPorts(refnum, input_ports);
  686. fGraphManager->GetOutputPorts(refnum, output_ports);
  687. // First disconnect all ports
  688. for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
  689. PortDisconnect(-1, input_ports[i], ALL_PORTS);
  690. }
  691. for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
  692. PortDisconnect(-1, output_ports[i], ALL_PORTS);
  693. }
  694. // Then issue port registration notification
  695. for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
  696. NotifyPortRegistation(input_ports[i], false);
  697. }
  698. for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
  699. NotifyPortRegistation(output_ports[i], false);
  700. }
  701. fGraphManager->Deactivate(refnum);
  702. fLastSwitchUsecs = 0; // Force switch to occur next cycle, even when called with "dead" clients
  703. // Wait for graph state change to be effective
  704. if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
  705. jack_error("JackEngine::ClientDeactivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
  706. return -1;
  707. } else {
  708. return 0;
  709. }
  710. }
  711. void JackEngine::ClientKill(int refnum)
  712. {
  713. jack_log("JackEngine::ClientKill ref = %ld", refnum);
  714. if (ClientDeactivate(refnum) < 0) {
  715. jack_error("JackEngine::ClientKill ref = %ld cannot be removed from the graph !!", refnum);
  716. }
  717. if (ClientExternalClose(refnum) < 0) {
  718. jack_error("JackEngine::ClientKill ref = %ld cannot be closed", refnum);
  719. }
  720. }
  721. //-----------------
  722. // Port management
  723. //-----------------
  724. int JackEngine::PortRegister(int refnum, const char* name, const char *type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index)
  725. {
  726. jack_log("JackEngine::PortRegister ref = %ld name = %s type = %s flags = %d buffer_size = %d", refnum, name, type, flags, buffer_size);
  727. JackClientInterface* client = fClientTable[refnum];
  728. // Check if port name already exists
  729. if (fGraphManager->GetPort(name) != NO_PORT) {
  730. jack_error("port_name \"%s\" already exists", name);
  731. return -1;
  732. }
  733. // buffer_size is actually ignored...
  734. *port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize);
  735. if (*port_index != NO_PORT) {
  736. if (client->GetClientControl()->fActive) {
  737. NotifyPortRegistation(*port_index, true);
  738. }
  739. return 0;
  740. } else {
  741. return -1;
  742. }
  743. }
  744. int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
  745. {
  746. jack_log("JackEngine::PortUnRegister ref = %ld port_index = %ld", refnum, port_index);
  747. JackClientInterface* client = fClientTable[refnum];
  748. assert(client);
  749. // Disconnect port ==> notification is sent
  750. PortDisconnect(-1, port_index, ALL_PORTS);
  751. if (fGraphManager->ReleasePort(refnum, port_index) == 0) {
  752. if (client->GetClientControl()->fActive) {
  753. NotifyPortRegistation(port_index, false);
  754. }
  755. return 0;
  756. } else {
  757. return -1;
  758. }
  759. }
  760. // this check is to prevent apps to self connect to other apps
  761. // TODO: make this work with multiple clients per app
  762. int JackEngine::CheckPortsConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
  763. {
  764. if (fSelfConnectMode == ' ') return 1;
  765. JackPort* src_port = fGraphManager->GetPort(src);
  766. JackPort* dst_port = fGraphManager->GetPort(dst);
  767. jack_log("JackEngine::CheckPortsConnect(ref = %d, src = %d, dst = %d)", refnum, src_port->GetRefNum(), dst_port->GetRefNum());
  768. //jack_log("%s -> %s", src_port->GetName(), dst_port->GetName());
  769. //jack_log("mode = '%c'", fSelfConnectMode);
  770. int src_self = src_port->GetRefNum() == refnum ? 1 : 0;
  771. int dst_self = dst_port->GetRefNum() == refnum ? 1 : 0;
  772. //jack_log("src_self is %s", src_self ? "true" : "false");
  773. //jack_log("dst_self is %s", dst_self ? "true" : "false");
  774. // 0 means client is connecting other client ports (control app patchbay functionality)
  775. // 1 means client is connecting its own port to port of other client (e.g. self connecting into "system" client)
  776. // 2 means client is connecting its own ports (for app internal functionality)
  777. int sum = src_self + dst_self;
  778. //jack_log("sum = %d", sum);
  779. if (sum == 0) return 1;
  780. char lmode = tolower(fSelfConnectMode);
  781. //jack_log("lmode = '%c'", lmode);
  782. if (sum == 2 && lmode == 'e') return 1;
  783. bool fail = lmode != fSelfConnectMode; // fail modes are upper case
  784. //jack_log("fail = %d", (int)fail);
  785. jack_info(
  786. "%s port self connect request%s (%s -> %s)",
  787. fail ? "rejecting" : "ignoring",
  788. sum == 1 ? " to external port" : "",
  789. src_port->GetName(),
  790. dst_port->GetName());
  791. return fail ? -1 : 0;
  792. }
  793. int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
  794. {
  795. jack_log("JackEngine::PortConnect ref = %d src = %s dst = %s", refnum, src, dst);
  796. jack_port_id_t port_src, port_dst;
  797. return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0)
  798. ? -1
  799. : PortConnect(refnum, port_src, port_dst);
  800. }
  801. int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
  802. {
  803. jack_log("JackEngine::PortConnect ref = %d src = %d dst = %d", refnum, src, dst);
  804. JackClientInterface* client;
  805. int ref;
  806. if (fGraphManager->CheckPorts(src, dst) < 0) {
  807. return -1;
  808. }
  809. ref = fGraphManager->GetOutputRefNum(src);
  810. assert(ref >= 0);
  811. client = fClientTable[ref];
  812. assert(client);
  813. if (!client->GetClientControl()->fActive) {
  814. jack_error("Cannot connect ports owned by inactive clients:"
  815. " \"%s\" is not active", client->GetClientControl()->fName);
  816. return -1;
  817. }
  818. ref = fGraphManager->GetInputRefNum(dst);
  819. assert(ref >= 0);
  820. client = fClientTable[ref];
  821. assert(client);
  822. if (!client->GetClientControl()->fActive) {
  823. jack_error("Cannot connect ports owned by inactive clients:"
  824. " \"%s\" is not active", client->GetClientControl()->fName);
  825. return -1;
  826. }
  827. int res = CheckPortsConnect(refnum, src, dst);
  828. if (res != 1) {
  829. return res;
  830. }
  831. res = fGraphManager->Connect(src, dst);
  832. if (res == 0) {
  833. NotifyPortConnect(src, dst, true);
  834. }
  835. return res;
  836. }
  837. int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
  838. {
  839. jack_log("JackEngine::PortDisconnect ref = %d src = %s dst = %s", refnum, src, dst);
  840. jack_port_id_t port_src, port_dst;
  841. return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0)
  842. ? -1
  843. : PortDisconnect(refnum, port_src, port_dst);
  844. }
  845. int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
  846. {
  847. jack_log("JackEngine::PortDisconnect ref = %d src = %d dst = %d", refnum, src, dst);
  848. if (dst == ALL_PORTS) {
  849. jack_int_t connections[CONNECTION_NUM_FOR_PORT];
  850. fGraphManager->GetConnections(src, connections);
  851. JackPort* port = fGraphManager->GetPort(src);
  852. int res = 0;
  853. if (port->GetFlags() & JackPortIsOutput) {
  854. for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
  855. if (PortDisconnect(refnum, src, connections[i]) != 0) {
  856. res = -1;
  857. }
  858. }
  859. } else {
  860. for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
  861. if (PortDisconnect(refnum, connections[i], src) != 0) {
  862. res = -1;
  863. }
  864. }
  865. }
  866. return res;
  867. }
  868. if (fGraphManager->CheckPorts(src, dst) < 0) {
  869. return -1;
  870. }
  871. int res = CheckPortsConnect(refnum, src, dst);
  872. if (res != 1) {
  873. return res;
  874. }
  875. res = fGraphManager->Disconnect(src, dst);
  876. if (res == 0)
  877. NotifyPortConnect(src, dst, false);
  878. return res;
  879. }
  880. int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name)
  881. {
  882. char old_name[REAL_JACK_PORT_NAME_SIZE+1];
  883. strcpy(old_name, fGraphManager->GetPort(port)->GetName());
  884. fGraphManager->GetPort(port)->SetName(name);
  885. NotifyPortRename(port, old_name);
  886. return 0;
  887. }
  888. //--------------------
  889. // Session management
  890. //--------------------
  891. void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, detail::JackChannelTransactionInterface *socket, JackSessionNotifyResult** result)
  892. {
  893. if (fSessionPendingReplies != 0) {
  894. JackSessionNotifyResult res(-1);
  895. res.Write(socket);
  896. jack_log("JackEngine::SessionNotify ... busy");
  897. if (result != NULL) *result = NULL;
  898. return;
  899. }
  900. for (int i = 0; i < CLIENT_NUM; i++) {
  901. JackClientInterface* client = fClientTable[i];
  902. if (client && (client->GetClientControl()->fSessionID < 0)) {
  903. client->GetClientControl()->fSessionID = jack_client_uuid_generate();
  904. }
  905. }
  906. fSessionResult = new JackSessionNotifyResult();
  907. for (int i = 0; i < CLIENT_NUM; i++) {
  908. JackClientInterface* client = fClientTable[i];
  909. if (client && client->GetClientControl()->fCallback[kSessionCallback]) {
  910. // check if this is a notification to a specific client.
  911. if (target != NULL && strlen(target) != 0) {
  912. if (strcmp(target, client->GetClientControl()->fName)) {
  913. continue;
  914. }
  915. }
  916. char path_buf[JACK_PORT_NAME_SIZE];
  917. if (path[strlen(path) - 1] == DIR_SEPARATOR) {
  918. snprintf(path_buf, sizeof path_buf, "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR);
  919. } else {
  920. snprintf(path_buf, sizeof path_buf, "%s%c%s%c", path, DIR_SEPARATOR, client->GetClientControl()->fName, DIR_SEPARATOR);
  921. }
  922. int res = JackTools::MkDir(path_buf);
  923. if (res) jack_error("JackEngine::SessionNotify: can not create session directory '%s'", path_buf);
  924. int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int)type, 0);
  925. if (result == kPendingSessionReply) {
  926. fSessionPendingReplies += 1;
  927. } else if (result == kImmediateSessionReply) {
  928. char uuid_buf[JACK_UUID_SIZE];
  929. snprintf(uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID);
  930. fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf,
  931. client->GetClientControl()->fName,
  932. client->GetClientControl()->fSessionCommand,
  933. client->GetClientControl()->fSessionFlags));
  934. }
  935. }
  936. }
  937. if (result != NULL) *result = fSessionResult;
  938. if (fSessionPendingReplies == 0) {
  939. fSessionResult->Write(socket);
  940. if (result == NULL) delete fSessionResult;
  941. fSessionResult = NULL;
  942. } else {
  943. fSessionTransaction = socket;
  944. }
  945. }
  946. int JackEngine::SessionReply(int refnum)
  947. {
  948. JackClientInterface* client = fClientTable[refnum];
  949. assert(client);
  950. char uuid_buf[JACK_UUID_SIZE];
  951. snprintf(uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID);
  952. fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf,
  953. client->GetClientControl()->fName,
  954. client->GetClientControl()->fSessionCommand,
  955. client->GetClientControl()->fSessionFlags));
  956. fSessionPendingReplies -= 1;
  957. if (fSessionPendingReplies == 0) {
  958. fSessionResult->Write(fSessionTransaction);
  959. if (fSessionTransaction != NULL) {
  960. delete fSessionResult;
  961. }
  962. fSessionResult = NULL;
  963. }
  964. return 0;
  965. }
  966. int JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res)
  967. {
  968. for (int i = 0; i < CLIENT_NUM; i++) {
  969. JackClientInterface* client = fClientTable[i];
  970. if (client && (strcmp(client_name, client->GetClientControl()->fName) == 0)) {
  971. snprintf(uuid_res, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID);
  972. return 0;
  973. }
  974. }
  975. // Did not find name.
  976. return -1;
  977. }
  978. int JackEngine::GetClientNameForUUID(const char *uuid, char *name_res)
  979. {
  980. for (int i = 0; i < CLIENT_NUM; i++) {
  981. JackClientInterface* client = fClientTable[i];
  982. if (!client) {
  983. continue;
  984. }
  985. char uuid_buf[JACK_UUID_SIZE];
  986. snprintf(uuid_buf, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID);
  987. if (strcmp(uuid,uuid_buf) == 0) {
  988. strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE);
  989. return 0;
  990. }
  991. }
  992. // Did not find uuid.
  993. return -1;
  994. }
  995. int JackEngine::ReserveClientName(const char *name, const char *uuid)
  996. {
  997. jack_log("JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid);
  998. if (ClientCheckName(name)) {
  999. jack_log("name already taken");
  1000. return -1;
  1001. }
  1002. EnsureUUID(atoi(uuid));
  1003. fReservationMap[atoi(uuid)] = name;
  1004. return 0;
  1005. }
  1006. int JackEngine::ClientHasSessionCallback(const char *name)
  1007. {
  1008. JackClientInterface* client = NULL;
  1009. for (int i = 0; i < CLIENT_NUM; i++) {
  1010. client = fClientTable[i];
  1011. if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) {
  1012. break;
  1013. }
  1014. }
  1015. if (client) {
  1016. return client->GetClientControl()->fCallback[kSessionCallback];
  1017. } else {
  1018. return -1;
  1019. }
  1020. }
  1021. } // end of namespace