JackClient.cpp

00001 /*
00002 Copyright (C) 2001 Paul Davis 
00003 Copyright (C) 2004-2006 Grame
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 
00019 */
00020 
00021 
00022 #include "JackClient.h"
00023 #include "JackGraphManager.h"
00024 #include "JackClientControl.h"
00025 #include "JackEngineControl.h"
00026 #include "JackGlobals.h"
00027 #include "JackChannel.h"
00028 #include "JackTransportEngine.h"
00029 #include <math.h>
00030 #include <string>
00031 #include <algorithm>
00032 
00033 using namespace std;
00034 
00035 namespace Jack
00036 {
00037 
00038 JackClient::JackClient()
00039 {}
00040 
00041 JackClient::JackClient(JackSynchro** table)
00042 {
00043     fThread = JackGlobals::MakeThread(this);
00044     fSynchroTable = table;
00045     fProcess = NULL;
00046     fGraphOrder = NULL;
00047     fXrun = NULL;
00048     fShutdown = NULL;
00049     fInit = NULL;
00050     fBufferSize = NULL;
00051     fFreewheel = NULL;
00052     fPortRegistration = NULL;
00053     fSync = NULL;
00054     fProcessArg = NULL;
00055     fGraphOrderArg = NULL;
00056     fXrunArg = NULL;
00057     fShutdownArg = NULL;
00058     fInitArg = NULL;
00059     fBufferSizeArg = NULL;
00060     fFreewheelArg = NULL;
00061     fPortRegistrationArg = NULL;
00062     fSyncArg = NULL;
00063     fConditionnal = 0; // Temporary??
00064 }
00065 
00066 JackClient::~JackClient()
00067 {
00068     delete fThread;
00069 }
00070 
00071 int JackClient::Close()
00072 {
00073     JackLog("JackClient::Close ref = %ld\n", GetClientControl()->fRefNum);
00074     Deactivate();
00075     int result = -1;
00076     fChannel->ClientClose(GetClientControl()->fRefNum, &result);
00077     fChannel->Stop();
00078     fChannel->Close();
00079     fSynchroTable[GetClientControl()->fRefNum]->Disconnect();
00080     return result;
00081 }
00082 
00083 bool JackClient::IsActive()
00084 {
00085     return (GetClientControl()) ? GetClientControl()->fActive : false;
00086 }
00087 
00088 pthread_t JackClient::GetThreadID()
00089 {
00090     return fThread->GetThreadID();
00091 }
00092 
00099 void JackClient::SetupDriverSync(bool freewheel)
00100 {
00101     if (!freewheel && !GetEngineControl()->fSyncMode) {
00102         JackLog("JackClient::SetupDriverSync driver sem in flush mode\n");
00103         fSynchroTable[AUDIO_DRIVER_REFNUM]->SetFlush(true);
00104         fSynchroTable[FREEWHEEL_DRIVER_REFNUM]->SetFlush(true);
00105         fSynchroTable[LOOPBACK_DRIVER_REFNUM]->SetFlush(true);
00106     } else {
00107         JackLog("JackClient::SetupDriverSync driver sem in normal mode\n");
00108         fSynchroTable[AUDIO_DRIVER_REFNUM]->SetFlush(false);
00109         fSynchroTable[FREEWHEEL_DRIVER_REFNUM]->SetFlush(false);
00110         fSynchroTable[LOOPBACK_DRIVER_REFNUM]->SetFlush(false);
00111     }
00112 }
00113 
00118 int JackClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value)
00119 {
00120         return 0;
00121 }
00122 
00123 int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, int value)
00124 {
00125     int res = 0;
00126 
00127     // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient
00128     switch (notify) {
00129 
00130         case JackNotifyChannelInterface::kAddClient:
00131         case JackNotifyChannelInterface::kRemoveClient:
00132             res = ClientNotifyImp(refnum, name, notify, sync, value);
00133             break;
00134                         
00135                 case JackNotifyChannelInterface::kActivateClient:
00136                         JackLog("JackClient::kActivateClient name = %s ref = %ld \n", name, refnum);
00137                         Init();
00138                         break;
00139         }
00140 
00141     /*
00142     The current semantic is that notifications can only be received when the client has been activated,
00143     although is this implementation, one could imagine calling notifications as soon as the client has be opened.
00144     */
00145     if (IsActive()) {
00146 
00147         switch (notify) {
00148 
00149             case JackNotifyChannelInterface::kBufferSizeCallback:
00150                 JackLog("JackClient::kBufferSizeCallback buffer_size = %ld\n", value);
00151                 if (fBufferSize)
00152                     res = fBufferSize(value, fBufferSizeArg);
00153                 break;
00154 
00155             case JackNotifyChannelInterface::kGraphOrderCallback:
00156                 JackLog("JackClient::kGraphOrderCallback\n");
00157                 if (fGraphOrder)
00158                     res = fGraphOrder(fGraphOrderArg);
00159                 break;
00160 
00161             case JackNotifyChannelInterface::kStartFreewheel:
00162                 JackLog("JackClient::kStartFreewheel\n");
00163                 SetupDriverSync(true);
00164                 fThread->DropRealTime();
00165                 if (fFreewheel)
00166                     fFreewheel(1, fFreewheelArg);
00167                 break;
00168 
00169             case JackNotifyChannelInterface::kStopFreewheel:
00170                 JackLog("JackClient::kStopFreewheel\n");
00171                 SetupDriverSync(false);
00172                 if (fFreewheel)
00173                     fFreewheel(0, fFreewheelArg);
00174                 fThread->AcquireRealTime();
00175                 break;
00176 
00177             case JackNotifyChannelInterface::kPortRegistrationOn:
00178                 JackLog("JackClient::kPortRegistrationOn port_index = %ld\n", value);
00179                 if (fPortRegistration)
00180                     fPortRegistration(value, 1, fPortRegistrationArg);
00181                 break;
00182 
00183             case JackNotifyChannelInterface::kPortRegistrationOff:
00184                 JackLog("JackClient::kPortRegistrationOff port_index = %ld \n", value);
00185                 if (fPortRegistration)
00186                     fPortRegistration(value, 0, fPortRegistrationArg);
00187                 break;
00188 
00189             case JackNotifyChannelInterface::kXRunCallback:
00190                 JackLog("JackClient::kXRunCallback\n");
00191                 if (fXrun)
00192                     res = fXrun(fXrunArg);
00193                 break;
00194 
00195             case JackNotifyChannelInterface::kZombifyClient:
00196                     JackLog("JackClient::kZombifyClient name = %s ref = %ld \n", name, refnum);
00197                 ShutDown();
00198                 break;
00199                 }
00200     }
00201 
00202     return res;
00203 }
00204 
00209 int JackClient::Activate()
00210 {
00211     JackLog("JackClient::Activate \n");
00212     if (IsActive())
00213         return 0;
00214 
00215 /* TODO : solve WIN32 thread Kill issue
00216 #ifdef WIN32
00217         // Done first so that the RT thread then access an allocated synchro
00218         if (!fSynchroTable[GetClientControl()->fRefNum]->Connect(GetClientControl()->fName)) {
00219         jack_error("Cannot ConnectSemaphore %s client", GetClientControl()->fName);
00220         return -1;
00221     }
00222 #endif
00223 */
00224 
00225         if (StartThread() < 0)
00226         return -1;
00227 
00228     int result = -1;
00229     fChannel->ClientActivate(GetClientControl()->fRefNum, &result);
00230     if (result < 0)
00231         return result;
00232 
00233     if (fSync != NULL)          /* If a SyncCallback is pending... */
00234         SetSyncCallback(fSync, fSyncArg);
00235 
00236     if (fTimebase != NULL)      /* If a TimebaseCallback is pending... */
00237         SetTimebaseCallback(fConditionnal, fTimebase, fTimebaseArg);
00238 
00239     GetClientControl()->fActive = true;
00240     return 0;
00241 }
00242 
00246 int JackClient::Deactivate()
00247 {
00248     JackLog("JackClient::Deactivate \n");
00249     if (!IsActive())
00250         return 0;
00251 
00252     GetClientControl()->fActive = false;
00253     int result = -1;
00254     fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
00255 
00256     JackLog("JackClient::Deactivate res = %ld \n", result);
00257     // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate
00258 
00259 /* TODO : solve WIN32 thread Kill issue    
00260 #ifdef WIN32
00261         fSynchroTable[GetClientControl()->fRefNum]->Disconnect();
00262         fThread->Stop();
00263 #else
00264         fThread->Kill();
00265 #endif
00266 */
00267         fThread->Kill();
00268     return result;
00269 }
00270 
00271 //----------------------
00272 // RT thread management
00273 //----------------------
00274 
00275 bool JackClient::CallProcessCallback()
00276 {
00277     return (fProcess == NULL) ? true : (fProcess(GetEngineControl()->fBufferSize, fProcessArg) == 0);
00278 }
00279 
00283 bool JackClient::Init()
00284 {
00285     if (fInit) {
00286         JackLog("JackClient::Init calling client thread init callback\n");
00287                 fInit(fInitArg);
00288     }
00289     return true;
00290 }
00291 
00292 int JackClient::StartThread()
00293 {
00294     JackLog("JackClient::StartThread : period = %ld computation = %ld constraint = %ld\n",
00295             long(int64_t(GetEngineControl()->fPeriod) / 1000.0f),
00296             long(int64_t(GetEngineControl()->fComputation) / 1000.0f),
00297             long(int64_t(GetEngineControl()->fConstraint) / 1000.0f));
00298 
00299     // Will do "something" on OSX only...
00300     fThread->SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
00301 
00302     if (fThread->Start() < 0) {
00303         jack_error("Start thread error");
00304         return -1;
00305     }
00306 
00307     if (GetEngineControl()->fRealTime) {
00308         if (fThread->AcquireRealTime(GetEngineControl()->fPriority - 1) < 0) {
00309             jack_error("AcquireRealTime error");
00310         }
00311     }
00312 
00313     return 0;
00314 }
00315 
00319 bool JackClient::Execute()
00320 {
00321     // Suspend itself: wait on the input synchro
00322     if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable, 0x7FFFFFFF) < 0) {
00323         jack_error("SuspendRefNum error");
00324         goto error;
00325     }
00326 
00327     // Process call
00328     if (IsActive()) {
00329         CallSyncCallback();
00330         bool res = CallProcessCallback();
00331         CallTimebaseCallback();
00332         if (!res)
00333             goto end;
00334     } else {
00335         JackLog("Process called for an inactive client\n");
00336         // Happens if client is still not activated (connected to the FW)
00337         // or still runs while being desactivated by the server
00338     }
00339 
00340     // Resume: signal output clients connected to the running client
00341     if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) {
00342         jack_error("ResumeRefNum error");
00343     }
00344 
00345     return true;
00346 
00347 end:
00348     JackLog("JackClient::Execute end name = %s\n", GetClientControl()->fName);
00349 
00350     // Continue graph execution for this cycle
00351     if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) {
00352         jack_error("ResumeRefNum error");
00353     }
00354 
00355     // Hum... not sure about this, the following "close" code is called in the RT thread...
00356     int result;
00357     fThread->DropRealTime();
00358     fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
00359     Close();  // Not sure...
00360     return false;
00361 
00362 error:
00363     jack_error("JackClient::Execute error name = %s", GetClientControl()->fName);
00364     // Hum... not sure about this, the following "close" code is called in the RT thread...
00365     fThread->DropRealTime();
00366     ShutDown();
00367     return false;
00368 }
00369 
00370 //-----------------
00371 // Port management
00372 //-----------------
00373 
00374 int JackClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size)
00375 {
00376     // Check port name length
00377     string port_name_str = string(port_name);
00378     if (port_name_str.size() == 0) {
00379         jack_error("port_name is empty.");
00380         return 0; // Means failure here...
00381     }
00382 
00383     string name = string(GetClientControl()->fName) + string(":") + port_name_str;
00384     if (name.size() >= JACK_PORT_NAME_SIZE) {
00385         jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n"
00386                    "Please use %lu characters or less.",
00387                    GetClientControl()->fName,
00388                    port_name,
00389                    JACK_PORT_NAME_SIZE - 1);
00390         return 0; // Means failure here...
00391     }
00392 
00393     // Check if port name already exists
00394     if (GetGraphManager()->GetPort(name.c_str()) != NO_PORT) {
00395         jack_error("port_name \"%s\" already exists.", port_name);
00396         return 0; // Means failure here...
00397     }
00398 
00399     JackLog("JackClient::PortRegister ref = %ld  name = %s \n", GetClientControl()->fRefNum, name.c_str());
00400 
00401     int result = -1;
00402     jack_port_id_t port_index = NO_PORT;
00403     fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), flags, buffer_size, &port_index, &result);
00404     JackLog("JackClient::PortRegister port_index = %ld \n", port_index);
00405 
00406     if (result == 0) {
00407         fPortList.push_back(port_index);
00408         return port_index;
00409     } else {
00410         return 0;
00411     }
00412 }
00413 
00414 int JackClient::PortUnRegister(jack_port_id_t port_index)
00415 {
00416     JackLog("JackClient::PortUnRegister port_index = %ld\n", port_index);
00417         list<jack_port_id_t>::iterator it = find(fPortList.begin(), fPortList.end(), port_index);
00418 
00419     if (it != fPortList.end()) {
00420         fPortList.erase(it);
00421         int result = -1;
00422         fChannel->PortUnRegister(GetClientControl()->fRefNum, port_index, &result);
00423         return result;
00424     } else {
00425         jack_error("unregistering a port %ld that is not own by the client", port_index);
00426         return -1;
00427     }
00428 }
00429 
00430 int JackClient::PortConnect(const char* src, const char* dst)
00431 {
00432     JackLog("JackClient::Connect src = %s dst = %s\n", src, dst);
00433     int result = -1;
00434     fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result);
00435     return result;
00436 }
00437 
00438 int JackClient::PortDisconnect(const char* src, const char* dst)
00439 {
00440     JackLog("JackClient::Disconnect src = %s dst = %s\n", src, dst);
00441     int result = -1;
00442     fChannel->PortDisconnect(GetClientControl()->fRefNum, src, dst, &result);
00443     return result;
00444 }
00445 
00446 int JackClient::PortConnect(jack_port_id_t src, jack_port_id_t dst)
00447 {
00448     JackLog("JackClient::PortConnect src = %ld dst = %ld\n", src, dst);
00449     int result = -1;
00450     fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result);
00451     return result;
00452 }
00453 
00454 int JackClient::PortDisconnect(jack_port_id_t src)
00455 {
00456     JackLog("JackClient::PortDisconnect src = %ld\n", src);
00457     int result = -1;
00458     fChannel->PortDisconnect(GetClientControl()->fRefNum, src, ALL_PORTS, &result);
00459     return result;
00460 }
00461 
00462 int JackClient::PortIsMine(jack_port_id_t port_index)
00463 {
00464     JackPort* port = GetGraphManager()->GetPort(port_index);
00465     return GetClientControl()->fRefNum == port->GetRefNum();
00466 }
00467 
00468 //--------------------
00469 // Context management
00470 //--------------------
00471 
00472 int JackClient::SetBufferSize(jack_nframes_t buffer_size)
00473 {
00474     int result = -1;
00475     fChannel->SetBufferSize(buffer_size, &result);
00476     return result;
00477 }
00478 
00479 int JackClient::SetFreeWheel(int onoff)
00480 {
00481     int result = -1;
00482     fChannel->SetFreewheel(onoff, &result);
00483     return result;
00484 }
00485 
00486 /*
00487 ShutDown is called:
00488 - from the RT thread when Execute method fails
00489 - possibly from a "closed" notification channel
00490 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
00491 */
00492 
00493 void JackClient::ShutDown()
00494 {
00495     JackLog("ShutDown\n");
00496     if (fShutdown) {
00497         GetClientControl()->fActive = false;
00498         fShutdown(fShutdownArg);
00499         fShutdown = NULL;
00500     }
00501 }
00502 
00503 //----------------------
00504 // Transport management
00505 //----------------------
00506 
00507 int JackClient::ReleaseTimebase()
00508 {
00509     int result = -1;
00510     fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result);
00511     if (result == 0) {
00512         fTimebase = NULL;
00513         fTimebaseArg = NULL;
00514     }
00515     return result;
00516 }
00517 
00518 /* Call the server if the client is active, otherwise keeps the arguments */
00519 int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg)
00520 {
00521     if (IsActive())
00522         GetClientControl()->fTransportState = (sync_callback == NULL) ? JackTransportStopped : JackTransportSynching;
00523     fSync = sync_callback;
00524     fSyncArg = arg;
00525     return 0;
00526 }
00527 
00528 int JackClient::SetSyncTimeout(jack_time_t timeout)
00529 {
00530     GetEngineControl()->fTransport.SetSyncTimeout(timeout);
00531     return 0;
00532 }
00533 
00534 /* Call the server if the client is active, otherwise keeps the arguments */
00535 int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg)
00536 {
00537     if (IsActive()) {
00538         int result = -1;
00539         fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result);
00540         JackLog("SetTimebaseCallback result = %ld\n", result);
00541         if (result == 0) {
00542             fTimebase = timebase_callback;
00543             fTimebaseArg = arg;
00544         } else {
00545             fTimebase = NULL;
00546             fTimebaseArg = NULL;
00547         }
00548         JackLog("SetTimebaseCallback OK result = %ld\n", result);
00549         return result;
00550     } else {
00551         fTimebase = timebase_callback;
00552         fTimebaseArg = arg;
00553         fConditionnal = conditional;
00554         return 0;
00555     }
00556 }
00557 
00558 // Must be RT safe
00559 int JackClient::RequestNewPos(jack_position_t* pos)
00560 {
00561     JackTransportEngine& transport = GetEngineControl()->fTransport;
00562     jack_position_t* request = transport.WriteNextStateStart(2);
00563     pos->unique_1 = pos->unique_2 = transport.GenerateUniqueID();
00564     JackTransportEngine::TransportCopyPosition(pos, request);
00565     JackLog("RequestNewPos pos = %ld\n", pos->frame);
00566     transport.WriteNextStateStop(2);
00567     return 0;
00568 }
00569 
00570 int JackClient::TransportLocate(jack_nframes_t frame)
00571 {
00572     jack_position_t pos;
00573     pos.frame = frame;
00574     pos.valid = (jack_position_bits_t)0;
00575     JackLog("TransportLocate pos = %ld\n", pos.frame);
00576     return RequestNewPos(&pos);
00577 }
00578 
00579 int JackClient::TransportReposition(jack_position_t* pos)
00580 {
00581     jack_position_t tmp = *pos;
00582     JackLog("TransportReposition pos = %ld\n", pos->frame);
00583     return (tmp.valid & ~JACK_POSITION_MASK) ? EINVAL : RequestNewPos(&tmp);
00584 }
00585 
00586 jack_transport_state_t JackClient::TransportQuery(jack_position_t* pos)
00587 {
00588     if (pos)
00589         GetEngineControl()->fTransport.ReadCurrentPos(pos);
00590     return GetEngineControl()->fTransport.GetState();
00591 }
00592 
00593 jack_nframes_t JackClient::GetCurrentTransportFrame()
00594 {
00595     jack_position_t pos;
00596     jack_transport_state_t state = TransportQuery(&pos);
00597 
00598     if (state == JackTransportRolling) {
00599         float usecs = GetMicroSeconds() - pos.usecs;
00600         jack_nframes_t elapsed = (jack_nframes_t)floor((((float) pos.frame_rate) / 1000000.0f) * usecs);
00601         return pos.frame + elapsed;
00602     } else {
00603         return pos.frame;
00604     }
00605 }
00606 
00607 // Must be RT safe: directly write in the transport shared mem
00608 void JackClient::TransportStart()
00609 {
00610     GetEngineControl()->fTransport.SetCommand(TransportCommandStart);
00611 }
00612 
00613 // Must be RT safe: directly write in the transport shared mem
00614 void JackClient::TransportStop()
00615 {
00616     GetEngineControl()->fTransport.SetCommand(TransportCommandStop);
00617 }
00618 
00619 // Never called concurently with the server
00620 // TODO check concurency with SetSyncCallback
00621 
00622 void JackClient::CallSyncCallback()
00623 {
00624     JackTransportEngine& transport = GetEngineControl()->fTransport;
00625     jack_position_t* cur_pos = transport.ReadCurrentState();
00626     jack_transport_state_t transport_state = transport.GetState();
00627 
00628     switch (transport_state) {
00629 
00630         case JackTransportStarting:  // Starting...
00631             if (fSync == NULL) {
00632                 GetClientControl()->fTransportState = JackTransportRolling;
00633             } else if (GetClientControl()->fTransportState == JackTransportStarting) {
00634                 if (fSync(transport_state, cur_pos, fSyncArg))
00635                     GetClientControl()->fTransportState = JackTransportRolling;
00636             }
00637             break;
00638 
00639         case JackTransportRolling:
00640             if (fSync != NULL && GetClientControl()->fTransportState == JackTransportStarting) { // Client still not ready
00641                 if (fSync(transport_state, cur_pos, fSyncArg))
00642                     GetClientControl()->fTransportState = JackTransportRolling;
00643             }
00644             break;
00645 
00646         case JackTransportSynching:
00647             // New pos when transport engine is stopped...
00648             if (fSync != NULL) {
00649                 fSync(JackTransportStopped, cur_pos, fSyncArg);
00650                 GetClientControl()->fTransportState = JackTransportStopped;
00651             }
00652             break;
00653 
00654         default:
00655             break;
00656     }
00657 }
00658 
00659 void JackClient::CallTimebaseCallback()
00660 {
00661     JackTransportEngine& transport = GetEngineControl()->fTransport;
00662 
00663     if (fTimebase != NULL && fTimebaseArg != NULL && GetClientControl()->fRefNum == transport.GetTimebaseMaster()) {
00664 
00665         jack_transport_state_t transport_state = transport.GetState();
00666         jack_position_t* cur_pos = transport.WriteNextStateStart(1);
00667 
00668         switch (transport_state) {
00669 
00670             case JackTransportRolling:
00671                 fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg);
00672                 break;
00673 
00674             case JackTransportSynching:
00675                 fTimebase(JackTransportStopped, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg);
00676                 break;
00677 
00678             default:
00679                 break;
00680         }
00681 
00682         transport.WriteNextStateStop(1);
00683     }
00684 }
00685 
00686 //---------------------
00687 // Callback management
00688 //---------------------
00689 
00690 void JackClient::OnShutdown(JackShutdownCallback callback, void *arg)
00691 {
00692     if (IsActive()) {
00693         jack_error("You cannot set callbacks on an active client");
00694     } else {
00695         fShutdownArg = arg;
00696         fShutdown = callback;
00697     }
00698 }
00699 
00700 int JackClient::SetProcessCallback(JackProcessCallback callback, void *arg)
00701 {
00702     if (IsActive()) {
00703         jack_error("You cannot set callbacks on an active client");
00704         return -1;
00705     } else {
00706         fProcessArg = arg;
00707         fProcess = callback;
00708         return 0;
00709     }
00710 }
00711 
00712 int JackClient::SetXRunCallback(JackXRunCallback callback, void *arg)
00713 {
00714     if (IsActive()) {
00715         jack_error("You cannot set callbacks on an active client");
00716         return -1;
00717     } else {
00718         fXrunArg = arg;
00719         fXrun = callback;
00720         return 0;
00721     }
00722 }
00723 
00724 int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg)
00725 {
00726     if (IsActive()) {
00727         jack_error("You cannot set callbacks on an active client");
00728         return -1;
00729     } else {
00730         fInitArg = arg;
00731         fInit = callback;
00732         return 0;
00733     }
00734 }
00735 
00736 int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg)
00737 {
00738     JackLog("SetGraphOrderCallback \n");
00739 
00740     if (IsActive()) {
00741         jack_error("You cannot set callbacks on an active client");
00742         return -1;
00743     } else {
00744         fGraphOrder = callback;
00745         fGraphOrderArg = arg;
00746         return 0;
00747     }
00748 }
00749 
00750 int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg)
00751 {
00752     if (IsActive()) {
00753         jack_error("You cannot set callbacks on an active client");
00754         return -1;
00755     } else {
00756         fBufferSizeArg = arg;
00757         fBufferSize = callback;
00758         return 0;
00759     }
00760 }
00761 
00762 int JackClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg)
00763 {
00764     if (IsActive()) {
00765         jack_error("You cannot set callbacks on an active client");
00766         return -1;
00767     } else {
00768         fFreewheelArg = arg;
00769         fFreewheel = callback;
00770         return 0;
00771     }
00772 }
00773 
00774 int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg)
00775 {
00776     if (IsActive()) {
00777         jack_error("You cannot set callbacks on an active client");
00778         return -1;
00779     } else {
00780         fPortRegistrationArg = arg;
00781         fPortRegistration = callback;
00782         return 0;
00783     }
00784 }
00785 
00786 } // end of namespace
00787 

Generated on Wed Jan 10 11:42:44 2007 for Jackdmp by  doxygen 1.4.5