Jack Server Settings; text selection in dialogs.

This commit is contained in:
Robin Davies
2021-08-31 02:40:17 -04:00
parent 6cb1300cc9
commit 2303a05cfc
17 changed files with 120 additions and 41 deletions
+4 -2
View File
@@ -188,7 +188,9 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
return ( return (
<DialogEx tag="AboutDlg" fullScreen open={this.props.open} <DialogEx tag="AboutDlg" fullScreen open={this.props.open}
onClose={() => { this.props.onClose() }} TransitionComponent={Transition}> onClose={() => { this.props.onClose() }} TransitionComponent={Transition}
style={{userSelect: "none"}}
>
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}> <div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
@@ -206,7 +208,7 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
</div> </div>
<div style={{ <div style={{
flex: "1 1 auto", position: "relative", overflow: "hidden", flex: "1 1 auto", position: "relative", overflow: "hidden",
overflowX: "hidden", overflowY: "auto" overflowX: "hidden", overflowY: "auto" , userSelect: "text"
}} }}
> >
<div style={{margin: 24}}> <div style={{margin: 24}}>
+5 -2
View File
@@ -407,7 +407,9 @@ const BankDialog = withStyles(styles, { withTheme: true })(
return ( return (
<DialogEx tag="BankDialog" fullScreen open={this.props.show} <DialogEx tag="BankDialog" fullScreen open={this.props.show}
onClose={() => { this.handleDialogClose() }} TransitionComponent={Transition}> onClose={() => { this.handleDialogClose() }} TransitionComponent={Transition}
style={{userSelect: "none"}}
>
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}> <div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
<AppBar className={classes.dialogAppBar} style={{ display: this.isEditMode() ? "none" : "block" }} > <AppBar className={classes.dialogAppBar} style={{ display: this.isEditMode() ? "none" : "block" }} >
@@ -539,7 +541,8 @@ const BankDialog = withStyles(styles, { withTheme: true })(
style={{ display: "none" }} style={{ display: "none" }}
/> />
<DialogEx tag="deletePrompt" open={this.state.showDeletePrompt} onClose={() => this.handleDeletePromptClose()}> <DialogEx tag="deletePrompt" open={this.state.showDeletePrompt} onClose={() => this.handleDeletePromptClose()}
style={{userSelect: "none"}}>
<DialogContent> <DialogContent>
<Typography>Are you sure you want to delete bank '{this.getSelectedBankName()}'?</Typography> <Typography>Are you sure you want to delete bank '{this.getSelectedBankName()}'?</Typography>
</DialogContent> </DialogContent>
+3 -1
View File
@@ -51,7 +51,9 @@ export default class JackServerSettings {
getSummaryText() { getSummaryText() {
if (this.valid) { if (this.valid) {
return this.alsaDevice + " Sample Rate: " + this.sampleRate + " BufferSize: " + this.bufferSize + " Number of Buffers: " + this.numberOfBuffers; let device = this.alsaDevice;
if (device.startsWith("hw:")) device = device.substr(3);
return device + " - Rate: " + this.sampleRate + " BufferSize: " + this.bufferSize + " Buffers: " + this.numberOfBuffers;
} else { } else {
return "Not configured"; return "Not configured";
} }
+2 -8
View File
@@ -408,9 +408,9 @@ class PiPedalModelImpl implements PiPedalModel {
this.onSocketReconnected = this.onSocketReconnected.bind(this); this.onSocketReconnected = this.onSocketReconnected.bind(this);
} }
onSocketReconnecting(retry: number, maxRetries: number): void { onSocketReconnecting(retry: number, maxRetries: number): void {
if (retry !== 0) { //if (retry !== 0) {
this.setState(State.Reconnecting); this.setState(State.Reconnecting);
} //}
} }
@@ -455,14 +455,10 @@ class PiPedalModelImpl implements PiPedalModel {
); );
} else if (message === "onPedalBoardChanged") { } else if (message === "onPedalBoardChanged") {
let pedalChangedBody = body as PedalBoardChangedBody; let pedalChangedBody = body as PedalBoardChangedBody;
// xxx: do we want to optimize for messages we went ourselves??
// we could actually protect against preview collisions in the model.
this.pedalBoard.set(new PedalBoard().deserialize(pedalChangedBody.pedalBoard)); this.pedalBoard.set(new PedalBoard().deserialize(pedalChangedBody.pedalBoard));
} else if (message === "onMidiValueChanged") { } else if (message === "onMidiValueChanged") {
let controlChangedBody = body as ControlChangedBody; let controlChangedBody = body as ControlChangedBody;
// xxx: do we want to optimize for messages we went ourselves??
// we could actually protect against preview collisions in the model.
this._setPedalBoardControlValue( this._setPedalBoardControlValue(
controlChangedBody.instanceId, controlChangedBody.instanceId,
controlChangedBody.symbol, controlChangedBody.symbol,
@@ -480,8 +476,6 @@ class PiPedalModelImpl implements PiPedalModel {
this.handleNotifyMidiListener(clientHandle, isNote, noteOrControl); this.handleNotifyMidiListener(clientHandle, isNote, noteOrControl);
} else if (message === "onControlChanged") { } else if (message === "onControlChanged") {
let controlChangedBody = body as ControlChangedBody; let controlChangedBody = body as ControlChangedBody;
// xxx: do we want to optimize for messages we went ourselves??
// we could actually protect against preview collisions in the model.
this._setPedalBoardControlValue( this._setPedalBoardControlValue(
controlChangedBody.instanceId, controlChangedBody.instanceId,
controlChangedBody.symbol, controlChangedBody.symbol,
+2 -1
View File
@@ -335,7 +335,8 @@ const PresetDialog = withStyles(styles, { withTheme: true })(
return ( return (
<DialogEx tag="PresetDialog" fullScreen open={this.props.show} <DialogEx tag="PresetDialog" fullScreen open={this.props.show}
onClose={() => { this.handleDialogClose() }} TransitionComponent={Transition}> onClose={() => { this.handleDialogClose() }} TransitionComponent={Transition}
style={{userSelect: "none"}}>
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}> <div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
<AppBar className={classes.dialogAppBar} style={{ display: this.isEditMode() ? "none" : "block" }} > <AppBar className={classes.dialogAppBar} style={{ display: this.isEditMode() ? "none" : "block" }} >
+2 -1
View File
@@ -96,8 +96,9 @@ export default class RenameDialog extends ResizeResponsiveComponent<RenameDialog
} }
}; };
return ( return (
<DialogEx tag="RenameDialog" open={open} fullWidth onClose={handleClose} aria-labelledby="Rename-dialog-title" style={{}} <DialogEx tag="RenameDialog" open={open} fullWidth onClose={handleClose} aria-labelledby="Rename-dialog-title"
fullScreen={this.state.fullScreen} fullScreen={this.state.fullScreen}
style={{userSelect: "none"}}
> >
<DialogContent> <DialogContent>
<TextField <TextField
+15 -5
View File
@@ -393,7 +393,9 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
return ( return (
<DialogEx tag="SettingsDialog" fullScreen open={this.props.open} <DialogEx tag="SettingsDialog" fullScreen open={this.props.open}
onClose={() => { this.props.onClose() }} TransitionComponent={Transition}> onClose={() => { this.props.onClose() }} TransitionComponent={Transition}
style={{userSelect: "none"}}
>
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}> <div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
@@ -426,11 +428,19 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
JackHostStatus.getDisplayView("Status:\u00A0", this.state.jackStatus) JackHostStatus.getDisplayView("Status:\u00A0", this.state.jackStatus)
} }
</div> </div>
{ this.state.jackConfiguration.errorState !== "" &&
(
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
<Typography variant="caption" color="textSecondary"><span style={{color: "#F00"}}>{this.state.jackConfiguration.errorState }</span></Typography>
</div>
)
}
<ButtonBase className={classes.setting} onClick={() => this.handleJackServerSettings()} <ButtonBase className={classes.setting} onClick={() => this.handleJackServerSettings()}
> >
<SelectHoverBackground selected={false} showHover={true} /> <SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<Typography display="block" variant="body2" noWrap>Jack Server Settings</Typography> <Typography display="block" variant="body2" noWrap>Audio device</Typography>
<Typography display="block" variant="caption" noWrap color="textSecondary">{this.state.jackServerSettings.getSummaryText()}</Typography> <Typography display="block" variant="caption" noWrap color="textSecondary">{this.state.jackServerSettings.getSummaryText()}</Typography>
</div> </div>
</ButtonBase> </ButtonBase>
@@ -454,7 +464,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
> >
<SelectHoverBackground selected={false} showHover={true} /> <SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<Typography display="block" variant="body2" noWrap>Input Channels</Typography> <Typography display="block" variant="body2" noWrap>Input channels</Typography>
<Typography display="block" variant="caption" color="textSecondary" noWrap>{this.state.jackSettings.getAudioInputDisplayValue(this.state.jackConfiguration)}</Typography> <Typography display="block" variant="caption" color="textSecondary" noWrap>{this.state.jackSettings.getAudioInputDisplayValue(this.state.jackConfiguration)}</Typography>
</div> </div>
</ButtonBase> </ButtonBase>
@@ -473,7 +483,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<ButtonBase className={classes.setting} disabled={!isConfigValid} onClick={() => this.handleMidiSelection()} > <ButtonBase className={classes.setting} disabled={!isConfigValid} onClick={() => this.handleMidiSelection()} >
<SelectHoverBackground selected={false} showHover={true} /> <SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>Select MIDI Input Channels</Typography> <Typography className={classes.primaryItem} display="block" variant="body2" noWrap>Select MIDI input channels</Typography>
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>{this.midiSummary()}</Typography> <Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>{this.midiSummary()}</Typography>
</div> </div>
@@ -488,7 +498,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<SelectHoverBackground selected={false} showHover={true} /> <SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap> <Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
Configure Wi-fi Hotspot</Typography> Configure Wi-Fi hotspot</Typography>
<Typography display="block" variant="caption" noWrap color="textSecondary"> <Typography display="block" variant="caption" noWrap color="textSecondary">
{this.state.wifiConfigSettings.getSummaryText()} {this.state.wifiConfigSettings.getSummaryText()}
</Typography> </Typography>
+2 -1
View File
@@ -153,8 +153,9 @@ export default class UploadDialog extends ResizeResponsiveComponent<UploadDialog
return ( return (
<DialogEx tag="UploadDialog" open={this.props.open} fullWidth onClose={() => this.handleClose()} style={{}} <DialogEx tag="UploadDialog" open={this.props.open} fullWidth onClose={() => this.handleClose()}
fullScreen={this.state.fullScreen} fullScreen={this.state.fullScreen}
style={{userSelect: "none"}}
> >
<DialogTitle>Upload preset</DialogTitle> <DialogTitle>Upload preset</DialogTitle>
<DialogContent> <DialogContent>
+3 -2
View File
@@ -250,7 +250,7 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
}; };
return ( return (
<DialogEx tag="WifiConfigDialog" open={open} fullWidth onClose={handleClose} style={{}} <DialogEx tag="WifiConfigDialog" open={open} fullWidth onClose={handleClose} style={{userSelect: "none"}}
fullScreen={this.state.fullScreen} fullScreen={this.state.fullScreen}
> >
{ this.state.fullScreen && ( { this.state.fullScreen && (
@@ -335,7 +335,8 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
OK OK
</Button> </Button>
</DialogActions> </DialogActions>
<DialogEx open={this.state.showWifiWarningDialog} tag="wifiConfirm" > <DialogEx open={this.state.showWifiWarningDialog} tag="wifiConfirm"
style={{userSelect: "none"}}>
<DialogContent> <DialogContent>
<Typography className={classes.pgraph} variant="body2" color="textPrimary"> <Typography className={classes.pgraph} variant="body2" color="textPrimary">
Enabling the Wi-Fi hotspot will disable regular Wi-Fi network access on the PiPedal device. Once Enabling the Wi-Fi hotspot will disable regular Wi-Fi network access on the PiPedal device. Once
+5 -1
View File
@@ -813,7 +813,11 @@ public:
void void
do_read() do_read()
{ {
// Set the timer // make the request empty before reading
// otherwise the operation behavour is undefined.
req_ = {};
// Set the time
timer_.expires_after(std::chrono::seconds(15)); timer_.expires_after(std::chrono::seconds(15));
// Read a request // Read a request
+55 -1
View File
@@ -193,6 +193,59 @@ static bool userExists(const char *userName)
return true; return true;
} }
void InstallPamEnv()
{
std::string newLine = "JACK_PROMISCOUS_SERVER DEFAULT=jack";
std::vector<std::string> lines;
std::filesystem::path path = "/etc/security/pam_env.conf";
try
{
if (std::filesystem::exists(path))
{
{
ifstream f(path);
if (!f.is_open())
{
throw PiPedalException("Can't open pam_env.conf");
}
while (true)
{
std::string line;
if (f.eof())
break;
std::getline(f, line);
lines.push_back(line);
}
}
for (auto &line : lines)
{
if (line == newLine)
{
return;
}
}
lines.push_back(newLine);
{
std::ofstream f(path);
if (!f.is_open())
{
throw PiPedalException("Can't write to file.");
}
for (auto&line: lines)
{
f << line << endl;
}
}
}
}
catch (const std::exception &e)
{
cout << "Failed to update " << path << ". " << e.what();
}
}
void InstallLimits() void InstallLimits()
{ {
if (SysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS) if (SysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
@@ -227,6 +280,7 @@ void MaybeStartJackService()
void InstallJackService() void InstallJackService()
{ {
InstallLimits(); InstallLimits();
InstallPamEnv();
if (SysExec(GROUPADD_BIN " -f " JACK_SERVICE_GROUP_NAME) != EXIT_SUCCESS) if (SysExec(GROUPADD_BIN " -f " JACK_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{ {
throw PiPedalException("Failed to create jack service group."); throw PiPedalException("Failed to create jack service group.");
@@ -554,7 +608,7 @@ int main(int argc, char **argv)
args.push_back((char *)(pkexec.c_str())); args.push_back((char *)(pkexec.c_str()));
std::string sPath = GetSelfExePath(); std::string sPath = GetSelfExePath();
args.push_back(const_cast<char*>(sPath.c_str())); args.push_back(const_cast<char *>(sPath.c_str()));
for (int arg = 1; arg < argc; ++arg) for (int arg = 1; arg < argc; ++arg)
{ {
args.push_back(const_cast<char *>(argv[arg])); args.push_back(const_cast<char *>(argv[arg]));
+2 -2
View File
@@ -1275,10 +1275,10 @@ private:
void ThreadProc() void ThreadProc()
{ {
this_->restarting = true; this_->restarting = true;
this_->Close(); // this_->Close(); (JackServerConfiguration now does a service restart.)
try { try {
ShutdownClient::SetJackServerConfiguration(jackServerSettings); ShutdownClient::SetJackServerConfiguration(jackServerSettings);
this_->Open(this_->channelSelection); //this_->Open(this_->channelSelection);
this_->restarting = false; this_->restarting = false;
onComplete(true, ""); onComplete(true, "");
isComplete = true; isComplete = true;
+3 -6
View File
@@ -214,20 +214,17 @@ void JackServerSettings::Write()
output << line << endl; output << line << endl;
} }
// the style used by qjackctl. :-/ // the style used by qjackctl. :-/
// Lower to -P70 in order to allow the USB soft-irq to run at higher priority than JACK (it runs at 80).
output << "/usr/bin/jackd " output << "/usr/bin/jackd "
<< "-R -P90" << "-R -P70 --silent"
<< " -dalsa -d" << this->alsaDevice_ << " -dalsa -d" << this->alsaDevice_
<< " -r" << this->sampleRate_ << " -r" << this->sampleRate_
<< " -p" << this->bufferSize_ << " -p" << this->bufferSize_
<< " -n" << this->numberOfBuffers_ << " -Xseq" << " -n" << this->numberOfBuffers_ << " -Xseq"
<< endl; << endl;
system("/usr/bin/chmod 755 " DRC_FILENAME); system("/usr/bin/chmod 755 " DRC_FILENAME);
system("pulseaudio --kill"); system("/usr/bin/systemctl unmask jack");
system("/usr/bin/systemctl enable jack"); system("/usr/bin/systemctl enable jack");
if (system("/usr/bin/systemctl restart jack") != 0)
{
throw PiPedalException("Failed to start jack audio service.");
}
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
+6 -1
View File
@@ -910,13 +910,17 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
Lv2Log::error(s.str().c_str()); Lv2Log::error(s.str().c_str());
} }
// Update jack server status. // Update jack server status.
this->jackConfiguration.SetIsRestarting(false);
if (!success) if (!success)
{ {
this->jackConfiguration.SetIsRestarting(false);
this->jackConfiguration.SetErrorStatus(errorMessage); this->jackConfiguration.SetErrorStatus(errorMessage);
fireJackConfigurationChanged(this->jackConfiguration);
} }
else else
{ {
// we now do a complete restart of the services,
// so just sit tight and wait for the restart.
#ifdef JUNK
this->jackConfiguration.SetErrorStatus(""); this->jackConfiguration.SetErrorStatus("");
fireJackConfigurationChanged(this->jackConfiguration); fireJackConfigurationChanged(this->jackConfiguration);
@@ -927,6 +931,7 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
jackHost->SetPedalBoard(lv2PedalBoard); jackHost->SetPedalBoard(lv2PedalBoard);
updateRealtimeVuSubscriptions(); updateRealtimeVuSubscriptions();
updateRealtimeMonitorPortSubscriptions(); updateRealtimeMonitorPortSubscriptions();
#endif
} }
}); });
} }
+7 -4
View File
@@ -86,11 +86,16 @@ static void ReleaseAccessPoint(const std::string gatewayAddress)
void delayedRestartProc() void delayedRestartProc()
{ {
sleep(1); // give a chance for websocket messages to propagate. sleep(1); // give a chance for websocket messages to propagate.
std::string pipedalConfigPath = std::filesystem::path(GetSelfExePath()).parent_path() / "pipedalConfig"; Lv2Log::error("Delayed Restart");
std::string pipedalConfigPath = std::filesystem::path(GetSelfExePath()).parent_path() / "pipedalconfig";
std::stringstream s; std::stringstream s;
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService"; s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
::system(s.str().c_str()); if (::system(s.str().c_str())!= EXIT_SUCCESS)
{
Lv2Log::error("Delayed Restart failed.");
}
} }
bool setJackConfiguration(JackServerSettings serverSettings) bool setJackConfiguration(JackServerSettings serverSettings)
@@ -247,8 +252,6 @@ private:
{ {
auto remainder = s.substr(strlen("setJackConfiguration ")); auto remainder = s.substr(strlen("setJackConfiguration "));
// xxx delete me
Lv2Log::error("setJackConfiguration: " + remainder);
std::stringstream input(remainder); std::stringstream input(remainder);
JackServerSettings serverSettings; JackServerSettings serverSettings;
+1 -1
View File
@@ -60,7 +60,7 @@ void json_writer::write(string_view v,bool enforceValidUtf8Encoding)
{ {
// convert to utf-32. // convert to utf-32.
// convert utf-32 to normalized utf-16. // convert utf-32 to normalized utf-16.
// write non-7-bit and unsafe characters as \uxxxx. // write non-7-bit and unsafe characters as \uHHHH.
auto p = v.begin(); auto p = v.begin();
os << '"'; os << '"';
+3 -2
View File
@@ -579,9 +579,10 @@ int main(int argc, char *argv[])
PiPedalModel model; PiPedalModel model;
// Pre-populate ALSA device info,wait for jackd service (daemon only) // Pre-populate ALSA device info,wait for jackd service (daemon only)
model.GetAlsaDevices(); // pre-cache ALSA devices.
if (systemd) if (systemd)
{ {
auto devices = model.GetAlsaDevices(); auto devices = model.GetAlsaDevices(); // pre-cache ALSA devices (most especially, the one which Jack will open, that we can no longer read)
auto serverSettings = model.GetJackServerSettings(); auto serverSettings = model.GetJackServerSettings();
if (serverSettings.IsValid()) if (serverSettings.IsValid())
@@ -590,7 +591,7 @@ int main(int argc, char *argv[])
if (!HasAlsaDevice(devices, serverSettings.GetAlsaDevice())) if (!HasAlsaDevice(devices, serverSettings.GetAlsaDevice()))
{ {
Lv2Log::info("Waiting for ALSA device " + serverSettings.GetAlsaDevice()); Lv2Log::info("Waiting for ALSA device " + serverSettings.GetAlsaDevice());
for (int i = 0; i < 15; ++i) for (int i = 0; i < 10; ++i)
{ {
sleep(1); sleep(1);
devices = model.GetAlsaDevices(); devices = model.GetAlsaDevices();