Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
    /*
        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;
}