ssh audio forwarding from mac to linux
This commit is contained in:
@@ -29,9 +29,36 @@ const PACKS_DIR = path.join(process.env.HOME || "~", ".config/openpeon/packs");
|
|||||||
const CONFIG_FILE = path.join(process.env.HOME || "~", ".config/openpeon/config.json");
|
const CONFIG_FILE = path.join(process.env.HOME || "~", ".config/openpeon/config.json");
|
||||||
const DEFAULT_PACK = "peon";
|
const DEFAULT_PACK = "peon";
|
||||||
const DEBOUNCE_MS = 500;
|
const DEBOUNCE_MS = 500;
|
||||||
const REMOTE_HOST = "linux-pc"; // SSH host for remote notifications
|
|
||||||
// =======================================
|
// =======================================
|
||||||
|
|
||||||
|
// Get the remote host to SSH back to (the machine the user is physically on)
|
||||||
|
function getRemoteHost(): string | null {
|
||||||
|
// Try SSH_CONNECTION to get client's IP (format: client_ip client_port server_ip server_port)
|
||||||
|
const sshConn = process.env.SSH_CONNECTION || "";
|
||||||
|
const clientIP = sshConn.split(" ")[0];
|
||||||
|
if (clientIP && clientIP !== "::1" && clientIP !== "127.0.0.1") {
|
||||||
|
return clientIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to SSH_CLIENT (older format)
|
||||||
|
const sshClient = process.env.SSH_CLIENT || "";
|
||||||
|
const clientIP2 = sshClient.split(" ")[0];
|
||||||
|
if (clientIP2 && clientIP2 !== "::1" && clientIP2 !== "127.0.0.1") {
|
||||||
|
return clientIP2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map Mac paths to Linux paths for SSH playback
|
||||||
|
function mapPathToRemote(soundPath: string): string {
|
||||||
|
// Mac home → Linux home (different username)
|
||||||
|
if (soundPath.startsWith("/Users/thomasglopes/")) {
|
||||||
|
return soundPath.replace("/Users/thomasglopes/", "/home/thomasgl/");
|
||||||
|
}
|
||||||
|
return soundPath;
|
||||||
|
}
|
||||||
|
|
||||||
// ============ SSH DETECTION ============
|
// ============ SSH DETECTION ============
|
||||||
function isSSH(): boolean {
|
function isSSH(): boolean {
|
||||||
if (
|
if (
|
||||||
@@ -168,31 +195,67 @@ function playSoundLocal(soundPath: string, volume: number): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function playSoundRemote(soundPath: string, volume: number): void {
|
function playSound(soundPath: string, volume: number): void {
|
||||||
// Play sound on remote host via SSH
|
const remoteHost = getRemoteHost();
|
||||||
const vol = Math.round(volume * 100);
|
|
||||||
|
// If in SSH session from Mac, play only on the remote Linux machine (where user physically is)
|
||||||
|
if (remoteHost && isSSH() && process.platform === "darwin") {
|
||||||
|
const remotePath = mapPathToRemote(soundPath);
|
||||||
|
// SSH back to Linux with correct username and mapped path
|
||||||
|
// pw-play expects volume as 0.0-1.0 float
|
||||||
exec(
|
exec(
|
||||||
`ssh -o ConnectTimeout=2 -o BatchMode=yes ${REMOTE_HOST} "pw-play --volume=${vol} '${soundPath}'" 2>/dev/null || true`,
|
`ssh -o ConnectTimeout=2 -o BatchMode=yes thomasgl@${remoteHost} "pw-play --volume=${volume} '${remotePath}' 2>/dev/null" 2>/dev/null || true`,
|
||||||
{ timeout: 5000 }
|
{ timeout: 5000 }
|
||||||
);
|
);
|
||||||
|
return; // Don't play locally - user is on Linux
|
||||||
}
|
}
|
||||||
|
|
||||||
function playSound(soundPath: string, volume: number): void {
|
// If in SSH session from Linux, play only on remote Mac
|
||||||
// Always play locally
|
if (remoteHost && isSSH() && process.platform === "linux") {
|
||||||
|
const vol = Math.round(volume * 100);
|
||||||
|
exec(
|
||||||
|
`ssh -o ConnectTimeout=2 -o BatchMode=yes ${remoteHost} "afplay -v ${vol/100} '${soundPath}' 2>/dev/null" 2>/dev/null || true`,
|
||||||
|
{ timeout: 5000 }
|
||||||
|
);
|
||||||
|
return; // Don't play locally - user is on Mac
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play locally when not in SSH session
|
||||||
playSoundLocal(soundPath, volume);
|
playSoundLocal(soundPath, volume);
|
||||||
|
|
||||||
// If on SSH, also play remotely
|
|
||||||
if (isSSH()) {
|
|
||||||
playSoundRemote(soundPath, volume);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendNotification(title: string, message: string): void {
|
function sendNotification(title: string, message: string): void {
|
||||||
|
const remoteHost = getRemoteHost();
|
||||||
|
|
||||||
|
// If SSH'd from Mac to Linux, send notification to Linux (where user is)
|
||||||
|
if (remoteHost && isSSH() && process.platform === "darwin") {
|
||||||
|
exec(
|
||||||
|
`ssh -o ConnectTimeout=2 -o BatchMode=yes thomasgl@${remoteHost} "notify-send -i ~/.pi/agent/extensions/assets/pi-logo.svg '${title}' '${message}'" 2>/dev/null || true`,
|
||||||
|
{ timeout: 5000 }
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If SSH'd from Linux to Mac, send notification to Mac (where user is)
|
||||||
|
if (remoteHost && isSSH() && process.platform === "linux") {
|
||||||
|
exec(
|
||||||
|
`ssh -o ConnectTimeout=2 -o BatchMode=yes ${remoteHost} "osascript -e 'display notification \"${message}\" with title \"${title}\"'" 2>/dev/null || true`,
|
||||||
|
{ timeout: 5000 }
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send locally when not in SSH session
|
||||||
if (process.platform === "linux") {
|
if (process.platform === "linux") {
|
||||||
exec(
|
exec(
|
||||||
`notify-send -i ~/.pi/agent/extensions/assets/pi-logo.svg '${title}' '${message}' 2>/dev/null || true`,
|
`notify-send -i ~/.pi/agent/extensions/assets/pi-logo.svg '${title}' '${message}' 2>/dev/null || true`,
|
||||||
{ timeout: 5000 }
|
{ timeout: 5000 }
|
||||||
);
|
);
|
||||||
|
} else if (process.platform === "darwin") {
|
||||||
|
exec(
|
||||||
|
`osascript -e 'display notification "${message}" with title "${title}"' 2>/dev/null || true`,
|
||||||
|
{ timeout: 5000 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user