Always emit quality format updates with fallbacks

Send file/device audio-quality notifications even when stream metadata is incomplete by deriving sane defaults from the requested quality level, so controller quality icons stay in sync.
This commit is contained in:
joren
2026-03-31 23:33:56 +02:00
parent c3cad15719
commit 20d5ecf231

View File

@@ -418,6 +418,16 @@ fn msg_device_audio_quality_changed(
build_qconnect_message(27, &payload) build_qconnect_message(27, &payload)
} }
fn quality_fallback_audio_params(quality: u32) -> (u32, u32, u32) {
match quality {
1 => (44100, 16, 2), // MP3
2 => (44100, 16, 2), // CD
3 => (96000, 24, 2), // Hi-Res up to 96kHz
4 | 5 => (192000, 24, 2), // Hi-Res up to 192/384kHz (use 192kHz fallback)
_ => (44100, 16, 2),
}
}
/// RNDR_SRVR_VOLUME_MUTED (29): renderer confirms mute state. /// RNDR_SRVR_VOLUME_MUTED (29): renderer confirms mute state.
fn msg_volume_muted(muted: bool) -> Vec<u8> { fn msg_volume_muted(muted: bool) -> Vec<u8> {
let payload = encode_field_varint(1, if muted { 1 } else { 0 }); let payload = encode_field_varint(1, if muted { 1 } else { 0 });
@@ -1117,8 +1127,11 @@ async fn run_connection(
duration_ms, duration_ms,
start_position_ms: requested_pos.unwrap_or(0), start_position_ms: requested_pos.unwrap_or(0),
}); });
if let (Some(sr), Some(bits)) = (stream_sr, stream_bits) { let (fallback_sr, fallback_bits, fallback_ch) =
let ch = stream_ch.unwrap_or(2).max(1); quality_fallback_audio_params(max_audio_quality);
let sr = stream_sr.unwrap_or(fallback_sr).max(1);
let bits = stream_bits.unwrap_or(fallback_bits).max(1);
let ch = stream_ch.unwrap_or(fallback_ch).max(1);
let file_msg = msg_file_audio_quality_changed( let file_msg = msg_file_audio_quality_changed(
sr as u64, sr as u64,
bits as u64, bits as u64,
@@ -1134,7 +1147,6 @@ async fn run_connection(
); );
ws_tx.send(Message::Binary(build_payload_frame(msg_id, &dev_msg).into())).await?; ws_tx.send(Message::Binary(build_payload_frame(msg_id, &dev_msg).into())).await?;
msg_id += 1; msg_id += 1;
}
current_buffer_state = 2; // OK current_buffer_state = 2; // OK
} }
Err(e) => { Err(e) => {
@@ -1374,8 +1386,11 @@ async fn run_connection(
duration_ms, duration_ms,
start_position_ms: 0, start_position_ms: 0,
}); });
if let (Some(sr), Some(bits)) = (stream_sr, stream_bits) { let (fallback_sr, fallback_bits, fallback_ch) =
let ch = stream_ch.unwrap_or(2).max(1); quality_fallback_audio_params(*quality);
let sr = stream_sr.unwrap_or(fallback_sr).max(1);
let bits = stream_bits.unwrap_or(fallback_bits).max(1);
let ch = stream_ch.unwrap_or(fallback_ch).max(1);
let file_msg = msg_file_audio_quality_changed( let file_msg = msg_file_audio_quality_changed(
sr as u64, sr as u64,
bits as u64, bits as u64,
@@ -1391,7 +1406,6 @@ async fn run_connection(
); );
ws_tx.send(Message::Binary(build_payload_frame(msg_id, &dev_msg).into())).await?; ws_tx.send(Message::Binary(build_payload_frame(msg_id, &dev_msg).into())).await?;
msg_id += 1; msg_id += 1;
}
// Re-emit quality confirmation after successful restart // Re-emit quality confirmation after successful restart
// so controllers observing the currently active stream update promptly. // so controllers observing the currently active stream update promptly.
let confirm = msg_max_audio_quality_changed(*quality as u64, None); let confirm = msg_max_audio_quality_changed(*quality as u64, None);