kinect_v2_sys/
audio.rs

1use crate::bindings::{
2    AudioBeamMode, BOOLEAN, BYTE, IAudioBeam, IAudioBeamFrame, IAudioBeamFrameArrivedEventArgs,
3    IAudioBeamFrameList, IAudioBeamFrameReader, IAudioBeamFrameReference, IAudioBeamList,
4    IAudioBeamSubFrame, IAudioBodyCorrelation, IFrameCapturedEventArgs, IKinectSensor,
5    KinectAudioCalibrationState, TIMESPAN, UINT64, WAITABLE_HANDLE,
6};
7use crate::bindings::{IAudioSource, UINT};
8use crate::frame::FrameCapturedEventArgs;
9use crate::kinect::KinectSensor;
10use std::ptr;
11use windows::Win32::Foundation::{E_FAIL, E_POINTER, HANDLE};
12use windows::Win32::System::Com::IStream;
13use windows::core::{Error, Interface};
14
15pub struct AudioSource {
16    ptr: *mut IAudioSource,
17}
18
19impl AudioSource {
20    pub(crate) fn new(ptr: *mut IAudioSource) -> Self {
21        assert!(!ptr.is_null());
22        Self { ptr }
23    }
24
25    pub fn subscribe_frame_captured(&self) -> Result<WAITABLE_HANDLE, Error> {
26        if self.ptr.is_null() {
27            return Err(Error::from(E_POINTER));
28        }
29        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
30        let subscribe_fn = vtbl
31            .SubscribeFrameCaptured
32            .ok_or_else(|| Error::from(E_FAIL))?;
33        let mut waitable_handle: WAITABLE_HANDLE = HANDLE::default();
34        let hr = unsafe { subscribe_fn(self.ptr, &mut waitable_handle) };
35        if hr.is_err() {
36            Err(Error::from_hresult(hr))
37        } else {
38            Ok(waitable_handle)
39        }
40    }
41
42    pub fn unsubscribe_frame_captured(
43        &self,
44        waitable_handle: WAITABLE_HANDLE,
45    ) -> Result<(), Error> {
46        if self.ptr.is_null() {
47            return Err(Error::from(E_POINTER));
48        }
49        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
50        let unsubscribe_fn = vtbl
51            .UnsubscribeFrameCaptured
52            .ok_or_else(|| Error::from(E_FAIL))?;
53        let hr = unsafe { unsubscribe_fn(self.ptr, waitable_handle) };
54        if hr.is_err() {
55            Err(Error::from_hresult(hr))
56        } else {
57            Ok(())
58        }
59    }
60
61    pub fn get_frame_captured_event_data(
62        &self,
63        waitable_handle: WAITABLE_HANDLE,
64    ) -> Result<FrameCapturedEventArgs, Error> {
65        if self.ptr.is_null() {
66            return Err(Error::from(E_POINTER));
67        }
68        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
69        let get_data_fn = vtbl
70            .GetFrameCapturedEventData
71            .ok_or_else(|| Error::from(E_FAIL))?;
72        let mut event_args_ptr: *mut IFrameCapturedEventArgs = ptr::null_mut();
73        let hr = unsafe { get_data_fn(self.ptr, waitable_handle, &mut event_args_ptr) };
74        if hr.is_err() {
75            Err(Error::from_hresult(hr))
76        } else {
77            Ok(FrameCapturedEventArgs::new(event_args_ptr))
78        }
79    }
80
81    pub fn get_kinect_sensor(&self) -> Result<KinectSensor, Error> {
82        if self.ptr.is_null() {
83            return Err(Error::from(E_POINTER));
84        }
85        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
86        let get_sensor_fn = vtbl.get_KinectSensor.ok_or_else(|| Error::from(E_FAIL))?;
87        let mut sensor: *mut IKinectSensor = ptr::null_mut();
88        let hr = unsafe { get_sensor_fn(self.ptr, &mut sensor) };
89        if hr.is_err() {
90            Err(Error::from_hresult(hr))
91        } else {
92            Ok(KinectSensor::new(sensor))
93        }
94    }
95
96    pub fn get_is_active(&self) -> Result<bool, Error> {
97        if self.ptr.is_null() {
98            return Err(Error::from(E_POINTER));
99        }
100        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
101        let get_active_fn = vtbl.get_IsActive.ok_or_else(|| Error::from(E_FAIL))?;
102        let mut is_active: BOOLEAN = 0;
103        let hr = unsafe { get_active_fn(self.ptr, &mut is_active) };
104        if hr.is_err() {
105            Err(Error::from_hresult(hr))
106        } else {
107            Ok(is_active != 0)
108        }
109    }
110
111    pub fn get_sub_frame_length_in_bytes(&self) -> Result<UINT, Error> {
112        if self.ptr.is_null() {
113            return Err(Error::from(E_POINTER));
114        }
115        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
116        let get_length_fn = vtbl
117            .get_SubFrameLengthInBytes
118            .ok_or_else(|| Error::from(E_FAIL))?;
119        let mut length: UINT = 0;
120        let hr = unsafe { get_length_fn(self.ptr, &mut length) };
121        if hr.is_err() {
122            Err(Error::from_hresult(hr))
123        } else {
124            Ok(length)
125        }
126    }
127
128    pub fn get_sub_frame_duration(&self) -> Result<TIMESPAN, Error> {
129        if self.ptr.is_null() {
130            return Err(Error::from(E_POINTER));
131        }
132        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
133        let get_duration_fn = vtbl
134            .get_SubFrameDuration
135            .ok_or_else(|| Error::from(E_FAIL))?;
136        let mut duration: TIMESPAN = 0;
137        let hr = unsafe { get_duration_fn(self.ptr, &mut duration) };
138        if hr.is_err() {
139            Err(Error::from_hresult(hr))
140        } else {
141            Ok(duration)
142        }
143    }
144
145    pub fn get_max_sub_frame_count(&self) -> Result<UINT, Error> {
146        if self.ptr.is_null() {
147            return Err(Error::from(E_POINTER));
148        }
149        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
150        let get_count_fn = vtbl
151            .get_MaxSubFrameCount
152            .ok_or_else(|| Error::from(E_FAIL))?;
153        let mut count: UINT = 0;
154        let hr = unsafe { get_count_fn(self.ptr, &mut count) };
155        if hr.is_err() {
156            Err(Error::from_hresult(hr))
157        } else {
158            Ok(count)
159        }
160    }
161
162    pub fn open_reader(&self) -> Result<AudioBeamFrameReader, Error> {
163        if self.ptr.is_null() {
164            return Err(Error::from(E_POINTER));
165        }
166        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
167        let open_reader_fn = vtbl.OpenReader.ok_or_else(|| Error::from(E_FAIL))?;
168        let mut reader: *mut IAudioBeamFrameReader = ptr::null_mut();
169        let hr = unsafe { open_reader_fn(self.ptr, &mut reader) };
170        if hr.is_err() {
171            Err(Error::from_hresult(hr))
172        } else {
173            Ok(AudioBeamFrameReader::new(reader))
174        }
175    }
176
177    pub fn get_audio_beams(&self) -> Result<AudioBeamList, Error> {
178        if self.ptr.is_null() {
179            return Err(Error::from(E_POINTER));
180        }
181        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
182        let get_beams_fn = vtbl.get_AudioBeams.ok_or_else(|| Error::from(E_FAIL))?;
183        let mut audio_beam_list: *mut IAudioBeamList = ptr::null_mut();
184        let hr = unsafe { get_beams_fn(self.ptr, &mut audio_beam_list) };
185        if hr.is_err() {
186            Err(Error::from_hresult(hr))
187        } else {
188            Ok(AudioBeamList::new(audio_beam_list))
189        }
190    }
191
192    pub fn get_audio_calibration_state(&self) -> Result<KinectAudioCalibrationState, Error> {
193        if self.ptr.is_null() {
194            return Err(Error::from(E_POINTER));
195        }
196        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
197        let get_state_fn = vtbl
198            .get_AudioCalibrationState
199            .ok_or_else(|| Error::from(E_FAIL))?;
200        let mut audio_calibration_state: KinectAudioCalibrationState =
201            KinectAudioCalibrationState::Unknown;
202        let hr = unsafe { get_state_fn(self.ptr, &mut audio_calibration_state) };
203        if hr.is_err() {
204            Err(Error::from_hresult(hr))
205        } else {
206            Ok(audio_calibration_state)
207        }
208    }
209}
210
211impl Drop for AudioSource {
212    fn drop(&mut self) {
213        if !self.ptr.is_null() {
214            unsafe {
215                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
216                    if let Some(release_fn) = vtbl.Release {
217                        release_fn(self.ptr);
218                    }
219                }
220            }
221            self.ptr = ptr::null_mut();
222        }
223    }
224}
225
226pub struct AudioBeam {
227    ptr: *mut IAudioBeam,
228}
229
230impl AudioBeam {
231    pub(crate) fn new(ptr: *mut IAudioBeam) -> Self {
232        assert!(!ptr.is_null());
233        Self { ptr }
234    }
235
236    pub fn get_audio_source(&self) -> Result<AudioSource, Error> {
237        if self.ptr.is_null() {
238            return Err(Error::from(E_POINTER));
239        }
240        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
241        let get_source_fn = vtbl.get_AudioSource.ok_or_else(|| Error::from(E_FAIL))?;
242        let mut audio_source_ptr: *mut IAudioSource = ptr::null_mut();
243        let hr = unsafe { get_source_fn(self.ptr, &mut audio_source_ptr) };
244        if hr.is_err() {
245            Err(Error::from_hresult(hr))
246        } else if audio_source_ptr.is_null() {
247            Err(Error::from(E_POINTER))
248        } else {
249            Ok(AudioSource::new(audio_source_ptr))
250        }
251    }
252
253    pub fn get_audio_beam_mode(&self) -> Result<AudioBeamMode, Error> {
254        if self.ptr.is_null() {
255            return Err(Error::from(E_POINTER));
256        }
257        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
258        let get_mode_fn = vtbl.get_AudioBeamMode.ok_or_else(|| Error::from(E_FAIL))?;
259        let mut audio_beam_mode: AudioBeamMode = AudioBeamMode::Automatic; // Default
260        let hr = unsafe { get_mode_fn(self.ptr, &mut audio_beam_mode) };
261        if hr.is_err() {
262            Err(Error::from_hresult(hr))
263        } else {
264            Ok(audio_beam_mode)
265        }
266    }
267
268    pub fn put_audio_beam_mode(&self, audio_beam_mode: AudioBeamMode) -> Result<(), Error> {
269        if self.ptr.is_null() {
270            return Err(Error::from(E_POINTER));
271        }
272        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
273        let put_mode_fn = vtbl.put_AudioBeamMode.ok_or_else(|| Error::from(E_FAIL))?;
274        let hr = unsafe { put_mode_fn(self.ptr, audio_beam_mode) };
275        if hr.is_err() {
276            Err(Error::from_hresult(hr))
277        } else {
278            Ok(())
279        }
280    }
281
282    pub fn get_beam_angle(&self) -> Result<f32, Error> {
283        if self.ptr.is_null() {
284            return Err(Error::from(E_POINTER));
285        }
286        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
287        let get_angle_fn = vtbl.get_BeamAngle.ok_or_else(|| Error::from(E_FAIL))?;
288        let mut beam_angle: f32 = 0.0;
289        let hr = unsafe { get_angle_fn(self.ptr, &mut beam_angle) };
290        if hr.is_err() {
291            Err(Error::from_hresult(hr))
292        } else {
293            Ok(beam_angle)
294        }
295    }
296
297    pub fn put_beam_angle(&self, beam_angle: f32) -> Result<(), Error> {
298        if self.ptr.is_null() {
299            return Err(Error::from(E_POINTER));
300        }
301        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
302        let put_angle_fn = vtbl.put_BeamAngle.ok_or_else(|| Error::from(E_FAIL))?;
303        let hr = unsafe { put_angle_fn(self.ptr, beam_angle) };
304        if hr.is_err() {
305            Err(Error::from_hresult(hr))
306        } else {
307            Ok(())
308        }
309    }
310
311    pub fn get_beam_angle_confidence(&self) -> Result<f32, Error> {
312        if self.ptr.is_null() {
313            return Err(Error::from(E_POINTER));
314        }
315        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
316        let get_confidence_fn = vtbl
317            .get_BeamAngleConfidence
318            .ok_or_else(|| Error::from(E_FAIL))?;
319        let mut beam_angle_confidence: f32 = 0.0;
320        let hr = unsafe { get_confidence_fn(self.ptr, &mut beam_angle_confidence) };
321        if hr.is_err() {
322            Err(Error::from_hresult(hr))
323        } else {
324            Ok(beam_angle_confidence)
325        }
326    }
327    pub fn open_input_stream(&self) -> Result<IStream, Error> {
328        if self.ptr.is_null() {
329            return Err(Error::from(E_POINTER));
330        }
331        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
332        let open_stream_fn = vtbl.OpenInputStream.ok_or_else(|| Error::from(E_FAIL))?;
333        let mut stream: *mut IStream = ptr::null_mut();
334        let hr = unsafe { open_stream_fn(self.ptr, &mut stream) };
335        if hr.is_err() {
336            Err(Error::from_hresult(hr))
337        } else if stream.is_null() {
338            Err(Error::from(E_POINTER))
339        } else {
340            // Create a safe IStream interface from the raw pointer
341            // The Windows crate handles COM reference counting automatically
342            // SAFETY: The raw pointer was just created by the COM API and is guaranteed to be valid
343            unsafe { Ok(IStream::from_raw(stream as *mut std::ffi::c_void)) }
344        }
345    }
346
347    pub fn get_relative_time(&self) -> Result<TIMESPAN, Error> {
348        if self.ptr.is_null() {
349            return Err(Error::from(E_POINTER));
350        }
351        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
352        let get_time_fn = vtbl.get_RelativeTime.ok_or_else(|| Error::from(E_FAIL))?;
353        let mut relative_time: TIMESPAN = 0;
354        let hr = unsafe { get_time_fn(self.ptr, &mut relative_time) };
355        if hr.is_err() {
356            Err(Error::from_hresult(hr))
357        } else {
358            Ok(relative_time)
359        }
360    }
361}
362
363impl Drop for AudioBeam {
364    fn drop(&mut self) {
365        if !self.ptr.is_null() {
366            unsafe {
367                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
368                    if let Some(release_fn) = vtbl.Release {
369                        release_fn(self.ptr);
370                    }
371                }
372            }
373            self.ptr = ptr::null_mut();
374        }
375    }
376}
377
378pub struct AudioBeamList {
379    ptr: *mut IAudioBeamList,
380}
381
382impl AudioBeamList {
383    pub(crate) fn new(ptr: *mut IAudioBeamList) -> Self {
384        assert!(!ptr.is_null());
385        Self { ptr }
386    }
387
388    pub fn get_beam_count(&self) -> Result<UINT, Error> {
389        if self.ptr.is_null() {
390            return Err(Error::from(E_POINTER));
391        }
392        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
393        let get_count_fn = vtbl.get_BeamCount.ok_or_else(|| Error::from(E_FAIL))?;
394        let mut count: UINT = 0;
395        let hr = unsafe { get_count_fn(self.ptr, &mut count) };
396        if hr.is_err() {
397            Err(Error::from_hresult(hr))
398        } else {
399            Ok(count)
400        }
401    }
402
403    pub fn open_audio_beam(&self, index: UINT) -> Result<AudioBeam, Error> {
404        if self.ptr.is_null() {
405            return Err(Error::from(E_POINTER));
406        }
407        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
408        let open_beam_fn = vtbl.OpenAudioBeam.ok_or_else(|| Error::from(E_FAIL))?;
409        let mut audio_beam_ptr: *mut IAudioBeam = ptr::null_mut();
410        let hr = unsafe { open_beam_fn(self.ptr, index, &mut audio_beam_ptr) };
411        if hr.is_err() {
412            Err(Error::from_hresult(hr))
413        } else if audio_beam_ptr.is_null() {
414            Err(Error::from(E_POINTER))
415        } else {
416            Ok(AudioBeam::new(audio_beam_ptr))
417        }
418    }
419}
420
421impl Drop for AudioBeamList {
422    fn drop(&mut self) {
423        if !self.ptr.is_null() {
424            unsafe {
425                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
426                    if let Some(release_fn) = vtbl.Release {
427                        release_fn(self.ptr);
428                    }
429                }
430            }
431            self.ptr = ptr::null_mut();
432        }
433    }
434}
435
436pub struct AudioBeamFrameList {
437    ptr: *mut IAudioBeamFrameList,
438}
439
440impl AudioBeamFrameList {
441    pub(crate) fn new(ptr: *mut IAudioBeamFrameList) -> Self {
442        assert!(!ptr.is_null());
443        Self { ptr }
444    }
445
446    pub fn get_beam_count(&self) -> Result<UINT, Error> {
447        if self.ptr.is_null() {
448            return Err(Error::from(E_POINTER));
449        }
450        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
451        let get_count_fn = vtbl.get_BeamCount.ok_or_else(|| Error::from(E_FAIL))?;
452        let mut count: UINT = 0;
453        let hr = unsafe { get_count_fn(self.ptr, &mut count) };
454        if hr.is_err() {
455            Err(Error::from_hresult(hr))
456        } else {
457            Ok(count)
458        }
459    }
460
461    pub fn open_audio_beam_frame(&self, index: UINT) -> Result<AudioBeamFrame, Error> {
462        if self.ptr.is_null() {
463            return Err(Error::from(E_POINTER));
464        }
465        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
466        let open_frame_fn = vtbl.OpenAudioBeamFrame.ok_or_else(|| Error::from(E_FAIL))?;
467        let mut audio_beam_frame_ptr: *mut IAudioBeamFrame = ptr::null_mut();
468        let hr = unsafe { open_frame_fn(self.ptr, index, &mut audio_beam_frame_ptr) };
469        if hr.is_err() {
470            Err(Error::from_hresult(hr))
471        } else if audio_beam_frame_ptr.is_null() {
472            Err(Error::from(E_POINTER))
473        } else {
474            Ok(AudioBeamFrame::new(audio_beam_frame_ptr))
475        }
476    }
477}
478
479impl Drop for AudioBeamFrameList {
480    fn drop(&mut self) {
481        if !self.ptr.is_null() {
482            unsafe {
483                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
484                    if let Some(release_fn) = vtbl.Release {
485                        release_fn(self.ptr);
486                    }
487                }
488            }
489            self.ptr = ptr::null_mut();
490        }
491    }
492}
493
494pub struct AudioBeamFrame {
495    ptr: *mut IAudioBeamFrame,
496}
497
498impl AudioBeamFrame {
499    pub(crate) fn new(ptr: *mut IAudioBeamFrame) -> Self {
500        assert!(!ptr.is_null());
501        Self { ptr }
502    }
503
504    pub fn get_audio_source(&self) -> Result<AudioSource, Error> {
505        if self.ptr.is_null() {
506            return Err(Error::from(E_POINTER));
507        }
508        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
509        let get_source_fn = vtbl.get_AudioSource.ok_or_else(|| Error::from(E_FAIL))?;
510        let mut audio_source_ptr: *mut IAudioSource = ptr::null_mut();
511        let hr = unsafe { get_source_fn(self.ptr, &mut audio_source_ptr) };
512        if hr.is_err() {
513            Err(Error::from_hresult(hr))
514        } else if audio_source_ptr.is_null() {
515            Err(Error::from(E_POINTER))
516        } else {
517            Ok(AudioSource::new(audio_source_ptr))
518        }
519    }
520
521    pub fn get_duration(&self) -> Result<TIMESPAN, Error> {
522        if self.ptr.is_null() {
523            return Err(Error::from(E_POINTER));
524        }
525        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
526        let get_duration_fn = vtbl.get_Duration.ok_or_else(|| Error::from(E_FAIL))?;
527        let mut duration: TIMESPAN = 0;
528        let hr = unsafe { get_duration_fn(self.ptr, &mut duration) };
529        if hr.is_err() {
530            Err(Error::from_hresult(hr))
531        } else {
532            Ok(duration)
533        }
534    }
535
536    pub fn get_audio_beam(&self) -> Result<AudioBeam, Error> {
537        if self.ptr.is_null() {
538            return Err(Error::from(E_POINTER));
539        }
540        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
541        let get_beam_fn = vtbl.get_AudioBeam.ok_or_else(|| Error::from(E_FAIL))?;
542        let mut audio_beam_ptr: *mut IAudioBeam = ptr::null_mut();
543        let hr = unsafe { get_beam_fn(self.ptr, &mut audio_beam_ptr) };
544        if hr.is_err() {
545            Err(Error::from_hresult(hr))
546        } else if audio_beam_ptr.is_null() {
547            Err(Error::from(E_POINTER))
548        } else {
549            Ok(AudioBeam::new(audio_beam_ptr))
550        }
551    }
552
553    pub fn get_sub_frame_count(&self) -> Result<UINT, Error> {
554        if self.ptr.is_null() {
555            return Err(Error::from(E_POINTER));
556        }
557        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
558        let get_count_fn = vtbl.get_SubFrameCount.ok_or_else(|| Error::from(E_FAIL))?;
559        let mut count: UINT = 0;
560        let hr = unsafe { get_count_fn(self.ptr, &mut count) };
561        if hr.is_err() {
562            Err(Error::from_hresult(hr))
563        } else {
564            Ok(count)
565        }
566    }
567
568    pub fn get_sub_frame(&self, sub_frame_index: UINT) -> Result<AudioBeamSubFrame, Error> {
569        if self.ptr.is_null() {
570            return Err(Error::from(E_POINTER));
571        }
572        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
573        let get_sub_frame_fn = vtbl.GetSubFrame.ok_or_else(|| Error::from(E_FAIL))?;
574        let mut audio_beam_sub_frame_ptr: *mut IAudioBeamSubFrame = ptr::null_mut();
575        let hr =
576            unsafe { get_sub_frame_fn(self.ptr, sub_frame_index, &mut audio_beam_sub_frame_ptr) };
577        if hr.is_err() {
578            Err(Error::from_hresult(hr))
579        } else if audio_beam_sub_frame_ptr.is_null() {
580            Err(Error::from(E_POINTER))
581        } else {
582            Ok(AudioBeamSubFrame::new(audio_beam_sub_frame_ptr))
583        }
584    }
585
586    pub fn get_relative_time_start(&self) -> Result<TIMESPAN, Error> {
587        if self.ptr.is_null() {
588            return Err(Error::from(E_POINTER));
589        }
590        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
591        let get_time_fn = vtbl
592            .get_RelativeTimeStart
593            .ok_or_else(|| Error::from(E_FAIL))?;
594        let mut relative_time: TIMESPAN = 0;
595        let hr = unsafe { get_time_fn(self.ptr, &mut relative_time) };
596        if hr.is_err() {
597            Err(Error::from_hresult(hr))
598        } else {
599            Ok(relative_time)
600        }
601    }
602}
603
604impl Drop for AudioBeamFrame {
605    fn drop(&mut self) {
606        if !self.ptr.is_null() {
607            unsafe {
608                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
609                    if let Some(release_fn) = vtbl.Release {
610                        release_fn(self.ptr);
611                    }
612                }
613            }
614            self.ptr = ptr::null_mut();
615        }
616    }
617}
618
619pub struct AudioBeamSubFrame {
620    ptr: *mut IAudioBeamSubFrame,
621}
622
623impl AudioBeamSubFrame {
624    pub(crate) fn new(ptr: *mut IAudioBeamSubFrame) -> Self {
625        assert!(!ptr.is_null());
626        Self { ptr }
627    }
628
629    pub fn get_frame_length_in_bytes(&self) -> Result<UINT, Error> {
630        if self.ptr.is_null() {
631            return Err(Error::from(E_POINTER));
632        }
633        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
634        let get_length_fn = vtbl
635            .get_FrameLengthInBytes
636            .ok_or_else(|| Error::from(E_FAIL))?;
637        let mut length: UINT = 0;
638        let hr = unsafe { get_length_fn(self.ptr, &mut length) };
639        if hr.is_err() {
640            Err(Error::from_hresult(hr))
641        } else {
642            Ok(length)
643        }
644    }
645
646    pub fn get_duration(&self) -> Result<TIMESPAN, Error> {
647        if self.ptr.is_null() {
648            return Err(Error::from(E_POINTER));
649        }
650        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
651        let get_duration_fn = vtbl.get_Duration.ok_or_else(|| Error::from(E_FAIL))?;
652        let mut duration: TIMESPAN = 0;
653        let hr = unsafe { get_duration_fn(self.ptr, &mut duration) };
654        if hr.is_err() {
655            Err(Error::from_hresult(hr))
656        } else {
657            Ok(duration)
658        }
659    }
660
661    pub fn get_beam_angle(&self) -> Result<f32, Error> {
662        if self.ptr.is_null() {
663            return Err(Error::from(E_POINTER));
664        }
665        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
666        let get_angle_fn = vtbl.get_BeamAngle.ok_or_else(|| Error::from(E_FAIL))?;
667        let mut beam_angle: f32 = 0.0;
668        let hr = unsafe { get_angle_fn(self.ptr, &mut beam_angle) };
669        if hr.is_err() {
670            Err(Error::from_hresult(hr))
671        } else {
672            Ok(beam_angle)
673        }
674    }
675
676    pub fn get_beam_angle_confidence(&self) -> Result<f32, Error> {
677        if self.ptr.is_null() {
678            return Err(Error::from(E_POINTER));
679        }
680        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
681        let get_confidence_fn = vtbl
682            .get_BeamAngleConfidence
683            .ok_or_else(|| Error::from(E_FAIL))?;
684        let mut beam_angle_confidence: f32 = 0.0;
685        let hr = unsafe { get_confidence_fn(self.ptr, &mut beam_angle_confidence) };
686        if hr.is_err() {
687            Err(Error::from_hresult(hr))
688        } else {
689            Ok(beam_angle_confidence)
690        }
691    }
692
693    pub fn get_audio_beam_mode(&self) -> Result<AudioBeamMode, Error> {
694        if self.ptr.is_null() {
695            return Err(Error::from(E_POINTER));
696        }
697        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
698        let get_mode_fn = vtbl.get_AudioBeamMode.ok_or_else(|| Error::from(E_FAIL))?;
699        let mut audio_beam_mode: AudioBeamMode = AudioBeamMode::Automatic; // Default
700        let hr = unsafe { get_mode_fn(self.ptr, &mut audio_beam_mode) };
701        if hr.is_err() {
702            Err(Error::from_hresult(hr))
703        } else {
704            Ok(audio_beam_mode)
705        }
706    }
707
708    pub fn get_audio_body_correlation_count(&self) -> Result<UINT, Error> {
709        if self.ptr.is_null() {
710            return Err(Error::from(E_POINTER));
711        }
712        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
713        let get_count_fn = vtbl
714            .get_AudioBodyCorrelationCount
715            .ok_or_else(|| Error::from(E_FAIL))?;
716        let mut count: UINT = 0;
717        let hr = unsafe { get_count_fn(self.ptr, &mut count) };
718        if hr.is_err() {
719            Err(Error::from_hresult(hr))
720        } else {
721            Ok(count)
722        }
723    }
724
725    pub fn get_audio_body_correlation(&self, index: UINT) -> Result<AudioBodyCorrelation, Error> {
726        if self.ptr.is_null() {
727            return Err(Error::from(E_POINTER));
728        }
729        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
730        let get_correlation_fn = vtbl
731            .GetAudioBodyCorrelation
732            .ok_or_else(|| Error::from(E_FAIL))?;
733        let mut audio_body_correlation: *mut IAudioBodyCorrelation = ptr::null_mut();
734        let hr = unsafe { get_correlation_fn(self.ptr, index, &mut audio_body_correlation) };
735        if hr.is_err() {
736            Err(Error::from_hresult(hr))
737        } else {
738            Ok(AudioBodyCorrelation::new(audio_body_correlation))
739        }
740    }
741
742    pub fn copy_frame_data_to_array(&self, buffer: &mut [u8]) -> Result<(), Error> {
743        if self.ptr.is_null() {
744            return Err(Error::from(E_POINTER));
745        }
746        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
747        let copy_data_fn = vtbl
748            .CopyFrameDataToArray
749            .ok_or_else(|| Error::from(E_FAIL))?;
750
751        let capacity = buffer.len() as UINT;
752        let buffer_ptr = buffer.as_mut_ptr() as *mut BYTE;
753
754        let hr = unsafe { copy_data_fn(self.ptr, capacity, buffer_ptr) };
755        if hr.is_err() {
756            Err(Error::from_hresult(hr))
757        } else {
758            Ok(())
759        }
760    }
761
762    pub fn access_underlying_buffer(&self) -> Result<&[u8], Error> {
763        if self.ptr.is_null() {
764            return Err(Error::from(E_POINTER));
765        }
766        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
767        let access_buffer_fn = vtbl
768            .AccessUnderlyingBuffer
769            .ok_or_else(|| Error::from(E_FAIL))?;
770
771        let mut capacity: UINT = 0;
772        let mut buffer: *mut BYTE = ptr::null_mut();
773        let hr = unsafe { access_buffer_fn(self.ptr, &mut capacity, &mut buffer) };
774
775        if hr.is_err() {
776            Err(Error::from_hresult(hr))
777        } else if buffer.is_null() || capacity == 0 {
778            Err(Error::from(E_POINTER))
779        } else {
780            // Create a safe slice from the raw pointer
781            let slice =
782                unsafe { std::slice::from_raw_parts(buffer as *const u8, capacity as usize) };
783            Ok(slice)
784        }
785    }
786
787    pub fn get_relative_time(&self) -> Result<TIMESPAN, Error> {
788        if self.ptr.is_null() {
789            return Err(Error::from(E_POINTER));
790        }
791        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
792        let get_time_fn = vtbl.get_RelativeTime.ok_or_else(|| Error::from(E_FAIL))?;
793        let mut relative_time: TIMESPAN = 0;
794        let hr = unsafe { get_time_fn(self.ptr, &mut relative_time) };
795        if hr.is_err() {
796            Err(Error::from_hresult(hr))
797        } else {
798            Ok(relative_time)
799        }
800    }
801}
802
803impl Drop for AudioBeamSubFrame {
804    fn drop(&mut self) {
805        if !self.ptr.is_null() {
806            unsafe {
807                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
808                    if let Some(release_fn) = vtbl.Release {
809                        release_fn(self.ptr);
810                    }
811                }
812            }
813            self.ptr = ptr::null_mut();
814        }
815    }
816}
817
818pub struct AudioBodyCorrelation {
819    ptr: *mut IAudioBodyCorrelation,
820}
821
822impl AudioBodyCorrelation {
823    pub(crate) fn new(ptr: *mut IAudioBodyCorrelation) -> Self {
824        assert!(!ptr.is_null());
825        Self { ptr }
826    }
827
828    pub fn get_body_tracking_id(&self) -> Result<UINT64, Error> {
829        if self.ptr.is_null() {
830            return Err(Error::from(E_POINTER));
831        }
832        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
833        let get_body_id_fn = vtbl.get_BodyTrackingId.ok_or_else(|| Error::from(E_FAIL))?;
834        let mut body_tracking_id: UINT64 = 0;
835        let hr = unsafe { get_body_id_fn(self.ptr, &mut body_tracking_id) };
836        if hr.is_err() {
837            Err(Error::from_hresult(hr))
838        } else {
839            Ok(body_tracking_id)
840        }
841    }
842}
843
844impl Drop for AudioBodyCorrelation {
845    fn drop(&mut self) {
846        if !self.ptr.is_null() {
847            unsafe {
848                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
849                    if let Some(release_fn) = vtbl.Release {
850                        release_fn(self.ptr);
851                    }
852                }
853            }
854            self.ptr = ptr::null_mut();
855        }
856    }
857}
858
859pub struct AudioBeamFrameReference {
860    ptr: *mut IAudioBeamFrameReference,
861}
862
863impl AudioBeamFrameReference {
864    pub(crate) fn new(ptr: *mut IAudioBeamFrameReference) -> Self {
865        assert!(!ptr.is_null());
866        Self { ptr }
867    }
868
869    pub fn acquire_beam_frame(&self) -> Result<AudioBeamFrameList, Error> {
870        if self.ptr.is_null() {
871            return Err(Error::from(E_POINTER));
872        }
873        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
874        let acquire_frame_fn = vtbl.AcquireBeamFrames.ok_or_else(|| Error::from(E_FAIL))?;
875        let mut audio_beam_frame_list_ptr: *mut IAudioBeamFrameList = ptr::null_mut();
876        let hr = unsafe { acquire_frame_fn(self.ptr, &mut audio_beam_frame_list_ptr) };
877        if hr.is_err() {
878            Err(Error::from_hresult(hr))
879        } else if audio_beam_frame_list_ptr.is_null() {
880            Err(Error::from(E_POINTER))
881        } else {
882            Ok(AudioBeamFrameList::new(audio_beam_frame_list_ptr))
883        }
884    }
885
886    pub fn get_relative_time(&self) -> Result<TIMESPAN, Error> {
887        if self.ptr.is_null() {
888            return Err(Error::from(E_POINTER));
889        }
890        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
891        let get_time_fn = vtbl.get_RelativeTime.ok_or_else(|| Error::from(E_FAIL))?;
892        let mut relative_time: TIMESPAN = 0;
893        let hr = unsafe { get_time_fn(self.ptr, &mut relative_time) };
894        if hr.is_err() {
895            Err(Error::from_hresult(hr))
896        } else {
897            Ok(relative_time)
898        }
899    }
900}
901
902impl Drop for AudioBeamFrameReference {
903    fn drop(&mut self) {
904        if !self.ptr.is_null() {
905            unsafe {
906                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
907                    if let Some(release_fn) = vtbl.Release {
908                        release_fn(self.ptr);
909                    }
910                }
911            }
912            self.ptr = ptr::null_mut();
913        }
914    }
915}
916
917pub struct AudioBeamFrameArrivedEventArgs {
918    ptr: *mut IAudioBeamFrameArrivedEventArgs,
919}
920
921impl AudioBeamFrameArrivedEventArgs {
922    pub(crate) fn new(ptr: *mut IAudioBeamFrameArrivedEventArgs) -> Self {
923        assert!(!ptr.is_null());
924        Self { ptr }
925    }
926
927    pub fn get_frame_reference(&self) -> Result<AudioBeamFrameReference, Error> {
928        if self.ptr.is_null() {
929            return Err(Error::from(E_POINTER));
930        }
931        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
932        let get_frame_fn = vtbl.get_FrameReference.ok_or_else(|| Error::from(E_FAIL))?;
933        let mut audio_beam_frame_reference_ptr: *mut IAudioBeamFrameReference = ptr::null_mut();
934        let hr = unsafe { get_frame_fn(self.ptr, &mut audio_beam_frame_reference_ptr) };
935        if hr.is_err() {
936            Err(Error::from_hresult(hr))
937        } else if audio_beam_frame_reference_ptr.is_null() {
938            Err(Error::from(E_POINTER))
939        } else {
940            Ok(AudioBeamFrameReference::new(audio_beam_frame_reference_ptr))
941        }
942    }
943}
944
945impl Drop for AudioBeamFrameArrivedEventArgs {
946    fn drop(&mut self) {
947        if !self.ptr.is_null() {
948            unsafe {
949                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
950                    if let Some(release_fn) = vtbl.Release {
951                        release_fn(self.ptr);
952                    }
953                }
954            }
955            self.ptr = ptr::null_mut();
956        }
957    }
958}
959
960pub struct AudioBeamFrameReader {
961    ptr: *mut IAudioBeamFrameReader,
962}
963
964impl AudioBeamFrameReader {
965    pub(crate) fn new(ptr: *mut IAudioBeamFrameReader) -> Self {
966        assert!(!ptr.is_null());
967        Self { ptr }
968    }
969
970    pub fn subscribe_frame_arrived(&self) -> Result<WAITABLE_HANDLE, Error> {
971        if self.ptr.is_null() {
972            return Err(Error::from(E_POINTER));
973        }
974        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
975        let subscribe_fn = vtbl
976            .SubscribeFrameArrived
977            .ok_or_else(|| Error::from(E_FAIL))?;
978        let mut waitable_handle: WAITABLE_HANDLE = HANDLE::default();
979        let hr = unsafe { subscribe_fn(self.ptr, &mut waitable_handle) };
980        if hr.is_err() {
981            Err(Error::from_hresult(hr))
982        } else {
983            Ok(waitable_handle)
984        }
985    }
986
987    pub fn unsubscribe_frame_arrived(&self, waitable_handle: WAITABLE_HANDLE) -> Result<(), Error> {
988        if self.ptr.is_null() {
989            return Err(Error::from(E_POINTER));
990        }
991        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
992        let unsubscribe_fn = vtbl
993            .UnsubscribeFrameArrived
994            .ok_or_else(|| Error::from(E_FAIL))?;
995        let hr = unsafe { unsubscribe_fn(self.ptr, waitable_handle) };
996        if hr.is_err() {
997            Err(Error::from_hresult(hr))
998        } else {
999            Ok(())
1000        }
1001    }
1002
1003    pub fn get_frame_arrived_event_data(
1004        &self,
1005        waitable_handle: WAITABLE_HANDLE,
1006    ) -> Result<AudioBeamFrameArrivedEventArgs, Error> {
1007        if self.ptr.is_null() {
1008            return Err(Error::from(E_POINTER));
1009        }
1010        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
1011        let get_data_fn = vtbl
1012            .GetFrameArrivedEventData
1013            .ok_or_else(|| Error::from(E_FAIL))?;
1014        let mut event_data: *mut IAudioBeamFrameArrivedEventArgs = ptr::null_mut();
1015        let hr = unsafe { get_data_fn(self.ptr, waitable_handle, &mut event_data) };
1016        if hr.is_err() {
1017            Err(Error::from_hresult(hr))
1018        } else {
1019            Ok(AudioBeamFrameArrivedEventArgs::new(event_data))
1020        }
1021    }
1022
1023    pub fn acquire_latest_beam_frames(&self) -> Result<AudioBeamFrameList, Error> {
1024        if self.ptr.is_null() {
1025            return Err(Error::from(E_POINTER));
1026        }
1027        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
1028        let acquire_fn = vtbl
1029            .AcquireLatestBeamFrames
1030            .ok_or_else(|| Error::from(E_FAIL))?;
1031        let mut audio_beam_frame_list_ptr: *mut IAudioBeamFrameList = ptr::null_mut();
1032        let hr = unsafe { acquire_fn(self.ptr, &mut audio_beam_frame_list_ptr) };
1033        if hr.is_err() {
1034            Err(Error::from_hresult(hr))
1035        } else if audio_beam_frame_list_ptr.is_null() {
1036            Err(Error::from(E_POINTER))
1037        } else {
1038            Ok(AudioBeamFrameList::new(audio_beam_frame_list_ptr))
1039        }
1040    }
1041
1042    pub fn get_is_paused(&self) -> Result<bool, Error> {
1043        if self.ptr.is_null() {
1044            return Err(Error::from(E_POINTER));
1045        }
1046        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
1047        let get_paused_fn = vtbl.get_IsPaused.ok_or_else(|| Error::from(E_FAIL))?;
1048        let mut is_paused: BOOLEAN = 0;
1049        let hr = unsafe { get_paused_fn(self.ptr, &mut is_paused) };
1050        if hr.is_err() {
1051            Err(Error::from_hresult(hr))
1052        } else {
1053            Ok(is_paused != 0)
1054        }
1055    }
1056
1057    pub fn put_is_paused(&self, is_paused: bool) -> Result<(), Error> {
1058        if self.ptr.is_null() {
1059            return Err(Error::from(E_POINTER));
1060        }
1061        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
1062        let put_paused_fn = vtbl.put_IsPaused.ok_or_else(|| Error::from(E_FAIL))?;
1063        let paused_value: BOOLEAN = if is_paused { 1 } else { 0 };
1064        let hr = unsafe { put_paused_fn(self.ptr, paused_value) };
1065        if hr.is_err() {
1066            Err(Error::from_hresult(hr))
1067        } else {
1068            Ok(())
1069        }
1070    }
1071
1072    pub fn get_audio_source(&self) -> Result<AudioSource, Error> {
1073        if self.ptr.is_null() {
1074            return Err(Error::from(E_POINTER));
1075        }
1076        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
1077        let get_source_fn = vtbl.get_AudioSource.ok_or_else(|| Error::from(E_FAIL))?;
1078        let mut audio_source_ptr: *mut IAudioSource = ptr::null_mut();
1079        let hr = unsafe { get_source_fn(self.ptr, &mut audio_source_ptr) };
1080        if hr.is_err() {
1081            Err(Error::from_hresult(hr))
1082        } else if audio_source_ptr.is_null() {
1083            Err(Error::from(E_POINTER))
1084        } else {
1085            Ok(AudioSource::new(audio_source_ptr))
1086        }
1087    }
1088}
1089
1090impl Drop for AudioBeamFrameReader {
1091    fn drop(&mut self) {
1092        if !self.ptr.is_null() {
1093            unsafe {
1094                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref() {
1095                    if let Some(release_fn) = vtbl.Release {
1096                        release_fn(self.ptr);
1097                    }
1098                }
1099            }
1100            self.ptr = ptr::null_mut();
1101        }
1102    }
1103}
1104
1105// tests
1106#[cfg(test)]
1107mod tests {
1108    use std::{thread, time::Duration};
1109
1110    use crate::{DEFAULT_FRAME_WAIT_TIMEOUT_MS, kinect};
1111
1112    use windows::Win32::{
1113        Foundation::{WAIT_OBJECT_0, WAIT_TIMEOUT},
1114        System::{Com::Urlmon::E_PENDING, Threading::WaitForSingleObject},
1115    };
1116
1117    #[test]
1118    fn get_latest_audio_frame() -> anyhow::Result<()> {
1119        let kinect = kinect::get_default_kinect_sensor()?;
1120        kinect.open()?;
1121        let audio_source = kinect.audio_source()?;
1122        let audio_beam_frame_reader = audio_source.open_reader()?;
1123
1124        let mut frame_counter = 0;
1125        loop {
1126            match audio_beam_frame_reader.acquire_latest_beam_frames() {
1127                Ok(frame_list) => {
1128                    let beam_count = frame_list.get_beam_count()?;
1129                    assert_eq!(beam_count, 1, "Expected only 1 audio beam");
1130
1131                    let audio_beam_frame = frame_list.open_audio_beam_frame(0)?;
1132                    let duration = audio_beam_frame.get_duration()?;
1133                    let sub_frame_count = audio_beam_frame.get_sub_frame_count()?;
1134                    let audio_beam = audio_beam_frame.get_audio_beam()?;
1135                    let beam_angle = audio_beam.get_beam_angle()?;
1136                    let beam_angle_confidence = audio_beam.get_beam_angle_confidence()?;
1137                    let relative_time = audio_beam.get_relative_time()?;
1138
1139                    println!(
1140                        "AudioFrame Duration: {duration}, SubFrameCount:{sub_frame_count}, Beam Angle: {beam_angle}, Confidence: {beam_angle_confidence}, Relative Time: {relative_time}"
1141                    );
1142
1143                    assert!(
1144                        sub_frame_count >= 1,
1145                        "Expected at least 1 sub-frame in audio beam frame"
1146                    );
1147                    assert!(
1148                        (-180.0..=180.0).contains(&beam_angle),
1149                        "Beam angle out of range"
1150                    );
1151                    assert!(
1152                        (0.0..=1.0).contains(&beam_angle_confidence),
1153                        "Beam angle confidence out of range"
1154                    );
1155                    assert!(relative_time >= 0, "Relative time should be non-negative");
1156
1157                    frame_counter += 1;
1158                    if frame_counter >= 10 {
1159                        break; // Limit to 10 frames for testing
1160                    }
1161                }
1162                Err(e) => {
1163                    if e.code() == E_PENDING {
1164                        println!("Audio frame not ready yet, waiting...");
1165                        // If the frame is not ready yet, wait and try again
1166                        thread::sleep(Duration::from_millis(100));
1167                    } else {
1168                        // If it's a different error, return it
1169                        return Err(anyhow::Error::new(e));
1170                    }
1171                }
1172            }
1173        }
1174
1175        Ok(())
1176    }
1177
1178    #[test]
1179    fn subscribe_audio_frame_arrived_event() -> anyhow::Result<()> {
1180        let kinect = kinect::get_default_kinect_sensor()?;
1181        kinect.open()?;
1182        let audio_source = kinect.audio_source()?;
1183        let audio_frame_reader = audio_source.open_reader()?;
1184        let waitable_handle = audio_frame_reader.subscribe_frame_arrived()?;
1185        let is_active = audio_source.get_is_active()?;
1186        assert!(is_active, "Audio source should be active");
1187
1188        let mut frame_counter = 0;
1189        loop {
1190            let wait_result =
1191                unsafe { WaitForSingleObject(waitable_handle, DEFAULT_FRAME_WAIT_TIMEOUT_MS) };
1192            if WAIT_OBJECT_0 == wait_result {
1193                let event_args =
1194                    audio_frame_reader.get_frame_arrived_event_data(waitable_handle)?;
1195
1196                let frame_reference = event_args.get_frame_reference()?;
1197                let frame_list = frame_reference.acquire_beam_frame()?;
1198                let beam_count = frame_list.get_beam_count()?;
1199                assert_eq!(beam_count, 1, "Expected only 1 audio beam");
1200
1201                let audio_beam_frame = frame_list.open_audio_beam_frame(0)?;
1202                let duration = audio_beam_frame.get_duration()?;
1203                let sub_frame_count = audio_beam_frame.get_sub_frame_count()?;
1204                let audio_beam = audio_beam_frame.get_audio_beam()?;
1205                let beam_mode = audio_beam.get_audio_beam_mode()?;
1206                let beam_angle = audio_beam.get_beam_angle()?;
1207                let beam_angle_confidence = audio_beam.get_beam_angle_confidence()?;
1208                let relative_time = audio_beam.get_relative_time()?;
1209
1210                println!(
1211                    "AudioFrame Duration ticks: {duration}, SubFrameCount:{sub_frame_count}, Beam Mode: {beam_mode:?}, Beam Angle: {beam_angle}, Confidence: {beam_angle_confidence}, Relative Time: {relative_time}"
1212                );
1213
1214                assert!(
1215                    sub_frame_count >= 1,
1216                    "Expected at least 1 sub-frame in audio beam frame"
1217                );
1218                assert!(
1219                    (-180.0..=180.0).contains(&beam_angle),
1220                    "Beam angle out of range"
1221                );
1222                assert!(
1223                    (0.0..=1.0).contains(&beam_angle_confidence),
1224                    "Beam angle confidence out of range"
1225                );
1226                assert!(relative_time >= 0, "Relative time should be non-negative");
1227
1228                for i in 0..sub_frame_count {
1229                    let sub_frame = audio_beam_frame.get_sub_frame(i)?;
1230                    let sub_frame_duration = sub_frame.get_duration()?;
1231                    assert!(
1232                        sub_frame_duration > 0,
1233                        "Sub-frame duration should be positive"
1234                    );
1235
1236                    let sub_frame_bytes = sub_frame.get_frame_length_in_bytes()?;
1237                    assert!(
1238                        sub_frame_bytes > 0,
1239                        "Sub-frame length in bytes should be positive"
1240                    );
1241
1242                    let sub_frame_data = sub_frame.access_underlying_buffer()?;
1243                    assert!(
1244                        !sub_frame_data.is_empty(),
1245                        "Sub-frame data should not be empty"
1246                    );
1247                    println!(
1248                        "SubFrame {}: Duration ticks: {}, Length: {}, Data Size: {} bytes",
1249                        i,
1250                        sub_frame_duration,
1251                        sub_frame_bytes,
1252                        sub_frame_data.len()
1253                    );
1254                }
1255
1256                frame_counter += 1;
1257                if frame_counter >= 10 {
1258                    break; // Limit to 10 frames for testing
1259                }
1260            } else if WAIT_TIMEOUT == wait_result {
1261                println!("No new audio frame available, waiting...");
1262            } else {
1263                return Err(anyhow::anyhow!(
1264                    "WaitForSingleObject failed with result: {:?}",
1265                    wait_result
1266                ));
1267            }
1268        }
1269
1270        // Unsubscribe from the event
1271        audio_frame_reader.unsubscribe_frame_arrived(waitable_handle)?;
1272
1273        Ok(())
1274    }
1275}