bool SC_JackDriver::DriverStart() { if (!mClient) return false; int err; SC_StringParser sp; jack_port_t **ports; int numPorts; // activate client err = jack_activate(mClient); if (err) { scprintf("%s: couldn't activate jack client\n", kJackDriverIdent); return false; } // connect default inputs sp = SC_StringParser(getenv("SC_JACK_DEFAULT_INPUTS"), ','); ports = mInputList->mPorts; numPorts = mInputList->mSize; for (int i = 0; !sp.AtEnd() && (i < numPorts); i++) { const char *thatPortName = sp.NextToken(); if (i == 0 && sp.AtEnd() && (strchr(thatPortName, ':') == 0)) { ConnectClientInputs(thatPortName); break; } const char *thisPortName = jack_port_name(ports[i]); if (thisPortName && thatPortName) ConnectPorts(thatPortName, thisPortName); } // connect default outputs sp = SC_StringParser(getenv("SC_JACK_DEFAULT_OUTPUTS"), ','); ports = mOutputList->mPorts; numPorts = mOutputList->mSize; for (int i = 0; !sp.AtEnd() && (i < numPorts); i++) { const char *thatPortName = sp.NextToken(); if (i == 0 && sp.AtEnd() && (strchr(thatPortName, ':') == 0)) { ConnectClientOutputs(thatPortName); break; } const char *thisPortName = jack_port_name(ports[i]); if (thisPortName && thatPortName) ConnectPorts(thisPortName, thatPortName); } return true; }
void SC_JackDriver::ConnectClientOutputs(const char * pattern) { const char **ports = jack_get_ports (mClient, pattern, NULL, JackPortIsInput); jack_port_t ** ourports = mOutputList->mPorts; if (!ports) return; int i = 0; while (ports[i]) { if (i == mOutputList->mSize) break; const char * src = jack_port_name(ourports[i]); const char * dst = ports[i]; ConnectPorts(src, dst); ++i; } free(ports); }
/* JackProxyDriver is wrapped in a JackWaitCallbackDriver decorator that behaves as a "dummy driver, until Initialize method returns. */ bool JackProxyDriver::Initialize() { jack_log("JackProxyDriver::Initialize"); // save existing local connections if needed if (fAutoSave) { SaveConnections(0); } // new loading, but existing client, restart the driver if (fClient) { jack_info("JackProxyDriver restarting..."); jack_client_close(fClient); } FreePorts(); // display some additional infos jack_info("JackProxyDriver started in %s mode.", (fEngineControl->fSyncMode) ? "sync" : "async"); do { jack_status_t status; char *old = NULL; if (fPromiscuous) { // as we are fiddling with the environment variable content, save it const char* tmp = getenv("JACK_PROMISCUOUS_SERVER"); if (tmp) { old = strdup(tmp); } // temporary enable promiscuous mode if (setenv("JACK_PROMISCUOUS_SERVER", fPromiscuous, 1) < 0) { free(old); jack_error("Error allocating memory."); return false; } } jack_info("JackProxyDriver connecting to %s", fUpstream); fClient = jack_client_open(fClientName, static_cast<jack_options_t>(JackNoStartServer|JackServerName), &status, fUpstream); if (fPromiscuous) { // restore previous environment variable content if (old) { if (setenv("JACK_PROMISCUOUS_SERVER", old, 1) < 0) { free(old); jack_error("Error allocating memory."); return false; } free(old); } else { unsetenv("JACK_PROMISCUOUS_SERVER"); } } // the connection failed, try again later if (!fClient) { JackSleep(1000000); } } while (!fClient); jack_info("JackProxyDriver connected to %s", fUpstream); // we are connected, let's register some callbacks jack_on_shutdown(fClient, shutdown_callback, this); if (jack_set_process_callback(fClient, process_callback, this) != 0) { jack_error("Cannot set process callback."); return false; } if (jack_set_buffer_size_callback(fClient, bufsize_callback, this) != 0) { jack_error("Cannot set buffer size callback."); return false; } if (jack_set_sample_rate_callback(fClient, srate_callback, this) != 0) { jack_error("Cannot set sample rate callback."); return false; } if (jack_set_port_connect_callback(fClient, connect_callback, this) != 0) { jack_error("Cannot set port connect callback."); return false; } // detect upstream physical playback ports if needed if (fDetectPlaybackChannels) { fPlaybackChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput); } // detect upstream physical capture ports if needed if (fDetectCaptureChannels) { fCaptureChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput); } if (AllocPorts() != 0) { jack_error("Can't allocate ports."); return false; } bufsize_callback(jack_get_buffer_size(fClient)); srate_callback(jack_get_sample_rate(fClient)); // restore local connections if needed if (fAutoSave) { LoadConnections(0); } // everything is ready, start upstream processing if (jack_activate(fClient) != 0) { jack_error("Cannot activate jack client."); return false; } // connect upstream ports if needed if (fAutoConnect) { ConnectPorts(); } return true; }
RString RageSoundDriver_JACK::Init() { jack_status_t status; RString error; // Open JACK client and call it "StepMania" or whatever client = jack_client_open(PRODUCT_FAMILY, JackNoStartServer, &status); if (client == NULL) return "Couldn't connect to JACK server"; sample_rate = jack_get_sample_rate(client); LOG->Trace("JACK connected at %u Hz", sample_rate); // Start this before callbacks StartDecodeThread(); // Set callback for processing audio if (jack_set_process_callback(client, ProcessTrampoline, this)) { error = "Couldn't set JACK process callback"; goto out_close; } if (jack_set_sample_rate_callback(client, SampleRateTrampoline, this)) { error = "Couldn't set JACK sample-rate callback"; goto out_close; } // TODO Set a jack_on_shutdown callback as well? Probably just stop // caring about sound altogether if that happens. // Create output ports port_l = jack_port_register(client, "out_l", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (port_l == NULL) { error = "Couldn't create JACK port out_l"; goto out_close; } port_r = jack_port_register(client, "out_r", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (port_r == NULL) { error = "Couldn't create JACK port out_r"; goto out_unreg_l; } // Go! if (jack_activate(client)) { error = "Couldn't activate JACK client"; goto out_unreg_r; } error = ConnectPorts(); if (!error.empty()) // Eh. Not fatal. JACK *is* running and we successfully created // our source ports, so it's unlkely any other driver will // function. LOG->Warn( "RageSoundDriver_JACK: Couldn't connect ports: %s", error.c_str() ); // Success! LOG->Trace("JACK sound driver started successfully"); return RString(); // Not success! out_unreg_r: jack_port_unregister(client, port_r); out_unreg_l: jack_port_unregister(client, port_l); out_close: jack_client_close(client); client = NULL; return error; }