core_api/node/contracts/
audiobridge.rs1use serde::{Deserialize, Serialize};
2
3pub const VERSION: &str = crate::node::V1;
4pub const NODE_TYPE: &str = "audiobridge";
5pub const RUNTIME_TARGET_PREFIX: &str = "/audiobridge/app/";
6pub const DEVICE_SNAPSHOT: &str = "device/snapshot";
7pub const DEVICE_REFRESH: &str = "device/refresh";
8pub const DEVICE_PAIR: &str = "device/pair";
9pub const DEVICE_UNPAIR: &str = "device/unpair";
10pub const DEVICE_TEST: &str = "device/test";
11
12#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13#[serde(rename_all = "camelCase", deny_unknown_fields)]
14pub struct EmptyRequest {}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17#[serde(rename_all = "camelCase", deny_unknown_fields)]
18pub struct DeviceRequest {
19 pub device_id: String,
20}
21
22#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
23#[serde(rename_all = "lowercase")]
24pub enum AudioEndpointDirection {
25 Input,
26 Output,
27}
28
29#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
30#[serde(rename_all = "camelCase")]
31pub enum MicrophonePermission {
32 NotDetermined,
33 Granted,
34 Denied,
35 Restricted,
36 Unavailable,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
40#[serde(rename_all = "camelCase")]
41pub struct AudioBridgeDevice {
42 pub device_id: String,
43 pub display_name: String,
44 pub transport: String,
45 pub direction: AudioEndpointDirection,
46 pub online: bool,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
50#[serde(rename_all = "camelCase")]
51pub struct AudioBridgeCandidate {
52 pub device_id: String,
53 pub display_name: String,
54 pub transport: String,
55 pub direction: AudioEndpointDirection,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59#[serde(rename_all = "camelCase")]
60pub struct DeviceSnapshot {
61 pub microphone_permission: MicrophonePermission,
62 #[serde(default)]
63 pub devices: Vec<AudioBridgeDevice>,
64 #[serde(default)]
65 pub candidates: Vec<AudioBridgeCandidate>,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69#[serde(rename_all = "camelCase")]
70pub struct PairingResponse {
71 pub changed: bool,
72 pub device: AudioBridgeDevice,
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn public_contract_does_not_expose_platform_identity() {
81 let value = serde_json::to_value(AudioBridgeDevice {
82 device_id: "device-1".to_string(),
83 display_name: "Living Room Speaker".to_string(),
84 transport: "bluetooth".to_string(),
85 direction: AudioEndpointDirection::Output,
86 online: true,
87 })
88 .expect("serialize device");
89 assert!(value.get("platformKey").is_none());
90 assert!(value.get("endpointId").is_none());
91 }
92
93 #[test]
94 fn device_snapshot_is_the_direct_response_payload() {
95 let value = serde_json::to_value(DeviceSnapshot {
96 microphone_permission: MicrophonePermission::NotDetermined,
97 devices: Vec::new(),
98 candidates: Vec::new(),
99 })
100 .expect("serialize device snapshot");
101 assert!(value.get("devices").is_some());
102 assert!(value.get("candidates").is_some());
103 assert!(value.get("snapshot").is_none());
104 }
105}