Hotspot: no scanning if not required.
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
#include "Finally.hpp"
|
#include "Finally.hpp"
|
||||||
#include "Lv2Log.hpp"
|
#include "Lv2Log.hpp"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
// enumerate alsa sequencer ports
|
// enumerate alsa sequencer ports
|
||||||
|
|
||||||
@@ -96,6 +97,26 @@ namespace pipedal
|
|||||||
int queueId = -1; // Queue for real-time timestamps
|
int queueId = -1; // Queue for real-time timestamps
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AlsaSequencerDeviceMonitorImpl : public AlsaSequencerDeviceMonitor
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~AlsaSequencerDeviceMonitorImpl() override;
|
||||||
|
|
||||||
|
virtual void StartMonitoring(
|
||||||
|
Callback &&onChangeCallback) override;
|
||||||
|
virtual void StopMonitoring() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int CreateInputQueue(snd_seq_t *seqHandle, int inPort);
|
||||||
|
|
||||||
|
bool started = false;
|
||||||
|
void ServiceProc();
|
||||||
|
std::unique_ptr<std::jthread> serviceThread;
|
||||||
|
std::atomic<bool> terminateThread{false};
|
||||||
|
Callback callback;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
using namespace impl;
|
using namespace impl;
|
||||||
|
|
||||||
@@ -247,9 +268,10 @@ namespace pipedal
|
|||||||
size_t inputBufferSize = snd_seq_get_input_buffer_size(seqHandle);
|
size_t inputBufferSize = snd_seq_get_input_buffer_size(seqHandle);
|
||||||
(void)inputBufferSize;
|
(void)inputBufferSize;
|
||||||
|
|
||||||
rc = snd_seq_set_input_buffer_size(seqHandle, 128*1024);
|
rc = snd_seq_set_input_buffer_size(seqHandle, 128 * 1024);
|
||||||
if (rc < 0) {
|
if (rc < 0)
|
||||||
Lv2Log::warning("Failed resize the ALSA sequencer input buffer: %s",snd_strerror(rc));
|
{
|
||||||
|
Lv2Log::warning("Failed resize the ALSA sequencer input buffer: %s", snd_strerror(rc));
|
||||||
}
|
}
|
||||||
snd_seq_set_client_name(seqHandle, "PiPedal");
|
snd_seq_set_client_name(seqHandle, "PiPedal");
|
||||||
|
|
||||||
@@ -584,10 +606,10 @@ namespace pipedal
|
|||||||
message.Set(0xF8); // MIDI Real Time Clock Tick
|
message.Set(0xF8); // MIDI Real Time Clock Tick
|
||||||
break;
|
break;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define MSG_DEBUG_LOG(x) \
|
#define MSG_DEBUG_LOG(x) \
|
||||||
case x:\
|
case x: \
|
||||||
Lv2Log::debug("ALSA Sequencer Message" #x);\
|
Lv2Log::debug("ALSA Sequencer Message" #x); \
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
#define MSG_DEBUG_LOG(x)
|
#define MSG_DEBUG_LOG(x)
|
||||||
#endif
|
#endif
|
||||||
@@ -733,6 +755,7 @@ namespace pipedal
|
|||||||
Finally seq_finally([seq]()
|
Finally seq_finally([seq]()
|
||||||
{ snd_seq_close(seq); });
|
{ snd_seq_close(seq); });
|
||||||
|
|
||||||
|
|
||||||
snd_seq_addr_t sender, dest;
|
snd_seq_addr_t sender, dest;
|
||||||
dest.client = myClientId;
|
dest.client = myClientId;
|
||||||
dest.port = 0;
|
dest.port = 0;
|
||||||
@@ -797,6 +820,208 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AlsaSequencerDeviceMonitor::ptr AlsaSequencerDeviceMonitor::Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<AlsaSequencerDeviceMonitorImpl>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlsaSequencerDeviceMonitorImpl::StartMonitoring(
|
||||||
|
Callback &&onChangeCallback)
|
||||||
|
{
|
||||||
|
started = true;
|
||||||
|
this->callback = std::move(onChangeCallback);
|
||||||
|
this->serviceThread = std::make_unique<std::jthread>(
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
ServiceProc();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
void AlsaSequencerDeviceMonitorImpl::ServiceProc()
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
snd_seq_t *seqHandle;
|
||||||
|
|
||||||
|
err = snd_seq_open(&seqHandle, "default", SND_SEQ_OPEN_DUPLEX, 0);
|
||||||
|
|
||||||
|
Finally seq_finally(
|
||||||
|
[seqHandle]()
|
||||||
|
{
|
||||||
|
snd_seq_close(seqHandle);
|
||||||
|
});
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
Lv2Log::error("Error opening ALSA Device Monitor sequencer: %s", snd_strerror(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
snd_seq_set_client_name(seqHandle, "Device Monitor");
|
||||||
|
|
||||||
|
int inPort = snd_seq_create_simple_port(
|
||||||
|
seqHandle, "PiPedal:portMonitor",
|
||||||
|
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
|
||||||
|
SND_SEQ_PORT_TYPE_APPLICATION);
|
||||||
|
if (inPort < 0)
|
||||||
|
{
|
||||||
|
Lv2Log::error("Error creating ALSA Device Monitor port: %s", snd_strerror(inPort));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Finally inPort_finaly {
|
||||||
|
[seqHandle, inPort]()
|
||||||
|
{
|
||||||
|
snd_seq_delete_port(seqHandle, inPort);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set client name
|
||||||
|
|
||||||
|
int queueId = CreateInputQueue(seqHandle,inPort);
|
||||||
|
if (queueId < 0)
|
||||||
|
{
|
||||||
|
Lv2Log::error("Error creating ALSA Device Monitor queue: %s", snd_strerror(queueId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Finally queue_finally(
|
||||||
|
[seqHandle, queueId]()
|
||||||
|
{
|
||||||
|
snd_seq_free_queue(seqHandle, queueId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Subscribe to system announcements
|
||||||
|
snd_seq_port_subscribe_t *subscription;
|
||||||
|
snd_seq_port_subscribe_alloca(&subscription);
|
||||||
|
snd_seq_addr_t sender, dest;
|
||||||
|
|
||||||
|
sender.client = SND_SEQ_CLIENT_SYSTEM;
|
||||||
|
sender.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE;
|
||||||
|
dest.client = snd_seq_client_id(seqHandle);
|
||||||
|
dest.port = inPort;
|
||||||
|
|
||||||
|
snd_seq_port_subscribe_set_sender(subscription, &sender);
|
||||||
|
snd_seq_port_subscribe_set_dest(subscription, &dest);
|
||||||
|
err = snd_seq_subscribe_port(seqHandle, subscription);
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
Lv2Log::error("Failed to subscribe to ALSA sequencer announcements: %s", snd_strerror(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create poll descriptors
|
||||||
|
std::vector<struct pollfd> pollFds;
|
||||||
|
|
||||||
|
snd_seq_nonblock(seqHandle, 1); // Set sequencer to non-blocking mode
|
||||||
|
while (!terminateThread)
|
||||||
|
{
|
||||||
|
int nPollFds = snd_seq_poll_descriptors_count(seqHandle, POLLIN);
|
||||||
|
pollFds.resize(nPollFds);
|
||||||
|
snd_seq_poll_descriptors(seqHandle, pollFds.data(), nPollFds, POLLIN);
|
||||||
|
|
||||||
|
// Poll for events
|
||||||
|
if (poll(pollFds.data(), nPollFds, 100) > 0)
|
||||||
|
{
|
||||||
|
snd_seq_event_t *event;
|
||||||
|
while (snd_seq_event_input(seqHandle, &event) > 0)
|
||||||
|
{
|
||||||
|
if (event->type == SND_SEQ_EVENT_CLIENT_START)
|
||||||
|
{
|
||||||
|
// Get the client name for logging/debugging
|
||||||
|
snd_seq_client_info_t *client_info;
|
||||||
|
snd_seq_client_info_alloca(&client_info);
|
||||||
|
if (snd_seq_get_any_client_info(seqHandle, event->data.addr.client, client_info) >= 0) {
|
||||||
|
std::string clientName = snd_seq_client_info_get_name(client_info);
|
||||||
|
callback(MonitorAction::DeviceAdded, event->data.addr.client, clientName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event->type == SND_SEQ_EVENT_CLIENT_EXIT)
|
||||||
|
{
|
||||||
|
callback(MonitorAction::DeviceRemoved, event->data.addr.client,"");
|
||||||
|
}
|
||||||
|
snd_seq_free_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlsaSequencerDeviceMonitorImpl::StopMonitoring()
|
||||||
|
{
|
||||||
|
if (started)
|
||||||
|
{
|
||||||
|
started = false;
|
||||||
|
terminateThread = true;
|
||||||
|
serviceThread = nullptr; // (joins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AlsaSequencerDeviceMonitorImpl::~AlsaSequencerDeviceMonitorImpl()
|
||||||
|
{
|
||||||
|
StopMonitoring();
|
||||||
|
}
|
||||||
|
|
||||||
|
int AlsaSequencerDeviceMonitorImpl::CreateInputQueue(snd_seq_t *seqHandle, int inPort)
|
||||||
|
{
|
||||||
|
if (!seqHandle)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("ALSA sequencer not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new queue if we don't have one yet
|
||||||
|
int queueId = -1;
|
||||||
|
{
|
||||||
|
queueId = snd_seq_alloc_named_queue(seqHandle, "PiPedal Device Monitor Queue");
|
||||||
|
if (queueId < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(SS("Failed to create ALSA queue: " << snd_strerror(queueId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set queue timing to real-time mode
|
||||||
|
snd_seq_queue_tempo_t *tempo;
|
||||||
|
snd_seq_queue_tempo_alloca(&tempo);
|
||||||
|
snd_seq_queue_tempo_set_tempo(tempo, 120); // 120 BPM default
|
||||||
|
snd_seq_queue_tempo_set_ppq(tempo, 96); // 96 ticks per quarter note
|
||||||
|
|
||||||
|
int rc = snd_seq_set_queue_tempo(seqHandle, queueId, tempo);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
snd_seq_free_queue(seqHandle, queueId);
|
||||||
|
throw std::runtime_error(SS("Failed to set queue tempo: " << snd_strerror(rc)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the queue
|
||||||
|
rc = snd_seq_start_queue(seqHandle, queueId, nullptr);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
snd_seq_free_queue(seqHandle, queueId);
|
||||||
|
throw std::runtime_error(SS("Failed to start queue: " << snd_strerror(rc)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the queue for input timestamping
|
||||||
|
snd_seq_port_info_t *port_info;
|
||||||
|
snd_seq_port_info_alloca(&port_info);
|
||||||
|
|
||||||
|
rc = snd_seq_get_port_info(seqHandle, inPort, port_info);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
snd_seq_free_queue(seqHandle, queueId);
|
||||||
|
throw std::runtime_error(SS("Failed to get port info: " << snd_strerror(rc)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable timestamping on the input port
|
||||||
|
snd_seq_port_info_set_timestamping(port_info, 1);
|
||||||
|
snd_seq_port_info_set_timestamp_real(port_info, 1);
|
||||||
|
snd_seq_port_info_set_timestamp_queue(port_info, queueId);
|
||||||
|
|
||||||
|
rc = snd_seq_set_port_info(seqHandle, inPort, port_info);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
snd_seq_free_queue(seqHandle, queueId);
|
||||||
|
throw std::runtime_error(SS("Failed to set port timestamping: " << snd_strerror(rc)));
|
||||||
|
}
|
||||||
|
return queueId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return queueId;
|
||||||
|
}
|
||||||
|
|
||||||
JSON_MAP_BEGIN(AlsaSequencerPortSelection)
|
JSON_MAP_BEGIN(AlsaSequencerPortSelection)
|
||||||
JSON_MAP_REFERENCE(AlsaSequencerPortSelection, id)
|
JSON_MAP_REFERENCE(AlsaSequencerPortSelection, id)
|
||||||
JSON_MAP_REFERENCE(AlsaSequencerPortSelection, name)
|
JSON_MAP_REFERENCE(AlsaSequencerPortSelection, name)
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ bool WifiConfigSettings::ValidateCountryCode(const std::string &text)
|
|||||||
return std::isalpha(text[0]) && std::isalpha(text[1]);
|
return std::isalpha(text[0]) && std::isalpha(text[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WifiConfigSettings::Load()
|
void WifiConfigSettings::Load()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -132,13 +131,16 @@ static void openWithPerms(
|
|||||||
f.open(path);
|
f.open(path);
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
// set the perms.
|
// set the perms.
|
||||||
std::filesystem::permissions(
|
std::filesystem::permissions(
|
||||||
path,
|
path,
|
||||||
perms,
|
perms,
|
||||||
std::filesystem::perm_options::replace);
|
std::filesystem::perm_options::replace);
|
||||||
} catch (const std::exception&) {
|
}
|
||||||
|
catch (const std::exception &)
|
||||||
|
{
|
||||||
Lv2Log::warning(SS("Failed to set permissions on" << path << "."));
|
Lv2Log::warning(SS("Failed to set permissions on" << path << "."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +151,7 @@ static void openWithPerms(
|
|||||||
|
|
||||||
void WifiConfigSettings::Save()
|
void WifiConfigSettings::Save()
|
||||||
{
|
{
|
||||||
WifiConfigSettings newSettings {*this};
|
WifiConfigSettings newSettings{*this};
|
||||||
|
|
||||||
// sync legacy settings, just in case i don't know what.
|
// sync legacy settings, just in case i don't know what.
|
||||||
newSettings.mdnsName_ = newSettings.hotspotName_;
|
newSettings.mdnsName_ = newSettings.hotspotName_;
|
||||||
@@ -167,8 +169,8 @@ void WifiConfigSettings::Save()
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ofstream_synced f;
|
ofstream_synced f;
|
||||||
openWithPerms(f,CONFIG_PATH);
|
openWithPerms(f, CONFIG_PATH);
|
||||||
json_writer writer(f,false);
|
json_writer writer(f, false);
|
||||||
writer.write(&newSettings);
|
writer.write(&newSettings);
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
@@ -300,17 +302,14 @@ namespace pipedal::priv
|
|||||||
connection["ipv4"]["method"] = sdbus::Variant(std::string("shared"));
|
connection["ipv4"]["method"] = sdbus::Variant(std::string("shared"));
|
||||||
connection["ipv6"]["method"] = sdbus::Variant(std::string("ignore"));
|
connection["ipv6"]["method"] = sdbus::Variant(std::string("ignore"));
|
||||||
|
|
||||||
|
connection["ipv4"]["address-data"] = sdbus::Variant(std::vector<std::map<std::string, sdbus::Variant>>{{{"address", sdbus::Variant("192.168.4.1")},
|
||||||
connection["ipv4"]["address-data"] = sdbus::Variant(std::vector<std::map<std::string, sdbus::Variant>>{{
|
{"prefix", sdbus::Variant(uint32_t(24))}}});
|
||||||
{"address", sdbus::Variant("192.168.4.1")},
|
|
||||||
{"prefix", sdbus::Variant(uint32_t(24))}
|
|
||||||
}});
|
|
||||||
connection["ipv4"]["dhcp-send-hostname"] = sdbus::Variant(true);
|
connection["ipv4"]["dhcp-send-hostname"] = sdbus::Variant(true);
|
||||||
connection["ipv4"]["dhcp-hostname"] = sdbus::Variant("raspberrypi");
|
connection["ipv4"]["dhcp-hostname"] = sdbus::Variant("raspberrypi");
|
||||||
connection["ipv4"]["dhcp-options"] = sdbus::Variant(std::vector<std::string>{
|
connection["ipv4"]["dhcp-options"] = sdbus::Variant(std::vector<std::string>{
|
||||||
"option:classless-static-route,192.168.4.0/24,0.0.0.0,0.0.0.0/0,192.168.4.1"
|
"option:classless-static-route,192.168.4.0/24,0.0.0.0,0.0.0.0/0,192.168.4.1"
|
||||||
//"option:classless-static-route,192.168.4.0/24,192.168.4.1"
|
//"option:classless-static-route,192.168.4.0/24,192.168.4.1"
|
||||||
});
|
});
|
||||||
|
|
||||||
auto connection_path = AddConnection(connection);
|
auto connection_path = AddConnection(connection);
|
||||||
return connection_path;
|
return connection_path;
|
||||||
@@ -326,7 +325,6 @@ namespace pipedal::priv
|
|||||||
return active_connection_path;
|
return active_connection_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RemoveConnection(const std::string &connection)
|
void RemoveConnection(const std::string &connection)
|
||||||
{
|
{
|
||||||
auto connection_proxy = sdbus::createProxy(
|
auto connection_proxy = sdbus::createProxy(
|
||||||
@@ -429,7 +427,6 @@ namespace pipedal::priv
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JSON_MAP_BEGIN(WifiConfigSettings)
|
JSON_MAP_BEGIN(WifiConfigSettings)
|
||||||
// v0
|
// v0
|
||||||
JSON_MAP_REFERENCE(WifiConfigSettings, valid)
|
JSON_MAP_REFERENCE(WifiConfigSettings, valid)
|
||||||
@@ -560,48 +557,47 @@ bool WifiConfigSettings::ValidateChannel(const std::string &countryCode, const s
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* trueValues[] {
|
static const char *trueValues[]{
|
||||||
"true",
|
"true",
|
||||||
"on",
|
"on",
|
||||||
"yes"
|
"yes"
|
||||||
"1",
|
"1",
|
||||||
nullptr
|
nullptr};
|
||||||
};
|
static const char *falseValues[]{
|
||||||
static const char* falseValues[] {
|
|
||||||
"false",
|
"false",
|
||||||
"off",
|
"off",
|
||||||
"no",
|
"no",
|
||||||
"0",
|
"0",
|
||||||
nullptr
|
nullptr};
|
||||||
};
|
|
||||||
|
|
||||||
static bool Matches(const std::string&value, const char**matches)
|
static bool Matches(const std::string &value, const char **matches)
|
||||||
{
|
{
|
||||||
while(*matches)
|
while (*matches)
|
||||||
{
|
{
|
||||||
if (value == *matches) return true;
|
if (value == *matches)
|
||||||
|
return true;
|
||||||
++matches;
|
++matches;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool TryStringToBool(const std::string &value, bool*outputValue)
|
static bool TryStringToBool(const std::string &value, bool *outputValue)
|
||||||
{
|
{
|
||||||
if (Matches(value,trueValues))
|
if (Matches(value, trueValues))
|
||||||
{
|
{
|
||||||
*outputValue = true;
|
*outputValue = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (Matches(value, falseValues)) {
|
if (Matches(value, falseValues))
|
||||||
|
{
|
||||||
*outputValue = false;
|
*outputValue = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*outputValue = false;
|
*outputValue = false;
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static WifiConfigSettings::ssid_t readSsid(std::istream&ss)
|
static WifiConfigSettings::ssid_t readSsid(std::istream &ss)
|
||||||
{
|
{
|
||||||
using ssid_t = WifiConfigSettings::ssid_t;
|
using ssid_t = WifiConfigSettings::ssid_t;
|
||||||
char c;
|
char c;
|
||||||
@@ -624,28 +620,33 @@ static WifiConfigSettings::ssid_t readSsid(std::istream&ss)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ss >> c;
|
ss >> c;
|
||||||
switch (c) {
|
switch (c)
|
||||||
case 'n':
|
{
|
||||||
result.push_back((uint8_t)'\n');
|
case 'n':
|
||||||
break;
|
result.push_back((uint8_t)'\n');
|
||||||
case 'r':
|
break;
|
||||||
result.push_back((uint8_t)'\r');
|
case 'r':
|
||||||
break;
|
result.push_back((uint8_t)'\r');
|
||||||
case 't':
|
break;
|
||||||
result.push_back((uint8_t)'\t');
|
case 't':
|
||||||
break;
|
result.push_back((uint8_t)'\t');
|
||||||
case 'b':
|
break;
|
||||||
result.push_back((uint8_t)'\b');
|
case 'b':
|
||||||
break;
|
result.push_back((uint8_t)'\b');
|
||||||
default:
|
break;
|
||||||
result.push_back((uint8_t)c);
|
default:
|
||||||
break;
|
result.push_back((uint8_t)c);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
result.push_back((uint8_t)c);
|
result.push_back((uint8_t)c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
while (!ss.eof())
|
while (!ss.eof())
|
||||||
{
|
{
|
||||||
if (c == ':')
|
if (c == ':')
|
||||||
@@ -662,7 +663,7 @@ static WifiConfigSettings::ssid_t readSsid(std::istream&ss)
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
static std::vector<WifiConfigSettings::ssid_t> stringToSsidArray(const std::string&value)
|
static std::vector<WifiConfigSettings::ssid_t> stringToSsidArray(const std::string &value)
|
||||||
{
|
{
|
||||||
using ssid_t = WifiConfigSettings::ssid_t;
|
using ssid_t = WifiConfigSettings::ssid_t;
|
||||||
std::istringstream ss(value);
|
std::istringstream ss(value);
|
||||||
@@ -683,16 +684,15 @@ static std::vector<WifiConfigSettings::ssid_t> stringToSsidArray(const std::stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
void WifiConfigSettings::ParseArguments(
|
void WifiConfigSettings::ParseArguments(
|
||||||
const std::vector<std::string> &argv,
|
const std::vector<std::string> &argv,
|
||||||
HotspotAutoStartMode startMode,
|
HotspotAutoStartMode startMode,
|
||||||
const std::string homeNetworkSsid
|
const std::string homeNetworkSsid
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this->valid_ = false ;
|
this->valid_ = false;
|
||||||
if (argv.size() != 4)
|
if (argv.size() != 4)
|
||||||
{
|
{
|
||||||
throw invalid_argument("Invalid number of arguments.");
|
throw invalid_argument("Invalid number of arguments.");
|
||||||
@@ -714,7 +714,6 @@ void WifiConfigSettings::ParseArguments(
|
|||||||
this->hasPassword_ = this->password_.length() != 0;
|
this->hasPassword_ = this->password_.length() != 0;
|
||||||
this->hasSavedPassword_ = oldSettings.hasSavedPassword_;
|
this->hasSavedPassword_ = oldSettings.hasSavedPassword_;
|
||||||
|
|
||||||
|
|
||||||
if (!ValidateCountryCode(this->countryCode_))
|
if (!ValidateCountryCode(this->countryCode_))
|
||||||
{
|
{
|
||||||
throw invalid_argument("Invalid country code.");
|
throw invalid_argument("Invalid country code.");
|
||||||
@@ -742,12 +741,12 @@ void WifiConfigSettings::ParseArguments(
|
|||||||
this->valid_ = true;
|
this->valid_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WifiConfigSettings::ConfigurationChanged(const WifiConfigSettings&other) const
|
bool WifiConfigSettings::ConfigurationChanged(const WifiConfigSettings &other) const
|
||||||
{
|
{
|
||||||
return !(
|
return !(
|
||||||
this->valid_ == other.valid_ &&
|
this->valid_ == other.valid_ &&
|
||||||
//this->rebootRequired_ == other.rebootRequired_ &&
|
// this->rebootRequired_ == other.rebootRequired_ &&
|
||||||
//this->enable_ == other.enable_ &&
|
// this->enable_ == other.enable_ &&
|
||||||
this->countryCode_ == other.countryCode_ &&
|
this->countryCode_ == other.countryCode_ &&
|
||||||
this->hotspotName_ == other.hotspotName_ &&
|
this->hotspotName_ == other.hotspotName_ &&
|
||||||
this->hasPassword_ == other.hasPassword_ &&
|
this->hasPassword_ == other.hasPassword_ &&
|
||||||
@@ -756,18 +755,16 @@ bool WifiConfigSettings::ConfigurationChanged(const WifiConfigSettings&other) co
|
|||||||
|
|
||||||
this->homeNetwork_ == other.homeNetwork_ &&
|
this->homeNetwork_ == other.homeNetwork_ &&
|
||||||
this->autoStartMode_ == other.autoStartMode_ &&
|
this->autoStartMode_ == other.autoStartMode_ &&
|
||||||
this->hasSavedPassword_ == other.hasSavedPassword_
|
this->hasSavedPassword_ == other.hasSavedPassword_);
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
bool WifiConfigSettings::operator==(const WifiConfigSettings&other) const
|
bool WifiConfigSettings::operator==(const WifiConfigSettings &other) const
|
||||||
{
|
{
|
||||||
return !ConfigurationChanged(other) && this->wifiWarningGiven_ == other.wifiWarningGiven_;
|
return !ConfigurationChanged(other) && this->wifiWarningGiven_ == other.wifiWarningGiven_;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CanSeeHomeNetwork(const std::string&home, const std::vector<std::string>&availableNetworks)
|
static bool CanSeeHomeNetwork(const std::string &home, const std::vector<std::string> &availableNetworks)
|
||||||
{
|
{
|
||||||
for (const auto &availableNetwork: availableNetworks)
|
for (const auto &availableNetwork : availableNetworks)
|
||||||
{
|
{
|
||||||
if (availableNetwork == home)
|
if (availableNetwork == home)
|
||||||
{
|
{
|
||||||
@@ -789,27 +786,28 @@ bool WifiConfigSettings::WantsHotspot(
|
|||||||
|
|
||||||
switch (autoStartMode)
|
switch (autoStartMode)
|
||||||
{
|
{
|
||||||
case HotspotAutoStartMode::Never:
|
case HotspotAutoStartMode::Never:
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case HotspotAutoStartMode::NoEthernetConnection:
|
case HotspotAutoStartMode::NoEthernetConnection:
|
||||||
return !ethernetConnected;
|
return !ethernetConnected;
|
||||||
case HotspotAutoStartMode::NotAtHome:
|
case HotspotAutoStartMode::NotAtHome:
|
||||||
return !CanSeeHomeNetwork(this->homeNetwork_, availableNetworks);
|
return !CanSeeHomeNetwork(this->homeNetwork_, availableNetworks);
|
||||||
case HotspotAutoStartMode::NoRememberedWifiConections:
|
case HotspotAutoStartMode::NoRememberedWifiConections:
|
||||||
return availableRememberedNetworks.size() == 0;
|
return availableRememberedNetworks.size() == 0;
|
||||||
case HotspotAutoStartMode::Always:
|
case HotspotAutoStartMode::Always:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pipedal::ssidToString(const std::vector<uint8_t> &ssid)
|
std::string pipedal::ssidToString(const std::vector<uint8_t> &ssid)
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
for (auto v: ssid)
|
for (auto v : ssid)
|
||||||
{
|
{
|
||||||
if (v == 0) break; // breaks for some arguably legal ssids, but I can live with that.
|
if (v == 0)
|
||||||
|
break; // breaks for some arguably legal ssids, but I can live with that.
|
||||||
s << (char)v;
|
s << (char)v;
|
||||||
}
|
}
|
||||||
return s.str();
|
return s.str();
|
||||||
@@ -819,7 +817,7 @@ std::vector<std::string> pipedal::ssidToStringVector(const std::vector<std::vect
|
|||||||
{
|
{
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
result.reserve(ssids.size());
|
result.reserve(ssids.size());
|
||||||
for (const std::vector<uint8_t> &ssid: ssids)
|
for (const std::vector<uint8_t> &ssid : ssids)
|
||||||
{
|
{
|
||||||
result.push_back(ssidToString(ssid));
|
result.push_back(ssidToString(ssid));
|
||||||
}
|
}
|
||||||
@@ -828,12 +826,34 @@ std::vector<std::string> pipedal::ssidToStringVector(const std::vector<std::vect
|
|||||||
bool WifiConfigSettings::WantsHotspot(
|
bool WifiConfigSettings::WantsHotspot(
|
||||||
bool ethernetConnected,
|
bool ethernetConnected,
|
||||||
const std::vector<std::vector<uint8_t>> &availableRememberedNetworks, // remembered networks that are currently visible
|
const std::vector<std::vector<uint8_t>> &availableRememberedNetworks, // remembered networks that are currently visible
|
||||||
const std::vector<std::vector<uint8_t>> &availableNetworks // all visible networks.
|
const std::vector<std::vector<uint8_t>> &availableNetworks // all visible networks.
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::vector<std::string> sAvailableRememberedNetworks = ssidToStringVector(availableRememberedNetworks);
|
std::vector<std::string> sAvailableRememberedNetworks = ssidToStringVector(availableRememberedNetworks);
|
||||||
std::vector<std::string> sAvailableNetworks = ssidToStringVector(availableNetworks);
|
std::vector<std::string> sAvailableNetworks = ssidToStringVector(availableNetworks);
|
||||||
return WantsHotspot(ethernetConnected,sAvailableRememberedNetworks,sAvailableNetworks);
|
return WantsHotspot(ethernetConnected, sAvailableRememberedNetworks, sAvailableNetworks);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WifiConfigSettings::NeedsWifi() const
|
||||||
|
{
|
||||||
|
HotspotAutoStartMode autoStartMode = (HotspotAutoStartMode)this->autoStartMode_;
|
||||||
|
return autoStartMode != HotspotAutoStartMode::Never;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WifiConfigSettings::NeedsScan() const
|
||||||
|
{
|
||||||
|
HotspotAutoStartMode autoStartMode = (HotspotAutoStartMode)this->autoStartMode_;
|
||||||
|
switch (autoStartMode)
|
||||||
|
{
|
||||||
|
case HotspotAutoStartMode::Never:
|
||||||
|
case HotspotAutoStartMode::NoEthernetConnection:
|
||||||
|
case HotspotAutoStartMode::Always:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case HotspotAutoStartMode::NotAtHome:
|
||||||
|
case HotspotAutoStartMode::NoRememberedWifiConections:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
|
||||||
namespace pipedal
|
namespace pipedal
|
||||||
@@ -331,6 +332,26 @@ namespace pipedal
|
|||||||
virtual void RemoveAllConnections() = 0;
|
virtual void RemoveAllConnections() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AlsaSequencerDeviceMonitor {
|
||||||
|
protected:
|
||||||
|
AlsaSequencerDeviceMonitor() {}
|
||||||
|
public:
|
||||||
|
virtual ~AlsaSequencerDeviceMonitor() {}
|
||||||
|
|
||||||
|
using self = AlsaSequencerDeviceMonitor;
|
||||||
|
using ptr = std::shared_ptr<self>;
|
||||||
|
static ptr Create();
|
||||||
|
enum class MonitorAction {
|
||||||
|
DeviceAdded,
|
||||||
|
DeviceRemoved
|
||||||
|
};
|
||||||
|
using Callback = std::function<void(MonitorAction action, int client, const std::string& clientName)>;
|
||||||
|
virtual void StartMonitoring(Callback &&onChangeCallback) = 0;
|
||||||
|
virtual void StopMonitoring() = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
std::string RawMidiIdToSequencerId(const std::vector<AlsaSequencerPort> &seqDevices, const std::string &rawMidiId);
|
std::string RawMidiIdToSequencerId(const std::vector<AlsaSequencerPort> &seqDevices, const std::string &rawMidiId);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -95,6 +95,10 @@ namespace pipedal {
|
|||||||
|
|
||||||
bool operator==(const WifiConfigSettings&other) const;
|
bool operator==(const WifiConfigSettings&other) const;
|
||||||
bool ConfigurationChanged(const WifiConfigSettings&other) const;
|
bool ConfigurationChanged(const WifiConfigSettings&other) const;
|
||||||
|
bool WantsHotspot(bool ethernetConnected)
|
||||||
|
{
|
||||||
|
return WantsHotspot(ethernetConnected, std::vector<std::string>{}, std::vector<std::string>{});
|
||||||
|
}
|
||||||
bool WantsHotspot(
|
bool WantsHotspot(
|
||||||
bool ethernetConnected,
|
bool ethernetConnected,
|
||||||
const std::vector<std::string> &availableRememberedNetworks, // remembered networks that are currently visible
|
const std::vector<std::string> &availableRememberedNetworks, // remembered networks that are currently visible
|
||||||
@@ -105,7 +109,8 @@ namespace pipedal {
|
|||||||
const std::vector<std::vector<uint8_t>> &availableRememberedNetworks, // remembered networks that are currently visible
|
const std::vector<std::vector<uint8_t>> &availableRememberedNetworks, // remembered networks that are currently visible
|
||||||
const std::vector<std::vector<uint8_t>> &availableNetworks // all visible networks.
|
const std::vector<std::vector<uint8_t>> &availableNetworks // all visible networks.
|
||||||
);
|
);
|
||||||
|
bool NeedsScan() const;
|
||||||
|
bool NeedsWifi() const;
|
||||||
public:
|
public:
|
||||||
DECLARE_JSON_MAP(WifiConfigSettings);
|
DECLARE_JSON_MAP(WifiConfigSettings);
|
||||||
};
|
};
|
||||||
|
|||||||
+28
-1
@@ -390,6 +390,7 @@ class AudioHostImpl : public AudioHost, private AudioDriverHost, private IPatchW
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
AlsaSequencer::ptr alsaSequencer;
|
AlsaSequencer::ptr alsaSequencer;
|
||||||
|
AlsaSequencerDeviceMonitor::ptr alsaDeviceMonitor;
|
||||||
|
|
||||||
void OnWritePatchPropertyBuffer(
|
void OnWritePatchPropertyBuffer(
|
||||||
PatchPropertyWriter::Buffer *);
|
PatchPropertyWriter::Buffer *);
|
||||||
@@ -1252,9 +1253,21 @@ public:
|
|||||||
|
|
||||||
cpuTemperatureMonitor = CpuTemperatureMonitor::Get();
|
cpuTemperatureMonitor = CpuTemperatureMonitor::Get();
|
||||||
this->alsaSequencer = AlsaSequencer::Create();
|
this->alsaSequencer = AlsaSequencer::Create();
|
||||||
|
this->alsaDeviceMonitor = AlsaSequencerDeviceMonitor::Create();
|
||||||
|
|
||||||
|
this->alsaDeviceMonitor->StartMonitoring(
|
||||||
|
[this](
|
||||||
|
AlsaSequencerDeviceMonitor::MonitorAction action,
|
||||||
|
int client,
|
||||||
|
const std::string &clientName)
|
||||||
|
{
|
||||||
|
HandleAlsaSequencerDevicesChanged(action, client, clientName);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
virtual ~AudioHostImpl()
|
virtual ~AudioHostImpl()
|
||||||
{
|
{
|
||||||
|
alsaDeviceMonitor->StopMonitoring();
|
||||||
Close();
|
Close();
|
||||||
CleanRestartThreads(true);
|
CleanRestartThreads(true);
|
||||||
audioDriver = nullptr;
|
audioDriver = nullptr;
|
||||||
@@ -1273,7 +1286,21 @@ public:
|
|||||||
{
|
{
|
||||||
return this->sampleRate;
|
return this->sampleRate;
|
||||||
}
|
}
|
||||||
|
void HandleAlsaSequencerDevicesChanged(
|
||||||
|
AlsaSequencerDeviceMonitor::MonitorAction action, int client, const std::string &clientName)
|
||||||
|
{
|
||||||
|
if (pNotifyCallbacks)
|
||||||
|
{
|
||||||
|
if (action == AlsaSequencerDeviceMonitor::MonitorAction::DeviceRemoved)
|
||||||
|
{
|
||||||
|
pNotifyCallbacks->OnAlsaSequencerDeviceRemoved(client);
|
||||||
|
}
|
||||||
|
else if (action == AlsaSequencerDeviceMonitor::MonitorAction::DeviceAdded)
|
||||||
|
{
|
||||||
|
pNotifyCallbacks->OnAlsaSequencerDeviceAdded(client,clientName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
void HandleAudioTerminatedAbnormally()
|
void HandleAudioTerminatedAbnormally()
|
||||||
{
|
{
|
||||||
Lv2Log::error("Audio processing terminated unexpectedly.");
|
Lv2Log::error("Audio processing terminated unexpectedly.");
|
||||||
|
|||||||
@@ -179,6 +179,8 @@ namespace pipedal
|
|||||||
virtual void OnNotifyMidiRealtimeSnapshotRequest(int32_t snapshotIndex,int64_t snapshotRequestId) = 0;
|
virtual void OnNotifyMidiRealtimeSnapshotRequest(int32_t snapshotIndex,int64_t snapshotRequestId) = 0;
|
||||||
|
|
||||||
virtual void OnAlsaDriverTerminatedAbnormally() = 0;
|
virtual void OnAlsaDriverTerminatedAbnormally() = 0;
|
||||||
|
virtual void OnAlsaSequencerDeviceAdded(int client, const std::string &clientName) = 0;
|
||||||
|
virtual void OnAlsaSequencerDeviceRemoved(int client) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JackHostStatus
|
class JackHostStatus
|
||||||
|
|||||||
+37
-18
@@ -80,7 +80,7 @@ namespace pipedal::impl
|
|||||||
bool hasWifi = false;
|
bool hasWifi = false;
|
||||||
HasWifiListener hasWifiListener;
|
HasWifiListener hasWifiListener;
|
||||||
void SetHasWifi(bool hasWifi);
|
void SetHasWifi(bool hasWifi);
|
||||||
virtual bool GetHasWifi() override ;
|
virtual bool GetHasWifi() override;
|
||||||
|
|
||||||
void onClose();
|
void onClose();
|
||||||
void onError(const std::string &message);
|
void onError(const std::string &message);
|
||||||
@@ -347,7 +347,7 @@ void HotspotManagerImpl::onStartMonitoring()
|
|||||||
|
|
||||||
this->networkManager = NetworkManager::Create(dbusDispatcher);
|
this->networkManager = NetworkManager::Create(dbusDispatcher);
|
||||||
|
|
||||||
if (!networkManager->WirelessEnabled())
|
if (!networkManager->WirelessEnabled() && wifiConfigSettings.NeedsWifi())
|
||||||
{
|
{
|
||||||
networkManager->WirelessEnabled(true);
|
networkManager->WirelessEnabled(true);
|
||||||
}
|
}
|
||||||
@@ -483,6 +483,7 @@ void HotspotManagerImpl::onReload()
|
|||||||
// force a reload.
|
// force a reload.
|
||||||
StopHotspot();
|
StopHotspot();
|
||||||
SetState(State::Monitoring);
|
SetState(State::Monitoring);
|
||||||
|
StartScanTimer(); // or stop it as the case may be.
|
||||||
MaybeStartHotspot();
|
MaybeStartHotspot();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -758,15 +759,25 @@ void HotspotManagerImpl::MaybeStartHotspot()
|
|||||||
// devices are transitioning. Do nothing.
|
// devices are transitioning. Do nothing.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::vector<AccessPoint::ptr> allAccessPoints = GetAllAccessPoints();
|
|
||||||
std::vector<std::vector<uint8_t>> allAccessPointSsids = GetAccessPointSsids(allAccessPoints);
|
|
||||||
std::vector<std::vector<uint8_t>> connectableSsids = GetKnownVisibleAccessPoints(allAccessPointSsids); // all the ssids currently visible for which we have credentials.
|
|
||||||
|
|
||||||
this->UpdateKnownNetworks(connectableSsids, allAccessPoints);
|
bool wantsHotspot;
|
||||||
|
|
||||||
bool wantsHotspot = this->wifiConfigSettings.WantsHotspot(
|
if (wifiConfigSettings.NeedsScan()) {
|
||||||
|
|
||||||
this->ethernetConnected, connectableSsids, allAccessPointSsids);
|
std::vector<AccessPoint::ptr> allAccessPoints = GetAllAccessPoints();
|
||||||
|
std::vector<std::vector<uint8_t>> allAccessPointSsids = GetAccessPointSsids(allAccessPoints);
|
||||||
|
std::vector<std::vector<uint8_t>> connectableSsids = GetKnownVisibleAccessPoints(allAccessPointSsids); // all the ssids currently visible for which we have credentials.
|
||||||
|
|
||||||
|
this->UpdateKnownNetworks(connectableSsids, allAccessPoints);
|
||||||
|
|
||||||
|
wantsHotspot = this->wifiConfigSettings.WantsHotspot(
|
||||||
|
this->ethernetConnected, connectableSsids, allAccessPointSsids);
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
wantsHotspot = this->wifiConfigSettings.WantsHotspot(
|
||||||
|
this->ethernetConnected);
|
||||||
|
}
|
||||||
|
|
||||||
if (this->state == State::Monitoring && wantsHotspot)
|
if (this->state == State::Monitoring && wantsHotspot)
|
||||||
{
|
{
|
||||||
@@ -996,8 +1007,14 @@ void HotspotManagerImpl::ScanNow()
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Lv2Log::debug("Scanning");
|
if (this->wifiConfigSettings.NeedsScan())
|
||||||
wlanWirelessDevice->RequestScan(options);
|
{
|
||||||
|
|
||||||
|
Lv2Log::debug("Scanning");
|
||||||
|
wlanWirelessDevice->RequestScan(options);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@@ -1036,7 +1053,8 @@ void HotspotManagerImpl::SetHasWifiListener(HasWifiListener &&listener)
|
|||||||
this->hasWifiListener(this->hasWifi);
|
this->hasWifiListener(this->hasWifi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool HotspotManagerImpl::GetHasWifi() {
|
bool HotspotManagerImpl::GetHasWifi()
|
||||||
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock{this->networkChangingListenerMutex};
|
std::lock_guard<std::recursive_mutex> lock{this->networkChangingListenerMutex};
|
||||||
return hasWifi;
|
return hasWifi;
|
||||||
}
|
}
|
||||||
@@ -1112,17 +1130,20 @@ static bool IsNetworkManagerRunning()
|
|||||||
return gUsingNetworkManager;
|
return gUsingNetworkManager;
|
||||||
}
|
}
|
||||||
bool bResult = false;
|
bool bResult = false;
|
||||||
auto result = sysExecForOutput("systemctl","is-active NetworkManager");
|
auto result = sysExecForOutput("systemctl", "is-active NetworkManager");
|
||||||
if (result.exitCode == EXIT_SUCCESS)
|
if (result.exitCode == EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
std::string text = result.output.erase(result.output.find_last_not_of(" \n\r\t")+1);
|
std::string text = result.output.erase(result.output.find_last_not_of(" \n\r\t") + 1);
|
||||||
if (text == "active")
|
if (text == "active")
|
||||||
{
|
{
|
||||||
bResult = true;
|
bResult = true;
|
||||||
} else if (text == "inactive")
|
}
|
||||||
|
else if (text == "inactive")
|
||||||
{
|
{
|
||||||
bResult = false;
|
bResult = false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
throw std::runtime_error(SS("UsingNetworkManager: unexpected result (" << text << ")"));
|
throw std::runtime_error(SS("UsingNetworkManager: unexpected result (" << text << ")"));
|
||||||
}
|
}
|
||||||
gNetworkManagerTestExecuted = true;
|
gNetworkManagerTestExecuted = true;
|
||||||
@@ -1134,11 +1155,10 @@ static bool IsNetworkManagerRunning()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HotspotManager::HasWifiDevice()
|
bool HotspotManager::HasWifiDevice()
|
||||||
{
|
{
|
||||||
// use procfs to decide this, as NetworkManager may not be available yet.
|
// use procfs to decide this, as NetworkManager may not be available yet.
|
||||||
if ( !(get_wireless_interfaces_sysfs().empty()) )
|
if (!(get_wireless_interfaces_sysfs().empty()))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1148,5 +1168,4 @@ bool HotspotManager::HasWifiDevice()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+91
-68
@@ -292,16 +292,12 @@ void PiPedalModel::Load()
|
|||||||
|
|
||||||
this->audioHost->SetNotificationCallbacks(this);
|
this->audioHost->SetNotificationCallbacks(this);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this->systemMidiBindings = storage.GetSystemMidiBindings();
|
this->systemMidiBindings = storage.GetSystemMidiBindings();
|
||||||
|
|
||||||
this->audioHost->SetSystemMidiBindings(this->systemMidiBindings);
|
this->audioHost->SetSystemMidiBindings(this->systemMidiBindings);
|
||||||
|
|
||||||
audioHost->SetAlsaSequencerConfiguration(storage.GetAlsaSequencerConfiguration());
|
audioHost->SetAlsaSequencerConfiguration(storage.GetAlsaSequencerConfiguration());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (configuration.GetMLock())
|
if (configuration.GetMLock())
|
||||||
{
|
{
|
||||||
#ifndef NO_MLOCK
|
#ifndef NO_MLOCK
|
||||||
@@ -515,7 +511,6 @@ void PiPedalModel::FireBanksChanged(int64_t clientId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::FirePedalboardChanged(int64_t clientId, bool loadAudioThread)
|
void PiPedalModel::FirePedalboardChanged(int64_t clientId, bool loadAudioThread)
|
||||||
{
|
{
|
||||||
if (loadAudioThread)
|
if (loadAudioThread)
|
||||||
@@ -601,12 +596,9 @@ void PiPedalModel::UpdateCurrentPedalboard(int64_t clientId, Pedalboard &pedalbo
|
|||||||
|
|
||||||
UpdateVst3Settings(pedalboard);
|
UpdateVst3Settings(pedalboard);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lv2PedalboardErrorList errorMessages;
|
Lv2PedalboardErrorList errorMessages;
|
||||||
std::shared_ptr<Lv2Pedalboard> lv2Pedalboard{
|
std::shared_ptr<Lv2Pedalboard> lv2Pedalboard{
|
||||||
this->pluginHost.UpdateLv2PedalboardStructure(pedalboard, this->lv2Pedalboard.get(), errorMessages)
|
this->pluginHost.UpdateLv2PedalboardStructure(pedalboard, this->lv2Pedalboard.get(), errorMessages)};
|
||||||
};
|
|
||||||
this->lv2Pedalboard = lv2Pedalboard;
|
this->lv2Pedalboard = lv2Pedalboard;
|
||||||
|
|
||||||
// apply the error messages to the lv2Pedalboard.
|
// apply the error messages to the lv2Pedalboard.
|
||||||
@@ -620,9 +612,7 @@ void PiPedalModel::UpdateCurrentPedalboard(int64_t clientId, Pedalboard &pedalbo
|
|||||||
UpdateRealtimeVuSubscriptions();
|
UpdateRealtimeVuSubscriptions();
|
||||||
UpdateRealtimeMonitorPortSubscriptions();
|
UpdateRealtimeMonitorPortSubscriptions();
|
||||||
|
|
||||||
|
this->FirePedalboardChanged(clientId, false);
|
||||||
|
|
||||||
this->FirePedalboardChanged(clientId,false);
|
|
||||||
this->SetPresetChanged(clientId, true);
|
this->SetPresetChanged(clientId, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1406,6 +1396,38 @@ void PiPedalModel::RestartAudio(bool useDummyAudioDriver)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PiPedalModel::OnAlsaSequencerDeviceAdded(int client, const std::string &clientName)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
|
auto alsaSequencerConfiguration = this->storage.GetAlsaSequencerConfiguration();
|
||||||
|
std::string key = "seq:" + clientName;
|
||||||
|
bool interested = false;
|
||||||
|
for (const auto &port : alsaSequencerConfiguration.connections())
|
||||||
|
{
|
||||||
|
if (port.id().starts_with(key))
|
||||||
|
{
|
||||||
|
interested = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (interested)
|
||||||
|
{
|
||||||
|
Post(
|
||||||
|
[this]
|
||||||
|
{
|
||||||
|
// reconfigure connections.
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(this->mutex);
|
||||||
|
if (this->audioHost) {
|
||||||
|
this->audioHost->SetAlsaSequencerConfiguration(this->storage.GetAlsaSequencerConfiguration());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void PiPedalModel::OnAlsaSequencerDeviceRemoved(int client)
|
||||||
|
{
|
||||||
|
// no action required.
|
||||||
|
}
|
||||||
|
|
||||||
void PiPedalModel::SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration)
|
void PiPedalModel::SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
@@ -1424,7 +1446,6 @@ void PiPedalModel::SetAlsaSequencerConfiguration(const AlsaSequencerConfiguratio
|
|||||||
subscriber->OnAlsaSequencerConfigurationChanged(alsaSequencerConfiguration);
|
subscriber->OnAlsaSequencerConfigurationChanged(alsaSequencerConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
AlsaSequencerConfiguration PiPedalModel::GetAlsaSequencerConfiguration()
|
AlsaSequencerConfiguration PiPedalModel::GetAlsaSequencerConfiguration()
|
||||||
{
|
{
|
||||||
@@ -1441,14 +1462,11 @@ std::vector<AlsaSequencerPortSelection> PiPedalModel::GetAlsaSequencerPorts()
|
|||||||
result.push_back(AlsaSequencerPortSelection{
|
result.push_back(AlsaSequencerPortSelection{
|
||||||
port.id,
|
port.id,
|
||||||
port.name,
|
port.name,
|
||||||
port.displaySortOrder
|
port.displaySortOrder});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::SetJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection)
|
void PiPedalModel::SetJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -1678,7 +1696,8 @@ void PiPedalModel::SendSetPatchProperty(
|
|||||||
std::shared_ptr<Lv2PluginInfo> pluginInfo = GetPluginInfo(pedalboardItem->uri_);
|
std::shared_ptr<Lv2PluginInfo> pluginInfo = GetPluginInfo(pedalboardItem->uri_);
|
||||||
auto pipedalUi = pluginInfo->piPedalUI();
|
auto pipedalUi = pluginInfo->piPedalUI();
|
||||||
auto fileProperty = pipedalUi->GetFileProperty(propertyUri);
|
auto fileProperty = pipedalUi->GetFileProperty(propertyUri);
|
||||||
if (fileProperty && value.is_string()) {
|
if (fileProperty && value.is_string())
|
||||||
|
{
|
||||||
|
|
||||||
json_variant abstractPath = pluginHost.AbstractPath(value);
|
json_variant abstractPath = pluginHost.AbstractPath(value);
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
@@ -1729,12 +1748,11 @@ void PiPedalModel::SendSetPatchProperty(
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
LV2_URID urid = this->pluginHost.GetLv2Urid(propertyUri.c_str());
|
LV2_URID urid = this->pluginHost.GetLv2Urid(propertyUri.c_str());
|
||||||
size_t sampleTimeout = 0.5*audioHost->GetSampleRate();
|
size_t sampleTimeout = 0.5 * audioHost->GetSampleRate();
|
||||||
RealtimePatchPropertyRequest *request = new RealtimePatchPropertyRequest(
|
RealtimePatchPropertyRequest *request = new RealtimePatchPropertyRequest(
|
||||||
onRequestComplete,
|
onRequestComplete,
|
||||||
clientId, instanceId, urid, atomValue, nullptr, onError,
|
clientId, instanceId, urid, atomValue, nullptr, onError,
|
||||||
sampleTimeout
|
sampleTimeout);
|
||||||
);
|
|
||||||
|
|
||||||
outstandingParameterRequests.push_back(request);
|
outstandingParameterRequests.push_back(request);
|
||||||
if (this->audioHost)
|
if (this->audioHost)
|
||||||
@@ -1802,10 +1820,10 @@ void PiPedalModel::SendGetPatchProperty(
|
|||||||
{
|
{
|
||||||
onError("Audio stopped.");
|
onError("Audio stopped.");
|
||||||
}
|
}
|
||||||
size_t sampleTimeout = 0.3*audioHost->GetSampleRate();
|
size_t sampleTimeout = 0.3 * audioHost->GetSampleRate();
|
||||||
RealtimePatchPropertyRequest *request = new RealtimePatchPropertyRequest(
|
RealtimePatchPropertyRequest *request = new RealtimePatchPropertyRequest(
|
||||||
onRequestComplete,
|
onRequestComplete,
|
||||||
clientId, instanceId, urid, onSuccess, onError,sampleTimeout);
|
clientId, instanceId, urid, onSuccess, onError, sampleTimeout);
|
||||||
|
|
||||||
outstandingParameterRequests.push_back(request);
|
outstandingParameterRequests.push_back(request);
|
||||||
this->audioHost->sendRealtimeParameterRequest(request);
|
this->audioHost->sendRealtimeParameterRequest(request);
|
||||||
@@ -1969,7 +1987,9 @@ void PiPedalModel::UpdateDefaults(PedalboardItem *pedalboardItem, std::unordered
|
|||||||
{
|
{
|
||||||
pedalboardItem->midiChannelBinding(MidiChannelBinding::DefaultForMissingValue());
|
pedalboardItem->midiChannelBinding(MidiChannelBinding::DefaultForMissingValue());
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (pedalboardItem->midiChannelBinding())
|
if (pedalboardItem->midiChannelBinding())
|
||||||
{
|
{
|
||||||
pedalboardItem->midiChannelBinding(std::optional<MidiChannelBinding>()); // clear it.
|
pedalboardItem->midiChannelBinding(std::optional<MidiChannelBinding>()); // clear it.
|
||||||
@@ -2245,22 +2265,23 @@ void PiPedalModel::OnNotifyMidiListen(uint8_t cc0, uint8_t cc1, uint8_t cc2)
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
bool isNote = (cc0 & 0xF0) == 0x90; // Note On
|
bool isNote = (cc0 & 0xF0) == 0x90; // Note On
|
||||||
if (isNote && cc2 == 0) {
|
if (isNote && cc2 == 0)
|
||||||
|
{
|
||||||
return; // Note off. Oopsie.
|
return; // Note off. Oopsie.
|
||||||
}
|
}
|
||||||
bool isControl = (cc0 & 0xF0) == 0xB0; // Control Change
|
bool isControl = (cc0 & 0xF0) == 0xB0; // Control Change
|
||||||
if (!isNote && !isControl) {
|
if (!isNote && !isControl)
|
||||||
|
{
|
||||||
return; // Not a note on or control change.
|
return; // Not a note on or control change.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < midiEventListeners.size(); ++i)
|
for (int i = 0; i < midiEventListeners.size(); ++i)
|
||||||
{
|
{
|
||||||
auto &listener = midiEventListeners[i];
|
auto &listener = midiEventListeners[i];
|
||||||
auto subscriber = this->GetNotificationSubscriber(listener.clientId);
|
auto subscriber = this->GetNotificationSubscriber(listener.clientId);
|
||||||
if (subscriber)
|
if (subscriber)
|
||||||
{
|
{
|
||||||
subscriber->OnNotifyMidiListener(listener.clientHandle, cc0,cc1,cc2);
|
subscriber->OnNotifyMidiListener(listener.clientHandle, cc0, cc1, cc2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2345,6 +2366,7 @@ void PiPedalModel::CancelMonitorPatchProperty(int64_t clientId, int64_t clientHa
|
|||||||
audioHost->SetListenForMidiEvent(false);
|
audioHost->SetListenForMidiEvent(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AlsaDeviceInfo> PiPedalModel::GetAlsaDevices()
|
std::vector<AlsaDeviceInfo> PiPedalModel::GetAlsaDevices()
|
||||||
{
|
{
|
||||||
std::vector<AlsaDeviceInfo> result = this->alsaDevices.GetAlsaDevices();
|
std::vector<AlsaDeviceInfo> result = this->alsaDevices.GetAlsaDevices();
|
||||||
@@ -2402,9 +2424,9 @@ void PiPedalModel::SetSystemMidiBindings(std::vector<MidiBinding> &bindings)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PedalboardItem*PiPedalModel::GetPedalboardItemForFileProperty(const UiFileProperty& fileProperty)
|
PedalboardItem *PiPedalModel::GetPedalboardItemForFileProperty(const UiFileProperty &fileProperty)
|
||||||
{
|
{
|
||||||
for (PedalboardItem*pedalboardItem: this->pedalboard.GetAllPlugins())
|
for (PedalboardItem *pedalboardItem : this->pedalboard.GetAllPlugins())
|
||||||
{
|
{
|
||||||
if (pedalboardItem->pathProperties_.contains(fileProperty.patchProperty()))
|
if (pedalboardItem->pathProperties_.contains(fileProperty.patchProperty()))
|
||||||
{
|
{
|
||||||
@@ -2421,7 +2443,6 @@ FileRequestResult PiPedalModel::GetFileList2(const std::string &relativePath_, c
|
|||||||
if (!storage.IsInUploadsDirectory(relativePath))
|
if (!storage.IsInUploadsDirectory(relativePath))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// if relativePath is in a resource directory of the plugin, then we have loaded a factory preset or are using a default property.
|
// if relativePath is in a resource directory of the plugin, then we have loaded a factory preset or are using a default property.
|
||||||
// map the resource path to the corresponding file in the uploads directory.
|
// map the resource path to the corresponding file in the uploads directory.
|
||||||
// :-(
|
// :-(
|
||||||
@@ -2429,13 +2450,13 @@ FileRequestResult PiPedalModel::GetFileList2(const std::string &relativePath_, c
|
|||||||
if (pedalboardItem)
|
if (pedalboardItem)
|
||||||
{
|
{
|
||||||
auto pluginInfo = GetPluginInfo(pedalboardItem->uri());
|
auto pluginInfo = GetPluginInfo(pedalboardItem->uri());
|
||||||
if (pluginInfo) {
|
if (pluginInfo)
|
||||||
std::filesystem::path resourcePath = fs::path(pluginInfo->bundle_path())
|
{
|
||||||
/ fileProperty.resourceDirectory();
|
std::filesystem::path resourcePath = fs::path(pluginInfo->bundle_path()) / fileProperty.resourceDirectory();
|
||||||
if (IsSubdirectory(relativePath,resourcePath))
|
if (IsSubdirectory(relativePath, resourcePath))
|
||||||
{
|
{
|
||||||
fs::path t = MakeRelativePath(relativePath,resourcePath);
|
fs::path t = MakeRelativePath(relativePath, resourcePath);
|
||||||
t = fileProperty.directory() / t;
|
t = fileProperty.directory() / t;
|
||||||
if (fs::exists(t))
|
if (fs::exists(t))
|
||||||
{
|
{
|
||||||
relativePath = t;
|
relativePath = t;
|
||||||
@@ -2469,10 +2490,9 @@ std::string PiPedalModel::CopyFilePropertyFile(
|
|||||||
bool overwrite)
|
bool overwrite)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
return storage.CopyFilePropertyFile(oldRelativePath, newRelativePath, uiFileProperty,overwrite);
|
return storage.CopyFilePropertyFile(oldRelativePath, newRelativePath, uiFileProperty, overwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::DeleteSampleFile(const std::filesystem::path &fileName)
|
void PiPedalModel::DeleteSampleFile(const std::filesystem::path &fileName)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
@@ -2484,28 +2504,29 @@ std::string PiPedalModel::CreateNewSampleDirectory(const std::string &relativePa
|
|||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
return storage.CreateNewSampleDirectory(relativePath, uiFileProperty);
|
return storage.CreateNewSampleDirectory(relativePath, uiFileProperty);
|
||||||
}
|
}
|
||||||
FilePropertyDirectoryTree::ptr PiPedalModel::GetFilePropertydirectoryTree(const UiFileProperty &uiFileProperty,const std::string&selectedPath)
|
FilePropertyDirectoryTree::ptr PiPedalModel::GetFilePropertydirectoryTree(const UiFileProperty &uiFileProperty, const std::string &selectedPath)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
return storage.GetFilePropertydirectoryTree(uiFileProperty,selectedPath);
|
return storage.GetFilePropertydirectoryTree(uiFileProperty, selectedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
UiFileProperty::ptr PiPedalModel::FindLoadedPatchProperty(int64_t instanceId,const std::string&patchPropertyUri)
|
UiFileProperty::ptr PiPedalModel::FindLoadedPatchProperty(int64_t instanceId, const std::string &patchPropertyUri)
|
||||||
{
|
{
|
||||||
|
|
||||||
auto pedalboardItems = pedalboard.GetAllPlugins();
|
auto pedalboardItems = pedalboard.GetAllPlugins();
|
||||||
|
|
||||||
for (const auto&pedalboardItem: pedalboardItems) {
|
for (const auto &pedalboardItem : pedalboardItems)
|
||||||
|
{
|
||||||
if (pedalboardItem->instanceId() == instanceId)
|
if (pedalboardItem->instanceId() == instanceId)
|
||||||
{
|
{
|
||||||
Lv2PluginInfo::ptr pluginInfo = GetPluginInfo(pedalboardItem->uri());
|
Lv2PluginInfo::ptr pluginInfo = GetPluginInfo(pedalboardItem->uri());
|
||||||
if (pluginInfo && pluginInfo->piPedalUI())
|
if (pluginInfo && pluginInfo->piPedalUI())
|
||||||
{
|
{
|
||||||
for (const auto&fileProperty: pluginInfo->piPedalUI()->fileProperties())
|
for (const auto &fileProperty : pluginInfo->piPedalUI()->fileProperties())
|
||||||
if (fileProperty->patchProperty() == patchPropertyUri)
|
if (fileProperty->patchProperty() == patchPropertyUri)
|
||||||
{
|
{
|
||||||
return fileProperty;
|
return fileProperty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2513,9 +2534,9 @@ UiFileProperty::ptr PiPedalModel::FindLoadedPatchProperty(int64_t instanceId,con
|
|||||||
throw std::runtime_error("Permission denied. Plugin not currently loaded.");
|
throw std::runtime_error("Permission denied. Plugin not currently loaded.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PiPedalModel::UploadUserFile(const std::string &directory, int64_t instanceId,const std::string &patchProperty, const std::string &filename, std::istream &stream, size_t contentLength)
|
std::string PiPedalModel::UploadUserFile(const std::string &directory, int64_t instanceId, const std::string &patchProperty, const std::string &filename, std::istream &stream, size_t contentLength)
|
||||||
{
|
{
|
||||||
UiFileProperty::ptr fileProperty = FindLoadedPatchProperty(instanceId,patchProperty);
|
UiFileProperty::ptr fileProperty = FindLoadedPatchProperty(instanceId, patchProperty);
|
||||||
if (!fileProperty)
|
if (!fileProperty)
|
||||||
{
|
{
|
||||||
Lv2Log::error(SS("Upload fle: Permission denied. No currently-loaded plugin provides that patch property: " << patchProperty));
|
Lv2Log::error(SS("Upload fle: Permission denied. No currently-loaded plugin provides that patch property: " << patchProperty));
|
||||||
@@ -2905,20 +2926,23 @@ bool PiPedalModel::GetHasWifi()
|
|||||||
return hasWifi;
|
return hasWifi;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string,std::string> PiPedalModel::GetWifiRegulatoryDomains()
|
std::map<std::string, std::string> PiPedalModel::GetWifiRegulatoryDomains()
|
||||||
{
|
{
|
||||||
std::map<std::string,std::string> result;
|
std::map<std::string, std::string> result;
|
||||||
try {
|
try
|
||||||
auto& regDb = RegDb::GetInstance();
|
{
|
||||||
|
auto ®Db = RegDb::GetInstance();
|
||||||
result = regDb.getRegulatoryDomains(storage.GetConfigRoot() / "iso_codes.json");
|
result = regDb.getRegulatoryDomains(storage.GetConfigRoot() / "iso_codes.json");
|
||||||
} catch (const std::exception&e)
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
Lv2Log::warning(SS("Unable to query Wifi Regulatory domains. " << e.what()));
|
Lv2Log::warning(SS("Unable to query Wifi Regulatory domains. " << e.what()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::CancelAudioRetry() {
|
void PiPedalModel::CancelAudioRetry()
|
||||||
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
if (audioRetryPostHandle)
|
if (audioRetryPostHandle)
|
||||||
{
|
{
|
||||||
@@ -2926,14 +2950,16 @@ void PiPedalModel::CancelAudioRetry() {
|
|||||||
this->CancelPost(audioRetryPostHandle);
|
this->CancelPost(audioRetryPostHandle);
|
||||||
audioRetryPostHandle = 0;
|
audioRetryPostHandle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
void PiPedalModel::OnAlsaDriverTerminatedAbnormally() {
|
|
||||||
|
void PiPedalModel::OnAlsaDriverTerminatedAbnormally()
|
||||||
|
{
|
||||||
// notification from the realtime thread, via the audiohost that the
|
// notification from the realtime thread, via the audiohost that the
|
||||||
// ALSA stream has broken. We want to restart.
|
// ALSA stream has broken. We want to restart.
|
||||||
|
|
||||||
// get off the service thread as promptly as possible
|
// get off the service thread as promptly as possible
|
||||||
this->Post([&]() {
|
this->Post([&]()
|
||||||
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
if (closed) return;
|
if (closed) return;
|
||||||
|
|
||||||
@@ -2981,8 +3007,7 @@ void PiPedalModel::OnAlsaDriverTerminatedAbnormally() {
|
|||||||
} else {
|
} else {
|
||||||
Lv2Log::error(SS("Unable to reastart audio."));
|
Lv2Log::error(SS("Unable to reastart audio."));
|
||||||
|
|
||||||
}
|
} });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PiPedalModel::IsInUploadsDirectory(const std::string &path)
|
bool PiPedalModel::IsInUploadsDirectory(const std::string &path)
|
||||||
@@ -2993,8 +3018,8 @@ bool PiPedalModel::IsInUploadsDirectory(const std::string &path)
|
|||||||
void PiPedalModel::MoveAudioFile(
|
void PiPedalModel::MoveAudioFile(
|
||||||
const std::string &directory,
|
const std::string &directory,
|
||||||
int32_t fromPosition,
|
int32_t fromPosition,
|
||||||
int32_t toPosition
|
int32_t toPosition)
|
||||||
) {
|
{
|
||||||
if (directory.empty())
|
if (directory.empty())
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Directory is empty.");
|
throw std::runtime_error("Directory is empty.");
|
||||||
@@ -3005,13 +3030,11 @@ void PiPedalModel::MoveAudioFile(
|
|||||||
void PiPedalModel::SetPedalboardItemTitle(int64_t instanceId, const std::string &title)
|
void PiPedalModel::SetPedalboardItemTitle(int64_t instanceId, const std::string &title)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
if (!this->pedalboard.SetItemTitle(instanceId,title))
|
if (!this->pedalboard.SetItemTitle(instanceId, title))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// no need to reload the pedalboard, but we do need to notify subscribers.
|
// no need to reload the pedalboard, but we do need to notify subscribers.
|
||||||
this->SetPresetChanged(-1, true);
|
this->SetPresetChanged(-1, true);
|
||||||
this->FirePedalboardChanged(-1,false);
|
this->FirePedalboardChanged(-1, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -240,6 +240,8 @@ namespace pipedal
|
|||||||
virtual void OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType) override;
|
virtual void OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType) override;
|
||||||
virtual void OnNotifyMidiRealtimeSnapshotRequest(int32_t snapshotIndex,int64_t snapshotRequestId) override;
|
virtual void OnNotifyMidiRealtimeSnapshotRequest(int32_t snapshotIndex,int64_t snapshotRequestId) override;
|
||||||
virtual void OnAlsaDriverTerminatedAbnormally() override;
|
virtual void OnAlsaDriverTerminatedAbnormally() override;
|
||||||
|
virtual void OnAlsaSequencerDeviceAdded(int client, const std::string &clientName) override;
|
||||||
|
virtual void OnAlsaSequencerDeviceRemoved(int client) override;
|
||||||
|
|
||||||
void OnNotifyPathPatchPropertyReceived(
|
void OnNotifyPathPatchPropertyReceived(
|
||||||
int64_t instanceId,
|
int64_t instanceId,
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
VU decay on a timer.
|
Test autohotspot detection.
|
||||||
|
|
||||||
Midi handling in the dummy audio connector.
|
|
||||||
|
|
||||||
PiPedal sequencer not visible. Is it missing duplex somewhere?
|
|
||||||
|
|
||||||
check filetime conversion in gcc 12.2! (missing c++ 20 time conversion functions)
|
check filetime conversion in gcc 12.2! (missing c++ 20 time conversion functions)
|
||||||
AudioFiles.cpp fileTimeToInt64
|
AudioFiles.cpp fileTimeToInt64
|
||||||
|
|||||||
@@ -54,19 +54,23 @@ function SelectMidiChannelsDialog(props: SelectMidiChannelsDialogProps) {
|
|||||||
const [allPorts, setAllPorts] = useState<DialogItem[] | null>(null);
|
const [allPorts, setAllPorts] = useState<DialogItem[] | null>(null);
|
||||||
const [model] = useState<PiPedalModel>(PiPedalModelFactory.getInstance());
|
const [model] = useState<PiPedalModel>(PiPedalModelFactory.getInstance());
|
||||||
const [changed, setChanged] = useState<boolean>(false);
|
const [changed, setChanged] = useState<boolean>(false);
|
||||||
|
const [ readyToDisplay, setReadyToDisplay ] = useState<boolean>(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
|
setReadyToDisplay(false);
|
||||||
model.getAlsaSequencerPorts().then((ports) => {
|
model.getAlsaSequencerPorts().then((ports) => {
|
||||||
setAvailablePorts(ports);
|
setAvailablePorts(ports);
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
model.showAlert(error);
|
model.showAlert(error);
|
||||||
|
setReadyToDisplay(true);
|
||||||
setAvailablePorts(null);
|
setAvailablePorts(null);
|
||||||
});
|
});
|
||||||
model.getAlsaSequencerConfiguration().then((config) => {
|
model.getAlsaSequencerConfiguration().then((config) => {
|
||||||
setConfiguration(config);
|
setConfiguration(config);
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
model.showAlert(error);
|
model.showAlert(error);
|
||||||
|
setReadyToDisplay(true);
|
||||||
setConfiguration(null);
|
setConfiguration(null);
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
@@ -78,7 +82,7 @@ function SelectMidiChannelsDialog(props: SelectMidiChannelsDialogProps) {
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (availablePorts !== null && configuration !== null) {
|
if (availablePorts !== null && configuration !== null) {
|
||||||
let result: DialogItem[] = [];
|
let result: DialogItem[] = [];
|
||||||
|
setReadyToDisplay(true);
|
||||||
for (let port of availablePorts) {
|
for (let port of availablePorts) {
|
||||||
result.push({
|
result.push({
|
||||||
id: port.id,
|
id: port.id,
|
||||||
@@ -159,7 +163,8 @@ function SelectMidiChannelsDialog(props: SelectMidiChannelsDialogProps) {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogEx tag="midiChannels" onClose={handleClose} aria-labelledby="select-midi-inputs" open={open}
|
<DialogEx tag="midiChannels" onClose={handleClose} aria-labelledby="select-midi-inputs"
|
||||||
|
open={open && readyToDisplay}
|
||||||
fullWidth maxWidth="xs"
|
fullWidth maxWidth="xs"
|
||||||
onEnterKey={handleClose}
|
onEnterKey={handleClose}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user