RageSoundDriver_JACK: Autoconnect by default. More robust port detection and connection logic.

This commit is contained in:
Ben "root" Anderson
2014-01-25 11:04:46 -06:00
parent 36864f8ae7
commit 970bb39a81
+59 -35
View File
@@ -4,6 +4,7 @@
#include "RageUtil.h" #include "RageUtil.h"
#include "PrefsManager.h" #include "PrefsManager.h"
#include "ProductInfo.h" #include "ProductInfo.h"
#include "Foreach.h"
REGISTER_SOUND_DRIVER_CLASS( JACK ); REGISTER_SOUND_DRIVER_CLASS( JACK );
@@ -84,13 +85,12 @@ RString RageSoundDriver_JACK::Init()
goto out_unreg_r; goto out_unreg_r;
} }
// Connect to playback port. This currently requires that you specify
// the client using the SoundDevice preference. The alternative is to
// connect automatically to something like `playback' if none is
// specified, which is not friendly JACK behavior.
error = ConnectPorts(); error = ConnectPorts();
if (!error.empty()) if (!error.empty())
goto out_deactivate; // 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! // Success!
LOG->Trace("JACK sound driver started successfully"); LOG->Trace("JACK sound driver started successfully");
@@ -98,8 +98,6 @@ RString RageSoundDriver_JACK::Init()
// Not success! // Not success!
out_deactivate:
jack_deactivate(client);
out_unreg_r: out_unreg_r:
jack_port_unregister(client, port_r); jack_port_unregister(client, port_r);
out_unreg_l: out_unreg_l:
@@ -115,40 +113,66 @@ RString RageSoundDriver_JACK::ConnectPorts()
vector<RString> portNames; vector<RString> portNames;
split(PREFSMAN->m_iSoundDevice.Get(), ",", portNames, true); split(PREFSMAN->m_iSoundDevice.Get(), ",", portNames, true);
switch (portNames.size()) const char *port_out_l, *port_out_r;
if( portNames.size() == 0 )
{ {
case 0: // The user has NOT specified any ports to connect to. Search
// No ports specified. Try the system outputs. // for all physical sinks and use the first two.
// XXX: If only one system playback port is available, const char **ports;
// only our left channel will be connected. ports = jack_get_ports( client, NULL, NULL, JackPortIsInput | JackPortIsPhysical );
portNames.push_back("system:playback_1"); if( ports[0] == NULL )
portNames.push_back("system:playback_2"); return "No physical sinks!";
case 1: port_out_l = ports[0];
// HACK: Pointing both channels at one port is probably the
// wrong way to mix to mono. For now, it works. if( ports[1] == NULL )
portNames.push_back(portNames[0]); // Only one physical sink. We're going mono!
break; port_out_r = ports[0];
case 2: else
break; port_out_r = ports[1];
default: }
LOG->Warn("More than two JACK ports specified; using the first two only."); else
break; {
// The user has specified ports to connect to. Loop through
// them to find two that are valid, then use them. If we find
// only one that is valid, connect both channels to it.
// Use jack_port_by_name to ensure ports exist, then
// jack_port_name to use their canonical name. (I'm not sure
// if that second step is necessary, I've seen something about
// "aliases" in the docs.)
FOREACH( RString, portNames, portName )
{
jack_port_t *out = jack_port_by_name( client, *portName );
// Make sure the port is a sink.
if( ! jack_port_flags( out ) & JackPortIsInput ) continue;
if( out != NULL )
{
if( port_out_l == NULL )
port_out_l = jack_port_name( out );
else
{
port_out_r = jack_port_name( out );
break;
}
}
}
if( port_out_l == NULL )
return "All specified sinks are invalid.";
if( port_out_r == NULL )
// Only found one valid sink. Going mono!
port_out_r = port_out_l;
} }
ASSERT(portNames.size() >= 2); RString ret = RString();
// Use jack_port_by_name to ensure ports exist, then jack_port_name to if ( jack_connect( client, jack_port_name(port_l), port_out_l ) != 0 )
// use their canonical name. (I'm not sure if that second step is ret = "Couldn't connect left JACK port";
// necessary, I've seen something about "aliases" in the docs.)
jack_port_t *port_out = jack_port_by_name(client, portNames[0]);
if (port_out == NULL || jack_connect(client, jack_port_name(port_l), jack_port_name(port_out)))
return "Couldn't connect left JACK port";
port_out = jack_port_by_name(client, portNames[1]); if( jack_connect( client, jack_port_name(port_r), port_out_r ) != 0 )
if (port_out == NULL || jack_connect(client, jack_port_name(port_r), jack_port_name(port_out))) if( ret == "") ret = "Couldn't connect right JACK port";
return "Couldn't connect right JACK port";
return RString(); return ret;
} }
int64_t RageSoundDriver_JACK::GetPosition() const int64_t RageSoundDriver_JACK::GetPosition() const