jack2/common/JackLibClient.cpp

215 lines
6.3 KiB
C++

/*
Copyright (C) 2004-2008 Grame
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "JackLibClient.h"
#include "JackTime.h"
#include "JackLibGlobals.h"
#include "JackGlobals.h"
#include "JackPlatformPlug.h"
#include "JackTools.h"
namespace Jack
{
// Used for external C API (JackAPI.cpp)
JackGraphManager* GetGraphManager()
{
if (JackLibGlobals::fGlobals) {
return JackLibGlobals::fGlobals->fGraphManager;
} else {
return NULL;
}
}
JackEngineControl* GetEngineControl()
{
if (JackLibGlobals::fGlobals) {
return JackLibGlobals::fGlobals->fEngineControl;
} else {
return NULL;
}
}
JackSynchro* GetSynchroTable()
{
return (JackLibGlobals::fGlobals ? JackLibGlobals::fGlobals->fSynchroTable : 0);
}
JackMetadata* GetMetadata()
{
if (JackLibGlobals::fGlobals) {
return JackLibGlobals::fGlobals->fMetadata;
} else {
return NULL;
}
}
//-------------------
// Client management
//-------------------
/*
ShutDown is called:
- from the RT thread when Execute method fails
- possibly from a "closed" notification channel
(Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
*/
void JackLibClient::ShutDown(jack_status_t code, const char* message)
{
jack_log("JackLibClient::ShutDown");
JackGlobals::fServerRunning = false;
JackClient::ShutDown(code, message);
}
JackLibClient::JackLibClient(JackSynchro* table): JackClient(table)
{
jack_log("JackLibClient::JackLibClient table = %x", table);
fChannel = new JackClientChannel();
}
JackLibClient::~JackLibClient()
{
jack_log("JackLibClient::~JackLibClient");
delete fChannel;
}
int JackLibClient::Open(const char* server_name, const char* name, jack_uuid_t uuid, jack_options_t options, jack_status_t* status)
{
int shared_engine, shared_client, shared_graph, result;
bool res;
jack_log("JackLibClient::Open name = %s", name);
if (strlen(name) >= JACK_CLIENT_NAME_SIZE) {
jack_error("\"%s\" is too long to be used as a JACK client name.\n"
"Please use %lu characters or less",
name,
JACK_CLIENT_NAME_SIZE - 1);
return -1;
}
strncpy(fServerName, server_name, sizeof(fServerName));
fServerName[sizeof(fServerName) - 1] = 0;
// Open server/client channel
char name_res[JACK_CLIENT_NAME_SIZE+1];
if (fChannel->Open(server_name, name, uuid, name_res, this, options, status) < 0) {
jack_error("Cannot connect to the server");
goto error;
}
// Start receiving notifications
if (fChannel->Start() < 0) {
jack_error("Cannot start channel");
goto error;
}
// Require new client
fChannel->ClientOpen(name_res, JackTools::GetPID(), uuid, &shared_engine, &shared_client, &shared_graph, &result);
if (result < 0) {
jack_error("Cannot open %s client", name_res);
goto error;
}
try {
// Map shared memory segments
JackLibGlobals::fGlobals->fEngineControl.SetShmIndex(shared_engine, fServerName);
JackLibGlobals::fGlobals->fGraphManager.SetShmIndex(shared_graph, fServerName);
fClientControl.SetShmIndex(shared_client, fServerName);
JackGlobals::fVerbose = GetEngineControl()->fVerbose;
} catch (...) {
jack_error("Map shared memory segments exception");
goto error;
}
SetupDriverSync(false);
// Connect shared synchro : the synchro must be usable in I/O mode when several clients live in the same process
assert(JackGlobals::fSynchroMutex);
JackGlobals::fSynchroMutex->Lock();
res = fSynchroTable[GetClientControl()->fRefNum].Connect(name_res, fServerName);
JackGlobals::fSynchroMutex->Unlock();
if (!res) {
jack_error("Cannot ConnectSemaphore %s client", name_res);
goto error;
}
JackGlobals::fClientTable[GetClientControl()->fRefNum] = this;
SetClockSource(GetEngineControl()->fClockSource);
jack_log("JackLibClient::Open name = %s refnum = %ld", name_res, GetClientControl()->fRefNum);
return 0;
error:
fChannel->Stop();
fChannel->Close();
return -1;
}
// 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;
}
JackGraphManager* JackLibClient::GetGraphManager() const
{
assert(JackLibGlobals::fGlobals->fGraphManager);
return JackLibGlobals::fGlobals->fGraphManager;
}
JackEngineControl* JackLibClient::GetEngineControl() const
{
assert(JackLibGlobals::fGlobals->fEngineControl);
return JackLibGlobals::fGlobals->fEngineControl;
}
JackClientControl* JackLibClient::GetClientControl() const
{
return fClientControl;
}
} // end of namespace