@@ -15,6 +15,7 @@ use anyhow::Context as _;
15
15
use ironrdp:: cliprdr:: backend:: { CliprdrBackend , CliprdrBackendFactory } ;
16
16
use ironrdp:: connector:: DesktopSize ;
17
17
use ironrdp:: rdpsnd:: pdu:: ClientAudioFormatPdu ;
18
+ use ironrdp:: rdpsnd:: pdu:: { AudioFormat , WaveFormat } ;
18
19
use ironrdp:: rdpsnd:: server:: { RdpsndServerHandler , RdpsndServerMessage } ;
19
20
use ironrdp:: server:: tokio:: sync:: mpsc:: UnboundedSender ;
20
21
use ironrdp:: server:: tokio:: time:: { self , sleep, Duration } ;
@@ -251,51 +252,92 @@ struct SndHandler {
251
252
task : Option < tokio:: task:: JoinHandle < ( ) > > ,
252
253
}
253
254
255
+ impl SndHandler {
256
+ fn choose_format ( & self , client_formats : & [ AudioFormat ] ) -> Option < u16 > {
257
+ for ( n, fmt) in client_formats. iter ( ) . enumerate ( ) {
258
+ if self . get_formats ( ) . contains ( fmt) {
259
+ return u16:: try_from ( n) . ok ( ) ;
260
+ }
261
+ }
262
+ None
263
+ }
264
+ }
265
+
254
266
impl RdpsndServerHandler for SndHandler {
255
- fn get_formats ( & self ) -> & [ ironrdp_rdpsnd:: pdu:: AudioFormat ] {
256
- use ironrdp_rdpsnd:: pdu:: { AudioFormat , WaveFormat } ;
257
-
258
- & [ AudioFormat {
259
- format : WaveFormat :: PCM ,
260
- n_channels : 2 ,
261
- n_samples_per_sec : 44100 ,
262
- n_avg_bytes_per_sec : 176400 ,
263
- n_block_align : 4 ,
264
- bits_per_sample : 16 ,
265
- data : None ,
266
- } ]
267
+ fn get_formats ( & self ) -> & [ AudioFormat ] {
268
+ & [
269
+ AudioFormat {
270
+ format : WaveFormat :: OPUS ,
271
+ n_channels : 2 ,
272
+ n_samples_per_sec : 48000 ,
273
+ n_avg_bytes_per_sec : 192000 ,
274
+ n_block_align : 4 ,
275
+ bits_per_sample : 16 ,
276
+ data : None ,
277
+ } ,
278
+ AudioFormat {
279
+ format : WaveFormat :: PCM ,
280
+ n_channels : 2 ,
281
+ n_samples_per_sec : 44100 ,
282
+ n_avg_bytes_per_sec : 176400 ,
283
+ n_block_align : 4 ,
284
+ bits_per_sample : 16 ,
285
+ data : None ,
286
+ } ,
287
+ ]
267
288
}
268
289
269
290
fn start ( & mut self , client_format : & ClientAudioFormatPdu ) -> Option < u16 > {
270
- async fn generate_sine_wave ( sample_rate : u32 , frequency : f32 , duration_ms : u64 ) -> Vec < u8 > {
271
- use core:: f32:: consts:: PI ;
272
-
273
- let total_samples = u64:: from ( sample_rate / 1000 ) . checked_mul ( duration_ms) . unwrap ( ) ;
274
- let samples_per_wave_length = sample_rate as f32 / frequency;
275
- let amplitude = 32767.0 ; // Max amplitude for 16-bit audio
276
-
277
- let capacity = total_samples. checked_mul ( 2 + 2 ) . unwrap ( ) ;
278
- let mut samples = Vec :: with_capacity ( usize:: try_from ( capacity) . unwrap ( ) ) ;
279
-
280
- for n in 0 ..total_samples {
281
- let t = ( n as f32 % samples_per_wave_length) / samples_per_wave_length;
282
- let sample = ( t * 2.0 * PI ) . sin ( ) ;
283
- #[ allow( clippy:: cast_possible_truncation) ]
284
- let sample = ( sample * amplitude) as i16 ;
285
- samples. extend_from_slice ( & sample. to_le_bytes ( ) ) ;
286
- samples. extend_from_slice ( & sample. to_le_bytes ( ) ) ;
287
- }
291
+ debug ! ( ?client_format) ;
288
292
289
- samples
290
- }
293
+ let Some ( nfmt) = self . choose_format ( & client_format. formats ) else {
294
+ return Some ( 0 ) ;
295
+ } ;
296
+
297
+ let fmt = client_format. formats [ usize:: from ( nfmt) ] . clone ( ) ;
298
+
299
+ let mut opus_enc = if fmt. format == WaveFormat :: OPUS {
300
+ let n_channels: opus:: Channels = match fmt. n_channels {
301
+ 1 => opus:: Channels :: Mono ,
302
+ 2 => opus:: Channels :: Stereo ,
303
+ n => {
304
+ warn ! ( "Invalid OPUS channels: {}" , n) ;
305
+ return Some ( 0 ) ;
306
+ }
307
+ } ;
308
+
309
+ match opus:: Encoder :: new ( fmt. n_samples_per_sec , n_channels, opus:: Application :: Audio ) {
310
+ Ok ( enc) => Some ( enc) ,
311
+ Err ( err) => {
312
+ warn ! ( "Failed to create OPUS encoder: {}" , err) ;
313
+ return Some ( 0 ) ;
314
+ }
315
+ }
316
+ } else {
317
+ None
318
+ } ;
291
319
292
320
let inner = Arc :: clone ( & self . inner ) ;
293
321
self . task = Some ( tokio:: spawn ( async move {
294
- let mut interval = time:: interval ( Duration :: from_millis ( 100 ) ) ;
322
+ let mut interval = time:: interval ( Duration :: from_millis ( 20 ) ) ;
295
323
let mut ts = 0 ;
324
+ let mut phase = 0.0f32 ;
296
325
loop {
297
326
interval. tick ( ) . await ;
298
- let data = generate_sine_wave ( 44100 , 440.0 , 100 ) . await ;
327
+ let wave = generate_sine_wave ( fmt. n_samples_per_sec , 440.0 , 20 , & mut phase) ;
328
+
329
+ let data = if let Some ( ref mut enc) = opus_enc {
330
+ match enc. encode_vec ( & wave, wave. len ( ) ) {
331
+ Ok ( data) => data,
332
+ Err ( err) => {
333
+ warn ! ( "Failed to encode with OPUS: {}" , err) ;
334
+ return ;
335
+ }
336
+ }
337
+ } else {
338
+ wave. into_iter ( ) . flat_map ( |value| value. to_le_bytes ( ) ) . collect ( )
339
+ } ;
340
+
299
341
let inner = inner. lock ( ) . unwrap ( ) ;
300
342
if let Some ( sender) = inner. ev_sender . as_ref ( ) {
301
343
let _ = sender. send ( ServerEvent :: Rdpsnd ( RdpsndServerMessage :: Wave ( data, ts) ) ) ;
@@ -304,8 +346,7 @@ impl RdpsndServerHandler for SndHandler {
304
346
}
305
347
} ) ) ;
306
348
307
- debug ! ( ?client_format) ;
308
- Some ( 0 )
349
+ Some ( nfmt)
309
350
}
310
351
311
352
fn stop ( & mut self ) {
@@ -316,6 +357,33 @@ impl RdpsndServerHandler for SndHandler {
316
357
}
317
358
}
318
359
360
+ fn generate_sine_wave ( sample_rate : u32 , frequency : f32 , duration_ms : u64 , phase : & mut f32 ) -> Vec < i16 > {
361
+ use core:: f32:: consts:: PI ;
362
+
363
+ let total_samples = ( u64:: from ( sample_rate) * duration_ms) / 1000 ;
364
+ let delta_phase = 2.0 * PI * frequency / sample_rate as f32 ;
365
+ let amplitude = 32767.0 ; // Max amplitude for 16-bit audio
366
+
367
+ let capacity = ( total_samples as usize ) * 2 ; // 2 channels
368
+ let mut samples = Vec :: with_capacity ( capacity) ;
369
+
370
+ for _ in 0 ..total_samples {
371
+ let sample = ( * phase) . sin ( ) ;
372
+ * phase += delta_phase;
373
+ // Wrap phase to maintain precision and avoid overflow
374
+ * phase %= 2.0 * PI ;
375
+
376
+ #[ allow( clippy:: cast_possible_truncation) ]
377
+ let sample_i16 = ( sample * amplitude) as i16 ;
378
+
379
+ // Write same sample to both channels (stereo)
380
+ samples. push ( sample_i16) ;
381
+ samples. push ( sample_i16) ;
382
+ }
383
+
384
+ samples
385
+ }
386
+
319
387
async fn run (
320
388
bind_addr : SocketAddr ,
321
389
hybrid : bool ,
0 commit comments