feat: cross-platform audio device listing and Mac Easter egg

- Add conditional compilation for get_pipewire_sinks():
  - Linux: Uses pactl to get PipeWire/PulseAudio sinks with volume info
  - macOS/Windows: Uses cpal to enumerate audio devices (no volume)
- AboutModal: Detect platform and show macOS or Linux label
- Easter egg: Tux penguin is 64px on Mac (asserts dominance)
This commit is contained in:
vicrodh committed 2026-01-12 01:25:59 -06:00
1 parent 8257e8866b
commit c43867d403
2 files changed
+58 -7

No files matched your search

+41 -5
View File
@@ -359,23 +359,24 @@ pub fn reinit_audio_device(
state.player.reinit_device(device) state.player.reinit_device(device)
} }
/// PipeWire/PulseAudio sink information /// PipeWire/PulseAudio sink information (cross-platform compatible struct)
#[derive(serde::Serialize, Clone)] #[derive(serde::Serialize, Clone)]
pub struct PipewireSink { pub struct PipewireSink {
/// Internal name (e.g., "alsa_output.usb-XXX") /// Internal name (e.g., "alsa_output.usb-XXX" on Linux, device name on Mac)
pub name: String, pub name: String,
/// User-friendly description (e.g., "AB13X Headset Adapter Analog Stereo") /// User-friendly description (e.g., "AB13X Headset Adapter Analog Stereo")
pub description: String, pub description: String,
/// Current volume percentage (0-100) /// Current volume percentage (0-100) - only available on Linux
pub volume: Option<u32>, pub volume: Option<u32>,
/// Whether this is the default sink /// Whether this is the default sink
pub is_default: bool, pub is_default: bool,
} }
/// Get PipeWire/PulseAudio sink information with friendly names /// Get PipeWire/PulseAudio sink information with friendly names (Linux)
#[cfg(target_os = "linux")]
#[tauri::command] #[tauri::command]
pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> { pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
log::info!("Command: get_pipewire_sinks"); log::info!("Command: get_pipewire_sinks (Linux)");
use std::process::Command; use std::process::Command;
@@ -459,3 +460,38 @@ pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
log::info!("Found {} PipeWire sinks", sinks.len()); log::info!("Found {} PipeWire sinks", sinks.len());
Ok(sinks) Ok(sinks)
} }
/// Get audio output devices using cpal (macOS/Windows fallback)
/// Returns devices in the same format as Linux for UI compatibility
#[cfg(not(target_os = "linux"))]
#[tauri::command]
pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
log::info!("Command: get_pipewire_sinks (non-Linux, using cpal)");
use rodio::cpal::traits::{DeviceTrait, HostTrait};
let host = rodio::cpal::default_host();
let default_device_name = host
.default_output_device()
.and_then(|d| d.name().ok());
let sinks: Vec<PipewireSink> = host
.output_devices()
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
.filter_map(|device| {
device.name().ok().map(|name| {
let is_default = default_device_name.as_ref().map(|d| d == &name).unwrap_or(false);
PipewireSink {
name: name.clone(),
description: name, // On Mac/Windows, name is usually descriptive enough
volume: None, // Volume not available via cpal
is_default,
}
})
})
.collect();
log::info!("Found {} audio output devices", sinks.len());
Ok(sinks)
}
+17 -2
View File
@@ -12,6 +12,10 @@
const APP_VERSION = '0.1.0'; const APP_VERSION = '0.1.0';
const BUILD_DATE = new Date().toISOString().split('T')[0]; const BUILD_DATE = new Date().toISOString().split('T')[0];
// Detect platform for Easter eggs
const isMac = typeof navigator !== 'undefined' && /Mac/.test(navigator.platform);
const platformLabel = isMac ? 'macOS (Tauri 2.0)' : 'Linux (Tauri 2.0)';
function handleOpenUrl(url: string) { function handleOpenUrl(url: string) {
openUrl(url).catch(err => console.error('Failed to open URL:', err)); openUrl(url).catch(err => console.error('Failed to open URL:', err));
} }
@@ -65,7 +69,7 @@
<span class="label">License</span> <span class="label">License</span>
<span class="value">MIT</span> <span class="value">MIT</span>
<span class="label">Platform</span> <span class="label">Platform</span>
<span class="value">Linux (Tauri 2.0)</span> <span class="value">{platformLabel}</span>
<span class="label">Build</span> <span class="label">Build</span>
<span class="value">{BUILD_DATE}</span> <span class="value">{BUILD_DATE}</span>
</div> </div>
@@ -113,7 +117,7 @@
<p class="signature-detail"> <p class="signature-detail">
Hatred towards all those companies that discriminate against the Linux community Hatred towards all those companies that discriminate against the Linux community
and don't provide us with a decent client for their product. and don't provide us with a decent client for their product.
<img src="/Tux.svg" alt="Tux" class="inline-icon tux" /> <img src="/Tux.svg" alt="Tux" class="inline-icon tux" class:mac-tux={isMac} />
</p> </p>
</div> </div>
</div> </div>
@@ -361,4 +365,15 @@
margin-left: 4px; margin-left: 4px;
height: 1.4em; height: 1.4em;
} }
/* Easter egg: On Mac, Tux asserts dominance */
.inline-icon.tux.mac-tux {
height: 64px;
margin-left: 12px;
margin-top: 8px;
display: block;
margin-left: auto;
margin-right: auto;
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
}
</style> </style>