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.

813 lines
25KB

  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 <assert.h>
  18. #ifndef WIN32
  19. #include <sys/types.h>
  20. #include <signal.h>
  21. #endif
  22. #include "JackEngine.h"
  23. #include "JackExternalClient.h"
  24. #include "JackInternalClient.h"
  25. #include "JackEngineControl.h"
  26. #include "JackClientControl.h"
  27. #include "JackGlobals.h"
  28. #include "JackChannel.h"
  29. #include "JackSyncInterface.h"
  30. #include "JackError.h"
  31. namespace Jack
  32. {
  33. JackEngine::JackEngine(JackGraphManager* manager,
  34. JackSynchro** table,
  35. JackEngineControl* control)
  36. {
  37. fGraphManager = manager;
  38. fSynchroTable = table;
  39. fEngineControl = control;
  40. fChannel = JackGlobals::MakeServerNotifyChannel();
  41. fSignal = JackGlobals::MakeInterProcessSync();
  42. for (int i = 0; i < CLIENT_NUM; i++)
  43. fClientTable[i] = NULL;
  44. }
  45. JackEngine::~JackEngine()
  46. {
  47. jack_log("JackEngine::~JackEngine");
  48. delete fChannel;
  49. delete fSignal;
  50. }
  51. int JackEngine::Open()
  52. {
  53. jack_log("JackEngine::Open");
  54. // Open audio thread => request thread communication channel
  55. if (fChannel->Open(fEngineControl->fServerName) < 0) {
  56. jack_error("Cannot connect to server");
  57. return -1;
  58. } else {
  59. return 0;
  60. }
  61. }
  62. int JackEngine::Close()
  63. {
  64. jack_log("JackEngine::Close");
  65. fChannel->Close();
  66. // Close (possibly) remaining clients (RT is stopped)
  67. for (int i = 0; i < CLIENT_NUM; i++) {
  68. /*
  69. Can only delete clients that where loaded using "jack_internal_client_load" (and not properly unloaded using "jack_internal_client_unload"...)
  70. */
  71. JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i]);
  72. if (loadable_client) {
  73. jack_log("JackEngine::Close delete loadable client %ld", i);
  74. delete loadable_client;
  75. fClientTable[i] = NULL;
  76. }
  77. }
  78. fSignal->Destroy();
  79. return 0;
  80. }
  81. //-----------------------------
  82. // Client ressource management
  83. //-----------------------------
  84. int JackEngine::AllocateRefnum()
  85. {
  86. for (int i = 0; i < CLIENT_NUM; i++) {
  87. if (!fClientTable[i]) {
  88. jack_log("JackEngine::AllocateRefNum ref = %ld", i);
  89. return i;
  90. }
  91. }
  92. return -1;
  93. }
  94. void JackEngine::ReleaseRefnum(int ref)
  95. {
  96. fClientTable[ref] = NULL;
  97. if (fEngineControl->fTemporary) {
  98. int i;
  99. for (i = REAL_REFNUM; i < CLIENT_NUM; i++) {
  100. if (fClientTable[i])
  101. break;
  102. }
  103. if (i == CLIENT_NUM) {
  104. // last client and temporay case: quit the server
  105. jack_log("JackEngine::ReleaseRefnum server quit");
  106. fEngineControl->fTemporary = false;
  107. #ifndef WIN32
  108. exit(0);
  109. #endif
  110. }
  111. }
  112. }
  113. //------------------
  114. // Graph management
  115. //------------------
  116. void JackEngine::ProcessNext(jack_time_t callback_usecs)
  117. {
  118. fLastSwitchUsecs = callback_usecs;
  119. if (fGraphManager->RunNextGraph()) // True if the graph actually switched to a new state
  120. fChannel->Notify(ALL_CLIENTS, kGraphOrderCallback, 0);
  121. fSignal->SignalAll(); // Signal for threads waiting for next cycle
  122. }
  123. void JackEngine::ProcessCurrent(jack_time_t callback_usecs)
  124. {
  125. if (callback_usecs < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle
  126. CheckXRun(callback_usecs);
  127. fGraphManager->RunCurrentGraph();
  128. }
  129. bool JackEngine::Process(jack_time_t callback_usecs)
  130. {
  131. bool res = true;
  132. // Cycle begin
  133. fEngineControl->CycleBegin(fClientTable, fGraphManager, callback_usecs);
  134. // Graph
  135. if (fGraphManager->IsFinishedGraph()) {
  136. ProcessNext(callback_usecs);
  137. res = true;
  138. } else {
  139. jack_log("Process: graph not finished!");
  140. if (callback_usecs > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
  141. jack_log("Process: switch to next state delta = %ld", long(callback_usecs - fLastSwitchUsecs));
  142. ProcessNext(callback_usecs);
  143. res = true;
  144. } else {
  145. jack_log("Process: waiting to switch delta = %ld", long(callback_usecs - fLastSwitchUsecs));
  146. ProcessCurrent(callback_usecs);
  147. res = false;
  148. }
  149. }
  150. // Cycle end
  151. fEngineControl->CycleEnd(fClientTable);
  152. return res;
  153. }
  154. /*
  155. Client that finish *after* the callback date are considered late even if their output buffers may have been
  156. correctly mixed in the time window: callbackUsecs <==> Read <==> Write.
  157. */
  158. void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions de fin
  159. {
  160. for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
  161. JackClientInterface* client = fClientTable[i];
  162. if (client && client->GetClientControl()->fActive) {
  163. JackClientTiming* timing = fGraphManager->GetClientTiming(i);
  164. jack_client_state_t status = timing->fStatus;
  165. jack_time_t finished_date = timing->fFinishedAt;
  166. if (status != NotTriggered && status != Finished) {
  167. jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status);
  168. fChannel->Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients
  169. }
  170. if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
  171. jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
  172. fChannel->Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients
  173. }
  174. }
  175. }
  176. }
  177. //---------------
  178. // Notifications
  179. //---------------
  180. void JackEngine::NotifyClient(int refnum, int event, int sync, int value1, int value2)
  181. {
  182. JackClientInterface* client = fClientTable[refnum];
  183. // The client may be notified by the RT thread while closing
  184. if (!client) {
  185. jack_log("JackEngine::NotifyClient: client not available anymore");
  186. } else if (client->GetClientControl()->fCallback[event]) {
  187. if (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, value1, value2) < 0)
  188. jack_error("NotifyClient fails name = %s event = %ld = val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
  189. } else {
  190. jack_log("JackEngine::NotifyClient: no callback for event = %ld", event);
  191. }
  192. }
  193. void JackEngine::NotifyClients(int event, int sync, int value1, int value2)
  194. {
  195. for (int i = 0; i < CLIENT_NUM; i++) {
  196. JackClientInterface* client = fClientTable[i];
  197. if (client) {
  198. if (client->GetClientControl()->fCallback[event]) {
  199. if (client->ClientNotify(i, client->GetClientControl()->fName, event, sync, value1, value2) < 0)
  200. jack_error("NotifyClient fails name = %s event = %ld = val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
  201. } else {
  202. jack_log("JackEngine::NotifyClients: no callback for event = %ld", event);
  203. }
  204. }
  205. }
  206. }
  207. int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum)
  208. {
  209. // Notify existing clients of the new client and new client of existing clients.
  210. for (int i = 0; i < CLIENT_NUM; i++) {
  211. JackClientInterface* old_client = fClientTable[i];
  212. if (old_client) {
  213. if (old_client->ClientNotify(refnum, name, kAddClient, true, 0, 0) < 0) {
  214. jack_error("NotifyAddClient old_client fails name = %s", old_client->GetClientControl()->fName);
  215. return -1;
  216. }
  217. if (new_client->ClientNotify(i, old_client->GetClientControl()->fName, kAddClient, true, 0, 0) < 0) {
  218. jack_error("NotifyAddClient new_client fails name = %s", name);
  219. return -1;
  220. }
  221. }
  222. }
  223. return 0;
  224. }
  225. void JackEngine::NotifyRemoveClient(const char* name, int refnum)
  226. {
  227. // Notify existing clients (including the one beeing suppressed) of the removed client
  228. for (int i = 0; i < CLIENT_NUM; i++) {
  229. JackClientInterface* client = fClientTable[i];
  230. if (client) {
  231. client->ClientNotify(refnum, name, kRemoveClient, true, 0, 0);
  232. }
  233. }
  234. }
  235. // Coming from the driver
  236. void JackEngine::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs)
  237. {
  238. // Use the audio thread => request thread communication channel
  239. fEngineControl->ResetFrameTime(callback_usecs);
  240. fEngineControl->NotifyXRun(delayed_usecs);
  241. fChannel->Notify(ALL_CLIENTS, kXRunCallback, 0);
  242. }
  243. void JackEngine::NotifyXRun(int refnum)
  244. {
  245. if (refnum == ALL_CLIENTS) {
  246. NotifyClients(kXRunCallback, false, 0, 0);
  247. } else {
  248. NotifyClient(refnum, kXRunCallback, false, 0, 0);
  249. }
  250. }
  251. void JackEngine::NotifyGraphReorder()
  252. {
  253. NotifyClients(kGraphOrderCallback, false, 0, 0);
  254. }
  255. void JackEngine::NotifyBufferSize(jack_nframes_t nframes)
  256. {
  257. NotifyClients(kBufferSizeCallback, true, nframes, 0);
  258. }
  259. void JackEngine::NotifyFreewheel(bool onoff)
  260. {
  261. fEngineControl->fRealTime = !onoff;
  262. NotifyClients((onoff ? kStartFreewheelCallback : kStopFreewheelCallback), true, 0, 0);
  263. }
  264. void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
  265. {
  266. NotifyClients((onoff ? kPortRegistrationOnCallback : kPortRegistrationOffCallback), false, port_index, 0);
  267. }
  268. void JackEngine::NotifyPortConnect(jack_port_id_t src, jack_port_id_t dst, bool onoff)
  269. {
  270. NotifyClients((onoff ? kPortConnectCallback : kPortDisconnectCallback), false, src, dst);
  271. }
  272. void JackEngine::NotifyActivate(int refnum)
  273. {
  274. NotifyClient(refnum, kActivateClient, true, 0, 0);
  275. }
  276. //----------------------------
  277. // Loadable client management
  278. //----------------------------
  279. int JackEngine::GetInternalClientName(int refnum, char* name_res)
  280. {
  281. assert(refnum >= 0 && refnum < CLIENT_NUM);
  282. JackClientInterface* client = fClientTable[refnum];
  283. if (client) {
  284. strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE);
  285. return 0;
  286. } else {
  287. return -1;
  288. }
  289. }
  290. int JackEngine::InternalClientHandle(const char* client_name, int* status, int* int_ref)
  291. {
  292. // Clear status
  293. *status = 0;
  294. for (int i = 0; i < CLIENT_NUM; i++) {
  295. JackClientInterface* client = fClientTable[i];
  296. if (client && dynamic_cast<JackLoadableInternalClient*>(client) && (strcmp(client->GetClientControl()->fName, client_name) == 0)) {
  297. jack_log("InternalClientHandle found client name = %s ref = %ld", client_name, i);
  298. *int_ref = i;
  299. return 0;
  300. }
  301. }
  302. *status |= (JackNoSuchClient | JackFailure);
  303. return -1;
  304. }
  305. int JackEngine::InternalClientUnload(int refnum, int* status)
  306. {
  307. assert(refnum >= 0 && refnum < CLIENT_NUM);
  308. JackClientInterface* client = fClientTable[refnum];
  309. if (client) {
  310. int res = client->Close();
  311. delete client;
  312. *status = 0;
  313. return res;
  314. } else {
  315. *status = (JackNoSuchClient | JackFailure);
  316. return -1;
  317. }
  318. }
  319. //-------------------
  320. // Client management
  321. //-------------------
  322. int JackEngine::ClientCheck(const char* name, char* name_res, int protocol, int options, int* status)
  323. {
  324. // Clear status
  325. *status = 0;
  326. strcpy(name_res, name);
  327. jack_log("Check protocol client %ld server = %ld", protocol, JACK_PROTOCOL_VERSION);
  328. if (protocol != JACK_PROTOCOL_VERSION) {
  329. *status |= (JackFailure | JackVersionError);
  330. jack_error("JACK protocol mismatch (%d vs %d)", protocol, JACK_PROTOCOL_VERSION);
  331. return -1;
  332. }
  333. if (ClientCheckName(name)) {
  334. *status |= JackNameNotUnique;
  335. if (options & JackUseExactName) {
  336. jack_error("cannot create new client; %s already exists", name);
  337. *status |= JackFailure;
  338. return -1;
  339. }
  340. if (GenerateUniqueName(name_res)) {
  341. *status |= JackFailure;
  342. return -1;
  343. }
  344. }
  345. return 0;
  346. }
  347. bool JackEngine::GenerateUniqueName(char* name)
  348. {
  349. int tens, ones;
  350. int length = strlen(name);
  351. if (length > JACK_CLIENT_NAME_SIZE - 4) {
  352. jack_error("%s exists and is too long to make unique", name);
  353. return true; /* failure */
  354. }
  355. /* generate a unique name by appending "-01".."-99" */
  356. name[length++] = '-';
  357. tens = length++;
  358. ones = length++;
  359. name[tens] = '0';
  360. name[ones] = '1';
  361. name[length] = '\0';
  362. while (ClientCheckName(name)) {
  363. if (name[ones] == '9') {
  364. if (name[tens] == '9') {
  365. jack_error("client %s has 99 extra instances already", name);
  366. return true; /* give up */
  367. }
  368. name[tens]++;
  369. name[ones] = '0';
  370. } else {
  371. name[ones]++;
  372. }
  373. }
  374. return false;
  375. }
  376. bool JackEngine::ClientCheckName(const char* name)
  377. {
  378. for (int i = 0; i < CLIENT_NUM; i++) {
  379. JackClientInterface* client = fClientTable[i];
  380. if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
  381. return true;
  382. }
  383. return false;
  384. }
  385. int JackEngine::GetClientPID(const char* name)
  386. {
  387. for (int i = 0; i < CLIENT_NUM; i++) {
  388. JackClientInterface* client = fClientTable[i];
  389. if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
  390. return client->GetClientControl()->fPID;
  391. }
  392. return 0;
  393. }
  394. // Used for external clients
  395. int JackEngine::ClientExternalOpen(const char* name, int pid, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
  396. {
  397. jack_log("JackEngine::ClientOpen: name = %s ", name);
  398. int refnum = AllocateRefnum();
  399. if (refnum < 0) {
  400. jack_error("No more refnum available");
  401. return -1;
  402. }
  403. JackExternalClient* client = new JackExternalClient();
  404. if (!fSynchroTable[refnum]->Allocate(name, fEngineControl->fServerName, 0)) {
  405. jack_error("Cannot allocate synchro");
  406. goto error;
  407. }
  408. if (client->Open(name, pid, refnum, shared_client) < 0) {
  409. jack_error("Cannot open client");
  410. goto error;
  411. }
  412. if (!fSignal->TimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
  413. // Failure if RT thread is not running (problem with the driver...)
  414. jack_error("Driver is not running");
  415. goto error;
  416. }
  417. fClientTable[refnum] = client;
  418. if (NotifyAddClient(client, name, refnum) < 0) {
  419. jack_error("Cannot notify add client");
  420. goto error;
  421. }
  422. fGraphManager->InitRefNum(refnum);
  423. fEngineControl->ResetRollingUsecs();
  424. *shared_engine = fEngineControl->GetShmIndex();
  425. *shared_graph_manager = fGraphManager->GetShmIndex();
  426. *ref = refnum;
  427. return 0;
  428. error:
  429. // Cleanup...
  430. fSynchroTable[refnum]->Destroy();
  431. fClientTable[refnum] = 0;
  432. client->Close();
  433. delete client;
  434. return -1;
  435. }
  436. // Used for server driver clients
  437. int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait)
  438. {
  439. jack_log("JackEngine::ClientInternalNew: name = %s", name);
  440. int refnum = AllocateRefnum();
  441. if (refnum < 0) {
  442. jack_error("No more refnum available");
  443. goto error;
  444. }
  445. if (!fSynchroTable[refnum]->Allocate(name, fEngineControl->fServerName, 0)) {
  446. jack_error("Cannot allocate synchro");
  447. goto error;
  448. }
  449. if (wait && !fSignal->TimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
  450. // Failure if RT thread is not running (problem with the driver...)
  451. jack_error("Driver is not running");
  452. goto error;
  453. }
  454. fClientTable[refnum] = client;
  455. if (NotifyAddClient(client, name, refnum) < 0) {
  456. jack_error("Cannot notify add client");
  457. goto error;
  458. }
  459. fGraphManager->InitRefNum(refnum);
  460. fEngineControl->ResetRollingUsecs();
  461. *shared_engine = fEngineControl;
  462. *shared_manager = fGraphManager;
  463. *ref = refnum;
  464. return 0;
  465. error:
  466. // Cleanup...
  467. fSynchroTable[refnum]->Destroy();
  468. fClientTable[refnum] = 0;
  469. return -1;
  470. }
  471. // Used for external clients
  472. int JackEngine::ClientExternalClose(int refnum)
  473. {
  474. JackClientInterface* client = fClientTable[refnum];
  475. if (client) {
  476. fEngineControl->fTransport.ResetTimebase(refnum);
  477. int res = ClientCloseAux(refnum, client, true);
  478. client->Close();
  479. delete client;
  480. return res;
  481. } else {
  482. return -1;
  483. }
  484. }
  485. // Used for server internal clients or drivers when the RT thread is stopped
  486. int JackEngine::ClientInternalClose(int refnum, bool wait)
  487. {
  488. JackClientInterface* client = fClientTable[refnum];
  489. return (client) ? ClientCloseAux(refnum, client, wait) : -1;
  490. }
  491. int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wait)
  492. {
  493. jack_log("JackEngine::ClientCloseAux ref = %ld", refnum);
  494. // Unregister all ports ==> notifications are sent
  495. jack_int_t ports[PORT_NUM_FOR_CLIENT];
  496. int i;
  497. fGraphManager->GetInputPorts(refnum, ports);
  498. for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
  499. PortUnRegister(refnum, ports[i]);
  500. }
  501. fGraphManager->GetOutputPorts(refnum, ports);
  502. for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
  503. PortUnRegister(refnum, ports[i]);
  504. }
  505. // Remove the client from the table
  506. ReleaseRefnum(refnum);
  507. // Remove all ports
  508. fGraphManager->RemoveAllPorts(refnum);
  509. // Wait until next cycle to be sure client is not used anymore
  510. if (wait) {
  511. if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure
  512. jack_error("JackEngine::ClientCloseAux wait error ref = %ld", refnum);
  513. }
  514. }
  515. // Notify running clients
  516. NotifyRemoveClient(client->GetClientControl()->fName, client->GetClientControl()->fRefNum);
  517. // Cleanup...
  518. fSynchroTable[refnum]->Destroy();
  519. fEngineControl->ResetRollingUsecs();
  520. return 0;
  521. }
  522. int JackEngine::ClientActivate(int refnum, bool state)
  523. {
  524. JackClientInterface* client = fClientTable[refnum];
  525. assert(fClientTable[refnum]);
  526. jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
  527. if (state)
  528. fGraphManager->Activate(refnum);
  529. // Wait for graph state change to be effective
  530. if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 10)) {
  531. jack_error("JackEngine::ClientActivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
  532. return -1;
  533. } else {
  534. NotifyActivate(refnum);
  535. return 0;
  536. }
  537. }
  538. // May be called without client
  539. int JackEngine::ClientDeactivate(int refnum)
  540. {
  541. JackClientInterface* client = fClientTable[refnum];
  542. if (client == NULL)
  543. return -1;
  544. jack_log("JackEngine::ClientDeactivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
  545. // Disconnect all ports ==> notifications are sent
  546. jack_int_t ports[PORT_NUM_FOR_CLIENT];
  547. int i;
  548. fGraphManager->GetInputPorts(refnum, ports);
  549. for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
  550. PortDisconnect(refnum, ports[i], ALL_PORTS);
  551. }
  552. fGraphManager->GetOutputPorts(refnum, ports);
  553. for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
  554. PortDisconnect(refnum, ports[i], ALL_PORTS);
  555. }
  556. fGraphManager->Deactivate(refnum);
  557. fLastSwitchUsecs = 0; // Force switch to occur next cycle, even when called with "dead" clients
  558. // Wait for graph state change to be effective
  559. if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 10)) {
  560. jack_error("JackEngine::ClientDeactivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
  561. return -1;
  562. } else {
  563. return 0;
  564. }
  565. }
  566. //-----------------
  567. // Port management
  568. //-----------------
  569. int JackEngine::PortRegister(int refnum, const char* name, const char *type, unsigned int flags, unsigned int buffer_size, unsigned int* port_index)
  570. {
  571. jack_log("JackEngine::PortRegister ref = %ld name = %s type = %s flags = %d buffer_size = %d", refnum, name, type, flags, buffer_size);
  572. assert(fClientTable[refnum]);
  573. // Check if port name already exists
  574. if (fGraphManager->GetPort(name) != NO_PORT) {
  575. jack_error("port_name \"%s\" already exists", name);
  576. return -1;
  577. }
  578. *port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize);
  579. if (*port_index != NO_PORT) {
  580. NotifyPortRegistation(*port_index, true);
  581. return 0;
  582. } else {
  583. return -1;
  584. }
  585. }
  586. int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
  587. {
  588. jack_log("JackEngine::PortUnRegister ref = %ld port_index = %ld", refnum, port_index);
  589. assert(fClientTable[refnum]);
  590. // Disconnect port ==> notification is sent
  591. PortDisconnect(refnum, port_index, ALL_PORTS);
  592. if (fGraphManager->ReleasePort(refnum, port_index) == 0) {
  593. NotifyPortRegistation(port_index, false);
  594. return 0;
  595. } else {
  596. return -1;
  597. }
  598. }
  599. int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
  600. {
  601. jack_log("JackEngine::PortConnect src = %s dst = %s", src, dst);
  602. jack_port_id_t port_src, port_dst;
  603. return (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0)
  604. ? -1
  605. : PortConnect(refnum, port_src, port_dst);
  606. }
  607. int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
  608. {
  609. jack_log("JackEngine::PortConnect src = %d dst = %d", src, dst);
  610. JackClientInterface* client;
  611. int ref;
  612. if (fGraphManager->CheckPorts(src, dst) < 0)
  613. return -1;
  614. ref = fGraphManager->GetOutputRefNum(src);
  615. assert(ref >= 0);
  616. client = fClientTable[ref];
  617. assert(client);
  618. if (!client->GetClientControl()->fActive) {
  619. jack_error("Cannot connect ports owned by inactive clients:"
  620. " \"%s\" is not active", client->GetClientControl()->fName);
  621. return -1;
  622. }
  623. ref = fGraphManager->GetInputRefNum(dst);
  624. assert(ref >= 0);
  625. client = fClientTable[ref];
  626. assert(client);
  627. if (!client->GetClientControl()->fActive) {
  628. jack_error("Cannot connect ports owned by inactive clients:"
  629. " \"%s\" is not active", client->GetClientControl()->fName);
  630. return -1;
  631. }
  632. int res = fGraphManager->Connect(src, dst);
  633. if (res == 0)
  634. NotifyPortConnect(src, dst, true);
  635. return res;
  636. }
  637. int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
  638. {
  639. jack_log("JackEngine::PortDisconnect src = %s dst = %s", src, dst);
  640. jack_port_id_t port_src, port_dst;
  641. if (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0) {
  642. return -1;
  643. } else if (fGraphManager->Disconnect(port_src, port_dst) == 0) {
  644. NotifyPortConnect(port_src, port_dst, false);
  645. return 0;
  646. } else {
  647. return -1;
  648. }
  649. }
  650. int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
  651. {
  652. jack_log("JackEngine::PortDisconnect src = %d dst = %d", src, dst);
  653. if (dst == ALL_PORTS) {
  654. jack_int_t connections[CONNECTION_NUM_FOR_PORT];
  655. fGraphManager->GetConnections(src, connections);
  656. // Notifications
  657. JackPort* port = fGraphManager->GetPort(src);
  658. if (port->GetFlags() & JackPortIsOutput) {
  659. for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
  660. jack_log("NotifyPortConnect src = %ld dst = %ld false", src, connections[i]);
  661. NotifyPortConnect(src, connections[i], false);
  662. }
  663. } else {
  664. for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
  665. jack_log("NotifyPortConnect src = %ld dst = %ld false", connections[i], src);
  666. NotifyPortConnect(connections[i], src, false);
  667. }
  668. }
  669. return fGraphManager->DisconnectAll(src);
  670. } else if (fGraphManager->CheckPorts(src, dst) < 0) {
  671. return -1;
  672. } else if (fGraphManager->Disconnect(src, dst) == 0) {
  673. // Notifications
  674. NotifyPortConnect(src, dst, false);
  675. return 0;
  676. } else {
  677. return -1;
  678. }
  679. }
  680. } // end of namespace