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.

781 lines
23KB

  1. /*
  2. Copyright (C) 2001 Paul Davis
  3. Copyright (C) 2004-2006 Grame
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "JackClient.h"
  17. #include "JackGraphManager.h"
  18. #include "JackClientControl.h"
  19. #include "JackEngineControl.h"
  20. #include "JackGlobals.h"
  21. #include "JackChannel.h"
  22. #include "JackTransportEngine.h"
  23. #include <math.h>
  24. #include <string>
  25. using namespace std;
  26. namespace Jack
  27. {
  28. JackClient::JackClient()
  29. {}
  30. JackClient::JackClient(JackSynchro** table)
  31. {
  32. fThread = JackGlobals::MakeThread(this);
  33. fSynchroTable = table;
  34. fProcess = NULL;
  35. fGraphOrder = NULL;
  36. fXrun = NULL;
  37. fShutdown = NULL;
  38. fInit = NULL;
  39. fBufferSize = NULL;
  40. fFreewheel = NULL;
  41. fPortRegistration = NULL;
  42. fSync = NULL;
  43. fProcessArg = NULL;
  44. fGraphOrderArg = NULL;
  45. fXrunArg = NULL;
  46. fShutdownArg = NULL;
  47. fInitArg = NULL;
  48. fBufferSizeArg = NULL;
  49. fFreewheelArg = NULL;
  50. fPortRegistrationArg = NULL;
  51. fSyncArg = NULL;
  52. fConditionnal = 0; // Temporary??
  53. }
  54. JackClient::~JackClient()
  55. {
  56. delete fThread;
  57. }
  58. int JackClient::Close()
  59. {
  60. JackLog("JackClient::Close ref = %ld\n", GetClientControl()->fRefNum);
  61. Deactivate();
  62. int result = -1;
  63. fChannel->ClientClose(GetClientControl()->fRefNum, &result);
  64. fChannel->Stop();
  65. fChannel->Close();
  66. fSynchroTable[GetClientControl()->fRefNum]->Disconnect();
  67. return result;
  68. }
  69. bool JackClient::IsActive()
  70. {
  71. return (GetClientControl()) ? GetClientControl()->fActive : false;
  72. }
  73. pthread_t JackClient::GetThreadID()
  74. {
  75. return fThread->GetThreadID();
  76. }
  77. /*!
  78. \brief
  79. In ASYNC mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
  80. The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
  81. Drivers synchro are setup in "flush" mode if server is ASYNC and NOT freewheel.
  82. */
  83. void JackClient::SetupDriverSync(bool freewheel)
  84. {
  85. if (!freewheel && !GetEngineControl()->fSyncMode) {
  86. JackLog("JackClient::SetupDriverSync driver sem in flush mode\n");
  87. fSynchroTable[AUDIO_DRIVER_REFNUM]->SetFlush(true);
  88. fSynchroTable[FREEWHEEL_DRIVER_REFNUM]->SetFlush(true);
  89. fSynchroTable[LOOPBACK_DRIVER_REFNUM]->SetFlush(true);
  90. } else {
  91. JackLog("JackClient::SetupDriverSync driver sem in normal mode\n");
  92. fSynchroTable[AUDIO_DRIVER_REFNUM]->SetFlush(false);
  93. fSynchroTable[FREEWHEEL_DRIVER_REFNUM]->SetFlush(false);
  94. fSynchroTable[LOOPBACK_DRIVER_REFNUM]->SetFlush(false);
  95. }
  96. }
  97. /*!
  98. \brief Notification received from the server.
  99. */
  100. int JackClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value)
  101. {
  102. return 0;
  103. }
  104. int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, int value)
  105. {
  106. int res = 0;
  107. // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient
  108. switch (notify) {
  109. case JackNotifyChannelInterface::kAddClient:
  110. case JackNotifyChannelInterface::kRemoveClient:
  111. res = ClientNotifyImp(refnum, name, notify, sync, value);
  112. break;
  113. }
  114. /*
  115. The current semantic is that notifications can only be received when the client has been activated,
  116. although is this implementation, one could imagine calling notifications as soon as the client has be opened.
  117. */
  118. if (IsActive()) {
  119. switch (notify) {
  120. case JackNotifyChannelInterface::kBufferSizeCallback:
  121. JackLog("JackClient::kBufferSizeCallback buffer_size = %ld\n", value);
  122. if (fBufferSize)
  123. res = fBufferSize(value, fBufferSizeArg);
  124. break;
  125. case JackNotifyChannelInterface::kGraphOrderCallback:
  126. JackLog("JackClient::kGraphOrderCallback\n");
  127. if (fGraphOrder)
  128. res = fGraphOrder(fGraphOrderArg);
  129. break;
  130. case JackNotifyChannelInterface::kStartFreewheel:
  131. JackLog("JackClient::kStartFreewheel\n");
  132. SetupDriverSync(true);
  133. fThread->DropRealTime();
  134. if (fFreewheel)
  135. fFreewheel(1, fFreewheelArg);
  136. break;
  137. case JackNotifyChannelInterface::kStopFreewheel:
  138. JackLog("JackClient::kStopFreewheel\n");
  139. SetupDriverSync(false);
  140. if (fFreewheel)
  141. fFreewheel(0, fFreewheelArg);
  142. fThread->AcquireRealTime();
  143. break;
  144. case JackNotifyChannelInterface::kPortRegistrationOn:
  145. JackLog("JackClient::kPortRegistrationOn port_index = %ld\n", value);
  146. if (fPortRegistration)
  147. fPortRegistration(value, 1, fPortRegistrationArg);
  148. break;
  149. case JackNotifyChannelInterface::kPortRegistrationOff:
  150. JackLog("JackClient::kPortRegistrationOff port_index = %ld \n", value);
  151. if (fPortRegistration)
  152. fPortRegistration(value, 0, fPortRegistrationArg);
  153. break;
  154. case JackNotifyChannelInterface::kXRunCallback:
  155. JackLog("JackClient::kXRunCallback\n");
  156. if (fXrun)
  157. res = fXrun(fXrunArg);
  158. break;
  159. case JackNotifyChannelInterface::kZombifyClient:
  160. //res = fThread->Kill(); Really neede ?? Unsafe in WIN32...
  161. JackLog("JackClient::kZombifyClient name = %s ref = %ld \n", name, refnum);
  162. ShutDown();
  163. break;
  164. }
  165. }
  166. return res;
  167. }
  168. /*!
  169. \brief We need to start thread before activating in the server, otherwise the FW driver
  170. connected to the client may not be activated.
  171. */
  172. int JackClient::Activate()
  173. {
  174. JackLog("JackClient::Activate \n");
  175. if (IsActive())
  176. return 0;
  177. #ifdef WIN32
  178. // Done first so that the RT thread then access an allocated synchro
  179. if (!fSynchroTable[GetClientControl()->fRefNum]->Connect(GetClientControl()->fName)) {
  180. jack_error("Cannot ConnectSemaphore %s client", GetClientControl()->fName);
  181. return -1;
  182. }
  183. #endif
  184. if (StartThread() < 0)
  185. return -1;
  186. int result = -1;
  187. fChannel->ClientActivate(GetClientControl()->fRefNum, &result);
  188. if (result < 0)
  189. return result;
  190. if (fSync != NULL) /* If a SyncCallback is pending... */
  191. SetSyncCallback(fSync, fSyncArg);
  192. if (fTimebase != NULL) /* If a TimebaseCallback is pending... */
  193. SetTimebaseCallback(fConditionnal, fTimebase, fTimebaseArg);
  194. GetClientControl()->fActive = true;
  195. return 0;
  196. }
  197. /*!
  198. \brief Need to stop thread after deactivating in the server.
  199. */
  200. int JackClient::Deactivate()
  201. {
  202. JackLog("JackClient::Deactivate \n");
  203. if (!IsActive())
  204. return 0;
  205. GetClientControl()->fActive = false;
  206. int result = -1;
  207. fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
  208. JackLog("JackClient::Deactivate res = %ld \n", result);
  209. // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate
  210. #ifdef WIN32
  211. fSynchroTable[GetClientControl()->fRefNum]->Disconnect();
  212. fThread->Stop();
  213. #else
  214. fThread->Kill();
  215. #endif
  216. return result;
  217. }
  218. //----------------------
  219. // RT thread management
  220. //----------------------
  221. bool JackClient::CallProcessCallback()
  222. {
  223. return (fProcess == NULL) ? true : (fProcess(GetEngineControl()->fBufferSize, fProcessArg) == 0);
  224. }
  225. /*!
  226. \brief Called once when the thread starts.
  227. */
  228. bool JackClient::Init()
  229. {
  230. if (fInit) {
  231. JackLog("JackClient::Init calling client thread init callback\n");
  232. fInit(fInitArg);
  233. }
  234. return true;
  235. }
  236. int JackClient::StartThread()
  237. {
  238. JackLog("JackClient::StartThread : period = %ld computation = %ld constraint = %ld\n",
  239. long(int64_t(GetEngineControl()->fPeriod) / 1000.0f),
  240. long(int64_t(GetEngineControl()->fComputation) / 1000.0f),
  241. long(int64_t(GetEngineControl()->fConstraint) / 1000.0f));
  242. // Will do "something" on OSX only...
  243. fThread->SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
  244. if (fThread->Start() < 0) {
  245. jack_error("Start thread error");
  246. return -1;
  247. }
  248. if (GetEngineControl()->fRealTime) {
  249. if (fThread->AcquireRealTime(GetEngineControl()->fPriority - 1) < 0) {
  250. jack_error("AcquireRealTime error");
  251. }
  252. }
  253. return 0;
  254. }
  255. /*!
  256. \brief RT thread.
  257. */
  258. bool JackClient::Execute()
  259. {
  260. // Suspend itself: wait on the input synchro
  261. if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable, 0x7FFFFFFF) < 0) {
  262. jack_error("SuspendRefNum error");
  263. goto error;
  264. }
  265. // Process call
  266. if (IsActive()) {
  267. CallSyncCallback();
  268. bool res = CallProcessCallback();
  269. CallTimebaseCallback();
  270. if (!res)
  271. goto end;
  272. } else {
  273. JackLog("Process called for an inactive client\n");
  274. // Happens if client is still not activated (connected to the FW)
  275. // or still runs while being desactivated by the server
  276. }
  277. // Resume: signal output clients connected to the running client
  278. if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) {
  279. jack_error("ResumeRefNum error");
  280. }
  281. return true;
  282. end:
  283. JackLog("JackClient::Execute end name = %s\n", GetClientControl()->fName);
  284. // Continue graph execution for this cycle
  285. if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) {
  286. jack_error("ResumeRefNum error");
  287. }
  288. // Hum... not sure about this, the following "close" code is called in the RT thread...
  289. int result;
  290. fThread->DropRealTime();
  291. fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
  292. Close(); // Not sure...
  293. return false;
  294. error:
  295. jack_error("JackClient::Execute error name = %s", GetClientControl()->fName);
  296. // Hum... not sure about this, the following "close" code is called in the RT thread...
  297. fThread->DropRealTime();
  298. ShutDown();
  299. return false;
  300. }
  301. //-----------------
  302. // Port management
  303. //-----------------
  304. int JackClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size)
  305. {
  306. // Check port name length
  307. string port_name_str = string(port_name);
  308. if (port_name_str.size() == 0) {
  309. jack_error("port_name is empty.");
  310. return 0; // Means failure here...
  311. }
  312. string name = string(GetClientControl()->fName) + string(":") + port_name_str;
  313. if (name.size() >= JACK_PORT_NAME_SIZE) {
  314. jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n"
  315. "Please use %lu characters or less.",
  316. GetClientControl()->fName,
  317. port_name,
  318. JACK_PORT_NAME_SIZE - 1);
  319. return 0; // Means failure here...
  320. }
  321. // Check if port name already exists
  322. if (GetGraphManager()->GetPort(name.c_str()) != NO_PORT) {
  323. jack_error("port_name \"%s\" already exists.", port_name);
  324. return 0; // Means failure here...
  325. }
  326. JackLog("JackClient::PortRegister ref = %ld name = %s \n", GetClientControl()->fRefNum, name.c_str());
  327. int result = -1;
  328. jack_port_id_t port_index = NO_PORT;
  329. fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), flags, buffer_size, &port_index, &result);
  330. JackLog("JackClient::PortRegister port_index = %ld \n", port_index);
  331. if (result == 0) {
  332. fPortList.push_back(port_index);
  333. return port_index;
  334. } else {
  335. return 0;
  336. }
  337. }
  338. int JackClient::PortUnRegister(jack_port_id_t port_index)
  339. {
  340. JackLog("JackClient::PortUnRegister port_index = %ld\n", port_index);
  341. list<jack_port_id_t>::iterator it;
  342. for (it = fPortList.begin(); it != fPortList.end() && *it != port_index; it++)
  343. ;
  344. if (it != fPortList.end()) {
  345. fPortList.erase(it);
  346. int result = -1;
  347. fChannel->PortUnRegister(GetClientControl()->fRefNum, port_index, &result);
  348. return result;
  349. } else {
  350. jack_error("unregistering a port %ld that is not own by the client", port_index);
  351. return -1;
  352. }
  353. }
  354. int JackClient::PortConnect(const char* src, const char* dst)
  355. {
  356. JackLog("JackClient::Connect src = %s dst = %s\n", src, dst);
  357. int result = -1;
  358. fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result);
  359. return result;
  360. }
  361. int JackClient::PortDisconnect(const char* src, const char* dst)
  362. {
  363. JackLog("JackClient::Disconnect src = %s dst = %s\n", src, dst);
  364. int result = -1;
  365. fChannel->PortDisconnect(GetClientControl()->fRefNum, src, dst, &result);
  366. return result;
  367. }
  368. int JackClient::PortConnect(jack_port_id_t src, jack_port_id_t dst)
  369. {
  370. JackLog("JackClient::PortConnect src = %ld dst = %ld\n", src, dst);
  371. int result = -1;
  372. fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result);
  373. return result;
  374. }
  375. int JackClient::PortDisconnect(jack_port_id_t src)
  376. {
  377. JackLog("JackClient::PortDisconnect src = %ld\n", src);
  378. int result = -1;
  379. fChannel->PortDisconnect(GetClientControl()->fRefNum, src, ALL_PORTS, &result);
  380. return result;
  381. }
  382. int JackClient::PortIsMine(jack_port_id_t port_index)
  383. {
  384. JackPort* port = GetGraphManager()->GetPort(port_index);
  385. return GetClientControl()->fRefNum == port->GetRefNum();
  386. }
  387. //--------------------
  388. // Context management
  389. //--------------------
  390. int JackClient::SetBufferSize(jack_nframes_t nframes)
  391. {
  392. int result = -1;
  393. fChannel->SetBufferSize(nframes, &result);
  394. return result;
  395. }
  396. int JackClient::SetFreeWheel(int onoff)
  397. {
  398. int result = -1;
  399. fChannel->SetFreewheel(onoff, &result);
  400. return result;
  401. }
  402. /*
  403. ShutDown is called:
  404. - from the RT thread when Execute method fails
  405. - possibly from a "closed" notification channel
  406. (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
  407. */
  408. void JackClient::ShutDown()
  409. {
  410. JackLog("ShutDown\n");
  411. if (fShutdown) {
  412. GetClientControl()->fActive = false;
  413. fShutdown(fShutdownArg);
  414. fShutdown = NULL;
  415. }
  416. }
  417. //----------------------
  418. // Transport management
  419. //----------------------
  420. int JackClient::ReleaseTimebase()
  421. {
  422. int result = -1;
  423. fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result);
  424. if (result == 0) {
  425. fTimebase = NULL;
  426. fTimebaseArg = NULL;
  427. }
  428. return result;
  429. }
  430. /* Call the server if the client is active, otherwise keeps the arguments */
  431. int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg)
  432. {
  433. if (IsActive())
  434. GetClientControl()->fTransportState = (sync_callback == NULL) ? JackTransportStopped : JackTransportSynching;
  435. fSync = sync_callback;
  436. fSyncArg = arg;
  437. return 0;
  438. }
  439. int JackClient::SetSyncTimeout(jack_time_t timeout)
  440. {
  441. GetEngineControl()->fTransport.SetSyncTimeout(timeout);
  442. return 0;
  443. }
  444. /* Call the server if the client is active, otherwise keeps the arguments */
  445. int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg)
  446. {
  447. if (IsActive()) {
  448. int result = -1;
  449. fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result);
  450. JackLog("SetTimebaseCallback result = %ld\n", result);
  451. if (result == 0) {
  452. fTimebase = timebase_callback;
  453. fTimebaseArg = arg;
  454. } else {
  455. fTimebase = NULL;
  456. fTimebaseArg = NULL;
  457. }
  458. JackLog("SetTimebaseCallback OK result = %ld\n", result);
  459. return result;
  460. } else {
  461. fTimebase = timebase_callback;
  462. fTimebaseArg = arg;
  463. fConditionnal = conditional;
  464. return 0;
  465. }
  466. }
  467. // Must be RT safe
  468. int JackClient::RequestNewPos(jack_position_t* pos)
  469. {
  470. JackTransportEngine& transport = GetEngineControl()->fTransport;
  471. jack_position_t* request = transport.WriteNextStateStart(2);
  472. pos->unique_1 = pos->unique_2 = transport.GenerateUniqueID();
  473. JackTransportEngine::TransportCopyPosition(pos, request);
  474. JackLog("RequestNewPos pos = %ld\n", pos->frame);
  475. transport.WriteNextStateStop(2);
  476. return 0;
  477. }
  478. int JackClient::TransportLocate(jack_nframes_t frame)
  479. {
  480. jack_position_t pos;
  481. pos.frame = frame;
  482. pos.valid = (jack_position_bits_t)0;
  483. JackLog("TransportLocate pos = %ld\n", pos.frame);
  484. return RequestNewPos(&pos);
  485. }
  486. int JackClient::TransportReposition(jack_position_t* pos)
  487. {
  488. jack_position_t tmp = *pos;
  489. JackLog("TransportReposition pos = %ld\n", pos->frame);
  490. return (tmp.valid & ~JACK_POSITION_MASK) ? EINVAL : RequestNewPos(&tmp);
  491. }
  492. jack_transport_state_t JackClient::TransportQuery(jack_position_t* pos)
  493. {
  494. if (pos)
  495. GetEngineControl()->fTransport.ReadCurrentPos(pos);
  496. return GetEngineControl()->fTransport.GetState();
  497. }
  498. jack_nframes_t JackClient::GetCurrentTransportFrame()
  499. {
  500. jack_position_t pos;
  501. jack_transport_state_t state = TransportQuery(&pos);
  502. if (state == JackTransportRolling) {
  503. float usecs = GetMicroSeconds() - pos.usecs;
  504. jack_nframes_t elapsed = (jack_nframes_t)floor((((float) pos.frame_rate) / 1000000.0f) * usecs);
  505. return pos.frame + elapsed;
  506. } else {
  507. return pos.frame;
  508. }
  509. }
  510. // Must be RT safe: directly write in the transport shared mem
  511. void JackClient::TransportStart()
  512. {
  513. GetEngineControl()->fTransport.SetCommand(TransportCommandStart);
  514. }
  515. // Must be RT safe: directly write in the transport shared mem
  516. void JackClient::TransportStop()
  517. {
  518. GetEngineControl()->fTransport.SetCommand(TransportCommandStop);
  519. }
  520. // Never called concurently with the server
  521. // TODO check concurency with SetSyncCallback
  522. void JackClient::CallSyncCallback()
  523. {
  524. JackTransportEngine& transport = GetEngineControl()->fTransport;
  525. jack_position_t* cur_pos = transport.ReadCurrentState();
  526. jack_transport_state_t transport_state = transport.GetState();
  527. switch (transport_state) {
  528. case JackTransportStarting: // Starting...
  529. if (fSync == NULL) {
  530. GetClientControl()->fTransportState = JackTransportRolling;
  531. } else if (GetClientControl()->fTransportState == JackTransportStarting) {
  532. if (fSync(transport_state, cur_pos, fSyncArg))
  533. GetClientControl()->fTransportState = JackTransportRolling;
  534. }
  535. break;
  536. case JackTransportRolling:
  537. if (fSync != NULL && GetClientControl()->fTransportState == JackTransportStarting) { // Client still not ready
  538. if (fSync(transport_state, cur_pos, fSyncArg))
  539. GetClientControl()->fTransportState = JackTransportRolling;
  540. }
  541. break;
  542. case JackTransportSynching:
  543. // New pos when transport engine is stopped...
  544. if (fSync != NULL) {
  545. fSync(JackTransportStopped, cur_pos, fSyncArg);
  546. GetClientControl()->fTransportState = JackTransportStopped;
  547. }
  548. break;
  549. default:
  550. break;
  551. }
  552. }
  553. void JackClient::CallTimebaseCallback()
  554. {
  555. JackTransportEngine& transport = GetEngineControl()->fTransport;
  556. if (fTimebase != NULL && fTimebaseArg != NULL && GetClientControl()->fRefNum == transport.GetTimebaseMaster()) {
  557. jack_transport_state_t transport_state = transport.GetState();
  558. jack_position_t* cur_pos = transport.WriteNextStateStart(1);
  559. switch (transport_state) {
  560. case JackTransportRolling:
  561. fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg);
  562. break;
  563. case JackTransportSynching:
  564. fTimebase(JackTransportStopped, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg);
  565. break;
  566. default:
  567. break;
  568. }
  569. transport.WriteNextStateStop(1);
  570. }
  571. }
  572. //---------------------
  573. // Callback management
  574. //---------------------
  575. void JackClient::OnShutdown(JackShutdownCallback callback, void *arg)
  576. {
  577. if (IsActive()) {
  578. jack_error("You cannot set callbacks on an active client");
  579. } else {
  580. fShutdownArg = arg;
  581. fShutdown = callback;
  582. }
  583. }
  584. int JackClient::SetProcessCallback(JackProcessCallback callback, void *arg)
  585. {
  586. if (IsActive()) {
  587. jack_error("You cannot set callbacks on an active client");
  588. return -1;
  589. } else {
  590. fProcessArg = arg;
  591. fProcess = callback;
  592. return 0;
  593. }
  594. }
  595. int JackClient::SetXRunCallback(JackXRunCallback callback, void *arg)
  596. {
  597. if (IsActive()) {
  598. jack_error("You cannot set callbacks on an active client");
  599. return -1;
  600. } else {
  601. fXrunArg = arg;
  602. fXrun = callback;
  603. return 0;
  604. }
  605. }
  606. int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg)
  607. {
  608. if (IsActive()) {
  609. jack_error("You cannot set callbacks on an active client");
  610. return -1;
  611. } else {
  612. fInitArg = arg;
  613. fInit = callback;
  614. return 0;
  615. }
  616. }
  617. int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg)
  618. {
  619. JackLog("SetGraphOrderCallback \n");
  620. if (IsActive()) {
  621. jack_error("You cannot set callbacks on an active client");
  622. return -1;
  623. } else {
  624. fGraphOrder = callback;
  625. fGraphOrderArg = arg;
  626. return 0;
  627. }
  628. }
  629. int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg)
  630. {
  631. if (IsActive()) {
  632. jack_error("You cannot set callbacks on an active client");
  633. return -1;
  634. } else {
  635. fBufferSizeArg = arg;
  636. fBufferSize = callback;
  637. return 0;
  638. }
  639. }
  640. int JackClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg)
  641. {
  642. if (IsActive()) {
  643. jack_error("You cannot set callbacks on an active client");
  644. return -1;
  645. } else {
  646. fFreewheelArg = arg;
  647. fFreewheel = callback;
  648. return 0;
  649. }
  650. }
  651. int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg)
  652. {
  653. if (IsActive()) {
  654. jack_error("You cannot set callbacks on an active client");
  655. return -1;
  656. } else {
  657. fPortRegistrationArg = arg;
  658. fPortRegistration = callback;
  659. return 0;
  660. }
  661. }
  662. } // end of namespace