Clean shutdown, stability
This commit is contained in:
Vendored
+7
@@ -10,6 +10,7 @@
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Attach to Edge",
|
||||
"port": 9222,
|
||||
@@ -148,7 +149,13 @@
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Add alsa source directories.",
|
||||
"text": "directory $cd:$cwd:/usr/src/alsa-lib-1.2.8",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
+4
-3
@@ -11,7 +11,7 @@ set (CMAKE_INSTALL_PREFIX "/usr/")
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
|
||||
add_subdirectory("submodules/pipedal_p2pd")
|
||||
#add_subdirectory("submodules/pipedal_p2pd")
|
||||
|
||||
add_subdirectory("PiPedalCommon")
|
||||
|
||||
@@ -82,8 +82,9 @@ install(CODE
|
||||
EXECUTABLES
|
||||
${CMAKE_INSTALL_PREFIX}/sbin/pipedaladmind
|
||||
${CMAKE_INSTALL_PREFIX}/sbin/pipedald
|
||||
${CMAKE_INSTALL_PREFIX}/sbin/pipedal_nm_p2pd
|
||||
${CMAKE_INSTALL_PREFIX}/sbin/pipedal_p2pd
|
||||
${CMAKE_INSTALL_PREFIX}/sbin/pipedal_update
|
||||
#${CMAKE_INSTALL_PREFIX}/sbin/pipedal_nm_p2pd
|
||||
#${CMAKE_INSTALL_PREFIX}/sbin/pipedal_p2pd
|
||||
${CMAKE_INSTALL_PREFIX}/bin/pipedalconfig
|
||||
)
|
||||
]]
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "ss.hpp"
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include "util.hpp"
|
||||
|
||||
DBusDispatcher::DBusDispatcher(bool systemBus)
|
||||
{
|
||||
@@ -87,6 +88,7 @@ void DBusDispatcher::WakeThread()
|
||||
}
|
||||
void DBusDispatcher::ThreadProc()
|
||||
{
|
||||
pipedal::SetThreadName("dbusd");
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <unistd.h> // for gethostname()
|
||||
#include "util.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
using namespace std;
|
||||
@@ -89,16 +89,6 @@ bool WifiConfigSettings::ValidateCountryCode(const std::string &text)
|
||||
return std::isalpha(text[0]) && std::isalpha(text[1]);
|
||||
}
|
||||
|
||||
static std::string GetHostName()
|
||||
{
|
||||
char buffer[1024];
|
||||
if (gethostname(buffer,1024) != 0)
|
||||
{
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
buffer[1023] = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void WifiConfigSettings::Load()
|
||||
{
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace pipedal
|
||||
|
||||
static void error(const char *format, ...)
|
||||
{
|
||||
if (Lv2Log::log_level_ >= LogLevel::Warning)
|
||||
if (Lv2Log::log_level_ >= LogLevel::Error)
|
||||
{
|
||||
va_list arglist;
|
||||
va_start(arglist, format);
|
||||
|
||||
@@ -35,4 +35,7 @@ namespace pipedal {
|
||||
std::u32string ToUtf32(const std::string &s);
|
||||
|
||||
inline bool isPathSeperator(char c) { return c == '/' || c == std::filesystem::path::preferred_separator;}
|
||||
|
||||
std::string GetHostName();
|
||||
|
||||
}
|
||||
|
||||
@@ -100,3 +100,15 @@ std::u32string pipedal::ToUtf32(const std::string &s)
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
|
||||
std::string pipedal::GetHostName()
|
||||
{
|
||||
char buffer[1024];
|
||||
if (gethostname(buffer,1024) != 0)
|
||||
{
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
buffer[1023] = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+46
-22
@@ -6,7 +6,7 @@ import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import ArrowBackIcon from '@mui/icons-material//ArrowBack';
|
||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||
|
||||
import JackHostStatus from './JackHostStatus';
|
||||
import { PiPedalError } from './PiPedalError';
|
||||
@@ -16,12 +16,9 @@ import { Theme, createStyles } from '@mui/material/styles';
|
||||
import { withStyles, WithStyles } from '@mui/styles';
|
||||
import Slide, { SlideProps } from '@mui/material/Slide';
|
||||
|
||||
|
||||
interface AboutDialogProps extends WithStyles<typeof styles> {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
|
||||
|
||||
};
|
||||
|
||||
interface AboutDialogState {
|
||||
@@ -76,6 +73,15 @@ const styles = (theme: Theme) => createStyles({
|
||||
},
|
||||
secondaryItem: {
|
||||
|
||||
},
|
||||
can_select: {
|
||||
userSelect: "text",
|
||||
cursor: "text"
|
||||
},
|
||||
no_select: {
|
||||
userSelect: "none",
|
||||
cursor: "text"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +179,7 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
|
||||
this.updateNotifications();
|
||||
}
|
||||
componentDidUpdate(prevProps: Readonly<AboutDialogProps>, prevState: Readonly<AboutDialogState>, snapshot: any): void {
|
||||
super.componentDidUpdate?.(prevProps,prevState,snapshot);
|
||||
super.componentDidUpdate?.(prevProps, prevState, snapshot);
|
||||
this.updateNotifications();
|
||||
}
|
||||
|
||||
@@ -185,6 +191,11 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
|
||||
render() {
|
||||
let classes = this.props.classes;
|
||||
let addressKey = 0;
|
||||
let serverVersion = this.model.serverVersion?.serverVersion ?? "";
|
||||
let nPos = serverVersion.indexOf(' ');
|
||||
if (nPos !== -1) {
|
||||
serverVersion = serverVersion.substring(nPos + 1);
|
||||
}
|
||||
return (
|
||||
<DialogEx tag="about" fullScreen open={this.props.open}
|
||||
onClose={() => { this.props.onClose() }} TransitionComponent={Transition}
|
||||
@@ -210,13 +221,16 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
|
||||
overflowX: "hidden", overflowY: "auto", userSelect: "text"
|
||||
}}
|
||||
>
|
||||
<div style={{ margin: 24 }}>
|
||||
<Typography noWrap display="block" variant="h6" color="textPrimary">
|
||||
PiPedal <span style={{ fontSize: "0.7em" }}>
|
||||
{(this.model.serverVersion ? this.model.serverVersion.serverVersion : "")
|
||||
+ (this.model.serverVersion?.debug ? " (Debug)" : "")}
|
||||
</span>
|
||||
</Typography>
|
||||
<div id="debug_info" className={classes.can_select} style={{ margin: 24 }}>
|
||||
<div style={{ display: "flex", flexFlow: "row nowrap" }}>
|
||||
<Typography noWrap display="block" variant="h6" color="textPrimary" style={{flexGrow: 1, flexShrink: 1}}>
|
||||
PiPedal <span style={{ fontSize: "0.7em" }}>
|
||||
{serverVersion
|
||||
+ (this.model.serverVersion?.debug ? " (Debug)" : "")}
|
||||
</span>
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
<Typography noWrap display="block" variant="body2" style={{ marginBottom: 12 }} >
|
||||
Copyright © 2022-2024 Robin Davies.
|
||||
</Typography>
|
||||
@@ -235,24 +249,34 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
|
||||
<Typography noWrap display="block" variant="caption" >
|
||||
ADDRESSES
|
||||
</Typography>
|
||||
<div style={{marginBottom: 16}}>
|
||||
{
|
||||
this.model.serverVersion?.webAddresses.map((address) =>
|
||||
(
|
||||
<Typography key={addressKey++} display="block" variant="body2" style={{ marginBottom: 0, marginLeft: 24 }} >
|
||||
{address}
|
||||
</Typography>
|
||||
))
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
{
|
||||
this.model.serverVersion?.webAddresses.map((address) =>
|
||||
(
|
||||
<Typography key={addressKey++} display="block" variant="body2" style={{ marginBottom: 0, marginLeft: 24 }} >
|
||||
{address}
|
||||
</Typography>
|
||||
))
|
||||
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
<Typography noWrap display="block" variant="caption" >
|
||||
SERVER OS
|
||||
</Typography>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<Typography display="block" variant="body2" style={{ marginBottom: 0, marginLeft: 24 }} >
|
||||
{this.model.serverVersion?.osVersion ?? ""}
|
||||
</Typography>
|
||||
</div>
|
||||
</div><div>
|
||||
|
||||
<Divider />
|
||||
<Typography display="block" variant="caption" >
|
||||
LEGAL NOTICES
|
||||
</Typography>
|
||||
<div dangerouslySetInnerHTML={{ __html: this.state.openSourceNotices }} style={{ fontSize: "0.8em",maxWidth: 400 }}>
|
||||
<div dangerouslySetInnerHTML={{ __html: this.state.openSourceNotices }} style={{ fontSize: "0.8em", maxWidth: 400 }}>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
+8
-4
@@ -59,11 +59,13 @@ const theme = createTheme(
|
||||
styleOverrides: {
|
||||
containedPrimary: {
|
||||
borderRadius: '9999px',
|
||||
paddingLeft: "14px", paddingRight: "16px"
|
||||
paddingLeft: "16px", paddingRight: "16px",
|
||||
textTransform: "none"
|
||||
},
|
||||
containedSecondary: {
|
||||
borderRadius: '9999px',
|
||||
paddingLeft: "14px", paddingRight: "16px"
|
||||
paddingLeft: "16px", paddingRight: "16px",
|
||||
textTransform: "none"
|
||||
}
|
||||
|
||||
},
|
||||
@@ -103,11 +105,13 @@ const theme = createTheme(
|
||||
styleOverrides: {
|
||||
containedPrimary: {
|
||||
borderRadius: '9999px',
|
||||
paddingLeft: "14px", paddingRight: "16px"
|
||||
paddingLeft: "16px", paddingRight: "16px",
|
||||
textTransform: "none"
|
||||
},
|
||||
containedSecondary: {
|
||||
borderRadius: '9999px',
|
||||
paddingLeft: "14px", paddingRight: "16px"
|
||||
paddingLeft: "16px", paddingRight: "16px",
|
||||
textTransform: "none"
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
+92
-31
@@ -48,7 +48,7 @@ import SettingsDialog from './SettingsDialog';
|
||||
import AboutDialog from './AboutDialog';
|
||||
import BankDialog from './BankDialog';
|
||||
|
||||
import { PiPedalModelFactory, PiPedalModel, State, ZoomedControlInfo,wantsLoadingScreen } from './PiPedalModel';
|
||||
import { PiPedalModelFactory, PiPedalModel, State, ZoomedControlInfo, wantsLoadingScreen } from './PiPedalModel';
|
||||
import ZoomedUiControl from './ZoomedUiControl'
|
||||
import MainPage from './MainPage';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
@@ -67,7 +67,7 @@ import { ReactComponent as SaveBankAsIcon } from './svg/ic_save_bank_as.svg';
|
||||
import { ReactComponent as EditBanksIcon } from './svg/ic_edit_banks.svg';
|
||||
import { ReactComponent as SettingsIcon } from './svg/ic_settings.svg';
|
||||
import { ReactComponent as HelpOutlineIcon } from './svg/ic_help_outline.svg';
|
||||
import DialogEx from './DialogEx';
|
||||
import DialogEx, { DialogStackState } from './DialogEx';
|
||||
|
||||
|
||||
const appStyles = (theme: Theme) => createStyles({
|
||||
@@ -139,10 +139,11 @@ const appStyles = (theme: Theme) => createStyles({
|
||||
marginTop: 0,
|
||||
fontWeight: 500,
|
||||
fontSize: "13pt",
|
||||
maxWidth: 350,
|
||||
opacity: 1,
|
||||
zIndex: 2010,
|
||||
paddingTop: 12,
|
||||
gravity: "center",
|
||||
textAlign: "center"
|
||||
},
|
||||
|
||||
errorMessageBox: {
|
||||
@@ -164,8 +165,6 @@ const appStyles = (theme: Theme) => createStyles({
|
||||
position: "relative",
|
||||
top: "20%",
|
||||
color: isDarkMode() ? theme.palette.text.secondary : "#888",
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
// border: "3px solid #888",
|
||||
borderRadius: "12px",
|
||||
padding: "12px",
|
||||
@@ -351,9 +350,40 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
this.handleCloseAlert = this.handleCloseAlert.bind(this);
|
||||
this.banksChangedHandler = this.banksChangedHandler.bind(this);
|
||||
this.showStatusMonitorHandler = this.showStatusMonitorHandler.bind(this);
|
||||
|
||||
this.onPopStateHandler = this.onPopStateHandler.bind(this);
|
||||
}
|
||||
|
||||
showDrawer() {
|
||||
if (!this.state.isDrawerOpen) {
|
||||
this.setState({ isDrawerOpen: true })
|
||||
this.pushOpenMenuState();
|
||||
}
|
||||
}
|
||||
hideDrawer(loadingDialog: boolean = false) {
|
||||
if (!loadingDialog && window.location.hash === "#menu") {
|
||||
window.history.back();
|
||||
} else {
|
||||
this.setState({ isDrawerOpen: false })
|
||||
}
|
||||
}
|
||||
|
||||
pushOpenMenuState() {
|
||||
let stackState = { tag: "OpenMenu", previousState: null };
|
||||
window.history.replaceState(stackState, "", window.location.href);
|
||||
window.history.pushState({}, "", "#menu");
|
||||
}
|
||||
onPopStateHandler(ev: PopStateEvent) {
|
||||
let stackState: DialogStackState | null = ev.state as (DialogStackState | null);
|
||||
if (stackState && stackState.tag === "OpenMenu") {
|
||||
if (this.state.isDrawerOpen) {
|
||||
this.setState({ isDrawerOpen: false });
|
||||
}
|
||||
ev.stopPropagation();
|
||||
window.history.replaceState(stackState.previousState, "", window.location.href);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
onOpenBank(bankId: number) {
|
||||
this.model_.openBank(bankId)
|
||||
@@ -524,11 +554,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
return undefined;
|
||||
}
|
||||
promptForUpdateHandler(newValue: boolean) {
|
||||
if (this.model_.enableAutoUpdate)
|
||||
{
|
||||
if (this.state.updateDialogOpen !== newValue)
|
||||
{
|
||||
this.setState({updateDialogOpen: newValue});
|
||||
if (this.model_.enableAutoUpdate) {
|
||||
if (this.state.updateDialogOpen !== newValue) {
|
||||
this.setState({ updateDialogOpen: newValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -537,6 +565,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
super.componentDidMount();
|
||||
window.addEventListener("beforeunload", this.beforeUnloadListener);
|
||||
window.addEventListener("unload", this.unloadListener);
|
||||
window.addEventListener("popstate", this.onPopStateHandler);
|
||||
|
||||
this.model_.errorMessage.addOnChangedHandler(this.errorChangeHandler_);
|
||||
this.model_.state.addOnChangedHandler(this.stateChangeHandler_);
|
||||
@@ -546,6 +575,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
this.model_.showStatusMonitor.addOnChangedHandler(this.showStatusMonitorHandler);
|
||||
this.model_.promptForUpdate.addOnChangedHandler(this.promptForUpdateHandler);
|
||||
this.alertMessageChangedHandler();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -568,6 +598,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
super.componentWillUnmount();
|
||||
window.removeEventListener("beforeunload", this.beforeUnloadListener);
|
||||
|
||||
window.removeEventListener("popstate", this.onPopStateHandler);
|
||||
|
||||
|
||||
this.model_.promptForUpdate.removeOnChangedHandler(this.promptForUpdateHandler);
|
||||
this.model_.errorMessage.removeOnChangedHandler(this.errorChangeHandler_);
|
||||
this.model_.state.removeOnChangedHandler(this.stateChangeHandler_);
|
||||
@@ -634,12 +667,6 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
}
|
||||
}
|
||||
|
||||
showDrawer() {
|
||||
this.setState({ isDrawerOpen: true })
|
||||
}
|
||||
hideDrawer() {
|
||||
this.setState({ isDrawerOpen: false })
|
||||
}
|
||||
shortBankList(banks: BankIndex): BankIndexEntry[] {
|
||||
let n = this.state.bankDisplayItems;
|
||||
let entries = banks.entries;
|
||||
@@ -796,7 +823,11 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
{
|
||||
showBankSelectDialog && (
|
||||
<ListItem button key={'bankDOTDOTDOT'} selected={false}
|
||||
onClick={() => this.handleDrawerSelectBank()}
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
this.hideDrawer(true);
|
||||
this.handleDrawerSelectBank();
|
||||
}}
|
||||
>
|
||||
|
||||
<ListItemText primary={"..."} />
|
||||
@@ -808,19 +839,34 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
</List>
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem button key='RenameBank' onClick={() => { this.handleDrawerRenameBank() }}>
|
||||
<ListItem button key='RenameBank'
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
this.hideDrawer(true);
|
||||
this.handleDrawerRenameBank()
|
||||
}}>
|
||||
<ListItemIcon >
|
||||
<RenameOutlineIcon color='inherit' className={classes.menuIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Rename bank' />
|
||||
</ListItem>
|
||||
<ListItem button key='SaveBank' onClick={() => { this.handleDrawerSaveBankAs() }} >
|
||||
<ListItem button key='SaveBank'
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
this.hideDrawer(true);
|
||||
this.handleDrawerSaveBankAs();
|
||||
}} >
|
||||
<ListItemIcon>
|
||||
<SaveBankAsIcon color="inherit" className={classes.menuIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Save as new bank' />
|
||||
</ListItem>
|
||||
<ListItem button key='EditBanks' onClick={() => { this.handleDrawerManageBanks(); }}>
|
||||
<ListItem button key='EditBanks'
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
this.hideDrawer(true);
|
||||
this.handleDrawerManageBanks();
|
||||
}}>
|
||||
<ListItemIcon>
|
||||
<EditBanksIcon color="inherit" className={classes.menuIcon} />
|
||||
</ListItemIcon>
|
||||
@@ -829,19 +875,34 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
</List>
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem button key='Settings' onClick={() => { this.handleDrawerSettingsClick() }}>
|
||||
<ListItem button key='Settings'
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
this.hideDrawer(true);
|
||||
this.handleDrawerSettingsClick()
|
||||
}}>
|
||||
<ListItemIcon>
|
||||
<SettingsIcon color="inherit" className={classes.menuIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Settings' />
|
||||
</ListItem>
|
||||
<ListItem button key='About' onClick={() => { this.handleDrawerAboutClick() }}>
|
||||
<ListItem button key='About'
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
this.hideDrawer(true);
|
||||
this.handleDrawerAboutClick();
|
||||
}}>
|
||||
<ListItemIcon>
|
||||
<HelpOutlineIcon color="inherit" className={classes.menuIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='About' />
|
||||
</ListItem>
|
||||
<ListItem button key='Donations' onClick={() => { this.handleDrawerDonationClick() }}>
|
||||
<ListItem button key='Donations'
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
this.hideDrawer(true);
|
||||
this.handleDrawerDonationClick();
|
||||
}}>
|
||||
<ListItemIcon >
|
||||
<VolunteerActivismIcon className={classes.menuIcon} color="inherit" />
|
||||
</ListItemIcon>
|
||||
@@ -865,10 +926,10 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
</div>
|
||||
</main>
|
||||
<BankDialog show={this.state.bankDialogOpen} isEditDialog={this.state.editBankDialogOpen} onDialogClose={() => this.setState({ bankDialogOpen: false })} />
|
||||
{ (this.state.aboutDialogOpen)&&
|
||||
(
|
||||
<AboutDialog open={this.state.aboutDialogOpen} onClose={() => this.setState({ aboutDialogOpen: false })} />
|
||||
)}
|
||||
{(this.state.aboutDialogOpen) &&
|
||||
(
|
||||
<AboutDialog open={this.state.aboutDialogOpen} onClose={() => this.setState({ aboutDialogOpen: false })} />
|
||||
)}
|
||||
<SettingsDialog
|
||||
open={this.state.isSettingsDialogOpen}
|
||||
onboarding={this.state.onboarding}
|
||||
@@ -931,7 +992,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
<div className={classes.errorContent} style={{
|
||||
display: (
|
||||
wantsLoadingScreen(this.state.displayState)
|
||||
? "block" : "none"
|
||||
? "block" : "none"
|
||||
)
|
||||
}}
|
||||
>
|
||||
@@ -941,7 +1002,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
<div className={classes.loadingBoxItem}>
|
||||
<CircularProgress color="inherit" className={classes.loadingBoxItem} />
|
||||
</div>
|
||||
<Typography noWrap variant="body2" className={classes.progressText}>
|
||||
<Typography display="block" noWrap variant="body2" className={classes.progressText}>
|
||||
{this.getReloadingMessage()}
|
||||
</Typography>
|
||||
</div>
|
||||
@@ -961,7 +1022,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
</p>
|
||||
</div>
|
||||
<div style={{ paddingTop: 50, paddingLeft: 36, textAlign: "left" }}>
|
||||
<Button variant='contained' color="primary"
|
||||
<Button variant='contained' color="primary"
|
||||
onClick={() => this.handleReload()} >
|
||||
Reload
|
||||
</Button>
|
||||
|
||||
+45
-23
@@ -31,21 +31,17 @@ interface DialogExState {
|
||||
}
|
||||
|
||||
class DialogStackEntry {
|
||||
constructor(tag: string)
|
||||
constructor(dialog: DialogEx)
|
||||
{
|
||||
this.tag = tag;
|
||||
this.tag = dialog.props.tag;
|
||||
this.dialog = dialog;
|
||||
}
|
||||
tag: string;
|
||||
dialog: DialogEx;
|
||||
};
|
||||
|
||||
let dialogStack: DialogStackEntry[] = [];
|
||||
|
||||
function peekDialogStack(): string {
|
||||
if (dialogStack.length !== 0) {
|
||||
return dialogStack[dialogStack.length-1].tag;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function popDialogStack(): void {
|
||||
if (dialogStack.length !== 0)
|
||||
@@ -53,12 +49,33 @@ function popDialogStack(): void {
|
||||
dialogStack.splice(dialogStack.length-1,1);
|
||||
}
|
||||
}
|
||||
function pushDialogStack(tag: string): void {
|
||||
dialogStack.push(new DialogStackEntry(tag));
|
||||
function pushDialogStack(dialog: DialogEx): void {
|
||||
dialogStack.push(new DialogStackEntry(dialog));
|
||||
}
|
||||
|
||||
export interface DialogStackState{
|
||||
tag: String;
|
||||
previousState: DialogStackState | null;
|
||||
};
|
||||
|
||||
|
||||
// Close all dialogs higher in the dialog stack than "tag".
|
||||
export function removeDialogStackEntriesAbove(tag: string)
|
||||
{
|
||||
for (let i = dialogStack.length-1; i >= 0; --i)
|
||||
{
|
||||
let entry = dialogStack[i];
|
||||
if (entry.tag === tag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
popDialogStack();
|
||||
if (entry.dialog.props.open && entry.dialog.props.onClose)
|
||||
{
|
||||
entry.dialog.props.onClose({}, "backdropClick");
|
||||
}
|
||||
}
|
||||
}
|
||||
class DialogEx extends React.Component<DialogExProps,DialogExState> {
|
||||
constructor(props: DialogExProps)
|
||||
{
|
||||
@@ -75,22 +92,28 @@ class DialogEx extends React.Component<DialogExProps,DialogExState> {
|
||||
hasHooks: boolean = false;
|
||||
stateWasPopped: boolean = false;
|
||||
|
||||
handlePopState(e: any): any
|
||||
handlePopState(ev: PopStateEvent): any
|
||||
{
|
||||
let shouldClose = (peekDialogStack() === this.props.tag);
|
||||
if (shouldClose)
|
||||
{
|
||||
let evTag: DialogStackState | null = ev.state as DialogStackState | null;
|
||||
if (evTag && evTag.tag === this.props.tag) {
|
||||
removeDialogStackEntriesAbove(this.props.tag);
|
||||
|
||||
if (!this.stateWasPopped)
|
||||
{
|
||||
this.stateWasPopped = true;
|
||||
popDialogStack();
|
||||
if (this.props.open) {
|
||||
this.props.onClose?.(e,"backdropClick");
|
||||
this.props.onClose?.(ev,"backdropClick");
|
||||
}
|
||||
}
|
||||
window.history.replaceState(evTag.previousState,"",window.location.href);
|
||||
window.removeEventListener("popstate",this.handlePopState);
|
||||
e.stopPropagation();
|
||||
|
||||
if (window.location.hash === "#menu") // The menu popstate is next?
|
||||
{
|
||||
window.history.back(); // then clear off the menu popstate too.
|
||||
}
|
||||
ev.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,19 +128,18 @@ class DialogEx extends React.Component<DialogExProps,DialogExState> {
|
||||
this.stateWasPopped = false;
|
||||
window.addEventListener("popstate",this.handlePopState);
|
||||
|
||||
pushDialogStack(this.props.tag);
|
||||
let state: {tag: string} = {tag: this.props.tag};
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
history.pushState(
|
||||
state,
|
||||
pushDialogStack(this);
|
||||
let dialogStackState: DialogStackState = {tag: this.props.tag,previousState: window.history.state as DialogStackState | null};
|
||||
window.history.replaceState(dialogStackState,"",window.location.href);
|
||||
window.history.pushState(
|
||||
null,
|
||||
"",
|
||||
"#" + this.props.tag
|
||||
);
|
||||
} else {
|
||||
if (!this.stateWasPopped)
|
||||
{
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
history.back();
|
||||
window.history.back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,17 +793,47 @@ export class PiPedalModel //implements PiPedalModel
|
||||
return this.webSocket;
|
||||
}
|
||||
|
||||
androidReconnectTimeout?: NodeJS.Timeout = undefined;
|
||||
|
||||
cancelAndroidReconnectTimer()
|
||||
{
|
||||
if (this.androidReconnectTimeout) {
|
||||
clearTimeout(this.androidReconnectTimeout);
|
||||
this.androidReconnectTimeout = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
startAndroidReconnectTimer()
|
||||
{
|
||||
this.cancelAndroidReconnectTimer();
|
||||
this.androidReconnectTimeout = setTimeout(()=>{
|
||||
this.androidReconnectTimeout = undefined;
|
||||
this.androidHost?.setDisconnected(true);
|
||||
},20*1000);
|
||||
}
|
||||
onSocketConnectionLost() {
|
||||
// remove all the events and subscriptions we have.
|
||||
if (this.isClosed)
|
||||
{
|
||||
return; // page unloading. do NOT change the UI.
|
||||
}
|
||||
this.vuSubscriptions = [];
|
||||
this.monitorPatchPropertyListeners = [];
|
||||
|
||||
if (this.isAndroidHosted()) {
|
||||
this.androidHost?.setDisconnected(true);
|
||||
// if unexpected, go back to the device browser immediately.
|
||||
if (this.reconnectReason === ReconnectReason.Disconnected)
|
||||
{
|
||||
this.androidHost?.setDisconnected(true);
|
||||
} else {
|
||||
this.startAndroidReconnectTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
onSocketReconnected() {
|
||||
this.cancelOnNetworkChanging();
|
||||
this.cancelAndroidReconnectTimer();
|
||||
|
||||
if (this.isAndroidHosted()) {
|
||||
this.androidHost?.setDisconnected(false);
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ class PiPedalSocket {
|
||||
ws.onerror = null;
|
||||
reject("Connection closed unexpectedly.");
|
||||
};
|
||||
ws.onerror = (evWheent: Event) => {
|
||||
ws.onerror = (evt: Event) => {
|
||||
ws.onclose = null;
|
||||
ws.onerror = null;
|
||||
reject("Failed to connect.");
|
||||
|
||||
@@ -451,7 +451,6 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
InputLabelProps={{
|
||||
shrink: true
|
||||
}}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
<div style={{ marginBottom: 8, flexGrow: 1, flexBasis: 1 }}>
|
||||
<form autoComplete='off' onSubmit={() => false}> {/*Prevents chrome from saving passwords */}
|
||||
@@ -477,7 +476,9 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
}}
|
||||
InputProps={{
|
||||
startAdornment:
|
||||
this.props.wifiConfigSettings.hasSavedPassword && !this.state.hasPassword && !this.state.showPassword ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : ""
|
||||
!this.state.hasPassword && !this.state.showPassword ?
|
||||
(this.props.wifiConfigSettings.hasSavedPassword? "(Unchanged)" : "(Required)")
|
||||
: ""
|
||||
,
|
||||
endAdornment: (
|
||||
<IconButton size="small"
|
||||
|
||||
+11
-13
@@ -256,17 +256,15 @@ namespace pipedal
|
||||
|
||||
std::mutex terminateSync;
|
||||
|
||||
bool terminateAudio_ = false;
|
||||
std::atomic<bool> terminateAudio_ = false;
|
||||
|
||||
void terminateAudio(bool terminate)
|
||||
{
|
||||
std::lock_guard lock{terminateSync};
|
||||
this->terminateAudio_ = terminate;
|
||||
}
|
||||
|
||||
bool terminateAudio()
|
||||
{
|
||||
std::lock_guard lock{terminateSync};
|
||||
return this->terminateAudio_;
|
||||
}
|
||||
|
||||
@@ -1297,10 +1295,10 @@ namespace pipedal
|
||||
FillOutputBuffer();
|
||||
|
||||
err = snd_pcm_start(handle);
|
||||
// if (err < 0)
|
||||
// {
|
||||
// throw PiPedalStateException(SS("Can't recover from ALSA underrun. (" << snd_strerror(err) << ")"));
|
||||
// }
|
||||
if (err < 0)
|
||||
{
|
||||
throw PiPedalStateException(SS("Can't recover from ALSA underrun. (" << snd_strerror(err) << ")"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (err == -ESTRPIPE)
|
||||
@@ -1320,7 +1318,7 @@ namespace pipedal
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw PiPedalStateException(SS("ALSA error:" << snd_strerror(err)));
|
||||
throw PiPedalStateException(SS("ALSA error: " << snd_strerror(err)));
|
||||
}
|
||||
|
||||
std::jthread *audioThread = nullptr;
|
||||
@@ -1663,16 +1661,16 @@ namespace pipedal
|
||||
}
|
||||
void Close()
|
||||
{
|
||||
if (hInParams)
|
||||
{
|
||||
snd_rawmidi_params_free(hInParams);
|
||||
hInParams = 0;
|
||||
}
|
||||
if (hIn)
|
||||
{
|
||||
snd_rawmidi_close(hIn);
|
||||
hIn = nullptr;
|
||||
}
|
||||
if (hInParams)
|
||||
{
|
||||
snd_rawmidi_params_free(hInParams);
|
||||
hInParams = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int GetDataLength(uint8_t cc)
|
||||
|
||||
+8
-10
@@ -349,17 +349,14 @@ private:
|
||||
|
||||
virtual void Close()
|
||||
{
|
||||
std::lock_guard guard{mutex};
|
||||
if (!isOpen)
|
||||
return;
|
||||
|
||||
isOpen = false;
|
||||
|
||||
if (realtimeMonitorPortSubscriptions != nullptr)
|
||||
{
|
||||
delete realtimeMonitorPortSubscriptions;
|
||||
realtimeMonitorPortSubscriptions = nullptr;
|
||||
std::lock_guard guard{mutex};
|
||||
if (!isOpen)
|
||||
return;
|
||||
|
||||
isOpen = false;
|
||||
}
|
||||
|
||||
if (active)
|
||||
{
|
||||
audioDriver->Deactivate();
|
||||
@@ -371,6 +368,7 @@ private:
|
||||
|
||||
StopReaderThread();
|
||||
|
||||
|
||||
// release any pdealboards owned by the process thread.
|
||||
this->activePedalboards.resize(0);
|
||||
this->realtimeActivePedalboard = nullptr;
|
||||
@@ -815,7 +813,7 @@ private:
|
||||
virtual void OnAudioTerminated() override
|
||||
{
|
||||
this->active = false;
|
||||
Lv2Log::info("Audio stopped.");
|
||||
Lv2Log::info("Audio thread terminated.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
+277
-94
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. Davies
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "AvahiService.hpp"
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-client/publish.h>
|
||||
#include <avahi-common/alternative.h>
|
||||
@@ -35,6 +36,7 @@
|
||||
#include <unistd.h>
|
||||
#include "Lv2Log.hpp"
|
||||
#include "ss.hpp"
|
||||
#include <chrono>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -43,43 +45,122 @@ void AvahiService::Announce(
|
||||
const std::string &name,
|
||||
const std::string &instanceId,
|
||||
const std::string &mdnsName,
|
||||
bool addTestGroup)
|
||||
bool wait)
|
||||
{
|
||||
if (terminated)
|
||||
return;
|
||||
// We should update an existing group if the name doesn't change.
|
||||
// but in practice, the name is the only thing that's going to change without restarting the server.
|
||||
if (this->name && strcmp(name.c_str(),this->name) == 0)
|
||||
// but in practice, the name is the only thing that's going to change without restarting the pipedal server.
|
||||
if (this->serviceName == name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Unannounce();
|
||||
|
||||
this->portNumber = portNumber;
|
||||
this->instanceId = instanceId;
|
||||
this->mdnsName = mdnsName;
|
||||
this->addTestGroup = addTestGroup;
|
||||
|
||||
this->name = avahi_strdup(name.c_str());
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
void AvahiService::Unannounce()
|
||||
{
|
||||
Stop();
|
||||
if (name)
|
||||
// this->name = avahi_strdup(name.c_str());
|
||||
if (!started)
|
||||
{
|
||||
avahi_free(name);
|
||||
this->name = nullptr;
|
||||
this->portNumber = portNumber;
|
||||
this->instanceId = instanceId;
|
||||
this->mdnsName = mdnsName;
|
||||
this->serviceName = name;
|
||||
|
||||
started = true;
|
||||
makeAnnouncement = true;
|
||||
createPending = true;
|
||||
Start();
|
||||
if (wait) {
|
||||
Wait();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// already started, so we have to use poll_lock instead.
|
||||
avahi_threaded_poll_lock(threadedPoll);
|
||||
|
||||
// all state that we have to protect with the lock now that the avahi serv3ce is running.
|
||||
this->portNumber = portNumber;
|
||||
this->instanceId = instanceId;
|
||||
this->mdnsName = mdnsName;
|
||||
this->serviceName = name;
|
||||
this->makeAnnouncement = true;
|
||||
|
||||
// we've requested a start but have not created the group.
|
||||
if (this->createPending)
|
||||
{
|
||||
// the first create will use our freshly updated parameters.
|
||||
// no action required.
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise we have to use a lock to effect the update.
|
||||
if (group)
|
||||
{
|
||||
avahi_entry_group_reset(group); // unannounce the previous
|
||||
SetState(ServiceState::Reset);
|
||||
create_group(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
Lv2Log::error("Failed to update mDNS service because of a synch problem.");
|
||||
}
|
||||
}
|
||||
avahi_threaded_poll_unlock(threadedPoll);
|
||||
if (wait)
|
||||
{
|
||||
Wait();
|
||||
}
|
||||
}
|
||||
this->group = nullptr;
|
||||
this->client = nullptr;
|
||||
this->threadedPoll = nullptr;
|
||||
}
|
||||
|
||||
void AvahiService::Unannounce(bool wait)
|
||||
{
|
||||
if (terminated)
|
||||
return;
|
||||
if (this->threadedPoll)
|
||||
{
|
||||
avahi_threaded_poll_lock(threadedPoll);
|
||||
if (started)
|
||||
{
|
||||
if (this->createPending)
|
||||
{
|
||||
// if service is starting up, and we haven't yet made our first announcement,
|
||||
// just signal that we don't want to announc.
|
||||
this->makeAnnouncement = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->makeAnnouncement = false;
|
||||
// we have previously made a successful announcement. Retract it.
|
||||
if (group)
|
||||
{
|
||||
int rc = avahi_entry_group_reset(group);
|
||||
if (rc < 0)
|
||||
{
|
||||
Lv2Log::error("Avahi: failed to un-announce.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
avahi_threaded_poll_unlock(threadedPoll);
|
||||
if (wait)
|
||||
{
|
||||
WaitForUnannounce();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AvahiService::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userData)
|
||||
{
|
||||
((AvahiService *)userData)->EntryGroupCallback(g, state);
|
||||
}
|
||||
|
||||
void AvahiService::SetState(ServiceState serviceState)
|
||||
{
|
||||
this->serviceState = serviceState;
|
||||
}
|
||||
|
||||
void AvahiService::EntryGroupCallback(AvahiEntryGroup *g, AvahiEntryGroupState state)
|
||||
{
|
||||
group = g;
|
||||
@@ -87,29 +168,39 @@ void AvahiService::EntryGroupCallback(AvahiEntryGroup *g, AvahiEntryGroupState s
|
||||
switch (state)
|
||||
{
|
||||
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||||
SetState(ServiceState::Established);
|
||||
Lv2Log::info(SS("DNS/SD group established."));
|
||||
|
||||
/* The entry group has been established successfully */
|
||||
Lv2Log::debug(SS("Service " << name << " successfully established."));
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_COLLISION:
|
||||
{
|
||||
char *n;
|
||||
/* A service name collision with a remote service
|
||||
* happened. Let's pick a new name */
|
||||
n = avahi_alternative_service_name(name);
|
||||
avahi_free(name);
|
||||
name = n;
|
||||
Lv2Log::error(SS("Service name collision, renaming service to '" << name << "'\n"));
|
||||
* happened. Let's pick a new name */
|
||||
SetState(ServiceState::Collision);
|
||||
char *n = avahi_alternative_service_name(avahiNameString);
|
||||
avahi_free(avahiNameString);
|
||||
avahiNameString = n;
|
||||
Lv2Log::warning(SS("Service name collision, renaming service to '" << avahiNameString << "'\n"));
|
||||
/* And recreate the services */
|
||||
create_group(avahi_entry_group_get_client(g));
|
||||
break;
|
||||
}
|
||||
case AVAHI_ENTRY_GROUP_FAILURE:
|
||||
Lv2Log::error(SS("Entry group failure: " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << "\n"));
|
||||
Lv2Log::error(SS("DNS/SD service shutting down."));
|
||||
/* Some kind of failure happened while we were registering our services */
|
||||
terminated = true;
|
||||
avahi_threaded_poll_quit(threadedPoll);
|
||||
SetState(ServiceState::Failed);
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||||
SetState(ServiceState::Uncommited);
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_REGISTERING:;
|
||||
SetState(ServiceState::Registering);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,11 +233,14 @@ static int toRawDns(char *rawResult, size_t size, const std::string &name)
|
||||
}
|
||||
void AvahiService::create_group(AvahiClient *c)
|
||||
{
|
||||
this->createPending = false;
|
||||
|
||||
char *n;
|
||||
int ret;
|
||||
assert(c);
|
||||
/* If this is the first time we're called, let's create a new
|
||||
* entry group if necessary */
|
||||
SetState(ServiceState::Requested);
|
||||
if (!group)
|
||||
{
|
||||
if (!(group = avahi_entry_group_new(c, entry_group_callback, (void *)this)))
|
||||
@@ -157,20 +251,26 @@ void AvahiService::create_group(AvahiClient *c)
|
||||
}
|
||||
/* If the group is empty (either because it was just created, or
|
||||
* because it was reset previously, add our entries. */
|
||||
if (avahi_entry_group_is_empty(group))
|
||||
if (this->makeAnnouncement && avahi_entry_group_is_empty(group))
|
||||
{
|
||||
Lv2Log::debug(SS("Adding service '" << name << "'"));
|
||||
Lv2Log::debug(SS("Adding service '" << avahiNameString << "'"));
|
||||
|
||||
std::string instanceTxtRecord = SS("id=" << this->instanceId);
|
||||
|
||||
#define PIPEDAL_SERVICE_TYPE "_pipedal._tcp"
|
||||
|
||||
if (avahiNameString)
|
||||
{
|
||||
avahi_free(avahiNameString);
|
||||
avahiNameString = nullptr;
|
||||
}
|
||||
avahiNameString = avahi_strdup(serviceName.c_str());
|
||||
if ((ret = avahi_entry_group_add_service(
|
||||
group,
|
||||
AVAHI_IF_UNSPEC,
|
||||
AVAHI_PROTO_INET, // IPv4 for now, until we figure out why dnsqmasq borks IPv6 routing.)
|
||||
(AvahiPublishFlags)0,
|
||||
name,
|
||||
avahiNameString,
|
||||
PIPEDAL_SERVICE_TYPE,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -186,55 +286,31 @@ void AvahiService::create_group(AvahiClient *c)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (this->addTestGroup)
|
||||
{
|
||||
Lv2Log::info("Added tests DNS/SD service.");
|
||||
std::string instanceTxtRecord = SS("id=" << "0a6045b0-1753-4104-b3e4-b9713b9cc360");
|
||||
|
||||
if ((ret = avahi_entry_group_add_service(
|
||||
group,
|
||||
AVAHI_IF_UNSPEC,
|
||||
AVAHI_PROTO_INET, // IPv4 for now, until we figure out why dnsqmasq borks IPv6 routing.)
|
||||
(AvahiPublishFlags)0,
|
||||
"Ed's PiPedal",
|
||||
PIPEDAL_SERVICE_TYPE,
|
||||
NULL,
|
||||
NULL,
|
||||
portNumber,
|
||||
|
||||
// txt records.
|
||||
instanceTxtRecord.c_str(),
|
||||
NULL)) < 0)
|
||||
{
|
||||
if (ret == AVAHI_ERR_COLLISION)
|
||||
goto collision;
|
||||
Lv2Log::error(SS("Failed to add _pipedal._tcp service: " << avahi_strerror(ret)));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell the server to register the service */
|
||||
if ((ret = avahi_entry_group_commit(group)) < 0)
|
||||
{
|
||||
Lv2Log::error(SS("Failed to commit entry group: " << avahi_strerror(ret)));
|
||||
goto fail;
|
||||
}
|
||||
Lv2Log::info(SS("DNS/SD service announced."));
|
||||
|
||||
Lv2Log::info(SS("DNS/SD service announced. (" << this->avahiNameString << ")"));
|
||||
}
|
||||
return;
|
||||
collision:
|
||||
/* A service name collision with a local service happened. Let's
|
||||
* pick a new name */
|
||||
n = avahi_alternative_service_name(name);
|
||||
avahi_free(name);
|
||||
name = n;
|
||||
Lv2Log::warning(SS("Service name collision, renaming service to '" << name << "'"));
|
||||
* pick a new avahiNameString */
|
||||
n = avahi_alternative_service_name(avahiNameString);
|
||||
avahi_free(avahiNameString);
|
||||
avahiNameString = n;
|
||||
Lv2Log::warning(SS("Service name collision, renaming service to '" << avahiNameString << "'"));
|
||||
avahi_entry_group_reset(group);
|
||||
create_group(c);
|
||||
return;
|
||||
fail:
|
||||
terminated = true;
|
||||
avahi_threaded_poll_quit(threadedPoll);
|
||||
Lv2Log::error("DNS/SD service shutting down.");
|
||||
SetState(ServiceState::Failed);
|
||||
|
||||
}
|
||||
|
||||
void AvahiService::client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void *userdata)
|
||||
@@ -250,7 +326,7 @@ void AvahiService::ClientCallback(AvahiClient *c, AvahiClientState state)
|
||||
{
|
||||
case AVAHI_CLIENT_S_RUNNING:
|
||||
/* The server has startup successfully and registered its host
|
||||
* name on the network, so it's time to create our services */
|
||||
* name on the network, so it's time to create our services */
|
||||
create_group(c);
|
||||
break;
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
@@ -259,11 +335,11 @@ void AvahiService::ClientCallback(AvahiClient *c, AvahiClientState state)
|
||||
if (this->clientErrno == AVAHI_ERR_DISCONNECTED)
|
||||
{
|
||||
// tear the client down and restart it
|
||||
Lv2Log::info("Avahi connection lost. Reconnecting.");
|
||||
Lv2Log::info("DNS/SD connection lost. Reconnecting.");
|
||||
|
||||
if (group)
|
||||
{
|
||||
avahi_entry_group_reset(group);
|
||||
avahi_entry_group_free(group);
|
||||
group = nullptr;
|
||||
}
|
||||
|
||||
@@ -278,28 +354,35 @@ void AvahiService::ClientCallback(AvahiClient *c, AvahiClientState state)
|
||||
if (!client)
|
||||
{
|
||||
Lv2Log::error(SS("Failed to create client: " << avahi_strerror(error)));
|
||||
terminated = true;
|
||||
avahi_threaded_poll_quit(threadedPoll);
|
||||
SetState(ServiceState::Failed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Lv2Log::error(SS("Client failure: " << avahi_strerror(avahi_client_errno(c))));
|
||||
terminated = true;
|
||||
Lv2Log::error(SS("DNS/SD client failure: " << avahi_strerror(avahi_client_errno(c))));
|
||||
avahi_threaded_poll_quit(threadedPoll);
|
||||
SetState(ServiceState::Failed);
|
||||
}
|
||||
break;
|
||||
case AVAHI_CLIENT_S_COLLISION:
|
||||
/* Let's drop our registered services. When the server is back
|
||||
* in AVAHI_SERVER_RUNNING state we will register them
|
||||
* again with the new host name. */
|
||||
* in AVAHI_SERVER_RUNNING state we will register them
|
||||
* again with the new host name. */
|
||||
case AVAHI_CLIENT_S_REGISTERING:
|
||||
/* The server records are now being established. This
|
||||
* might be caused by a host name change. We need to wait
|
||||
* for our own records to register until the host name is
|
||||
* properly esatblished. */
|
||||
* might be caused by a host name change. We need to wait
|
||||
* for our own records to register until the host name is
|
||||
* properly esatblished. */
|
||||
if (group)
|
||||
avahi_entry_group_reset(group);
|
||||
SetState(ServiceState::Settling);
|
||||
break;
|
||||
case AVAHI_CLIENT_CONNECTING:
|
||||
SetState(ServiceState::Settling);
|
||||
break;
|
||||
case AVAHI_CLIENT_CONNECTING:;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +393,8 @@ void AvahiService::Start()
|
||||
int ret = 1;
|
||||
struct timeval tv;
|
||||
this->clientErrno = 0;
|
||||
while (true)
|
||||
SetState(ServiceState::Initializing);
|
||||
for (int retry = 0; retry < 3; ++retry)
|
||||
{
|
||||
/* Allocate main loop object */
|
||||
if (!this->threadedPoll)
|
||||
@@ -339,30 +423,129 @@ void AvahiService::Start()
|
||||
return;
|
||||
fail:
|
||||
Stop();
|
||||
sleep(1);
|
||||
SetState(ServiceState::Failed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void AvahiService::Stop()
|
||||
{
|
||||
if (stopped)
|
||||
return;
|
||||
this->stopped = true;
|
||||
|
||||
/* Cleanup things */
|
||||
if (group)
|
||||
{
|
||||
avahi_entry_group_reset(group);
|
||||
avahi_entry_group_free(group);
|
||||
group = nullptr;
|
||||
}
|
||||
if (client)
|
||||
{
|
||||
avahi_client_free(client);
|
||||
client = nullptr;
|
||||
}
|
||||
Unannounce(true);
|
||||
sleep(1); // let traffic setting. avahi doens't seem to shut down cleany otherwise.
|
||||
|
||||
if (threadedPoll)
|
||||
{
|
||||
avahi_threaded_poll_lock(threadedPoll);
|
||||
if (group)
|
||||
{
|
||||
avahi_entry_group_free(group);
|
||||
group = nullptr;
|
||||
}
|
||||
avahi_threaded_poll_unlock(threadedPoll);
|
||||
avahi_threaded_poll_lock(threadedPoll);
|
||||
if (client)
|
||||
{
|
||||
avahi_client_free(client);
|
||||
client = nullptr;
|
||||
}
|
||||
avahi_threaded_poll_unlock(threadedPoll);
|
||||
|
||||
avahi_threaded_poll_stop(threadedPoll);
|
||||
avahi_threaded_poll_free(threadedPoll);
|
||||
SetState(ServiceState::Closed);
|
||||
threadedPoll = nullptr;
|
||||
}
|
||||
|
||||
/* Cleanup things */
|
||||
if (avahiNameString)
|
||||
{
|
||||
avahi_free(avahiNameString);
|
||||
avahiNameString = nullptr;
|
||||
}
|
||||
Lv2Log::info("DNS/SD service stopped.");
|
||||
}
|
||||
|
||||
void AvahiService::Wait()
|
||||
{
|
||||
using clock = std::chrono::steady_clock;
|
||||
auto start = clock::now();
|
||||
auto waitTime = start + std::chrono::duration_cast<clock::duration>(std::chrono::seconds(5));
|
||||
while (true)
|
||||
{
|
||||
bool done;
|
||||
switch (serviceState)
|
||||
{
|
||||
default:
|
||||
case ServiceState::Unitialized:
|
||||
throw std::runtime_error("Invalid state");
|
||||
|
||||
case ServiceState::Initializing:
|
||||
case ServiceState::Settling:
|
||||
case ServiceState::Requested:
|
||||
case ServiceState::Uncommited:
|
||||
case ServiceState::Registering:
|
||||
case ServiceState::Collision:
|
||||
done = false;
|
||||
break;
|
||||
case ServiceState::Reset:
|
||||
case ServiceState::Established:
|
||||
case ServiceState::Failed:
|
||||
case ServiceState::Closed:
|
||||
done = true;
|
||||
break;
|
||||
};
|
||||
if (done) break;
|
||||
if (clock::now() > waitTime)
|
||||
{
|
||||
Lv2Log::error("DNS/SD announcement timed out.");
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
}
|
||||
void AvahiService::WaitForUnannounce()
|
||||
{
|
||||
using clock = std::chrono::steady_clock;
|
||||
auto start = clock::now();
|
||||
auto waitTime = start + std::chrono::duration_cast<clock::duration>(std::chrono::seconds(5));
|
||||
|
||||
while (true)
|
||||
{
|
||||
bool done;
|
||||
switch (serviceState)
|
||||
{
|
||||
default:
|
||||
throw std::runtime_error("Invalid state");
|
||||
|
||||
case ServiceState::Initializing:
|
||||
case ServiceState::Settling:
|
||||
case ServiceState::Requested:
|
||||
case ServiceState::Registering:
|
||||
case ServiceState::Collision:
|
||||
done = false;
|
||||
break;
|
||||
case ServiceState::Uncommited:
|
||||
case ServiceState::Unitialized:
|
||||
case ServiceState::Reset:
|
||||
case ServiceState::Established:
|
||||
case ServiceState::Failed:
|
||||
case ServiceState::Closed:
|
||||
done = true;
|
||||
break;
|
||||
};
|
||||
if (done) break;
|
||||
if (clock::now() > waitTime)
|
||||
{
|
||||
Lv2Log::error("DNS/SD unannounce timed out.");
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+32
-5
@@ -26,10 +26,12 @@
|
||||
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
|
||||
// forward declarations.
|
||||
class AvahiEntryGroup;
|
||||
class AvahiThreadedPoll;
|
||||
#include <atomic>
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
|
||||
@@ -38,12 +40,37 @@ namespace pipedal {
|
||||
|
||||
class AvahiService {
|
||||
public:
|
||||
~AvahiService() { Unannounce(); }
|
||||
~AvahiService() { Stop(); }
|
||||
void Announce(
|
||||
int portNumber, const std::string &name, const std::string &instanceId, const std::string&mdnsName,bool addTestGroup = false);
|
||||
int portNumber, const std::string &name, const std::string &instanceId, const std::string&mdnsName, bool wait);
|
||||
|
||||
void Unannounce();
|
||||
void Unannounce(bool wait);
|
||||
private:
|
||||
enum class ServiceState {
|
||||
Unitialized,
|
||||
Initializing,
|
||||
Settling,
|
||||
Requested,
|
||||
Uncommited,
|
||||
Registering,
|
||||
Collision,
|
||||
Reset,
|
||||
Established,
|
||||
Failed,
|
||||
Closed
|
||||
};
|
||||
|
||||
std::atomic<ServiceState> serviceState;
|
||||
void Wait();
|
||||
void WaitForUnannounce();
|
||||
void SetState(ServiceState serviceState);
|
||||
|
||||
std::atomic<bool> terminated = false;
|
||||
bool stopped = false;
|
||||
bool started = false;
|
||||
bool createPending = false;
|
||||
bool makeAnnouncement = false;
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
static void entry_group_callback(AvahiEntryGroup*g, AvahiEntryGroupState state, void *userData);
|
||||
@@ -59,13 +86,13 @@ namespace pipedal {
|
||||
|
||||
int portNumber = -1;
|
||||
std::string instanceId;
|
||||
std::string serviceName;
|
||||
std::string mdnsName;
|
||||
bool addTestGroup = false;
|
||||
|
||||
AvahiClient *client = NULL;
|
||||
AvahiEntryGroup *group = NULL;
|
||||
AvahiThreadedPoll *threadedPoll = NULL;
|
||||
char*name = NULL;
|
||||
char*avahiNameString = NULL;
|
||||
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ endif()
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
set (USE_SANITIZE False)
|
||||
set (USE_SANITIZE true)
|
||||
|
||||
|
||||
if (!ENABLE_VST3)
|
||||
|
||||
@@ -1295,6 +1295,7 @@ void RequireNetworkManager()
|
||||
throw std::runtime_error("The current OS is not using NetworkManager.");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CommandLineParser parser;
|
||||
|
||||
+97
-79
@@ -54,13 +54,12 @@ namespace pipedal::impl
|
||||
|
||||
std::vector<std::string> GetKnownWifiNetworks();
|
||||
|
||||
virtual PostHandle Post(PostCallback&&fn) override;
|
||||
virtual PostHandle PostDelayed(const clock::duration&delay,PostCallback&&fn) override;
|
||||
virtual PostHandle Post(PostCallback &&fn) override;
|
||||
virtual PostHandle PostDelayed(const clock::duration &delay, PostCallback &&fn) override;
|
||||
virtual bool CancelPost(PostHandle handle) override;
|
||||
|
||||
virtual void SetNetworkChangingListener(NetworkChangingListener &&listener) override;
|
||||
|
||||
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
@@ -104,8 +103,7 @@ namespace pipedal::impl
|
||||
|
||||
void UpdateKnownNetworks(
|
||||
std::vector<ssid_t> &knownSsids,
|
||||
std::vector<AccessPoint::ptr> &allAccessPoints
|
||||
);
|
||||
std::vector<AccessPoint::ptr> &allAccessPoints);
|
||||
|
||||
void FireNetworkChanging();
|
||||
|
||||
@@ -151,7 +149,6 @@ using namespace pipedal::impl;
|
||||
|
||||
HotspotManagerImpl::HotspotManagerImpl()
|
||||
{
|
||||
SetDBusLogLevel(DBusLogLevel::None);
|
||||
}
|
||||
|
||||
void HotspotManagerImpl::Open()
|
||||
@@ -167,7 +164,24 @@ void HotspotManagerImpl::Open()
|
||||
|
||||
void HotspotManagerImpl::onClose()
|
||||
{
|
||||
StopHotspot();
|
||||
this->closed = true; // avoids a memory barrier probelm.
|
||||
|
||||
CancelDeviceChangedTimer();
|
||||
CancelWaitForNetworkManagerTimer();
|
||||
CancelAccessPointsChangedTimer();
|
||||
|
||||
|
||||
if (networkManager && activeConnection)
|
||||
{
|
||||
try {
|
||||
networkManager->DeactivateConnection(activeConnection->getObjectPath());
|
||||
activeConnection = nullptr;
|
||||
} catch (const std::exception&e)
|
||||
{
|
||||
// nothrow.
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseNetworkManager();
|
||||
|
||||
Lv2Log::debug("HotspotManager: state=Closed");
|
||||
@@ -250,6 +264,7 @@ void HotspotManagerImpl::UpdateNetworkManagerStatus()
|
||||
this->StartWaitForNetworkManagerTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void HotspotManagerImpl::CancelDeviceChangedTimer()
|
||||
{
|
||||
if (devicesChangedTimerHandle)
|
||||
@@ -386,7 +401,6 @@ void HotspotManagerImpl::onStartMonitoring()
|
||||
|
||||
StartScanTimer();
|
||||
onAccessPointChanged();
|
||||
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -397,6 +411,7 @@ void HotspotManagerImpl::onStartMonitoring()
|
||||
|
||||
void HotspotManagerImpl::StartWaitForNetworkManagerTimer()
|
||||
{
|
||||
|
||||
CancelWaitForNetworkManagerTimer();
|
||||
networkManagerTimerHandle = dbusDispatcher.PostDelayed(
|
||||
std::chrono::seconds(5),
|
||||
@@ -408,6 +423,7 @@ void HotspotManagerImpl::StartWaitForNetworkManagerTimer()
|
||||
}
|
||||
void HotspotManagerImpl::CancelWaitForNetworkManagerTimer()
|
||||
{
|
||||
|
||||
if (networkManagerTimerHandle)
|
||||
{
|
||||
dbusDispatcher.CancelPost(networkManagerTimerHandle);
|
||||
@@ -436,7 +452,7 @@ void HotspotManagerImpl::onReload()
|
||||
case State::Error:
|
||||
// ignore.
|
||||
return;
|
||||
default:
|
||||
default:
|
||||
MaybeStartHotspot();
|
||||
return;
|
||||
}
|
||||
@@ -473,8 +489,6 @@ void HotspotManagerImpl::Close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
HotspotManager::ptr HotspotManager::Create()
|
||||
{
|
||||
return std::make_unique<HotspotManagerImpl>();
|
||||
@@ -496,8 +510,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct NetworkSortRecord {
|
||||
struct NetworkSortRecord
|
||||
{
|
||||
std::string ssid;
|
||||
bool connected = false;
|
||||
bool knownNetwork = false;
|
||||
@@ -506,12 +520,11 @@ struct NetworkSortRecord {
|
||||
};
|
||||
void HotspotManagerImpl::UpdateKnownNetworks(
|
||||
std::vector<ssid_t> &knownSsids,
|
||||
std::vector<AccessPoint::ptr> & allAccessPoints
|
||||
)
|
||||
std::vector<AccessPoint::ptr> &allAccessPoints)
|
||||
{
|
||||
std::map<std::string,NetworkSortRecord> map;
|
||||
std::map<std::string, NetworkSortRecord> map;
|
||||
|
||||
for (auto &knownSsid: knownSsids)
|
||||
for (auto &knownSsid : knownSsids)
|
||||
{
|
||||
std::string ssid = ssidToString(knownSsid);
|
||||
if (ssid.length() != 0)
|
||||
@@ -521,17 +534,22 @@ void HotspotManagerImpl::UpdateKnownNetworks(
|
||||
record.knownNetwork = true;
|
||||
}
|
||||
}
|
||||
for (auto&accessPoint: allAccessPoints)
|
||||
for (auto &accessPoint : allAccessPoints)
|
||||
{
|
||||
uint8_t strength = accessPoint->Strength();
|
||||
auto vSsid = accessPoint->Ssid();
|
||||
std::string ssid = ssidToString(vSsid);
|
||||
if (ssid.length() != 0)
|
||||
try {
|
||||
uint8_t strength = accessPoint->Strength();
|
||||
auto vSsid = accessPoint->Ssid();
|
||||
std::string ssid = ssidToString(vSsid);
|
||||
if (ssid.length() != 0)
|
||||
{
|
||||
NetworkSortRecord &record = map[ssid];
|
||||
record.ssid = ssid;
|
||||
record.visibleNetwork = true;
|
||||
record.strength = strength;
|
||||
}
|
||||
} catch (const std::exception&ignored)
|
||||
{
|
||||
NetworkSortRecord&record = map[ssid];
|
||||
record.ssid = ssid;
|
||||
record.visibleNetwork = true;
|
||||
record.strength = strength;
|
||||
// race to get the info before it changes. np.
|
||||
}
|
||||
}
|
||||
if (this->wlanDevice)
|
||||
@@ -539,24 +557,23 @@ void HotspotManagerImpl::UpdateKnownNetworks(
|
||||
auto activeConnectionPath = this->wlanDevice->ActiveConnection();
|
||||
if (activeConnectionPath.length() > 2) // "/" -> no connection. Be paranoid about "".
|
||||
{
|
||||
auto activeConnection = ActiveConnection::Create(dbusDispatcher,activeConnectionPath);
|
||||
auto activeConnection = ActiveConnection::Create(dbusDispatcher, activeConnectionPath);
|
||||
std::string activeSsid = activeConnection->Id();
|
||||
auto it = map.find(activeSsid);
|
||||
if (it != map.end())
|
||||
{
|
||||
it->second.connected = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
std::vector<NetworkSortRecord> records;
|
||||
records.reserve(map.size());
|
||||
for (auto & mapEntry: map)
|
||||
for (auto &mapEntry : map)
|
||||
{
|
||||
records.push_back(mapEntry.second);
|
||||
}
|
||||
std::sort(records.begin(),records.end(), [](const NetworkSortRecord&left, const NetworkSortRecord &right)
|
||||
{
|
||||
std::sort(records.begin(), records.end(), [](const NetworkSortRecord &left, const NetworkSortRecord &right)
|
||||
{
|
||||
if (left.connected != right.connected)
|
||||
{
|
||||
return left.connected > right.connected;
|
||||
@@ -573,27 +590,25 @@ void HotspotManagerImpl::UpdateKnownNetworks(
|
||||
{
|
||||
return left.strength > right.strength;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return false; });
|
||||
if (records.size() > 10)
|
||||
{
|
||||
records.resize(10);
|
||||
}
|
||||
std::vector<std::string> result;
|
||||
result.reserve(records.size());
|
||||
for (auto &record: records)
|
||||
for (auto &record : records)
|
||||
{
|
||||
result.push_back(std::move(record.ssid));
|
||||
}
|
||||
{
|
||||
std::lock_guard lock { this->knownWifiNetworksMutex };
|
||||
std::lock_guard lock{this->knownWifiNetworksMutex};
|
||||
this->knownWifiNetworks = std::move(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::vector<AccessPoint::ptr> HotspotManagerImpl::GetAllAccessPoints() {
|
||||
std::vector<AccessPoint::ptr> HotspotManagerImpl::GetAllAccessPoints()
|
||||
{
|
||||
std::vector<AccessPoint::ptr> accessPoints;
|
||||
|
||||
for (const auto &accessPointPath : wlanWirelessDevice->AccessPoints())
|
||||
@@ -602,15 +617,14 @@ std::vector<AccessPoint::ptr> HotspotManagerImpl::GetAllAccessPoints() {
|
||||
accessPoints.push_back(std::move(accessPoint));
|
||||
}
|
||||
return accessPoints;
|
||||
|
||||
}
|
||||
std::vector<std::vector<uint8_t>> HotspotManagerImpl::GetKnownVisibleAccessPoints(const std::vector<ssid_t>&allAccessPoints)
|
||||
std::vector<std::vector<uint8_t>> HotspotManagerImpl::GetKnownVisibleAccessPoints(const std::vector<ssid_t> &allAccessPoints)
|
||||
{
|
||||
std::vector<std::vector<uint8_t>> knownSsids = this->GetAllAutoConnectSsids();
|
||||
|
||||
std::unordered_set<std::vector<uint8_t>, VectorHash<uint8_t>> index{knownSsids.begin(), knownSsids.end()};
|
||||
|
||||
std::vector<ssid_t> result;
|
||||
std::vector<ssid_t> result;
|
||||
std::vector<AccessPoint::ptr> accessPoints;
|
||||
|
||||
for (const auto &accessPoint : allAccessPoints)
|
||||
@@ -684,14 +698,16 @@ void HotspotManagerImpl::onAccessPointChanged()
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<std::vector<uint8_t>> GetAccessPointSsids(std::vector<AccessPoint::ptr>&accessPoints)
|
||||
static std::vector<std::vector<uint8_t>> GetAccessPointSsids(std::vector<AccessPoint::ptr> &accessPoints)
|
||||
{
|
||||
std::vector<std::vector<uint8_t>> result;
|
||||
for (const auto&accessPoint: accessPoints)
|
||||
for (const auto &accessPoint : accessPoints)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
result.push_back(accessPoint->Ssid());
|
||||
} catch (const std::exception&ignored)
|
||||
}
|
||||
catch (const std::exception &ignored)
|
||||
{
|
||||
// race to get a disappearing ssid. Ignore the error.
|
||||
}
|
||||
@@ -700,8 +716,10 @@ static std::vector<std::vector<uint8_t>> GetAccessPointSsids(std::vector<AccessP
|
||||
}
|
||||
void HotspotManagerImpl::MaybeStartHotspot()
|
||||
{
|
||||
if (this->state == State::Error) return;
|
||||
if (this->closed) return;
|
||||
if (this->state == State::Error)
|
||||
return;
|
||||
if (this->closed)
|
||||
return;
|
||||
|
||||
if (!wlanDevice || !wlanWirelessDevice)
|
||||
{
|
||||
@@ -711,12 +729,12 @@ void HotspotManagerImpl::MaybeStartHotspot()
|
||||
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 = this->wifiConfigSettings.WantsHotspot(
|
||||
this->UpdateKnownNetworks(connectableSsids, allAccessPoints);
|
||||
|
||||
this->ethernetConnected,connectableSsids,allAccessPointSsids);
|
||||
bool wantsHotspot = this->wifiConfigSettings.WantsHotspot(
|
||||
|
||||
this->ethernetConnected, connectableSsids, allAccessPointSsids);
|
||||
|
||||
if (this->state == State::Monitoring && wantsHotspot)
|
||||
{
|
||||
@@ -764,7 +782,7 @@ Connection::ptr HotspotManagerImpl::FindExistingConnection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -874,28 +892,26 @@ void HotspotManagerImpl::StopHotspot()
|
||||
{
|
||||
if (activeConnection)
|
||||
{
|
||||
FireNetworkChanging();
|
||||
networkManager->DeactivateConnection(activeConnection->getObjectPath());
|
||||
activeConnection = nullptr;
|
||||
|
||||
FireNetworkChanging();
|
||||
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error("HotspotManager: Failed to deactivate hotspot.");
|
||||
Lv2Log::error(SS("HotspotManager: Failed to deactivate hotspot. " << e.what()));
|
||||
activeConnection = nullptr;
|
||||
}
|
||||
if (this->state == State::HotspotConnected || this->state == State::HotspotConnecting)
|
||||
{
|
||||
Lv2Log::info("HotspotManager: state=HotspotMonitoring");
|
||||
Lv2Log::debug("HotspotManager: state=HotspotMonitoring");
|
||||
SetState(State::Monitoring);
|
||||
|
||||
Lv2Log::info("HotspotManager: PiPedal hotspot disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
static const std::chrono::seconds scanInterval { 60};
|
||||
static const std::chrono::seconds scanInterval{60};
|
||||
|
||||
void HotspotManagerImpl::StartScanTimer()
|
||||
{
|
||||
@@ -904,7 +920,8 @@ void HotspotManagerImpl::StartScanTimer()
|
||||
}
|
||||
void HotspotManagerImpl::StopScanTimer()
|
||||
{
|
||||
if (this->scanTimerHandle) {
|
||||
if (this->scanTimerHandle)
|
||||
{
|
||||
dbusDispatcher.CancelPost(this->scanTimerHandle);
|
||||
this->scanTimerHandle = 0;
|
||||
}
|
||||
@@ -913,14 +930,17 @@ void HotspotManagerImpl::ScanNow()
|
||||
{
|
||||
this->scanTimerHandle = 0;
|
||||
|
||||
if (wlanWirelessDevice) {
|
||||
if (wlanWirelessDevice)
|
||||
{
|
||||
|
||||
std::map<std::string, sdbus::Variant> options;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
Lv2Log::debug("Scanning");
|
||||
wlanWirelessDevice->RequestScan(options);
|
||||
} catch (const std::exception &e)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error(SS("HotspotMonitor: Wi-Fi RequestScan failed." << e.what()));
|
||||
return;
|
||||
@@ -928,44 +948,42 @@ void HotspotManagerImpl::ScanNow()
|
||||
|
||||
this->scanTimerHandle = this->dbusDispatcher.PostDelayed(
|
||||
std::chrono::duration_cast<std::chrono::steady_clock::duration>(scanInterval),
|
||||
[this]() {
|
||||
[this]()
|
||||
{
|
||||
ScanNow();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HotspotManagerImpl::PostHandle HotspotManagerImpl::Post(PostCallback&&fn)
|
||||
HotspotManagerImpl::PostHandle HotspotManagerImpl::Post(PostCallback &&fn)
|
||||
{
|
||||
return dbusDispatcher.Post(std::move(fn));
|
||||
}
|
||||
HotspotManagerImpl::PostHandle HotspotManagerImpl::PostDelayed(const clock::duration&delay,PostCallback&&fn)
|
||||
HotspotManagerImpl::PostHandle HotspotManagerImpl::PostDelayed(const clock::duration &delay, PostCallback &&fn)
|
||||
{
|
||||
return dbusDispatcher.PostDelayed(delay,std::move(fn));
|
||||
|
||||
return dbusDispatcher.PostDelayed(delay, std::move(fn));
|
||||
}
|
||||
bool HotspotManagerImpl::CancelPost(PostHandle handle) {
|
||||
bool HotspotManagerImpl::CancelPost(PostHandle handle)
|
||||
{
|
||||
return dbusDispatcher.CancelPost(handle);
|
||||
}
|
||||
|
||||
void HotspotManagerImpl::SetNetworkChangingListener(NetworkChangingListener &&listener)
|
||||
void HotspotManagerImpl::SetNetworkChangingListener(NetworkChangingListener &&listener)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock { this->networkChangingListenerMutex};
|
||||
std::lock_guard<std::recursive_mutex> lock{this->networkChangingListenerMutex};
|
||||
this->networkChangingListener = std::move(listener);
|
||||
}
|
||||
void HotspotManagerImpl::FireNetworkChanging() {
|
||||
std::lock_guard<std::recursive_mutex> lock { this->networkChangingListenerMutex};
|
||||
void HotspotManagerImpl::FireNetworkChanging()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock{this->networkChangingListenerMutex};
|
||||
if (this->networkChangingListener)
|
||||
{
|
||||
this->networkChangingListener(this->ethernetConnected,!!activeConnection);
|
||||
this->networkChangingListener(this->ethernetConnected, !!activeConnection);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::string> HotspotManagerImpl::GetKnownWifiNetworks()
|
||||
std::vector<std::string> HotspotManagerImpl::GetKnownWifiNetworks()
|
||||
{
|
||||
std::lock_guard lock(knownWifiNetworksMutex); // pushed off the service thread.
|
||||
return this->knownWifiNetworks;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+84
-30
@@ -39,6 +39,9 @@
|
||||
#include "DBusToLv2Log.hpp"
|
||||
#include "SysExec.hpp"
|
||||
#include "Updater.hpp"
|
||||
#include "util.hpp"
|
||||
#include "DBusLog.hpp"
|
||||
#include "AvahiService.hpp"
|
||||
|
||||
#ifndef NO_MLOCK
|
||||
#include <sys/mman.h>
|
||||
@@ -88,6 +91,7 @@ PiPedalModel::PiPedalModel()
|
||||
|
||||
|
||||
DbusLogToLv2Log();
|
||||
SetDBusLogLevel(DBusLogLevel::Info);
|
||||
|
||||
hotspotManager = HotspotManager::Create();
|
||||
hotspotManager->SetNetworkChangingListener(
|
||||
@@ -100,24 +104,41 @@ PiPedalModel::PiPedalModel()
|
||||
|
||||
void PiPedalModel::Close()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
std::unique_ptr<AudioHost> oldAudioHost;
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
|
||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||
{
|
||||
t[i] = this->subscribers[i];
|
||||
}
|
||||
size_t n = this->subscribers.size();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
t[i]->Close();
|
||||
}
|
||||
delete[] t;
|
||||
if (avahiService) {
|
||||
this->avahiService = nullptr; // and close.
|
||||
}
|
||||
|
||||
if (audioHost)
|
||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||
{
|
||||
t[i] = this->subscribers[i];
|
||||
}
|
||||
size_t n = this->subscribers.size();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
t[i]->Close();
|
||||
}
|
||||
delete[] t;
|
||||
|
||||
this->subscribers.resize(0);
|
||||
|
||||
oldAudioHost = std::move(this->audioHost);
|
||||
} // end lock.
|
||||
|
||||
// lockless to avoid deadlocks while shutting down the audio thread.
|
||||
if (oldAudioHost)
|
||||
{
|
||||
audioHost->Close();
|
||||
oldAudioHost->Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -977,11 +998,11 @@ void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSet
|
||||
#if NEW_WIFI_CONFIG
|
||||
if (this->storage.SetWifiConfigSettings(wifiConfigSettings))
|
||||
{
|
||||
this->UpdateDnsSd();
|
||||
if (this->hotspotManager)
|
||||
{
|
||||
this->hotspotManager->Reload();
|
||||
}
|
||||
this->UpdateDnsSd();
|
||||
}
|
||||
#else
|
||||
this->storage.SetWifiConfigSettings(wifiConfigSettings);
|
||||
@@ -1022,20 +1043,28 @@ static std::string GetP2pdName()
|
||||
|
||||
void PiPedalModel::UpdateDnsSd()
|
||||
{
|
||||
// avahiService.Unannounce(); let Announce decide whether it wants to unannounce or update.
|
||||
|
||||
if (!avahiService)
|
||||
{
|
||||
throw std::runtime_error("Not ready.");
|
||||
}
|
||||
ServiceConfiguration deviceIdFile;
|
||||
deviceIdFile.Load();
|
||||
|
||||
std::string p2pdName = GetP2pdName();
|
||||
if (p2pdName != "")
|
||||
WifiConfigSettings wifiSettings;
|
||||
wifiSettings.Load();
|
||||
std::string serviceName = wifiSettings.hotspotName_;
|
||||
if (serviceName == "")
|
||||
{
|
||||
deviceIdFile.deviceName = p2pdName;
|
||||
serviceName = deviceIdFile.deviceName;
|
||||
}
|
||||
if (serviceName == "")
|
||||
{
|
||||
serviceName = "pipedal";
|
||||
}
|
||||
|
||||
if (deviceIdFile.deviceName != "" && deviceIdFile.uuid != "")
|
||||
std::string hostName = GetHostName();
|
||||
if (serviceName != "" && deviceIdFile.uuid != "")
|
||||
{
|
||||
avahiService.Announce(webPort, deviceIdFile.deviceName, deviceIdFile.uuid, "pipedal");
|
||||
avahiService->Announce(webPort, serviceName, deviceIdFile.uuid, hostName,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1376,12 +1405,19 @@ void PiPedalModel::UpdateRealtimeVuSubscriptions()
|
||||
addedInstances.insert(activeVuSubscriptions[i].instanceid);
|
||||
}
|
||||
}
|
||||
std::vector<int64_t> instanceids(addedInstances.begin(), addedInstances.end());
|
||||
audioHost->SetVuSubscriptions(instanceids);
|
||||
if (audioHost)
|
||||
{
|
||||
std::vector<int64_t> instanceids(addedInstances.begin(), addedInstances.end());
|
||||
audioHost->SetVuSubscriptions(instanceids);
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::UpdateRealtimeMonitorPortSubscriptions()
|
||||
{
|
||||
if (!audioHost)
|
||||
{
|
||||
return;
|
||||
}
|
||||
audioHost->SetMonitorPortSubscriptions(this->activeMonitorPortSubscriptions);
|
||||
}
|
||||
|
||||
@@ -1484,7 +1520,10 @@ void PiPedalModel::SendSetPatchProperty(
|
||||
clientId, instanceId, urid, atomValue, nullptr, onError);
|
||||
|
||||
outstandingParameterRequests.push_back(request);
|
||||
this->audioHost->sendRealtimeParameterRequest(request);
|
||||
if (this->audioHost)
|
||||
{
|
||||
this->audioHost->sendRealtimeParameterRequest(request);
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::SendGetPatchProperty(
|
||||
@@ -1545,7 +1584,10 @@ void PiPedalModel::SendGetPatchProperty(
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
outstandingParameterRequests.push_back(request);
|
||||
this->audioHost->sendRealtimeParameterRequest(request);
|
||||
if (this->audioHost)
|
||||
{
|
||||
this->audioHost->sendRealtimeParameterRequest(request);
|
||||
}
|
||||
}
|
||||
|
||||
BankIndex PiPedalModel::GetBankIndex() const
|
||||
@@ -1802,7 +1844,10 @@ void PiPedalModel::DeleteAtomOutputListeners(int64_t clientId)
|
||||
--i;
|
||||
}
|
||||
}
|
||||
audioHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
||||
if (audioHost)
|
||||
{
|
||||
audioHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::DeleteMidiListeners(int64_t clientId)
|
||||
@@ -1816,7 +1861,10 @@ void PiPedalModel::DeleteMidiListeners(int64_t clientId)
|
||||
--i;
|
||||
}
|
||||
}
|
||||
audioHost->SetListenForMidiEvent(midiEventListeners.size() != 0);
|
||||
if (audioHost)
|
||||
{
|
||||
audioHost->SetListenForMidiEvent(midiEventListeners.size() != 0);
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::OnPatchSetReply(uint64_t instanceId, LV2_URID patchSetProperty, const LV2_Atom *atomValue)
|
||||
@@ -2248,6 +2296,12 @@ static bool HasAlsaDevice(const std::vector<AlsaDeviceInfo> devices, const std::
|
||||
|
||||
void PiPedalModel::StartHotspotMonitoring()
|
||||
{
|
||||
this->avahiService = std::make_unique<AvahiService>();
|
||||
|
||||
SetThreadName("avahi"); // hack to name the avahi service thread.
|
||||
UpdateDnsSd(); // now that the server is running, publish a DNS-SD announcement.
|
||||
SetThreadName("main");
|
||||
|
||||
this->hotspotManager->Open();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include "WifiDirectConfigSettings.hpp"
|
||||
#include "AdminClient.hpp"
|
||||
#include "AvahiService.hpp"
|
||||
#include <thread>
|
||||
#include "Promise.hpp"
|
||||
#include "AtomConverter.hpp"
|
||||
@@ -49,6 +48,7 @@ namespace pipedal
|
||||
struct RealtimeNextMidiProgramRequest;
|
||||
class Lv2PluginChangeMonitor;
|
||||
class Updater;
|
||||
class AvahiService;
|
||||
|
||||
class IPiPedalModelSubscriber
|
||||
{
|
||||
@@ -113,7 +113,7 @@ namespace pipedal
|
||||
|
||||
std::vector<MidiBinding> systemMidiBindings;
|
||||
|
||||
AvahiService avahiService;
|
||||
std::unique_ptr<AvahiService> avahiService;
|
||||
uint16_t webPort;
|
||||
|
||||
PiPedalAlsaDevices alsaDevices;
|
||||
@@ -197,6 +197,7 @@ namespace pipedal
|
||||
std::vector<RealtimePatchPropertyRequest *> outstandingParameterRequests;
|
||||
|
||||
IPiPedalModelSubscriber *GetNotificationSubscriber(int64_t clientId);
|
||||
std::atomic<bool> closed = false;
|
||||
|
||||
private: // IAudioHostCallbacks
|
||||
virtual void OnNotifyLv2StateChanged(uint64_t instanceId) override;
|
||||
|
||||
@@ -516,26 +516,47 @@ private:
|
||||
|
||||
std::mutex activePortMonitorsMutex;
|
||||
std::vector<std::shared_ptr<PortMonitorSubscription>> activePortMonitors;
|
||||
std::atomic<bool> closed = false;
|
||||
|
||||
public:
|
||||
virtual int64_t GetClientId() { return clientId; }
|
||||
|
||||
virtual ~PiPedalSocketHandler()
|
||||
{
|
||||
if (!closed)
|
||||
{
|
||||
FinalCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
bool finalCleanup = false;
|
||||
void FinalCleanup()
|
||||
{
|
||||
if (finalCleanup) return;
|
||||
finalCleanup = true;
|
||||
// avoid use after free.
|
||||
for (int i = 0; i < this->activePortMonitors.size(); ++i)
|
||||
{
|
||||
model.UnmonitorPort(activePortMonitors[i]->subscriptionHandle);
|
||||
}
|
||||
activePortMonitors.resize(0);
|
||||
for (int i = 0; i < this->activeVuSubscriptions.size(); ++i)
|
||||
{
|
||||
model.RemoveVuSubscription(activeVuSubscriptions[i].subscriptionHandle);
|
||||
}
|
||||
activeVuSubscriptions.resize(0);
|
||||
|
||||
model.RemoveNotificationSubsription(this);
|
||||
|
||||
}
|
||||
|
||||
virtual void Close()
|
||||
{
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
|
||||
FinalCleanup(); // do it while we can. &model will no longer be valid after this. ( :-( )
|
||||
|
||||
SocketHandler::Close();
|
||||
}
|
||||
|
||||
@@ -935,6 +956,10 @@ public:
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (closed)
|
||||
{
|
||||
this->SendError(replyTo, "Server has shut down.");
|
||||
}
|
||||
if (message == "setControl")
|
||||
{
|
||||
ControlChangedBody message;
|
||||
|
||||
+4
-1
@@ -1181,7 +1181,7 @@ void Updater::ValidateSignature(const std::filesystem::path &file, const std::fi
|
||||
<< " --verify "
|
||||
<< signatureFile << " " << file;
|
||||
|
||||
Lv2Log::info(SS("/usr/bin/gpg " << ss.str()));
|
||||
Lv2Log::debug(SS("/usr/bin/gpg " << ss.str()));
|
||||
auto gpgOutput = sysExecForOutput("/usr/bin/gpg", ss.str());
|
||||
if (gpgOutput.exitCode != EXIT_SUCCESS)
|
||||
{
|
||||
@@ -1191,17 +1191,20 @@ void Updater::ValidateSignature(const std::filesystem::path &file, const std::fi
|
||||
|
||||
if (!IsSignatureGood(gpgText))
|
||||
{
|
||||
Lv2Log::error(gpgOutput.output);
|
||||
throw std::runtime_error("Update signature is not valid.");
|
||||
}
|
||||
std::string keyId = getFingerprint(gpgText);
|
||||
|
||||
if (keyId != UPDATE_GPG_FINGERPRINT && keyId != UPDATE_GPG_FINGERPRINT2)
|
||||
{
|
||||
Lv2Log::error(gpgOutput.output);
|
||||
throw std::runtime_error(SS("Update signature has the wrong id: " << keyId));
|
||||
}
|
||||
std::string origin = getAddress(gpgText);
|
||||
if (origin != UPDATE_GPG_ADDRESS && origin != UPDATE_GPG_ADDRESS2)
|
||||
{
|
||||
Lv2Log::error(gpgOutput.output);
|
||||
throw std::runtime_error(SS("Update signature has an incorrect address." << origin));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-12
@@ -557,16 +557,6 @@ pipedal::last_modified(const std::filesystem::path &path)
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getHostName()
|
||||
{
|
||||
char buff[512];
|
||||
if (gethostname(buff, sizeof(buff)) == 0)
|
||||
{
|
||||
buff[511] = '\0';
|
||||
return buff;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string getIpv4Address(const std::string interface)
|
||||
{
|
||||
@@ -1165,7 +1155,7 @@ namespace pipedal
|
||||
|
||||
std::stringstream ss;
|
||||
ss << port;
|
||||
// m_endpoint.listen(this->address, ss.str());
|
||||
//m_endpoint.listen(this->address, ss.str());
|
||||
m_endpoint.listen(tcp::v6(), (uint16_t)port);
|
||||
m_endpoint.start_accept();
|
||||
|
||||
@@ -1305,7 +1295,7 @@ std::shared_ptr<WebServer> pipedal::WebServer::create(
|
||||
|
||||
void WebServerImpl::DisplayIpAddresses()
|
||||
{
|
||||
std::string hostName = getHostName();
|
||||
std::string hostName = GetHostName();
|
||||
if (hostName.length() != 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
|
||||
/// Write a string message to the given channel
|
||||
/**
|
||||
* @param channel The channel to write to
|
||||
* @param channel The channel to write tosu
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level channel, std::string const & msg) {
|
||||
@@ -126,19 +126,19 @@ public:
|
||||
{
|
||||
case elevel::devel:
|
||||
case elevel::library:
|
||||
Lv2Log::debug(msg);
|
||||
Lv2Log::debug("WebServer: %s",msg.c_str());
|
||||
break;
|
||||
case elevel::info:
|
||||
Lv2Log::info(msg);
|
||||
Lv2Log::info("WebServer: %s",msg.c_str());
|
||||
break;
|
||||
case elevel::warn:
|
||||
Lv2Log::warning(msg);
|
||||
Lv2Log::warning("WebServer: %s",msg.c_str());
|
||||
break;
|
||||
case elevel::rerror:
|
||||
Lv2Log::error(msg);
|
||||
Lv2Log::error("WebServer: %s",msg.c_str());
|
||||
break;
|
||||
case elevel::fatal:
|
||||
Lv2Log::error("Fatal error: " + msg);
|
||||
Lv2Log::error("WebServer fatal error: %s",msg.c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -159,7 +159,7 @@ public:
|
||||
}
|
||||
|
||||
bool dynamic_test(level channel) {
|
||||
return (m_channels) & channel != 0;
|
||||
return (m_channels & channel) != 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
+12
-5
@@ -81,10 +81,18 @@ static bool isJackServiceRunning()
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
|
||||
|
||||
static void AsanCheck()
|
||||
{
|
||||
char *t = new char[5];
|
||||
t[5] = 'x';
|
||||
delete t;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
umask(002); // newly created files in /var/pipedal get 775-ish permissions, which improves debugging/live-service interaction.
|
||||
#endif
|
||||
@@ -269,7 +277,6 @@ int main(int argc, char *argv[])
|
||||
(unsigned long)getpid());
|
||||
}
|
||||
|
||||
model.StartHotspotMonitoring();
|
||||
model.WaitForAudioDeviceToComeOnline();
|
||||
|
||||
|
||||
@@ -317,9 +324,9 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
server->RunInBackground(-1);
|
||||
|
||||
SetThreadName("avahi");
|
||||
model.UpdateDnsSd(); // now that the server is running, publish a DNS-SD announcement.
|
||||
SetThreadName("main");
|
||||
|
||||
model.StartHotspotMonitoring();
|
||||
|
||||
|
||||
{
|
||||
sigwait(&sigSet, &sig);
|
||||
|
||||
Reference in New Issue
Block a user