Commit db132e19 authored by Devin Anderson's avatar Devin Anderson
Browse files

Update server control API with jackctl_server_open and jackctl_server_close...

Update server control API with jackctl_server_open and jackctl_server_close (see http://trac.jackaudio.org/ticket/219 for rationale).  Update drivers to support Start/Stop of slave drivers.  Update dbus to use new jackctl_server_* functions.  Freewheel driver is no longer an implicit slave of the master audio driver.  Haven't tested freewheeling, and didn't update Solaris OSS driver.  Tested slave addition by adding loopback driver, but don't have a slave driver in this branch on Linux platform to test with.
parent e97dcccf
......@@ -313,6 +313,26 @@ int JackAudioDriver::ProcessGraphSync()
return res;
}
int JackAudioDriver::Start()
{
int res = JackDriver::Start();
if ((res >= 0) && fIsMaster) {
res = StartSlaves();
}
return res;
}
int JackAudioDriver::Stop()
{
int res = JackDriver::Stop();
if (fIsMaster) {
if (StopSlaves() < 0) {
res = -1;
}
}
return res;
}
void JackAudioDriver::WaitUntilNextCycle()
{
int wait_time_usec = (int((float(fEngineControl->fBufferSize) / (float(fEngineControl->fSampleRate))) * 1000000.0f));
......
......@@ -92,6 +92,9 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
virtual int Attach();
virtual int Detach();
virtual int Start();
virtual int Stop();
virtual int Write();
virtual int SetBufferSize(jack_nframes_t buffer_size);
......
......@@ -826,6 +826,11 @@ EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr
EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
{
server_ptr->engine->Stop();
return true;
}
EXPORT bool jackctl_server_close(jackctl_server *server_ptr)
{
server_ptr->engine->Close();
delete server_ptr->engine;
......@@ -853,7 +858,7 @@ EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
}
EXPORT bool
jackctl_server_start(
jackctl_server_open(
jackctl_server *server_ptr,
jackctl_driver *driver_ptr)
{
......@@ -913,18 +918,8 @@ jackctl_server_start(
goto fail_delete;
}
rc = server_ptr->engine->Start();
if (rc < 0)
{
jack_error("JackServer::Start() failed with %d", rc);
goto fail_close;
}
return true;
fail_close:
server_ptr->engine->Close();
fail_delete:
delete server_ptr->engine;
server_ptr->engine = NULL;
......@@ -946,6 +941,19 @@ fail:
return false;
}
EXPORT bool
jackctl_server_start(
jackctl_server *server_ptr)
{
int rc = server_ptr->engine->Start();
bool result = rc >= 0;
if (! result)
{
jack_error("JackServer::Start() failed with %d", rc);
}
return result;
}
EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
{
return driver_ptr->desc_ptr->name;
......
......@@ -101,13 +101,21 @@ jackctl_server_get_drivers_list(
jackctl_server_t * server);
EXPORT bool
jackctl_server_start(
jackctl_server_open(
jackctl_server_t * server,
jackctl_driver_t * driver);
EXPORT bool
jackctl_server_start(
jackctl_server_t * server);
EXPORT bool
jackctl_server_stop(
jackctl_server_t * server);
jackctl_server_t * server);
EXPORT bool
jackctl_server_close(
jackctl_server_t * server);
EXPORT const JSList *
jackctl_server_get_parameters(
......
......@@ -328,11 +328,41 @@ int JackDriver::Start()
return 0;
}
int JackDriver::StartSlaves()
{
int res = 0;
list<JackDriverInterface*>::const_iterator it;
for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
JackDriverInterface* slave = *it;
if (slave->Start() < 0) {
res = -1;
// XXX: We should attempt to stop all of the slaves that we've
// started here.
break;
}
}
return res;
}
int JackDriver::Stop()
{
return 0;
}
int JackDriver::StopSlaves()
{
int res = 0;
list<JackDriverInterface*>::const_iterator it;
for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
JackDriverInterface* slave = *it;
if (slave->Stop() < 0)
res = -1;
}
return res;
}
bool JackDriver::IsFixedBufferSize()
{
return true;
......
......@@ -198,7 +198,9 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface
virtual int Write();
virtual int Start();
virtual int StartSlaves();
virtual int Stop();
virtual int StopSlaves();
virtual bool IsFixedBufferSize();
virtual int SetBufferSize(jack_nframes_t buffer_size);
......
......@@ -87,26 +87,18 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
goto fail_close3;
}
if (fFreewheelDriver->Open() < 0) { // before engine open
jack_error("Cannot open driver");
goto fail_close4;
}
if (fAudioDriver->Attach() < 0) {
jack_error("Cannot attach audio driver");
goto fail_close5;
goto fail_close4;
}
fFreewheelDriver->SetMaster(false);
fAudioDriver->SetMaster(true);
fAudioDriver->AddSlave(fFreewheelDriver); // After ???
//fAudioDriver->AddSlave(fFreewheelDriver);
InitTime();
SetClockSource(fEngineControl->fClockSource);
return 0;
fail_close5:
fFreewheelDriver->Close();
fail_close4:
fEngine->Close();
......@@ -128,7 +120,9 @@ int JackServer::Close()
fChannel.Close();
fAudioDriver->Detach();
fAudioDriver->Close();
fFreewheelDriver->Close();
if (fFreewheel) {
fFreewheelDriver->Close();
}
fEngine->Close();
// TODO: move that in reworked JackServerGlobals::Destroy()
JackMessageBuffer::Destroy();
......@@ -238,6 +232,7 @@ int JackServer::SetFreewheel(bool onoff)
} else {
fFreewheel = false;
fFreewheelDriver->Stop();
fFreewheelDriver->Close();
fGraphManager->Restore(&fConnectionState); // Restore previous connection state
fEngine->NotifyFreewheel(onoff);
fFreewheelDriver->SetMaster(false);
......@@ -250,6 +245,10 @@ int JackServer::SetFreewheel(bool onoff)
fGraphManager->Save(&fConnectionState); // Save connection state
fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
fEngine->NotifyFreewheel(onoff);
if (fFreewheelDriver->Open() < 0) {
jack_error("Cannot open freewheel driver");
return -1;
}
fFreewheelDriver->SetMaster(true);
return fFreewheelDriver->Start();
} else {
......@@ -296,11 +295,11 @@ JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* dr
if (slave == NULL) {
delete info;
return NULL;
} else {
slave->Attach();
fAudioDriver->AddSlave(slave);
return info;
}
slave->Attach();
slave->SetMaster(false);
fAudioDriver->AddSlave(slave);
return info;
}
void JackServer::RemoveSlave(JackDriverInfo* info)
......@@ -322,32 +321,30 @@ int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_par
JackDriverInfo* info = new JackDriverInfo();
JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
if (master == NULL || info == NULL) {
if (master == NULL) {
delete info;
delete master;
return -1;
} else {
}
// Get slaves list
std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
std::list<JackDriverInterface*>::const_iterator it;
// Get slaves list
std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
std::list<JackDriverInterface*>::const_iterator it;
// Move slaves in new master
for (it = slave_list.begin(); it != slave_list.end(); it++) {
JackDriverInterface* slave = *it;
master->AddSlave(slave);
}
// Move slaves in new master
for (it = slave_list.begin(); it != slave_list.end(); it++) {
JackDriverInterface* slave = *it;
master->AddSlave(slave);
}
// Delete old master
delete fDriverInfo;
// Delete old master
delete fDriverInfo;
// Activate master
fAudioDriver = master;
fDriverInfo = info;
fAudioDriver->Attach();
fAudioDriver->SetMaster(true);
return fAudioDriver->Start();
}
// Activate master
fAudioDriver = master;
fDriverInfo = info;
fAudioDriver->Attach();
fAudioDriver->SetMaster(true);
return fAudioDriver->Start();
}
//----------------------
......
......@@ -244,6 +244,10 @@ int main(int argc, char* argv[])
std::list<char*> slaves_list;
std::list<char*>::iterator it;
// Assume that we fail.
int return_value = -1;
bool notify_sent = false;
copyright(stdout);
#if defined(JACK_DBUS) && defined(__linux__)
server_ctl = jackctl_server_create(audio_acquire, audio_release);
......@@ -285,7 +289,7 @@ int main(int argc, char* argv[])
jackctl_parameter_set_value(param, &value);
} else {
usage(stdout);
goto fail_free1;
goto destroy_server;
}
}
break;
......@@ -402,7 +406,7 @@ int main(int argc, char* argv[])
case 'h':
usage(stdout);
goto fail_free1;
goto destroy_server;
}
}
......@@ -423,14 +427,14 @@ int main(int argc, char* argv[])
if (!master_driver_name) {
usage(stderr);
goto fail_free1;
goto destroy_server;
}
// Master driver
master_driver_ctl = jackctl_server_get_driver(server_ctl, master_driver_name);
if (master_driver_ctl == NULL) {
fprintf(stderr, "Unknown driver \"%s\"\n", master_driver_name);
goto fail_free1;
goto destroy_server;
}
if (optind < argc) {
......@@ -442,7 +446,7 @@ int main(int argc, char* argv[])
if (master_driver_nargs == 0) {
fprintf(stderr, "No driver specified ... hmm. JACK won't do"
" anything when run like this.\n");
goto fail_free1;
goto destroy_server;
}
master_driver_args = (char **) malloc(sizeof(char *) * master_driver_nargs);
......@@ -453,15 +457,16 @@ int main(int argc, char* argv[])
}
if (jackctl_parse_driver_params(master_driver_ctl, master_driver_nargs, master_driver_args)) {
goto fail_free1;
goto destroy_server;
}
// Setup signals then start server
// Setup signals
signals = jackctl_setup_signals(0);
if (!jackctl_server_start(server_ctl, master_driver_ctl)) {
fprintf(stderr, "Failed to start server\n");
goto fail_free1;
// Open server
if (! jackctl_server_open(server_ctl, master_driver_ctl)) {
fprintf(stderr, "Failed to open server\n");
goto destroy_server;
}
// Slave drivers
......@@ -469,7 +474,7 @@ int main(int argc, char* argv[])
jackctl_driver_t * slave_driver_ctl = jackctl_server_get_driver(server_ctl, *it);
if (slave_driver_ctl == NULL) {
fprintf(stderr, "Unknown driver \"%s\"\n", *it);
goto fail_free2;
goto close_server;
}
jackctl_server_add_slave(server_ctl, slave_driver_ctl);
}
......@@ -477,6 +482,8 @@ int main(int argc, char* argv[])
// Loopback driver
if (loopback > 0) {
loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback");
// XX: What if this fails?
if (loopback_driver_ctl != NULL) {
const JSList * loopback_parameters = jackctl_driver_get_parameters(loopback_driver_ctl);
param = jackctl_get_parameter(loopback_parameters, "channels");
......@@ -486,6 +493,13 @@ int main(int argc, char* argv[])
}
jackctl_server_add_slave(server_ctl, loopback_driver_ctl);
}
}
// Start the server
if (!jackctl_server_start(server_ctl)) {
fprintf(stderr, "Failed to start server\n");
goto close_server;
}
// Internal clients
......@@ -493,30 +507,28 @@ int main(int argc, char* argv[])
jackctl_internal_t * internal_driver_ctl = jackctl_server_get_internal(server_ctl, *it);
if (internal_driver_ctl == NULL) {
fprintf(stderr, "Unknown internal \"%s\"\n", *it);
goto fail_free2;
goto stop_server;
}
jackctl_server_load_internal(server_ctl, internal_driver_ctl);
}
notify_server_start(server_name);
notify_sent = true;
return_value = 0;
// Waits for signal
jackctl_wait_signals(signals);
if (!jackctl_server_stop(server_ctl))
stop_server:
if (! jackctl_server_stop(server_ctl)) {
fprintf(stderr, "Cannot stop server...\n");
jackctl_server_destroy(server_ctl);
notify_server_stop(server_name);
return 0;
fail_free1:
jackctl_server_destroy(server_ctl);
return -1;
fail_free2:
jackctl_server_stop(server_ctl);
}
if (notify_sent) {
notify_server_stop(server_name);
}
close_server:
jackctl_server_close(server_ctl);
destroy_server:
jackctl_server_destroy(server_ctl);
notify_server_stop(server_name);
return -1;
return return_value;
}
......@@ -133,7 +133,7 @@ jackctl_server_destroy(
jackctl_server_t * server);
/**
* Call this function to start JACK server
* Call this function to open JACK server
*
* @param server server object handle
* @param driver driver to use
......@@ -141,10 +141,21 @@ jackctl_server_destroy(
* @return success status: true - success, false - fail
*/
bool
jackctl_server_start(
jackctl_server_open(
jackctl_server_t * server,
jackctl_driver_t * driver);
/**
* Call this function to start JACK server
*
* @param server server object handle
*
* @return success status: true - success, false - fail
*/
bool
jackctl_server_start(
jackctl_server_t * server);
/**
* Call this function to stop JACK server
*
......@@ -156,6 +167,17 @@ bool
jackctl_server_stop(
jackctl_server_t * server);
/**
* Call this function to close JACK server
*
* @param server server object handle
*
* @return success status: true - success, false - fail
*/
bool
jackctl_server_close(
jackctl_server_t * server);
/**
* Call this function to get list of available drivers. List node data
* pointers is a driver object handle (::jackctl_driver_t).
......
......@@ -153,14 +153,21 @@ jack_controller_start_server(
controller_ptr->xruns = 0;
if (!jackctl_server_start(
if (!jackctl_server_open(
controller_ptr->server,
controller_ptr->driver))
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to start server");
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to open server");
goto fail;
}
if (!jackctl_server_start(
controller_ptr->server))
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to start server");
goto fail_close_server;
}
controller_ptr->client = jack_client_open(
"dbusapi",
JackNoStartServer,
......@@ -213,6 +220,12 @@ fail_stop_server:
jack_error("failed to stop jack server");
}
fail_close_server:
if (!jackctl_server_close(controller_ptr->server))
{
jack_error("failed to close jack server");
}
fail:
return FALSE;
}
......@@ -250,6 +263,12 @@ jack_controller_stop_server(
return FALSE;
}
if (!jackctl_server_close(controller_ptr->server))
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to close server");
return FALSE;
}
controller_ptr->started = false;
return TRUE;
......
......@@ -207,8 +207,9 @@ int main(int argc, char *argv[])
print_internal((jackctl_internal_t *)node_ptr->data);
node_ptr = jack_slist_next(node_ptr);
}
jackctl_server_start(server, jackctl_server_get_driver(server, driver_name));
jackctl_server_open(server, jackctl_server_get_driver(server, driver_name));
jackctl_server_start(server);
jackctl_server_load_internal(server, jackctl_server_get_internal(server, client_name));
/*
......
......@@ -340,13 +340,23 @@ int JackAlsaDriver::Close()
int JackAlsaDriver::Start()
{
JackAudioDriver::Start();
return alsa_driver_start((alsa_driver_t *)fDriver);
int res = JackAudioDriver::Start();
if (res >= 0) {
res = alsa_driver_start((alsa_driver_t *)fDriver);
if (res < 0) {
JackAudioDriver::Stop();
}
}
return res;
}
int JackAlsaDriver::Stop()
{
return alsa_driver_stop((alsa_driver_t *)fDriver);
int res = alsa_driver_stop((alsa_driver_t *)fDriver);
if (JackAudioDriver::Stop() < 0) {
res = -1;
}
return res;
}
int JackAlsaDriver::Read()
......
......@@ -526,7 +526,7 @@ int JackFFADODriver::Attach()
port = fGraphManager->GetPort(port_index);
// Add one buffer more latency if "async" mode is used...
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency;
port->SetLatencyRange(JackPlaybackLatency, &range);
// playback port aliases (jackd1 style port names)
snprintf(buf, sizeof(buf) - 1, "%s:playback_%i", fClientControl.fName, (int) chn + 1);
......@@ -653,13 +653,23 @@ int JackFFADODriver::Close()
int JackFFADODriver::Start()
{
JackAudioDriver::Start();
return ffado_driver_start((ffado_driver_t *)fDriver);
int res = JackAudioDriver::Start();
if (res >= 0) {
res = ffado_driver_start((ffado_driver_t *)fDriver);
if (res < 0) {
JackAudioDriver::Stop();
}
}
return res;
}
int JackFFADODriver::Stop()
{
return ffado_driver_stop((ffado_driver_t *)fDriver);
int res = ffado_driver_stop((ffado_driver_t *)fDriver);
if (JackAudioDriver::Stop() < 0) {
res = -1;
}
return res;
}
int JackFFADODriver::Read()
......