ironrdp_rdpsnd/
server.rs

1use ironrdp_core::{impl_as_any, Decode as _, ReadCursor};
2use ironrdp_pdu::gcc::ChannelName;
3use ironrdp_pdu::{decode_err, pdu_other_err, PduResult};
4use ironrdp_svc::{CompressionCondition, SvcMessage, SvcProcessor, SvcProcessorMessages, SvcServerProcessor};
5use tracing::{debug, error};
6
7use crate::pdu::{self, ClientAudioFormatPdu, QualityMode};
8
9pub type RdpsndSvcMessages = SvcProcessorMessages<RdpsndServer>;
10
11pub trait RdpsndError: core::error::Error + Send + Sync + 'static {}
12
13impl<T> RdpsndError for T where T: core::error::Error + Send + Sync + 'static {}
14
15/// Message sent by the event loop.
16#[derive(Debug)]
17pub enum RdpsndServerMessage {
18    /// Wave data, with timestamp
19    Wave(Vec<u8>, u32),
20    SetVolume {
21        left: u16,
22        right: u16,
23    },
24    Close,
25    /// Failure received from the OS event loop.
26    ///
27    /// Implementation should log/display this error.
28    Error(Box<dyn RdpsndError>),
29}
30
31pub trait RdpsndServerHandler: Send + core::fmt::Debug {
32    fn get_formats(&self) -> &[pdu::AudioFormat];
33
34    fn start(&mut self, client_format: &ClientAudioFormatPdu) -> Option<u16>;
35
36    fn stop(&mut self);
37}
38
39#[derive(Debug, Copy, Clone, PartialEq, Eq)]
40enum RdpsndState {
41    Start,
42    WaitingForClientFormats,
43    WaitingForQualityMode,
44    WaitingForTrainingConfirm,
45    Ready,
46    Stop,
47}
48
49#[derive(Debug)]
50pub struct RdpsndServer {
51    handler: Box<dyn RdpsndServerHandler>,
52    state: RdpsndState,
53    client_format: Option<ClientAudioFormatPdu>,
54    quality_mode: Option<QualityMode>,
55    block_no: u8,
56    format_no: Option<u16>,
57}
58
59impl RdpsndServer {
60    pub const NAME: ChannelName = ChannelName::from_static(b"rdpsnd\0\0");
61
62    pub fn new(handler: Box<dyn RdpsndServerHandler>) -> Self {
63        Self {
64            handler,
65            state: RdpsndState::Start,
66            client_format: None,
67            quality_mode: None,
68            format_no: None,
69            block_no: 0,
70        }
71    }
72
73    pub fn version(&self) -> PduResult<pdu::Version> {
74        let client_format = self
75            .client_format
76            .as_ref()
77            .ok_or_else(|| pdu_other_err!("invalid state, client format not yet received"))?;
78
79        Ok(client_format.version)
80    }
81
82    pub fn flags(&self) -> PduResult<pdu::AudioFormatFlags> {
83        let client_format = self
84            .client_format
85            .as_ref()
86            .ok_or_else(|| pdu_other_err!("invalid state, client format not yet received"))?;
87
88        Ok(client_format.flags)
89    }
90
91    pub fn training_pdu(&mut self) -> PduResult<RdpsndSvcMessages> {
92        let pdu = pdu::TrainingPdu {
93            timestamp: 4231, // a random number
94            data: vec![],
95        };
96        Ok(RdpsndSvcMessages::new(vec![
97            pdu::ServerAudioOutputPdu::Training(pdu).into()
98        ]))
99    }
100
101    pub fn wave(&mut self, data: Vec<u8>, ts: u32) -> PduResult<RdpsndSvcMessages> {
102        let version = self.version()?;
103        let format_no = self
104            .format_no
105            .ok_or_else(|| pdu_other_err!("invalid state - no format"))?;
106
107        // The server doesn't wait for wave confirm, apparently FreeRDP neither.
108        let msg = if version >= pdu::Version::V8 {
109            let pdu = pdu::Wave2Pdu {
110                block_no: self.block_no,
111                timestamp: 0,
112                audio_timestamp: ts,
113                format_no,
114                data: data.into(),
115            };
116            RdpsndSvcMessages::new(vec![pdu::ServerAudioOutputPdu::Wave2(pdu).into()])
117        } else {
118            let pdu = pdu::WavePdu {
119                block_no: self.block_no,
120                format_no,
121                timestamp: 0,
122                data: data.into(),
123            };
124            RdpsndSvcMessages::new(vec![pdu::ServerAudioOutputPdu::Wave(pdu).into()])
125        };
126
127        self.block_no = self.block_no.overflowing_add(1).0;
128
129        Ok(msg)
130    }
131
132    pub fn set_volume(&mut self, volume_left: u16, volume_right: u16) -> PduResult<RdpsndSvcMessages> {
133        if !self.flags()?.contains(pdu::AudioFormatFlags::VOLUME) {
134            return Err(pdu_other_err!("client doesn't support volume"));
135        }
136        let pdu = pdu::VolumePdu {
137            volume_left,
138            volume_right,
139        };
140        Ok(RdpsndSvcMessages::new(vec![
141            pdu::ServerAudioOutputPdu::Volume(pdu).into()
142        ]))
143    }
144
145    pub fn close(&mut self) -> PduResult<RdpsndSvcMessages> {
146        Ok(RdpsndSvcMessages::new(vec![pdu::ServerAudioOutputPdu::Close.into()]))
147    }
148}
149
150impl_as_any!(RdpsndServer);
151
152impl SvcProcessor for RdpsndServer {
153    fn channel_name(&self) -> ChannelName {
154        Self::NAME
155    }
156
157    fn compression_condition(&self) -> CompressionCondition {
158        CompressionCondition::Never
159    }
160
161    fn process(&mut self, payload: &[u8]) -> PduResult<Vec<SvcMessage>> {
162        let pdu = pdu::ClientAudioOutputPdu::decode(&mut ReadCursor::new(payload)).map_err(|e| decode_err!(e))?;
163        debug!(?pdu);
164        let msg = match self.state {
165            RdpsndState::WaitingForClientFormats => {
166                let pdu::ClientAudioOutputPdu::AudioFormat(af) = pdu else {
167                    error!("Invalid PDU");
168                    self.state = RdpsndState::Stop;
169                    return Ok(vec![]);
170                };
171                self.client_format = Some(af);
172                if self.version()? >= pdu::Version::V6 {
173                    self.state = RdpsndState::WaitingForQualityMode;
174                    vec![]
175                } else {
176                    self.state = RdpsndState::WaitingForTrainingConfirm;
177                    self.training_pdu()?.into()
178                }
179            }
180            RdpsndState::WaitingForQualityMode => {
181                let pdu::ClientAudioOutputPdu::QualityMode(pdu) = pdu else {
182                    error!("Invalid PDU");
183                    self.state = RdpsndState::Stop;
184                    return Ok(vec![]);
185                };
186                self.quality_mode = Some(pdu.quality_mode);
187                self.state = RdpsndState::WaitingForTrainingConfirm;
188                self.training_pdu()?.into()
189            }
190            RdpsndState::WaitingForTrainingConfirm => {
191                let pdu::ClientAudioOutputPdu::TrainingConfirm(_) = pdu else {
192                    error!("Invalid PDU");
193                    self.state = RdpsndState::Stop;
194                    return Ok(vec![]);
195                };
196                let client_format = self.client_format.as_ref().expect("available in this state");
197                self.state = RdpsndState::Ready;
198                self.format_no = self.handler.start(client_format);
199                vec![]
200            }
201            RdpsndState::Ready => {
202                if let pdu::ClientAudioOutputPdu::WaveConfirm(c) = pdu {
203                    debug!(?c);
204                }
205                vec![]
206            }
207            state => {
208                error!(?state, "Invalid state");
209                vec![]
210            }
211        };
212        Ok(msg)
213    }
214
215    fn start(&mut self) -> PduResult<Vec<SvcMessage>> {
216        if self.state != RdpsndState::Start {
217            error!("Attempted to start rdpsnd channel in invalid state");
218        }
219
220        let pdu = pdu::ServerAudioOutputPdu::AudioFormat(pdu::ServerAudioFormatPdu {
221            version: pdu::Version::V8,
222            formats: self.handler.get_formats().into(),
223        });
224
225        self.state = RdpsndState::WaitingForClientFormats;
226        Ok(vec![SvcMessage::from(pdu)])
227    }
228}
229
230impl Drop for RdpsndServer {
231    fn drop(&mut self) {
232        self.handler.stop();
233    }
234}
235
236impl SvcServerProcessor for RdpsndServer {}