Skip to main content

webrtc_sys/
audio_device_controller.rs

1// Copyright 2026 LiveKit, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub use cxx::SharedPtr;
16
17use crate::impl_thread_safety;
18
19#[cxx::bridge(namespace = "livekit_ffi")]
20pub mod ffi {
21    unsafe extern "C++" {
22        include!("livekit/audio_device_controller.h");
23        include!("livekit/peer_connection_factory.h");
24
25        type AudioDeviceController;
26        type PeerConnectionFactory = crate::peer_connection_factory::ffi::PeerConnectionFactory;
27
28        fn audio_device(self: &PeerConnectionFactory) -> SharedPtr<AudioDeviceController>;
29
30        fn playout_devices(self: &AudioDeviceController) -> i16;
31        fn recording_devices(self: &AudioDeviceController) -> i16;
32        fn playout_device_name(self: &AudioDeviceController, index: u16) -> String;
33        fn recording_device_name(self: &AudioDeviceController, index: u16) -> String;
34        fn playout_device_guid(self: &AudioDeviceController, index: u16) -> String;
35        fn recording_device_guid(self: &AudioDeviceController, index: u16) -> String;
36
37        fn set_playout_device(self: &AudioDeviceController, index: u16) -> bool;
38        fn set_recording_device(self: &AudioDeviceController, index: u16) -> bool;
39        fn set_playout_device_by_guid(self: &AudioDeviceController, guid: String) -> bool;
40        fn set_recording_device_by_guid(self: &AudioDeviceController, guid: String) -> bool;
41
42        fn stop_recording(self: &AudioDeviceController) -> bool;
43        fn init_recording(self: &AudioDeviceController) -> bool;
44        fn start_recording(self: &AudioDeviceController) -> bool;
45        fn recording_is_initialized(self: &AudioDeviceController) -> bool;
46
47        fn stop_playout(self: &AudioDeviceController) -> bool;
48        fn init_playout(self: &AudioDeviceController) -> bool;
49        fn start_playout(self: &AudioDeviceController) -> bool;
50        fn playout_is_initialized(self: &AudioDeviceController) -> bool;
51
52        fn builtin_aec_is_available(self: &AudioDeviceController) -> bool;
53        fn builtin_agc_is_available(self: &AudioDeviceController) -> bool;
54        fn builtin_ns_is_available(self: &AudioDeviceController) -> bool;
55        fn enable_builtin_aec(self: &AudioDeviceController, enable: bool) -> bool;
56        fn enable_builtin_agc(self: &AudioDeviceController, enable: bool) -> bool;
57        fn enable_builtin_ns(self: &AudioDeviceController, enable: bool) -> bool;
58
59        fn set_adm_recording_enabled(self: &AudioDeviceController, enabled: bool);
60        fn adm_recording_enabled(self: &AudioDeviceController) -> bool;
61
62        fn set_adm_playout_enabled(self: &AudioDeviceController, enabled: bool);
63        fn adm_playout_enabled(self: &AudioDeviceController) -> bool;
64
65        fn acquire_platform_adm(self: &AudioDeviceController) -> bool;
66        fn release_platform_adm(self: &AudioDeviceController);
67        fn platform_adm_ref_count(self: &AudioDeviceController) -> i32;
68        fn is_platform_adm_active(self: &AudioDeviceController) -> bool;
69    }
70}
71
72impl_thread_safety!(ffi::AudioDeviceController, Send + Sync);
73
74#[cfg(test)]
75mod tests {
76    use crate::peer_connection_factory::ffi::create_peer_connection_factory;
77    use std::sync::Mutex;
78
79    static TEST_MUTEX: Mutex<()> = Mutex::new(());
80
81    #[test]
82    fn test_audio_device_controller_bridge() {
83        let _guard = TEST_MUTEX.lock().expect("test mutex poisoned");
84        let factory = create_peer_connection_factory();
85        let audio = factory.audio_device();
86
87        let recording_count = audio.recording_devices();
88        let playout_count = audio.playout_devices();
89        assert!(recording_count >= 0);
90        assert!(playout_count >= 0);
91
92        if recording_count > 0 {
93            let _ = audio.recording_device_name(0);
94            let guid = audio.recording_device_guid(0);
95            let _ = audio.set_recording_device_by_guid(guid);
96        }
97
98        if playout_count > 0 {
99            let _ = audio.playout_device_name(0);
100            let guid = audio.playout_device_guid(0);
101            let _ = audio.set_playout_device_by_guid(guid);
102        }
103
104        let initial_recording = audio.adm_recording_enabled();
105        audio.set_adm_recording_enabled(!initial_recording);
106        assert_eq!(audio.adm_recording_enabled(), !initial_recording);
107        audio.set_adm_recording_enabled(initial_recording);
108        assert_eq!(audio.adm_recording_enabled(), initial_recording);
109
110        let initial_playout = audio.adm_playout_enabled();
111        audio.set_adm_playout_enabled(!initial_playout);
112        assert_eq!(audio.adm_playout_enabled(), !initial_playout);
113        audio.set_adm_playout_enabled(initial_playout);
114        assert_eq!(audio.adm_playout_enabled(), initial_playout);
115
116        assert!(audio.platform_adm_ref_count() >= 0);
117        let _ = audio.is_platform_adm_active();
118    }
119}