aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--alc/backends/jack.cpp79
1 files changed, 75 insertions, 4 deletions
diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp
index fe3aa794..bc3a2d09 100644
--- a/alc/backends/jack.cpp
+++ b/alc/backends/jack.cpp
@@ -24,6 +24,7 @@
#include <cstdlib>
#include <cstdio>
+#include <cstring>
#include <memory.h>
#include <array>
@@ -152,6 +153,57 @@ bool jack_load()
}
+struct DeviceEntry {
+ std::string mName;
+ std::string mPattern;
+};
+
+al::vector<DeviceEntry> PlaybackList;
+
+
+void EnumerateDevices(al::vector<DeviceEntry> &list)
+{
+ al::vector<DeviceEntry>{}.swap(list);
+
+ list.emplace_back(DeviceEntry{jackDevice, ""});
+
+ std::string customList{ConfigValueStr(nullptr, "jack", "custom-devices").value_or("")};
+ size_t strpos{0};
+ while(strpos < customList.size())
+ {
+ size_t nextpos{customList.find(';', strpos)};
+ size_t seppos{customList.find('=', strpos)};
+ if(seppos >= nextpos || seppos == strpos)
+ {
+ const std::string entry{customList.substr(strpos, nextpos-strpos)};
+ ERR("Invalid device entry: \"%s\"\n", entry.c_str());
+ if(nextpos != std::string::npos) ++nextpos;
+ strpos = nextpos;
+ continue;
+ }
+
+ size_t count{1};
+ std::string name{customList.substr(strpos, seppos-strpos)};
+ auto check_name = [&name](const DeviceEntry &entry) -> bool
+ { return entry.mName == name; };
+ while(std::find_if(list.cbegin(), list.cend(), check_name) != list.cend())
+ {
+ name = customList.substr(strpos, seppos-strpos);
+ name += " #";
+ name += std::to_string(++count);
+ }
+
+ ++seppos;
+ list.emplace_back(DeviceEntry{std::move(name), customList.substr(seppos, nextpos-seppos)});
+ const auto &entry = list.back();
+ TRACE("Got custom device: %s = %s\n", entry.mName.c_str(), entry.mPattern.c_str());
+
+ if(nextpos != std::string::npos) ++nextpos;
+ strpos = nextpos;
+ }
+}
+
+
struct JackPlayback final : public BackendBase {
JackPlayback(ALCdevice *device) noexcept : BackendBase{device} { }
~JackPlayback() override;
@@ -168,6 +220,8 @@ struct JackPlayback final : public BackendBase {
void stop() override;
ClockLatency getClockLatency() override;
+ std::string mPortPattern;
+
jack_client_t *mClient{nullptr};
std::array<jack_port_t*,MAX_OUTPUT_CHANNELS> mPort{};
@@ -299,10 +353,22 @@ int JackPlayback::mixerProc()
void JackPlayback::open(const ALCchar *name)
{
+ mPortPattern.clear();
+
if(!name)
name = jackDevice;
else if(strcmp(name, jackDevice) != 0)
- throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name};
+ {
+ if(PlaybackList.empty())
+ EnumerateDevices(PlaybackList);
+
+ auto check_name = [name](const DeviceEntry &entry) -> bool
+ { return entry.mName == name; };
+ auto iter = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), check_name);
+ if(iter == PlaybackList.cend())
+ throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name};
+ mPortPattern = iter->mPattern;
+ }
const char *client_name{"alsoft"};
jack_status_t status;
@@ -387,7 +453,7 @@ void JackPlayback::start()
const char *devname{mDevice->DeviceName.c_str()};
if(ConfigValueBool(devname, "jack", "connect-ports").value_or(true))
{
- const char **ports{jack_get_ports(mClient, nullptr, nullptr,
+ const char **ports{jack_get_ports(mClient, mPortPattern.c_str(), nullptr,
JackPortIsPhysical|JackPortIsInput)};
if(ports == nullptr)
{
@@ -503,11 +569,16 @@ bool JackBackendFactory::querySupport(BackendType type)
std::string JackBackendFactory::probe(BackendType type)
{
std::string outnames;
+ auto append_name = [&outnames](const DeviceEntry &entry) -> void
+ {
+ /* Includes null char. */
+ outnames.append(entry.mName.c_str(), entry.mName.length()+1);
+ };
switch(type)
{
case BackendType::Playback:
- /* Includes null char. */
- outnames.append(jackDevice, sizeof(jackDevice));
+ EnumerateDevices(PlaybackList);
+ std::for_each(PlaybackList.cbegin(), PlaybackList.cend(), append_name);
break;
case BackendType::Capture:
break;