/*! \brief We need to start thread before activating in the server, otherwise the FW driver connected to the client may not be activated. */ int JackClient::Activate() { jack_log("JackClient::Activate"); if (IsActive()) { return 0; } // RT thread is started only when needed... if (IsRealTime()) { if (StartThread() < 0) { return -1; } } /* Insertion of client in the graph will cause a kGraphOrderCallback notification to be delivered by the server, the client wants to receive it. */ GetClientControl()->fActive = true; // Transport related callback become "active" GetClientControl()->fTransportSync = true; GetClientControl()->fTransportTimebase = true; int result = -1; GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); return result; }
// Notifications received from the server // TODO this should be done once for all clients in the process, when a shared notification channel // will be shared by all clients... int JackLibClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) { int res = 0; assert(JackGlobals::fSynchroMutex); JackGlobals::fSynchroMutex->Lock(); // Done all time switch (notify) { case kAddClient: jack_log("JackClient::AddClient name = %s, ref = %ld ", name, refnum); // the synchro must be usable in I/O mode when several clients live in the same process res = fSynchroTable[refnum].Connect(name, fServerName) ? 0 : -1; break; case kRemoveClient: jack_log("JackClient::RemoveClient name = %s, ref = %ld ", name, refnum); if (GetClientControl() && strcmp(GetClientControl()->fName, name) != 0) { res = fSynchroTable[refnum].Disconnect() ? 0 : -1; } break; } JackGlobals::fSynchroMutex->Unlock(); return res; }
int JackClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size) { // Check if port name is empty string port_short_name_str = string(port_name); if (port_short_name_str.size() == 0) { jack_error("port_name is empty"); return 0; // Means failure here... } // Check port name length string port_full_name_str = string(GetClientControl()->fName) + string(":") + port_short_name_str; if (port_full_name_str.size() >= REAL_JACK_PORT_NAME_SIZE) { jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n" "Please use %lu characters or less", GetClientControl()->fName, port_name, JACK_PORT_NAME_SIZE - 1); return 0; // Means failure here... } int result = -1; jack_port_id_t port_index = NO_PORT; fChannel->PortRegister(GetClientControl()->fRefNum, port_full_name_str.c_str(), port_type, flags, buffer_size, &port_index, &result); if (result == 0) { jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum, port_full_name_str.c_str(), port_type, port_index); fPortList.push_back(port_index); return port_index; } else { return 0; } }
inline void JackClient::End() { jack_log("JackClient::Execute end name = %s", GetClientControl()->fName); // Hum... not sure about this, the following "close" code is called in the RT thread... int result; fThread.DropSelfRealTime(); GetClientControl()->fActive = false; fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); fThread.Terminate(); }
inline void JackClient::Error() { jack_error("JackClient::Execute error name = %s", GetClientControl()->fName); // Hum... not sure about this, the following "close" code is called in the RT thread... int result; fThread.DropSelfRealTime(); GetClientControl()->fActive = false; fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); ShutDown(jack_status_t(JackFailure | JackServerError), JACK_SERVER_FAILURE); fThread.Terminate(); }
int JackClient::ReleaseTimebase() { int result = -1; fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result); if (result == 0) { GetClientControl()->fTransportTimebase = false; fTimebase = NULL; fTimebaseArg = NULL; } return result; }
int JackClient::SetPortConnectCallback(JackPortConnectCallback callback, void *arg) { if (IsActive()) { jack_error("You cannot set callbacks on an active client"); return -1; } else { GetClientControl()->fCallback[kPortConnectCallback] = (callback != NULL); GetClientControl()->fCallback[kPortDisconnectCallback] = (callback != NULL); fPortConnectArg = arg; fPortConnect = callback; return 0; } }
int JackClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg) { if (IsActive()) { jack_error("You cannot set callbacks on an active client"); return -1; } else { GetClientControl()->fCallback[kStartFreewheelCallback] = (callback != NULL); GetClientControl()->fCallback[kStopFreewheelCallback] = (callback != NULL); fFreewheelArg = arg; fFreewheel = callback; return 0; } }
char* JackClient::GetClientNameByUUID(const char* uuid) { char name_res[JACK_CLIENT_NAME_SIZE + 1]; int result = -1; fChannel->GetClientNameForUUID(GetClientControl()->fRefNum, uuid, name_res, &result); return (result) ? NULL : strdup(name_res); }
char* JackClient::GetUUIDForClientName(const char* client_name) { char uuid_res[JACK_UUID_SIZE]; int result = -1; fChannel->GetUUIDForClientName(GetClientControl()->fRefNum, client_name, uuid_res, &result); return (result) ? NULL : strdup(uuid_res); }
int JackClient::InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va) { if (strlen(client_name) >= JACK_CLIENT_NAME_SIZE) { jack_error ("\"%s\" is too long for a JACK client name.\n" "Please use %lu characters or less.", client_name, JACK_CLIENT_NAME_SIZE); return 0; } if (va->load_name && (strlen(va->load_name) >= JACK_PATH_MAX)) { jack_error("\"%s\" is too long for a shared object name.\n" "Please use %lu characters or less.", va->load_name, JACK_PATH_MAX); int my_status1 = *status | (JackFailure | JackInvalidOption); *status = (jack_status_t)my_status1; return 0; } if (va->load_init && (strlen(va->load_init) >= JACK_LOAD_INIT_LIMIT)) { jack_error ("\"%s\" is too long for internal client init " "string.\nPlease use %lu characters or less.", va->load_init, JACK_LOAD_INIT_LIMIT); int my_status1 = *status | (JackFailure | JackInvalidOption); *status = (jack_status_t)my_status1; return 0; } int int_ref, result = -1; fChannel->InternalClientLoad(GetClientControl()->fRefNum, client_name, va->load_name, va->load_init, options, (int*)status, &int_ref, -1, &result); return int_ref; }
char* JackClient::GetInternalClientName(int ref) { char name_res[JACK_CLIENT_NAME_SIZE+1]; int result = -1; fChannel->GetInternalClientName(GetClientControl()->fRefNum, ref, name_res, &result); return (result < 0) ? NULL : strdup(name_res); }
int JackClient::PortDisconnect(jack_port_id_t src) { jack_log("JackClient::PortDisconnect src = %ld", src); int result = -1; fChannel->PortDisconnect(GetClientControl()->fRefNum, src, ALL_PORTS, &result); return result; }
/* Call the server if the client is active, otherwise keeps the arguments */ int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg) { GetClientControl()->fTransportSync = (fSync != NULL); fSyncArg = arg; fSync = sync_callback; return ActivateAux(); }
int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg) { int result = -1; fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); if (result == 0) { GetClientControl()->fTransportTimebase = true; fTimebase = timebase_callback; fTimebaseArg = arg; return ActivateAux(); } else { fTimebase = NULL; fTimebaseArg = NULL; return result; } }
inline void JackClient::SignalSync() { // Resume: signal output clients connected to the running client if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) { jack_error("ResumeRefNum error"); } }
inline bool JackClient::WaitSync() { // Suspend itself: wait on the input synchro if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable, 0x7FFFFFFF) < 0) { jack_error("SuspendRefNum error"); return false; } else { return true; } }
inline void JackClient::CallSyncCallbackAux() { if (GetClientControl()->fTransportSync) { JackTransportEngine& transport = GetEngineControl()->fTransport; jack_position_t* cur_pos = transport.ReadCurrentState(); jack_transport_state_t transport_state = transport.GetState(); if (fSync != NULL) { if (fSync(transport_state, cur_pos, fSyncArg)) { GetClientControl()->fTransportState = JackTransportRolling; GetClientControl()->fTransportSync = false; } } else { GetClientControl()->fTransportState = JackTransportRolling; GetClientControl()->fTransportSync = false; } } }
void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg) { if (IsActive()) { jack_error("You cannot set callbacks on an active client"); } else { // Shutdown callback will either be an old API version or the new version (with info) GetClientControl()->fCallback[kShutDownCallback] = (callback != NULL); fInfoShutdownArg = arg; fInfoShutdown = callback; } }
int JackClient::Close() { jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); int result = 0; Deactivate(); // Channels is stopped first to avoid receiving notifications while closing fChannel->Stop(); // Then close client fChannel->ClientClose(GetClientControl()->fRefNum, &result); fChannel->Close(); assert(JackGlobals::fSynchroMutex); JackGlobals::fSynchroMutex->Lock(); fSynchroTable[GetClientControl()->fRefNum].Disconnect(); JackGlobals::fSynchroMutex->Unlock(); JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; return result; }
int JackClient::SetSessionCallback(JackSessionCallback callback, void *arg) { if (IsActive()) { jack_error("You cannot set callbacks on an active client"); return -1; } else { GetClientControl()->fCallback[kSessionCallback] = (callback != NULL); fSessionArg = arg; fSession = callback; return 0; } }
int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg) { if (IsActive()) { jack_error("You cannot set callbacks on an active client"); return -1; } else { GetClientControl()->fCallback[kBufferSizeCallback] = (callback != NULL); fBufferSizeArg = arg; fBufferSize = callback; return 0; } }
inline int JackClient::ActivateAux() { // If activated without RT thread... if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { jack_log("JackClient::ActivateAux"); // RT thread is started if (StartThread() < 0) { return -1; } int result = -1; GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); return result; } else { return 0; } }
int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg) { if (IsActive()) { jack_error("You cannot set callbacks on an active client"); return -1; } else { GetClientControl()->fCallback[kGraphOrderCallback] = (callback != NULL); fGraphOrder = callback; fGraphOrderArg = arg; return 0; } }
inline void JackClient::CallTimebaseCallbackAux() { JackTransportEngine& transport = GetEngineControl()->fTransport; int master; bool unused; transport.GetTimebaseMaster(master, unused); if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase... jack_transport_state_t transport_state = transport.GetState(); jack_position_t* cur_pos = transport.WriteNextStateStart(1); if (GetClientControl()->fTransportTimebase) { fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true } else if (transport_state == JackTransportRolling) { fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); } transport.WriteNextStateStop(1); } }
int JackClient::PortDisconnect(const char* src, const char* dst) { jack_log("JackClient::Disconnect src = %s dst = %s", src, dst); if (strlen(src) >= REAL_JACK_PORT_NAME_SIZE) { jack_error("\"%s\" is too long to be used as a JACK port name.\n", src); return -1; } if (strlen(dst) >= REAL_JACK_PORT_NAME_SIZE) { jack_error("\"%s\" is too long to be used as a JACK port name.\n", src); return -1; } int result = -1; fChannel->PortDisconnect(GetClientControl()->fRefNum, src, dst, &result); return result; }
int JackClient::PortUnRegister(jack_port_id_t port_index) { jack_log("JackClient::PortUnRegister port_index = %ld", port_index); list<jack_port_id_t>::iterator it = find(fPortList.begin(), fPortList.end(), port_index); if (it != fPortList.end()) { fPortList.erase(it); int result = -1; fChannel->PortUnRegister(GetClientControl()->fRefNum, port_index, &result); return result; } else { jack_error("unregistering a port %ld that is not own by the client", port_index); return -1; } }
int JackClient::SessionReply(jack_session_event_t* ev) { if (ev->command_line) { strncpy(GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand)); } else { GetClientControl()->fSessionCommand[0] = '\0'; } GetClientControl()->fSessionFlags = ev->flags; jack_log("JackClient::SessionReply... we are here"); if (fChannel->IsChannelThread()) { jack_log("JackClient::SessionReply... in callback reply"); // OK, immediate reply... fSessionReply = kImmediateSessionReply; return 0; } jack_log("JackClient::SessionReply... out of cb"); int result = -1; fChannel->SessionReply(GetClientControl()->fRefNum, &result); return result; }
/*! \brief Need to stop thread after deactivating in the server. */ int JackClient::Deactivate() { jack_log("JackClient::Deactivate"); if (!IsActive()) { return 0; } GetClientControl()->fActive = false; // Transport related callback become "unactive" GetClientControl()->fTransportSync = false; GetClientControl()->fTransportTimebase = false; // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate int result = -1; fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); jack_log("JackClient::Deactivate res = %ld", result); // RT thread is stopped only when needed... if (IsRealTime()) { fThread.Kill(); } return result; }
int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg) { if (IsActive()) { jack_error("You cannot set callbacks on an active client"); return -1; } else { GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); fSampleRateArg = arg; fSampleRate = callback; // Now invoke it if (callback) { callback(GetEngineControl()->fSampleRate, arg); } return 0; } }