Skip to main content

webrtc_sys/
audio_track.rs

1// Copyright 2025 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
15use cxx::type_id;
16use cxx::ExternType;
17use std::any::Any;
18use std::sync::Arc;
19
20use crate::impl_thread_safety;
21
22#[cxx::bridge(namespace = "livekit_ffi")]
23pub mod ffi {
24
25    pub struct AudioSourceOptions {
26        pub echo_cancellation: bool,
27        pub noise_suppression: bool,
28        pub auto_gain_control: bool,
29    }
30
31    extern "C++" {
32        include!("livekit/media_stream_track.h");
33
34        type MediaStreamTrack = crate::media_stream_track::ffi::MediaStreamTrack;
35        type CompleteCallback = crate::audio_track::CompleteCallback;
36    }
37
38    unsafe extern "C++" {
39        include!("livekit/audio_track.h");
40
41        type AudioTrack;
42        type NativeAudioSink;
43        type AudioTrackSource;
44
45        fn add_sink(self: &AudioTrack, sink: &SharedPtr<NativeAudioSink>);
46        fn remove_sink(self: &AudioTrack, sink: &SharedPtr<NativeAudioSink>);
47        fn new_native_audio_sink(
48            observer: Box<AudioSinkWrapper>,
49            sample_rate: i32,
50            num_channels: i32,
51        ) -> SharedPtr<NativeAudioSink>;
52
53        unsafe fn capture_frame(
54            self: &AudioTrackSource,
55            data: &[i16],
56            sample_rate: u32,
57            nb_channels: u32,
58            nb_frames: usize,
59            userdata: *const SourceContext,
60            on_complete: CompleteCallback,
61        ) -> bool;
62        fn clear_buffer(self: &AudioTrackSource);
63        fn audio_options(self: &AudioTrackSource) -> AudioSourceOptions;
64        fn set_audio_options(self: &AudioTrackSource, options: &AudioSourceOptions);
65
66        fn new_audio_track_source(
67            options: AudioSourceOptions,
68            sample_rate: i32,
69            num_channels: i32,
70            queue_size_ms: i32,
71        ) -> SharedPtr<AudioTrackSource>;
72
73        fn audio_to_media(track: SharedPtr<AudioTrack>) -> SharedPtr<MediaStreamTrack>;
74        unsafe fn media_to_audio(track: SharedPtr<MediaStreamTrack>) -> SharedPtr<AudioTrack>;
75        fn _shared_audio_track() -> SharedPtr<AudioTrack>;
76        fn _shared_audio_track_source() -> SharedPtr<AudioTrackSource>;
77    }
78
79    extern "Rust" {
80        type AudioSinkWrapper;
81        type SourceContext;
82
83        fn on_data(
84            self: &AudioSinkWrapper,
85            data: &[i16],
86            sample_rate: i32,
87            nb_channels: usize,
88            nb_frames: usize,
89        );
90    }
91}
92
93impl_thread_safety!(ffi::AudioTrack, Send + Sync);
94impl_thread_safety!(ffi::NativeAudioSink, Send + Sync);
95impl_thread_safety!(ffi::AudioTrackSource, Send + Sync);
96
97#[repr(transparent)]
98pub struct SourceContext(pub Box<dyn Any + Send>);
99
100#[repr(transparent)]
101pub struct CompleteCallback(pub extern "C" fn(ctx: *const SourceContext));
102
103unsafe impl ExternType for CompleteCallback {
104    type Id = type_id!("livekit_ffi::CompleteCallback");
105    type Kind = cxx::kind::Trivial;
106}
107
108pub trait AudioSink: Send {
109    fn on_data(&self, data: &[i16], sample_rate: i32, nb_channels: usize, nb_frames: usize);
110}
111
112pub struct AudioSinkWrapper {
113    observer: Arc<dyn AudioSink>,
114}
115
116impl AudioSinkWrapper {
117    pub fn new(observer: Arc<dyn AudioSink>) -> Self {
118        Self { observer }
119    }
120
121    fn on_data(&self, data: &[i16], sample_rate: i32, nb_channels: usize, nb_frames: usize) {
122        self.observer.on_data(data, sample_rate, nb_channels, nb_frames);
123    }
124}