Skip to main content

gosuto_libwebrtc/native/
rtp_parameters.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 gosuto_webrtc_sys::{rtp_parameters as sys_rp, webrtc as sys_webrtc};
16
17use crate::rtp_parameters::*;
18
19impl From<sys_webrtc::ffi::Priority> for Priority {
20    fn from(value: sys_webrtc::ffi::Priority) -> Self {
21        match value {
22            sys_webrtc::ffi::Priority::VeryLow => Self::VeryLow,
23            sys_webrtc::ffi::Priority::Low => Self::Low,
24            sys_webrtc::ffi::Priority::Medium => Self::Medium,
25            sys_webrtc::ffi::Priority::High => Self::High,
26            _ => panic!("unknown Priority"),
27        }
28    }
29}
30
31impl From<sys_rp::ffi::RtpExtension> for RtpHeaderExtensionParameters {
32    fn from(value: sys_rp::ffi::RtpExtension) -> Self {
33        Self { uri: value.uri, id: value.id, encrypted: value.encrypt }
34    }
35}
36
37impl From<sys_rp::ffi::RtpParameters> for RtpParameters {
38    fn from(value: sys_rp::ffi::RtpParameters) -> Self {
39        Self {
40            codecs: value.codecs.into_iter().map(Into::into).collect(),
41            header_extensions: value.header_extensions.into_iter().map(Into::into).collect(),
42            rtcp: value.rtcp.into(),
43        }
44    }
45}
46
47impl From<sys_rp::ffi::RtpCodecParameters> for RtpCodecParameters {
48    fn from(value: sys_rp::ffi::RtpCodecParameters) -> Self {
49        Self {
50            mime_type: value.mime_type,
51            payload_type: value.payload_type as u8,
52            clock_rate: value.has_clock_rate.then_some(value.clock_rate as u64),
53            channels: value.has_num_channels.then_some(value.num_channels as u16),
54        }
55    }
56}
57
58impl From<sys_rp::ffi::RtcpParameters> for RtcpParameters {
59    fn from(value: sys_rp::ffi::RtcpParameters) -> Self {
60        Self { cname: value.cname, reduced_size: value.reduced_size }
61    }
62}
63
64impl From<sys_rp::ffi::RtpEncodingParameters> for RtpEncodingParameters {
65    fn from(value: sys_rp::ffi::RtpEncodingParameters) -> Self {
66        Self {
67            active: value.active,
68            max_bitrate: value.has_max_bitrate_bps.then_some(value.max_bitrate_bps as u64),
69            max_framerate: value.has_max_framerate.then_some(value.max_framerate),
70            priority: value.network_priority.into(),
71            rid: value.rid,
72            scale_resolution_down_by: value
73                .has_scale_resolution_down_by
74                .then_some(value.scale_resolution_down_by),
75        }
76    }
77}
78
79impl From<sys_rp::ffi::RtpCodecCapability> for RtpCodecCapability {
80    fn from(value: sys_rp::ffi::RtpCodecCapability) -> Self {
81        Self {
82            channels: value.has_num_channels.then_some(value.num_channels as u16),
83            mime_type: value.mime_type,
84            clock_rate: value.has_clock_rate.then_some(value.clock_rate as u64),
85            sdp_fmtp_line: {
86                let parameters: Vec<String> = value
87                    .parameters
88                    .into_iter()
89                    .map(|key_value| {
90                        if !key_value.key.is_empty() {
91                            format!("{}={}", key_value.key, key_value.value)
92                        } else {
93                            key_value.value
94                        }
95                    })
96                    .collect();
97
98                if !parameters.is_empty() {
99                    Some(parameters.join(";"))
100                } else {
101                    None
102                }
103            },
104        }
105    }
106}
107
108impl From<sys_rp::ffi::RtpHeaderExtensionCapability> for RtpHeaderExtensionCapability {
109    fn from(value: sys_rp::ffi::RtpHeaderExtensionCapability) -> Self {
110        Self { direction: value.direction.into(), uri: value.uri }
111    }
112}
113
114impl From<sys_rp::ffi::RtpCapabilities> for RtpCapabilities {
115    fn from(value: sys_rp::ffi::RtpCapabilities) -> Self {
116        Self {
117            codecs: value.codecs.into_iter().map(Into::into).collect(),
118            header_extensions: value.header_extensions.into_iter().map(Into::into).collect(),
119        }
120    }
121}
122
123impl From<Priority> for sys_webrtc::ffi::Priority {
124    fn from(value: Priority) -> Self {
125        match value {
126            Priority::VeryLow => Self::VeryLow,
127            Priority::Low => Self::Low,
128            Priority::Medium => Self::Medium,
129            Priority::High => Self::High,
130        }
131    }
132}
133
134impl From<RtpHeaderExtensionParameters> for sys_rp::ffi::RtpExtension {
135    fn from(value: RtpHeaderExtensionParameters) -> Self {
136        Self { uri: value.uri, id: value.id, encrypt: value.encrypted }
137    }
138}
139
140impl From<RtpParameters> for sys_rp::ffi::RtpParameters {
141    fn from(value: RtpParameters) -> Self {
142        Self {
143            codecs: value.codecs.into_iter().map(Into::into).collect(),
144            header_extensions: value.header_extensions.into_iter().map(Into::into).collect(),
145            encodings: Vec::new(),
146            rtcp: value.rtcp.into(),
147            transaction_id: "".to_string(),
148            mid: "".to_string(),
149            has_degradation_preference: false,
150            degradation_preference: sys_rp::ffi::DegradationPreference::Balanced,
151        }
152    }
153}
154
155impl From<RtpCodecParameters> for sys_rp::ffi::RtpCodecParameters {
156    fn from(value: RtpCodecParameters) -> Self {
157        Self {
158            payload_type: value.payload_type as i32,
159            mime_type: value.mime_type,
160            has_clock_rate: value.clock_rate.is_some(),
161            clock_rate: value.clock_rate.unwrap_or_default() as i32,
162            has_num_channels: value.channels.is_some(),
163            num_channels: value.channels.unwrap_or_default() as i32,
164            name: "".to_string(),
165            kind: sys_rp::ffi::MediaType::Audio,
166            has_max_ptime: false,
167            max_ptime: 0,
168            has_ptime: false,
169            ptime: 0,
170            rtcp_feedback: Vec::new(),
171            parameters: Vec::new(),
172        }
173    }
174}
175
176impl From<RtcpParameters> for sys_rp::ffi::RtcpParameters {
177    fn from(value: RtcpParameters) -> Self {
178        Self {
179            cname: value.cname,
180            reduced_size: value.reduced_size,
181            has_ssrc: false,
182            ssrc: 0,
183            mux: false,
184        }
185    }
186}
187
188impl From<RtpEncodingParameters> for sys_rp::ffi::RtpEncodingParameters {
189    fn from(value: RtpEncodingParameters) -> Self {
190        Self {
191            active: value.active,
192            has_max_bitrate_bps: value.max_bitrate.is_some(),
193            max_bitrate_bps: value.max_bitrate.unwrap_or_default() as i32,
194            has_max_framerate: value.max_framerate.is_some(),
195            max_framerate: value.max_framerate.unwrap_or_default(),
196            network_priority: value.priority.into(),
197            rid: value.rid,
198            has_scale_resolution_down_by: value.scale_resolution_down_by.is_some(),
199            scale_resolution_down_by: value.scale_resolution_down_by.unwrap_or_default(),
200            adaptive_ptime: false,
201            bitrate_priority: sys_rp::DEFAULT_BITRATE_PRIORITY,
202            has_min_bitrate_bps: false,
203            min_bitrate_bps: 0,
204            has_num_temporal_layers: false,
205            num_temporal_layers: 0,
206            has_scalability_mode: false,
207            scalability_mode: "".to_string(),
208            has_ssrc: false,
209            ssrc: 0,
210        }
211    }
212}
213
214impl From<RtpCodecCapability> for sys_rp::ffi::RtpCodecCapability {
215    fn from(value: RtpCodecCapability) -> Self {
216        let mime_type: Vec<&str> = value.mime_type.split('/').collect();
217        let kind = match mime_type[0] {
218            "audio" => sys_webrtc::ffi::MediaType::Audio,
219            "video" => sys_webrtc::ffi::MediaType::Video,
220            _ => panic!("invalid media type"),
221        };
222        let name = mime_type[1].to_string();
223
224        Self {
225            name,
226            kind,
227            has_clock_rate: value.clock_rate.is_some(),
228            clock_rate: value.clock_rate.unwrap_or_default() as i32,
229            has_num_channels: value.channels.is_some(),
230            num_channels: value.channels.unwrap_or_default() as i32,
231            parameters: {
232                value
233                    .sdp_fmtp_line
234                    .map(|sdp_fmtp_line| {
235                        sdp_fmtp_line
236                            .split(';')
237                            .map(|v| {
238                                let key_value: Vec<&str> = v.split('=').collect();
239                                if key_value.len() == 2 {
240                                    sys_rp::ffi::StringKeyValue {
241                                        key: key_value[0].to_string(),
242                                        value: key_value[1].to_string(),
243                                    }
244                                } else {
245                                    sys_rp::ffi::StringKeyValue {
246                                        key: "".to_string(),
247                                        value: key_value[0].to_string(),
248                                    }
249                                }
250                            })
251                            .collect()
252                    })
253                    .unwrap_or_default()
254            },
255            // Ignore
256            mime_type: String::default(), // !!
257            has_preferred_payload_type: false,
258            preferred_payload_type: 0,
259            rtcp_feedback: Vec::default(),
260        }
261    }
262}