Routage complexe #4
+6
-8
@@ -447,19 +447,18 @@ app.whenReady().then(async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('server-audio-users:create', (event, { name, group, input_channel, output_channel, publish }) => {
|
ipcMain.handle('server-audio-users:create', (event, { name, group, input_channel, output_channel }) => {
|
||||||
try {
|
try {
|
||||||
const config = readConfig();
|
const config = readConfig();
|
||||||
const users = config.server_audio_users || [];
|
const users = config.server_audio_users || [];
|
||||||
if (users.find(u => u.name === name)) {
|
if (users.find(u => u.name === name)) {
|
||||||
return { success: false, error: `Un utilisateur "${name}" existe déjà` };
|
return { success: false, error: `Un utilisateur "${name}" existe déjà` };
|
||||||
}
|
}
|
||||||
const isPublish = publish !== false;
|
const parsedInput = input_channel !== null && input_channel !== undefined ? parseInt(input_channel) : null;
|
||||||
const user = {
|
const user = {
|
||||||
name,
|
name,
|
||||||
group,
|
group,
|
||||||
publish: isPublish,
|
input_channel: parsedInput,
|
||||||
input_channel: isPublish && input_channel !== null && input_channel !== undefined ? parseInt(input_channel) : null,
|
|
||||||
output_channel: output_channel !== null && output_channel !== '' ? parseInt(output_channel) : null
|
output_channel: output_channel !== null && output_channel !== '' ? parseInt(output_channel) : null
|
||||||
};
|
};
|
||||||
config.server_audio_users = [...users, user];
|
config.server_audio_users = [...users, user];
|
||||||
@@ -470,18 +469,17 @@ app.whenReady().then(async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('server-audio-users:update', (event, { name, group, input_channel, output_channel, publish }) => {
|
ipcMain.handle('server-audio-users:update', (event, { name, group, input_channel, output_channel }) => {
|
||||||
try {
|
try {
|
||||||
const config = readConfig();
|
const config = readConfig();
|
||||||
const users = config.server_audio_users || [];
|
const users = config.server_audio_users || [];
|
||||||
const idx = users.findIndex(u => u.name === name);
|
const idx = users.findIndex(u => u.name === name);
|
||||||
if (idx === -1) return { success: false, error: `Utilisateur "${name}" introuvable` };
|
if (idx === -1) return { success: false, error: `Utilisateur "${name}" introuvable` };
|
||||||
const isPublish = publish !== false;
|
const parsedInput = input_channel !== null && input_channel !== undefined ? parseInt(input_channel) : null;
|
||||||
config.server_audio_users[idx] = {
|
config.server_audio_users[idx] = {
|
||||||
name,
|
name,
|
||||||
group,
|
group,
|
||||||
publish: isPublish,
|
input_channel: parsedInput,
|
||||||
input_channel: isPublish && input_channel !== null && input_channel !== undefined ? parseInt(input_channel) : null,
|
|
||||||
output_channel: output_channel !== null && output_channel !== '' ? parseInt(output_channel) : null
|
output_channel: output_channel !== null && output_channel !== '' ? parseInt(output_channel) : null
|
||||||
};
|
};
|
||||||
writeConfig(config);
|
writeConfig(config);
|
||||||
|
|||||||
+14
-29
@@ -803,7 +803,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const action = btn.dataset.sauAction;
|
const action = btn.dataset.sauAction;
|
||||||
const name = btn.dataset.sauName;
|
const name = btn.dataset.sauName;
|
||||||
if (action === 'edit') {
|
if (action === 'edit') {
|
||||||
await editServerAudioUser(name, btn.dataset.sauGroup, btn.dataset.sauInput, btn.dataset.sauOutput, btn.dataset.sauPublish !== 'false');
|
await editServerAudioUser(name, btn.dataset.sauGroup, btn.dataset.sauInput, btn.dataset.sauOutput);
|
||||||
} else if (action === 'delete') {
|
} else if (action === 'delete') {
|
||||||
await deleteServerAudioUser(name);
|
await deleteServerAudioUser(name);
|
||||||
}
|
}
|
||||||
@@ -834,19 +834,14 @@ function renderServerAudioUsers() {
|
|||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<table class="sau-table">
|
<table class="sau-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Nom</th><th>Groupe</th><th>Mode</th><th>Entrée</th><th>Sortie</th><th></th></tr>
|
<tr><th>Nom</th><th>Groupe</th><th>Entrée</th><th>Sortie</th><th></th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
${users.map(u => {
|
${users.map(u => `
|
||||||
const isListenOnly = u.publish === false;
|
|
||||||
const modeLabel = isListenOnly ? '<span class="ch-badge ch-badge-listen">👂 Écoute</span>' : '<span class="ch-badge ch-badge-active">🎤 Actif</span>';
|
|
||||||
const inputLabel = isListenOnly ? '<span class="ch-badge ch-badge-muted">—</span>' : `<span class="ch-badge">${chLabel(u.input_channel, 'input')}</span>`;
|
|
||||||
return `
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="sau-name">${escapeHtml(u.name)}</td>
|
<td class="sau-name">${escapeHtml(u.name)}</td>
|
||||||
<td><span class="ch-badge ch-badge-group">${escapeHtml(u.group)}</span></td>
|
<td><span class="ch-badge ch-badge-group">${escapeHtml(u.group)}</span></td>
|
||||||
<td>${modeLabel}</td>
|
<td><span class="ch-badge">${chLabel(u.input_channel, 'input')}</span></td>
|
||||||
<td>${inputLabel}</td>
|
|
||||||
<td><span class="ch-badge">${chLabel(u.output_channel, 'output')}</span></td>
|
<td><span class="ch-badge">${chLabel(u.output_channel, 'output')}</span></td>
|
||||||
<td class="sau-actions">
|
<td class="sau-actions">
|
||||||
<button class="btn btn-small btn-secondary"
|
<button class="btn btn-small btn-secondary"
|
||||||
@@ -854,14 +849,12 @@ function renderServerAudioUsers() {
|
|||||||
data-sau-name="${escapeHtml(u.name)}"
|
data-sau-name="${escapeHtml(u.name)}"
|
||||||
data-sau-group="${escapeHtml(u.group)}"
|
data-sau-group="${escapeHtml(u.group)}"
|
||||||
data-sau-input="${u.input_channel}"
|
data-sau-input="${u.input_channel}"
|
||||||
data-sau-output="${u.output_channel}"
|
data-sau-output="${u.output_channel}">Éditer</button>
|
||||||
data-sau-publish="${u.publish !== false}">Éditer</button>
|
|
||||||
<button class="btn btn-small btn-danger"
|
<button class="btn btn-small btn-danger"
|
||||||
data-sau-action="delete"
|
data-sau-action="delete"
|
||||||
data-sau-name="${escapeHtml(u.name)}">✕</button>
|
data-sau-name="${escapeHtml(u.name)}">✕</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>`;
|
</tr>`).join('')}
|
||||||
}).join('')}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>`;
|
</table>`;
|
||||||
}
|
}
|
||||||
@@ -881,9 +874,7 @@ function buildChannelOptions(dir) {
|
|||||||
label: names[i] ? `Ch ${i}: ${names[i]}` : `Ch ${i}`
|
label: names[i] ? `Ch ${i}: ${names[i]}` : `Ch ${i}`
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (dir === 'output') {
|
opts.unshift({ value: '', label: dir === 'input' ? 'Aucune entrée' : 'Aucune sortie' });
|
||||||
opts.unshift({ value: '', label: 'Aucune sortie' });
|
|
||||||
}
|
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
@@ -897,8 +888,8 @@ async function addServerAudioUser() {
|
|||||||
const outOpts = buildChannelOptions('output');
|
const outOpts = buildChannelOptions('output');
|
||||||
|
|
||||||
const inputField = inOpts
|
const inputField = inOpts
|
||||||
? { name: 'input_channel', label: 'Canal d\'entrée', type: 'select', options: inOpts, default: '0' }
|
? { name: 'input_channel', label: 'Canal d\'entrée', type: 'select', options: inOpts, default: '' }
|
||||||
: { name: 'input_channel', label: 'Canal entrée (index)', type: 'number', default: 0, min: 0, max: 63 };
|
: { name: 'input_channel', label: 'Canal entrée (index, vide = aucune)', type: 'number', default: '', min: 0, max: 63 };
|
||||||
const outputField = outOpts
|
const outputField = outOpts
|
||||||
? { name: 'output_channel', label: 'Canal de sortie', type: 'select', options: outOpts, default: '' }
|
? { name: 'output_channel', label: 'Canal de sortie', type: 'select', options: outOpts, default: '' }
|
||||||
: { name: 'output_channel', label: 'Canal sortie (index, vide = aucune)', type: 'number', default: '', min: 0, max: 63 };
|
: { name: 'output_channel', label: 'Canal sortie (index, vide = aucune)', type: 'number', default: '', min: 0, max: 63 };
|
||||||
@@ -908,7 +899,6 @@ async function addServerAudioUser() {
|
|||||||
fields: [
|
fields: [
|
||||||
{ name: 'name', label: 'Nom (identifiant unique, ex: foh)' },
|
{ name: 'name', label: 'Nom (identifiant unique, ex: foh)' },
|
||||||
{ name: 'group', label: 'Groupe', type: 'select', options: groupOptions, default: defaultGroup },
|
{ name: 'group', label: 'Groupe', type: 'select', options: groupOptions, default: defaultGroup },
|
||||||
{ name: 'publish', label: 'Publier audio vers le groupe (décocher = écoute seule)', type: 'checkbox', default: true },
|
|
||||||
inputField,
|
inputField,
|
||||||
outputField
|
outputField
|
||||||
],
|
],
|
||||||
@@ -917,12 +907,10 @@ async function addServerAudioUser() {
|
|||||||
|
|
||||||
if (!result || !result.name.trim()) return;
|
if (!result || !result.name.trim()) return;
|
||||||
|
|
||||||
const publish = result.publish !== false && result.publish !== 'false';
|
|
||||||
const res = await window.electronAPI.serverAudioUsers.create({
|
const res = await window.electronAPI.serverAudioUsers.create({
|
||||||
name: result.name.trim(),
|
name: result.name.trim(),
|
||||||
group: result.group,
|
group: result.group,
|
||||||
publish,
|
input_channel: result.input_channel !== '' ? parseInt(result.input_channel) : null,
|
||||||
input_channel: publish ? (result.input_channel !== '' ? parseInt(result.input_channel) : null) : null,
|
|
||||||
output_channel: result.output_channel !== '' ? parseInt(result.output_channel) : null
|
output_channel: result.output_channel !== '' ? parseInt(result.output_channel) : null
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -934,17 +922,17 @@ async function addServerAudioUser() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function editServerAudioUser(name, group, input_channel, output_channel, publish = true) {
|
async function editServerAudioUser(name, group, input_channel, output_channel) {
|
||||||
const groupsData = await window.electronAPI.groups.list();
|
const groupsData = await window.electronAPI.groups.list();
|
||||||
const groupOptions = (groupsData.groups || []).map(g => ({ value: slugify(g.name), label: g.name }));
|
const groupOptions = (groupsData.groups || []).map(g => ({ value: slugify(g.name), label: g.name }));
|
||||||
|
|
||||||
const inOpts = buildChannelOptions('input');
|
const inOpts = buildChannelOptions('input');
|
||||||
const outOpts = buildChannelOptions('output');
|
const outOpts = buildChannelOptions('output');
|
||||||
|
|
||||||
const inputDefault = input_channel !== null && input_channel !== undefined && input_channel !== 'null' ? String(input_channel) : '0';
|
const inputDefault = input_channel !== null && input_channel !== undefined && input_channel !== 'null' ? String(input_channel) : '';
|
||||||
const inputField = inOpts
|
const inputField = inOpts
|
||||||
? { name: 'input_channel', label: 'Canal d\'entrée', type: 'select', options: inOpts, default: inputDefault }
|
? { name: 'input_channel', label: 'Canal d\'entrée', type: 'select', options: inOpts, default: inputDefault }
|
||||||
: { name: 'input_channel', label: 'Canal entrée (index)', type: 'number', default: inputDefault, min: 0, max: 63 };
|
: { name: 'input_channel', label: 'Canal entrée (index, vide = aucune)', type: 'number', default: inputDefault, min: 0, max: 63 };
|
||||||
const outputDefault = output_channel !== null && output_channel !== undefined && output_channel !== 'null' ? String(output_channel) : '';
|
const outputDefault = output_channel !== null && output_channel !== undefined && output_channel !== 'null' ? String(output_channel) : '';
|
||||||
const outputField = outOpts
|
const outputField = outOpts
|
||||||
? { name: 'output_channel', label: 'Canal de sortie', type: 'select', options: outOpts, default: outputDefault }
|
? { name: 'output_channel', label: 'Canal de sortie', type: 'select', options: outOpts, default: outputDefault }
|
||||||
@@ -954,7 +942,6 @@ async function editServerAudioUser(name, group, input_channel, output_channel, p
|
|||||||
title: `Modifier "${name}"`,
|
title: `Modifier "${name}"`,
|
||||||
fields: [
|
fields: [
|
||||||
{ name: 'group', label: 'Groupe', type: 'select', options: groupOptions, default: group },
|
{ name: 'group', label: 'Groupe', type: 'select', options: groupOptions, default: group },
|
||||||
{ name: 'publish', label: 'Publier audio vers le groupe (décocher = écoute seule)', type: 'checkbox', default: publish },
|
|
||||||
inputField,
|
inputField,
|
||||||
outputField
|
outputField
|
||||||
],
|
],
|
||||||
@@ -963,12 +950,10 @@ async function editServerAudioUser(name, group, input_channel, output_channel, p
|
|||||||
|
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
|
||||||
const newPublish = result.publish !== false && result.publish !== 'false';
|
|
||||||
const res = await window.electronAPI.serverAudioUsers.update({
|
const res = await window.electronAPI.serverAudioUsers.update({
|
||||||
name,
|
name,
|
||||||
group: result.group,
|
group: result.group,
|
||||||
publish: newPublish,
|
input_channel: result.input_channel !== '' ? parseInt(result.input_channel) : null,
|
||||||
input_channel: newPublish ? (result.input_channel !== '' ? parseInt(result.input_channel) : null) : null,
|
|
||||||
output_channel: result.output_channel !== '' ? parseInt(result.output_channel) : null
|
output_channel: result.output_channel !== '' ? parseInt(result.output_channel) : null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1044,24 +1044,6 @@ body {
|
|||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ch-badge-active {
|
|
||||||
background: rgba(76, 175, 80, 0.12);
|
|
||||||
border-color: rgba(76, 175, 80, 0.3);
|
|
||||||
color: #4caf50;
|
|
||||||
font-family: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ch-badge-listen {
|
|
||||||
background: rgba(255, 152, 0, 0.12);
|
|
||||||
border-color: rgba(255, 152, 0, 0.3);
|
|
||||||
color: #ff9800;
|
|
||||||
font-family: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ch-badge-muted {
|
|
||||||
color: var(--text-secondary);
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group-check {
|
.form-group-check {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ class AudioBridgeManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const publish = user.publish !== false;
|
const rawInputChannel = user.input_channel ?? user.inputChannel ?? null;
|
||||||
|
const inputChannel = rawInputChannel !== null && rawInputChannel !== undefined ? rawInputChannel : null;
|
||||||
|
const publish = inputChannel !== null;
|
||||||
|
|
||||||
token.addGrant({
|
token.addGrant({
|
||||||
room: groupId,
|
room: groupId,
|
||||||
@@ -79,12 +81,11 @@ class AudioBridgeManager extends EventEmitter {
|
|||||||
const jwt = await token.toJwt();
|
const jwt = await token.toJwt();
|
||||||
|
|
||||||
const outputChannel = user.output_channel ?? user.outputChannel;
|
const outputChannel = user.output_channel ?? user.outputChannel;
|
||||||
const rawInputChannel = user.input_channel ?? user.inputChannel;
|
|
||||||
|
|
||||||
serverAudioUsers.push({
|
serverAudioUsers.push({
|
||||||
name: user.name,
|
name: user.name,
|
||||||
groupId,
|
groupId,
|
||||||
inputChannel: rawInputChannel !== null && rawInputChannel !== undefined ? rawInputChannel : null,
|
inputChannel,
|
||||||
outputChannel: outputChannel !== null && outputChannel !== undefined ? outputChannel : null,
|
outputChannel: outputChannel !== null && outputChannel !== undefined ? outputChannel : null,
|
||||||
publish,
|
publish,
|
||||||
token: jwt
|
token: jwt
|
||||||
|
|||||||
Reference in New Issue
Block a user