RageSoundDriver_JACK: Autoconnect by default. More robust port detection and connection logic.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user