feat(qconnect): add session management protobuf types and outbound reporting

Add missing SRVR_CTRL session management message types (81-87, 97-101)
that were completely absent from the protobuf definitions. Without these,
prost silently discarded all session topology messages from the server.

- Add 12 new proto structs for session/renderer/volume/quality events
- Add decoder branches and map functions for all new message types
- Add SessionManagementEvent variant to bypass queue reducer
- Add v2_qconnect_report_playback_state and v2_qconnect_report_volume
- Add comprehensive logging for inbound message diagnostics
This commit is contained in:
vicrodh committed 2026-02-21 15:35:55 -06:00
1 parent b160773e50
commit 8a9e08ad91
13 files changed
+950 -106

No files matched your search

+18
View File
@@ -209,6 +209,18 @@ where
}
async fn apply_server_event(&self, event: QueueServerEvent) -> Result<(), QconnectAppError> {
// Session management events bypass the queue reducer entirely.
// They provide session topology info (renderers, active renderer, etc.)
if event.event_type.is_session_management() {
self.sink
.on_event(QconnectAppEvent::SessionManagementEvent {
message_type: event.message_type().to_string(),
payload: event.payload.clone(),
})
.await;
return Ok(());
}
let mut completed_uuid: Option<String> = None;
let mut canceled_uuid: Option<String> = None;
let mut ignored_queue_error_uuid: Option<String> = None;
@@ -601,6 +613,12 @@ fn map_server_event(event: &QueueServerEvent, current: &QConnectQueueState) -> Q
.map(value_to_string)
.unwrap_or_else(|| "queue_error_message".to_string()),
},
// Session management events are intercepted in apply_server_event()
// and should never reach map_server_event(). Treat as no-op if they do.
_ => QueueEvent::QueueCleared {
action_uuid: None,
version: current.version,
},
}
}
+7
View File
@@ -1,6 +1,7 @@
use async_trait::async_trait;
use qconnect_core::{QConnectQueueState, QConnectRendererState, RendererCommand};
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum QconnectAppEvent {
@@ -30,6 +31,12 @@ pub enum QconnectAppEvent {
action_uuid: String,
},
QueueResyncTriggered,
/// Session management event from server (types 81-87, 97-101).
/// These don't affect the queue reducer but provide session topology info.
SessionManagementEvent {
message_type: String,
payload: Value,
},
}
#[async_trait]
+1 -1
View File
@@ -17,7 +17,7 @@ pub use feature_flags::{
};
pub use qconnect_core::{
evaluate_remote_queue_admission, resolve_handoff_intent, AdmissionDecision, HandoffIntent,
QConnectQueueState, QConnectRendererState, RendererCommand, TrackOrigin,
QConnectQueueState, QConnectRendererState, QueueVersion, RendererCommand, TrackOrigin,
};
pub use qconnect_protocol::{QueueCommandType, RendererReport, RendererReportType};
pub use state::QconnectRuntimeState;
+327 -6
View File
@@ -6,12 +6,16 @@ use uuid::Uuid;
use crate::{
queue_command_proto::{
AutoplayModeSetMessage, AutoplayTracksLoadedMessage, AutoplayTracksRemovedMessage,
QConnectMessage, QConnectMessageType, QConnectMessages, QueueClearedMessage,
QueueErrorMessage, QueueStateMessage, QueueTrack, QueueTrackWithContext,
QueueTracksAddedFromAutoplayMessage, QueueTracksAddedMessage, QueueTracksInsertedMessage,
QueueTracksLoadedMessage, QueueTracksRemovedMessage, QueueTracksReorderedMessage,
QueueVersionRef, RendererMuteVolumeMessage, RendererSetActiveMessage,
RendererSetLoopModeMessage, RendererSetMaxAudioQualityMessage,
CtrlActiveRendererChangedMessage, CtrlAddRendererMessage,
CtrlDeviceAudioQualityChangedMessage, CtrlFileAudioQualityChangedMessage,
CtrlLoopModeSetMessage, CtrlMaxAudioQualityChangedMessage, CtrlRemoveRendererMessage,
CtrlRendererStateUpdatedMessage, CtrlSessionStateMessage, CtrlUpdateRendererMessage,
CtrlVolumeChangedMessage, CtrlVolumeMutedMessage, QConnectMessage, QConnectMessageType,
QConnectMessages, QueueClearedMessage, QueueErrorMessage, QueueStateMessage, QueueTrack,
QueueTrackWithContext, QueueTracksAddedFromAutoplayMessage, QueueTracksAddedMessage,
QueueTracksInsertedMessage, QueueTracksLoadedMessage, QueueTracksRemovedMessage,
QueueTracksReorderedMessage, QueueVersionRef, RendererMuteVolumeMessage,
RendererSetActiveMessage, RendererSetLoopModeMessage, RendererSetMaxAudioQualityMessage,
RendererSetShuffleModeMessage, RendererSetStateMessage, RendererSetVolumeMessage,
ShuffleModeSetMessage,
},
@@ -120,6 +124,83 @@ fn decode_queue_server_event(
};
map_tracks_added_from_autoplay(payload)?
}
// Session management events (81-87, 97-101)
code if code == QConnectMessageType::MessageTypeSrvrCtrlSessionState as i32 => {
let Some(payload) = message.srvr_ctrl_session_state else {
return Ok(None);
};
map_session_state(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlRendererStateUpdated as i32 => {
let Some(payload) = message.srvr_ctrl_renderer_state_updated else {
return Ok(None);
};
map_ctrl_renderer_state_updated(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlAddRenderer as i32 => {
let Some(payload) = message.srvr_ctrl_add_renderer else {
return Ok(None);
};
map_add_renderer(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlUpdateRenderer as i32 => {
let Some(payload) = message.srvr_ctrl_update_renderer else {
return Ok(None);
};
map_update_renderer(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlRemoveRenderer as i32 => {
let Some(payload) = message.srvr_ctrl_remove_renderer else {
return Ok(None);
};
map_remove_renderer(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlActiveRendererChanged as i32 => {
let Some(payload) = message.srvr_ctrl_active_renderer_changed else {
return Ok(None);
};
map_active_renderer_changed(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlVolumeChanged as i32 => {
let Some(payload) = message.srvr_ctrl_volume_changed else {
return Ok(None);
};
map_ctrl_volume_changed(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlLoopModeSet as i32 => {
let Some(payload) = message.srvr_ctrl_loop_mode_set else {
return Ok(None);
};
map_ctrl_loop_mode_set(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlVolumeMuted as i32 => {
let Some(payload) = message.srvr_ctrl_volume_muted else {
return Ok(None);
};
map_ctrl_volume_muted(payload)?
}
code if code == QConnectMessageType::MessageTypeSrvrCtrlMaxAudioQualityChanged as i32 => {
let Some(payload) = message.srvr_ctrl_max_audio_quality_changed else {
return Ok(None);
};
map_ctrl_max_audio_quality_changed(payload)?
}
code if code
== QConnectMessageType::MessageTypeSrvrCtrlFileAudioQualityChanged as i32 =>
{
let Some(payload) = message.srvr_ctrl_file_audio_quality_changed else {
return Ok(None);
};
map_ctrl_file_audio_quality_changed(payload)?
}
code if code
== QConnectMessageType::MessageTypeSrvrCtrlDeviceAudioQualityChanged as i32 =>
{
let Some(payload) = message.srvr_ctrl_device_audio_quality_changed else {
return Ok(None);
};
map_ctrl_device_audio_quality_changed(payload)?
}
_ => return Ok(None),
};
@@ -169,6 +250,45 @@ fn resolve_queue_message_type(message: &QConnectMessage) -> Option<i32> {
QConnectMessageType::MessageTypeSrvrCtrlQueueTracksAddedFromAutoplay as i32,
);
}
// Session management
if message.srvr_ctrl_session_state.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlSessionState as i32);
}
if message.srvr_ctrl_renderer_state_updated.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlRendererStateUpdated as i32);
}
if message.srvr_ctrl_add_renderer.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlAddRenderer as i32);
}
if message.srvr_ctrl_update_renderer.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlUpdateRenderer as i32);
}
if message.srvr_ctrl_remove_renderer.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlRemoveRenderer as i32);
}
if message.srvr_ctrl_active_renderer_changed.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlActiveRendererChanged as i32);
}
if message.srvr_ctrl_volume_changed.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlVolumeChanged as i32);
}
if message.srvr_ctrl_loop_mode_set.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlLoopModeSet as i32);
}
if message.srvr_ctrl_volume_muted.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlVolumeMuted as i32);
}
if message.srvr_ctrl_max_audio_quality_changed.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlMaxAudioQualityChanged as i32);
}
if message.srvr_ctrl_file_audio_quality_changed.is_some() {
return Some(QConnectMessageType::MessageTypeSrvrCtrlFileAudioQualityChanged as i32);
}
if message.srvr_ctrl_device_audio_quality_changed.is_some() {
return Some(
QConnectMessageType::MessageTypeSrvrCtrlDeviceAudioQualityChanged as i32,
);
}
None
})
}
@@ -642,6 +762,207 @@ fn map_tracks_added_from_autoplay(
})
}
// --- Session management event mappers ---
fn map_session_state(payload: CtrlSessionStateMessage) -> Result<QueueServerEvent, ProtocolError> {
let session_uuid = uuid_bytes_to_string_opt(payload.session_uuid, "session_state.session_uuid")?;
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlSessionState,
action_uuid: None,
queue_version: queue_version_opt(payload.queue_version)?,
payload: json!({
"session_uuid": session_uuid,
"active_renderer_id": payload.active_renderer_id,
"playing_state": payload.playing_state,
"loop_mode": payload.loop_mode
}),
})
}
fn map_ctrl_renderer_state_updated(
payload: CtrlRendererStateUpdatedMessage,
) -> Result<QueueServerEvent, ProtocolError> {
let player_state = payload.player_state.map(|ps| {
json!({
"playing_state": ps.playing_state,
"buffer_state": ps.buffer_state,
"current_position": ps.current_position.as_ref().and_then(|pos| pos.value),
"duration": ps.duration,
"current_queue_item_id": ps.current_queue_item_id
})
});
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlRendererStateUpdated,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id,
"status": payload.status,
"player_state": player_state
}),
})
}
fn map_add_renderer(payload: CtrlAddRendererMessage) -> Result<QueueServerEvent, ProtocolError> {
let device_info = payload.device_info.map(|di| {
json!({
"friendly_name": di.friendly_name,
"brand": di.brand,
"model": di.model,
"device_type": di.device_type
})
});
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlAddRenderer,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id,
"device_info": device_info
}),
})
}
fn map_update_renderer(
payload: CtrlUpdateRendererMessage,
) -> Result<QueueServerEvent, ProtocolError> {
let device_info = payload.device_info.map(|di| {
json!({
"friendly_name": di.friendly_name,
"brand": di.brand,
"model": di.model,
"device_type": di.device_type
})
});
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlUpdateRenderer,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id,
"device_info": device_info
}),
})
}
fn map_remove_renderer(
payload: CtrlRemoveRendererMessage,
) -> Result<QueueServerEvent, ProtocolError> {
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlRemoveRenderer,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id
}),
})
}
fn map_active_renderer_changed(
payload: CtrlActiveRendererChangedMessage,
) -> Result<QueueServerEvent, ProtocolError> {
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlActiveRendererChanged,
action_uuid: None,
queue_version: None,
payload: json!({
"active_renderer_id": payload.active_renderer_id
}),
})
}
fn map_ctrl_volume_changed(
payload: CtrlVolumeChangedMessage,
) -> Result<QueueServerEvent, ProtocolError> {
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlVolumeChanged,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id,
"volume": payload.volume
}),
})
}
fn map_ctrl_loop_mode_set(
payload: CtrlLoopModeSetMessage,
) -> Result<QueueServerEvent, ProtocolError> {
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlLoopModeSet,
action_uuid: None,
queue_version: None,
payload: json!({
"loop_mode": payload.loop_mode
}),
})
}
fn map_ctrl_volume_muted(
payload: CtrlVolumeMutedMessage,
) -> Result<QueueServerEvent, ProtocolError> {
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlVolumeMuted,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id,
"value": payload.value
}),
})
}
fn map_ctrl_max_audio_quality_changed(
payload: CtrlMaxAudioQualityChangedMessage,
) -> Result<QueueServerEvent, ProtocolError> {
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlMaxAudioQualityChanged,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id,
"max_audio_quality": payload.max_audio_quality,
"network_type": payload.network_type
}),
})
}
fn map_ctrl_file_audio_quality_changed(
payload: CtrlFileAudioQualityChangedMessage,
) -> Result<QueueServerEvent, ProtocolError> {
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlFileAudioQualityChanged,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id,
"sampling_rate": payload.sampling_rate,
"bit_depth": payload.bit_depth,
"nb_channels": payload.nb_channels,
"audio_quality": payload.audio_quality
}),
})
}
fn map_ctrl_device_audio_quality_changed(
payload: CtrlDeviceAudioQualityChangedMessage,
) -> Result<QueueServerEvent, ProtocolError> {
Ok(QueueServerEvent {
event_type: QueueEventType::SrvrCtrlDeviceAudioQualityChanged,
action_uuid: None,
queue_version: None,
payload: json!({
"renderer_id": payload.renderer_id,
"sampling_rate": payload.sampling_rate,
"bit_depth": payload.bit_depth,
"nb_channels": payload.nb_channels
}),
})
}
fn queue_track_to_json(
track: QueueTrack,
context_uuid: Option<&str>,
+55
View File
@@ -17,6 +17,19 @@ pub enum QueueEventType {
SrvrCtrlAutoplayTracksRemoved,
SrvrCtrlQueueTracksAddedFromAutoplay,
SrvrCtrlQueueErrorMessage,
// Session management events (types 81-87, 97-101)
SrvrCtrlSessionState,
SrvrCtrlRendererStateUpdated,
SrvrCtrlAddRenderer,
SrvrCtrlUpdateRenderer,
SrvrCtrlRemoveRenderer,
SrvrCtrlActiveRendererChanged,
SrvrCtrlVolumeChanged,
SrvrCtrlLoopModeSet,
SrvrCtrlVolumeMuted,
SrvrCtrlMaxAudioQualityChanged,
SrvrCtrlFileAudioQualityChanged,
SrvrCtrlDeviceAudioQualityChanged,
}
impl QueueEventType {
@@ -37,10 +50,52 @@ impl QueueEventType {
"MESSAGE_TYPE_SRVR_CTRL_QUEUE_TRACKS_ADDED_FROM_AUTOPLAY"
}
Self::SrvrCtrlQueueErrorMessage => "MESSAGE_TYPE_SRVR_CTRL_QUEUE_ERROR_MESSAGE",
Self::SrvrCtrlSessionState => "MESSAGE_TYPE_SRVR_CTRL_SESSION_STATE",
Self::SrvrCtrlRendererStateUpdated => "MESSAGE_TYPE_SRVR_CTRL_RENDERER_STATE_UPDATED",
Self::SrvrCtrlAddRenderer => "MESSAGE_TYPE_SRVR_CTRL_ADD_RENDERER",
Self::SrvrCtrlUpdateRenderer => "MESSAGE_TYPE_SRVR_CTRL_UPDATE_RENDERER",
Self::SrvrCtrlRemoveRenderer => "MESSAGE_TYPE_SRVR_CTRL_REMOVE_RENDERER",
Self::SrvrCtrlActiveRendererChanged => {
"MESSAGE_TYPE_SRVR_CTRL_ACTIVE_RENDERER_CHANGED"
}
Self::SrvrCtrlVolumeChanged => "MESSAGE_TYPE_SRVR_CTRL_VOLUME_CHANGED",
Self::SrvrCtrlLoopModeSet => "MESSAGE_TYPE_SRVR_CTRL_LOOP_MODE_SET",
Self::SrvrCtrlVolumeMuted => "MESSAGE_TYPE_SRVR_CTRL_VOLUME_MUTED",
Self::SrvrCtrlMaxAudioQualityChanged => {
"MESSAGE_TYPE_SRVR_CTRL_MAX_AUDIO_QUALITY_CHANGED"
}
Self::SrvrCtrlFileAudioQualityChanged => {
"MESSAGE_TYPE_SRVR_CTRL_FILE_AUDIO_QUALITY_CHANGED"
}
Self::SrvrCtrlDeviceAudioQualityChanged => {
"MESSAGE_TYPE_SRVR_CTRL_DEVICE_AUDIO_QUALITY_CHANGED"
}
}
}
}
impl QueueEventType {
/// Returns true for session management events that should NOT go through
/// the queue reducer.
pub const fn is_session_management(self) -> bool {
matches!(
self,
Self::SrvrCtrlSessionState
| Self::SrvrCtrlRendererStateUpdated
| Self::SrvrCtrlAddRenderer
| Self::SrvrCtrlUpdateRenderer
| Self::SrvrCtrlRemoveRenderer
| Self::SrvrCtrlActiveRendererChanged
| Self::SrvrCtrlVolumeChanged
| Self::SrvrCtrlLoopModeSet
| Self::SrvrCtrlVolumeMuted
| Self::SrvrCtrlMaxAudioQualityChanged
| Self::SrvrCtrlFileAudioQualityChanged
| Self::SrvrCtrlDeviceAudioQualityChanged
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueueServerEvent {
pub event_type: QueueEventType,
@@ -37,6 +37,13 @@ pub enum QConnectMessageType {
MessageTypeCtrlSrvrSetAutoplayMode = 78,
MessageTypeCtrlSrvrAutoplayLoadTracks = 79,
MessageTypeCtrlSrvrAutoplayRemoveTracks = 80,
MessageTypeSrvrCtrlSessionState = 81,
MessageTypeSrvrCtrlRendererStateUpdated = 82,
MessageTypeSrvrCtrlAddRenderer = 83,
MessageTypeSrvrCtrlUpdateRenderer = 84,
MessageTypeSrvrCtrlRemoveRenderer = 85,
MessageTypeSrvrCtrlActiveRendererChanged = 86,
MessageTypeSrvrCtrlVolumeChanged = 87,
MessageTypeSrvrCtrlQueueErrorMessage = 88,
MessageTypeSrvrCtrlQueueCleared = 89,
MessageTypeSrvrCtrlQueueState = 90,
@@ -46,6 +53,11 @@ pub enum QConnectMessageType {
MessageTypeSrvrCtrlQueueTracksRemoved = 94,
MessageTypeSrvrCtrlQueueTracksReordered = 95,
MessageTypeSrvrCtrlShuffleModeSet = 96,
MessageTypeSrvrCtrlLoopModeSet = 97,
MessageTypeSrvrCtrlVolumeMuted = 98,
MessageTypeSrvrCtrlMaxAudioQualityChanged = 99,
MessageTypeSrvrCtrlFileAudioQualityChanged = 100,
MessageTypeSrvrCtrlDeviceAudioQualityChanged = 101,
MessageTypeSrvrCtrlAutoplayModeSet = 102,
MessageTypeSrvrCtrlAutoplayTracksLoaded = 103,
MessageTypeSrvrCtrlAutoplayTracksRemoved = 104,
@@ -709,6 +721,145 @@ pub struct RendererMaxAudioQualityChangedMessage {
pub network_type: Option<i32>,
}
// --- SRVR_CTRL session management messages (server → controller) ---
/// Type 81: Session state after joining
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlSessionStateMessage {
#[prost(bytes = "vec", optional, tag = "1")]
pub session_uuid: Option<Vec<u8>>,
#[prost(int32, optional, tag = "2")]
pub active_renderer_id: Option<i32>,
#[prost(message, optional, tag = "3")]
pub queue_version: Option<QueueVersionRef>,
#[prost(int32, optional, tag = "4")]
pub playing_state: Option<i32>,
#[prost(int32, optional, tag = "5")]
pub loop_mode: Option<i32>,
}
/// Nested player state for CtrlRendererStateUpdatedMessage
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlRendererPlayerState {
#[prost(int32, optional, tag = "1")]
pub playing_state: Option<i32>,
#[prost(int32, optional, tag = "2")]
pub buffer_state: Option<i32>,
#[prost(message, optional, tag = "3")]
pub current_position: Option<PlaybackPositionMessage>,
#[prost(uint32, optional, tag = "4")]
pub duration: Option<u32>,
#[prost(int32, optional, tag = "5")]
pub current_queue_item_id: Option<i32>,
}
/// Type 82: Renderer state updated (controller view)
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlRendererStateUpdatedMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
#[prost(int32, optional, tag = "2")]
pub status: Option<i32>,
#[prost(message, optional, tag = "3")]
pub player_state: Option<CtrlRendererPlayerState>,
}
/// Type 83: New renderer added to session
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlAddRendererMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
#[prost(message, optional, tag = "2")]
pub device_info: Option<DeviceInfoMessage>,
}
/// Type 84: Renderer info updated
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlUpdateRendererMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
#[prost(message, optional, tag = "2")]
pub device_info: Option<DeviceInfoMessage>,
}
/// Type 85: Renderer removed from session
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlRemoveRendererMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
}
/// Type 86: Active renderer changed
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlActiveRendererChangedMessage {
#[prost(int32, optional, tag = "1")]
pub active_renderer_id: Option<i32>,
}
/// Type 87: Volume changed on a renderer (controller view)
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlVolumeChangedMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
#[prost(uint32, optional, tag = "2")]
pub volume: Option<u32>,
}
/// Type 97: Loop mode set
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlLoopModeSetMessage {
#[prost(int32, optional, tag = "1")]
pub loop_mode: Option<i32>,
}
/// Type 98: Volume muted (controller view)
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlVolumeMutedMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
#[prost(bool, optional, tag = "2")]
pub value: Option<bool>,
}
/// Type 99: Max audio quality changed (controller view)
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlMaxAudioQualityChangedMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
#[prost(int32, optional, tag = "2")]
pub max_audio_quality: Option<i32>,
#[prost(int32, optional, tag = "3")]
pub network_type: Option<i32>,
}
/// Type 100: File audio quality changed (controller view)
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlFileAudioQualityChangedMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
#[prost(uint32, optional, tag = "2")]
pub sampling_rate: Option<u32>,
#[prost(uint32, optional, tag = "3")]
pub bit_depth: Option<u32>,
#[prost(uint32, optional, tag = "4")]
pub nb_channels: Option<u32>,
#[prost(int32, optional, tag = "5")]
pub audio_quality: Option<i32>,
}
/// Type 101: Device audio quality changed (controller view)
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CtrlDeviceAudioQualityChangedMessage {
#[prost(int32, optional, tag = "1")]
pub renderer_id: Option<i32>,
#[prost(uint32, optional, tag = "2")]
pub sampling_rate: Option<u32>,
#[prost(uint32, optional, tag = "3")]
pub bit_depth: Option<u32>,
#[prost(uint32, optional, tag = "4")]
pub nb_channels: Option<u32>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct QConnectMessages {
#[prost(uint64, optional, tag = "1")]
@@ -791,6 +942,20 @@ pub struct QConnectMessage {
pub ctrl_srvr_autoplay_load_tracks: Option<AutoplayLoadTracksMessage>,
#[prost(message, optional, tag = "80")]
pub ctrl_srvr_autoplay_remove_tracks: Option<AutoplayRemoveTracksMessage>,
#[prost(message, optional, tag = "81")]
pub srvr_ctrl_session_state: Option<CtrlSessionStateMessage>,
#[prost(message, optional, tag = "82")]
pub srvr_ctrl_renderer_state_updated: Option<CtrlRendererStateUpdatedMessage>,
#[prost(message, optional, tag = "83")]
pub srvr_ctrl_add_renderer: Option<CtrlAddRendererMessage>,
#[prost(message, optional, tag = "84")]
pub srvr_ctrl_update_renderer: Option<CtrlUpdateRendererMessage>,
#[prost(message, optional, tag = "85")]
pub srvr_ctrl_remove_renderer: Option<CtrlRemoveRendererMessage>,
#[prost(message, optional, tag = "86")]
pub srvr_ctrl_active_renderer_changed: Option<CtrlActiveRendererChangedMessage>,
#[prost(message, optional, tag = "87")]
pub srvr_ctrl_volume_changed: Option<CtrlVolumeChangedMessage>,
#[prost(message, optional, tag = "88")]
pub srvr_ctrl_queue_error_message: Option<QueueErrorMessage>,
#[prost(message, optional, tag = "89")]
@@ -809,6 +974,16 @@ pub struct QConnectMessage {
pub srvr_ctrl_queue_tracks_reordered: Option<QueueTracksReorderedMessage>,
#[prost(message, optional, tag = "96")]
pub srvr_ctrl_shuffle_mode_set: Option<ShuffleModeSetMessage>,
#[prost(message, optional, tag = "97")]
pub srvr_ctrl_loop_mode_set: Option<CtrlLoopModeSetMessage>,
#[prost(message, optional, tag = "98")]
pub srvr_ctrl_volume_muted: Option<CtrlVolumeMutedMessage>,
#[prost(message, optional, tag = "99")]
pub srvr_ctrl_max_audio_quality_changed: Option<CtrlMaxAudioQualityChangedMessage>,
#[prost(message, optional, tag = "100")]
pub srvr_ctrl_file_audio_quality_changed: Option<CtrlFileAudioQualityChangedMessage>,
#[prost(message, optional, tag = "101")]
pub srvr_ctrl_device_audio_quality_changed: Option<CtrlDeviceAudioQualityChangedMessage>,
#[prost(message, optional, tag = "102")]
pub srvr_ctrl_autoplay_mode_set: Option<AutoplayModeSetMessage>,
#[prost(message, optional, tag = "103")]