diff --git a/frontend/src/components/GraphCanvas.svelte b/frontend/src/components/GraphCanvas.svelte
index 11feb1f..c5b089f 100644
--- a/frontend/src/components/GraphCanvas.svelte
+++ b/frontend/src/components/GraphCanvas.svelte
@@ -690,10 +690,12 @@
| Class | {nd.mode} / {nd.node_type} |
| Volume | {Math.round(nd.volume * 100)}% {nd.mute ? '(muted)' : ''} |
| Ports | {nd.port_ids.length} |
- {#if nd.sample_rate > 0}| Sample Rate | {nd.sample_rate} Hz |
{/if}
- {#if nd.channels > 0}| Channels | {nd.channels} |
{/if}
+ {#if nd.node_type === 'audio' || nd.channels > 0}
+ | Channels | {nd.channels > 0 ? nd.channels : '-'} |
+ | Sample Rate | {nd.sample_rate > 0 ? nd.sample_rate + ' Hz' : 'default'} |
+ {#if nd.quantum > 0}| Latency | {nd.quantum} samples{#if nd.sample_rate > 0} ({(nd.quantum / nd.sample_rate * 1000).toFixed(1)} ms){/if} |
{/if}
+ {/if}
{#if nd.format}| Format | {nd.format} |
{/if}
- {#if nd.quantum > 0}| Latency | {nd.quantum} samples @ {nd.sample_rate} Hz |
{/if}
{#if nd.rate > 0}| Period Size | {nd.rate} |
{/if}
{#if nd.device_name}| Device | {nd.device_name} |
{/if}
{#if nd.device_bus}| Bus | {nd.device_bus} |
{/if}
diff --git a/src/graph_engine.cpp b/src/graph_engine.cpp
index 03e6b94..b890dc9 100644
--- a/src/graph_engine.cpp
+++ b/src/graph_engine.cpp
@@ -102,10 +102,22 @@ static void on_node_info(void *data, const struct pw_node_info *info) {
const char *str;
str = spa_dict_lookup(info->props, "default.clock.rate");
- if (str) nobj->node.sample_rate = (uint32_t)atoi(str);
+ if (str && strlen(str) > 0) nobj->node.sample_rate = (uint32_t)atoi(str);
str = spa_dict_lookup(info->props, "default.clock.quantum");
- if (str) nobj->node.quantum = (uint32_t)atoi(str);
+ if (str && strlen(str) > 0) nobj->node.quantum = (uint32_t)atoi(str);
+
+ // Also try clock.rate (set on some devices)
+ if (nobj->node.sample_rate == 0) {
+ str = spa_dict_lookup(info->props, "clock.rate");
+ if (str && strlen(str) > 0) nobj->node.sample_rate = (uint32_t)atoi(str);
+ }
+
+ // Also try api.alsa.rate
+ if (nobj->node.sample_rate == 0) {
+ str = spa_dict_lookup(info->props, "api.alsa.rate");
+ if (str && strlen(str) > 0) nobj->node.sample_rate = (uint32_t)atoi(str);
+ }
str = spa_dict_lookup(info->props, "audio.channels");
if (str) nobj->node.channels = (uint32_t)atoi(str);
@@ -125,26 +137,31 @@ static void on_node_info(void *data, const struct pw_node_info *info) {
str = spa_dict_lookup(info->props, "priority.driver");
if (str) nobj->node.priority = atoi(str);
- // Latency info
+ // Latency: "256/48000" format
str = spa_dict_lookup(info->props, "node.latency");
if (str) {
- // Format: "256/48000" -> quantum=256 rate=48000
uint32_t q = 0, r = 0;
if (sscanf(str, "%u/%u", &q, &r) == 2) {
- nobj->node.quantum = q;
- nobj->node.sample_rate = r;
+ if (nobj->node.quantum == 0) nobj->node.quantum = q;
+ if (nobj->node.sample_rate == 0 && r > 0) nobj->node.sample_rate = r;
}
}
- // Fallback: read clock rate from device props
+ // ALSA period size
+ str = spa_dict_lookup(info->props, "api.alsa.period-size");
+ if (str) nobj->node.rate = (uint32_t)atoi(str);
+
+ // Fallback: clock.rate
if (nobj->node.sample_rate == 0) {
str = spa_dict_lookup(info->props, "clock.rate");
if (str) nobj->node.sample_rate = (uint32_t)atoi(str);
}
- // ALSA latency
- str = spa_dict_lookup(info->props, "api.alsa.period-size");
- if (str) nobj->node.rate = (uint32_t)atoi(str); // reuse rate field for period-size
+ // Fallback: api.alsa.rate
+ if (nobj->node.sample_rate == 0) {
+ str = spa_dict_lookup(info->props, "api.alsa.rate");
+ if (str) nobj->node.sample_rate = (uint32_t)atoi(str);
+ }
}
}