diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/media/webrtc/sdp/rsdparsa_capi | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/webrtc/sdp/rsdparsa_capi')
-rw-r--r-- | dom/media/webrtc/sdp/rsdparsa_capi/Cargo.toml | 12 | ||||
-rw-r--r-- | dom/media/webrtc/sdp/rsdparsa_capi/src/attribute.rs | 1472 | ||||
-rw-r--r-- | dom/media/webrtc/sdp/rsdparsa_capi/src/lib.rs | 298 | ||||
-rw-r--r-- | dom/media/webrtc/sdp/rsdparsa_capi/src/media_section.rs | 233 | ||||
-rw-r--r-- | dom/media/webrtc/sdp/rsdparsa_capi/src/network.rs | 266 | ||||
-rw-r--r-- | dom/media/webrtc/sdp/rsdparsa_capi/src/types.rs | 199 |
6 files changed, 2480 insertions, 0 deletions
diff --git a/dom/media/webrtc/sdp/rsdparsa_capi/Cargo.toml b/dom/media/webrtc/sdp/rsdparsa_capi/Cargo.toml new file mode 100644 index 0000000000..a0aeff086f --- /dev/null +++ b/dom/media/webrtc/sdp/rsdparsa_capi/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rsdparsa_capi" +version = "0.1.0" +authors = ["Paul Ellenbogen <pe5@cs.princeton.edu>", + "Nils Ohlmeier <github@ohlmeier.org>"] +license = "MPL-2.0" + +[dependencies] +libc = "^0.2.0" +log = "0.4" +rsdparsa = {package = "webrtc-sdp", version = "0.3.10"} +nserror = { path = "../../../../../xpcom/rust/nserror" } diff --git a/dom/media/webrtc/sdp/rsdparsa_capi/src/attribute.rs b/dom/media/webrtc/sdp/rsdparsa_capi/src/attribute.rs new file mode 100644 index 0000000000..82483f151f --- /dev/null +++ b/dom/media/webrtc/sdp/rsdparsa_capi/src/attribute.rs @@ -0,0 +1,1472 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use libc::{c_float, size_t}; +use std::ptr; +use std::slice; + +use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; +use rsdparsa::attribute_type::*; +use rsdparsa::SdpSession; + +use network::{RustAddress, RustExplicitlyTypedAddress}; +use types::StringView; + +#[no_mangle] +pub unsafe extern "C" fn num_attributes(session: *const SdpSession) -> u32 { + (*session).attribute.len() as u32 +} + +#[no_mangle] +pub unsafe extern "C" fn get_attribute_ptr( + session: *const SdpSession, + index: u32, + ret: *mut *const SdpAttribute, +) -> nsresult { + match (*session).attribute.get(index as usize) { + Some(attribute) => { + *ret = attribute as *const SdpAttribute; + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} + +fn count_attribute(attributes: &[SdpAttribute], search: SdpAttributeType) -> usize { + let mut count = 0; + for attribute in (*attributes).iter() { + if SdpAttributeType::from(attribute) == search { + count += 1; + } + } + count +} + +fn argsearch(attributes: &[SdpAttribute], attribute_type: SdpAttributeType) -> Option<usize> { + for (i, attribute) in (*attributes).iter().enumerate() { + if SdpAttributeType::from(attribute) == attribute_type { + return Some(i); + } + } + None +} + +pub unsafe fn has_attribute( + attributes: *const Vec<SdpAttribute>, + attribute_type: SdpAttributeType, +) -> bool { + argsearch((*attributes).as_slice(), attribute_type).is_some() +} + +fn get_attribute( + attributes: &[SdpAttribute], + attribute_type: SdpAttributeType, +) -> Option<&SdpAttribute> { + argsearch(attributes, attribute_type).map(|i| &attributes[i]) +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub enum RustSdpAttributeDtlsMessageType { + Client, + Server, +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeDtlsMessage { + pub role: u8, + pub value: StringView, +} + +impl<'a> From<&'a SdpAttributeDtlsMessage> for RustSdpAttributeDtlsMessage { + fn from(other: &SdpAttributeDtlsMessage) -> Self { + match other { + &SdpAttributeDtlsMessage::Client(ref x) => RustSdpAttributeDtlsMessage { + role: RustSdpAttributeDtlsMessageType::Client as u8, + value: StringView::from(x.as_str()), + }, + &SdpAttributeDtlsMessage::Server(ref x) => RustSdpAttributeDtlsMessage { + role: RustSdpAttributeDtlsMessageType::Server as u8, + value: StringView::from(x.as_str()), + }, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_dtls_message( + attributes: *const Vec<SdpAttribute>, + ret: *mut RustSdpAttributeDtlsMessage, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::DtlsMessage); + if let Some(&SdpAttribute::DtlsMessage(ref dtls_message)) = attr { + *ret = RustSdpAttributeDtlsMessage::from(dtls_message); + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_iceufrag( + attributes: *const Vec<SdpAttribute>, + ret: *mut StringView, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IceUfrag); + if let Some(&SdpAttribute::IceUfrag(ref string)) = attr { + *ret = StringView::from(string.as_str()); + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_icepwd( + attributes: *const Vec<SdpAttribute>, + ret: *mut StringView, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IcePwd); + if let Some(&SdpAttribute::IcePwd(ref string)) = attr { + *ret = StringView::from(string.as_str()); + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_identity( + attributes: *const Vec<SdpAttribute>, + ret: *mut StringView, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Identity); + if let Some(&SdpAttribute::Identity(ref string)) = attr { + *ret = StringView::from(string.as_str()); + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_iceoptions( + attributes: *const Vec<SdpAttribute>, + ret: *mut *const Vec<String>, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IceOptions); + if let Some(&SdpAttribute::IceOptions(ref options)) = attr { + *ret = options; + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_maxptime( + attributes: *const Vec<SdpAttribute>, + ret: *mut u64, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::MaxPtime); + if let Some(&SdpAttribute::MaxPtime(ref max_ptime)) = attr { + *ret = *max_ptime; + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeFingerprint { + hash_algorithm: u16, + fingerprint: *const Vec<u8>, +} + +impl<'a> From<&'a SdpAttributeFingerprint> for RustSdpAttributeFingerprint { + fn from(other: &SdpAttributeFingerprint) -> Self { + RustSdpAttributeFingerprint { + hash_algorithm: other.hash_algorithm as u16, + fingerprint: &other.fingerprint, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_fingerprint_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Fingerprint) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_fingerprints( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_fingerprints: *mut RustSdpAttributeFingerprint, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Fingerprint(ref data) = *x { + Some(RustSdpAttributeFingerprint::from(data)) + } else { + None + } + }) + .collect(); + let fingerprints = slice::from_raw_parts_mut(ret_fingerprints, ret_size); + fingerprints.copy_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone)] +pub enum RustSdpAttributeSetup { + Active, + Actpass, + Holdconn, + Passive, +} + +impl<'a> From<&'a SdpAttributeSetup> for RustSdpAttributeSetup { + fn from(other: &SdpAttributeSetup) -> Self { + match *other { + SdpAttributeSetup::Active => RustSdpAttributeSetup::Active, + SdpAttributeSetup::Actpass => RustSdpAttributeSetup::Actpass, + SdpAttributeSetup::Holdconn => RustSdpAttributeSetup::Holdconn, + SdpAttributeSetup::Passive => RustSdpAttributeSetup::Passive, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_setup( + attributes: *const Vec<SdpAttribute>, + ret: *mut RustSdpAttributeSetup, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Setup); + if let Some(&SdpAttribute::Setup(ref setup)) = attr { + *ret = RustSdpAttributeSetup::from(setup); + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeSsrc { + pub id: u32, + pub attribute: StringView, + pub value: StringView, +} + +impl<'a> From<&'a SdpAttributeSsrc> for RustSdpAttributeSsrc { + fn from(other: &SdpAttributeSsrc) -> Self { + RustSdpAttributeSsrc { + id: other.id, + attribute: StringView::from(&other.attribute), + value: StringView::from(&other.value), + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_ssrc_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Ssrc) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_ssrcs( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_ssrcs: *mut RustSdpAttributeSsrc, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Ssrc(ref data) = *x { + Some(RustSdpAttributeSsrc::from(data)) + } else { + None + } + }) + .collect(); + let ssrcs = slice::from_raw_parts_mut(ret_ssrcs, ret_size); + ssrcs.copy_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub enum RustSdpSsrcGroupSemantic { + Duplication, + FlowIdentification, + ForwardErrorCorrection, + ForwardErrorCorrectionFr, + SIM, +} + +impl<'a> From<&'a SdpSsrcGroupSemantic> for RustSdpSsrcGroupSemantic { + fn from(other: &SdpSsrcGroupSemantic) -> Self { + match *other { + SdpSsrcGroupSemantic::Duplication => RustSdpSsrcGroupSemantic::Duplication, + SdpSsrcGroupSemantic::FlowIdentification => { + RustSdpSsrcGroupSemantic::FlowIdentification + } + SdpSsrcGroupSemantic::ForwardErrorCorrection => { + RustSdpSsrcGroupSemantic::ForwardErrorCorrection + } + SdpSsrcGroupSemantic::ForwardErrorCorrectionFr => { + RustSdpSsrcGroupSemantic::ForwardErrorCorrectionFr + } + SdpSsrcGroupSemantic::Sim => RustSdpSsrcGroupSemantic::SIM, + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpSsrcGroup { + pub semantic: RustSdpSsrcGroupSemantic, + pub ssrcs: *const Vec<SdpAttributeSsrc>, +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_ssrc_group_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::SsrcGroup) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_ssrc_groups( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_ssrc_groups: *mut RustSdpSsrcGroup, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::SsrcGroup(ref semantic, ref ssrcs) = *x { + Some(RustSdpSsrcGroup { + semantic: RustSdpSsrcGroupSemantic::from(semantic), + ssrcs: ssrcs, + }) + } else { + None + } + }) + .collect(); + let ssrc_groups = slice::from_raw_parts_mut(ret_ssrc_groups, ret_size); + ssrc_groups.copy_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeRtpmap { + pub payload_type: u8, + pub codec_name: StringView, + pub frequency: u32, + pub channels: u32, +} + +impl<'a> From<&'a SdpAttributeRtpmap> for RustSdpAttributeRtpmap { + fn from(other: &SdpAttributeRtpmap) -> Self { + RustSdpAttributeRtpmap { + payload_type: other.payload_type as u8, + codec_name: StringView::from(other.codec_name.as_str()), + frequency: other.frequency as u32, + channels: other.channels.unwrap_or(0), + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_rtpmap_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Rtpmap) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_rtpmaps( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_rtpmaps: *mut RustSdpAttributeRtpmap, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Rtpmap(ref data) = *x { + Some(RustSdpAttributeRtpmap::from(data)) + } else { + None + } + }) + .collect(); + let rtpmaps = slice::from_raw_parts_mut(ret_rtpmaps, ret_size); + rtpmaps.copy_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustRtxFmtpParameters { + pub apt: u8, + pub has_rtx_time: bool, + pub rtx_time: u32, +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeFmtpParameters { + // H264 + pub packetization_mode: u32, + pub level_asymmetry_allowed: bool, + pub profile_level_id: u32, + pub max_fs: u32, + pub max_cpb: u32, + pub max_dpb: u32, + pub max_br: u32, + pub max_mbps: u32, + + // VP8 and VP9 + // max_fs, already defined in H264 + pub max_fr: u32, + + // Opus + pub maxplaybackrate: u32, + pub maxaveragebitrate: u32, + pub usedtx: bool, + pub stereo: bool, + pub useinbandfec: bool, + pub cbr: bool, + pub ptime: u32, + pub minptime: u32, + pub maxptime: u32, + + // telephone-event + pub dtmf_tones: StringView, + + // RTX + pub rtx: RustRtxFmtpParameters, + + // Red + pub encodings: *const Vec<u8>, + + // Unknown + pub unknown_tokens: *const Vec<String>, +} + +impl<'a> From<&'a SdpAttributeFmtpParameters> for RustSdpAttributeFmtpParameters { + fn from(other: &SdpAttributeFmtpParameters) -> Self { + let rtx = if let Some(rtx) = other.rtx { + RustRtxFmtpParameters { + apt: rtx.apt, + has_rtx_time: rtx.rtx_time.is_some(), + rtx_time: rtx.rtx_time.unwrap_or(0), + } + } else { + RustRtxFmtpParameters { + apt: 0, + has_rtx_time: false, + rtx_time: 0, + } + }; + + RustSdpAttributeFmtpParameters { + packetization_mode: other.packetization_mode, + level_asymmetry_allowed: other.level_asymmetry_allowed, + profile_level_id: other.profile_level_id, + max_fs: other.max_fs, + max_cpb: other.max_cpb, + max_dpb: other.max_dpb, + max_br: other.max_br, + max_mbps: other.max_mbps, + usedtx: other.usedtx, + stereo: other.stereo, + useinbandfec: other.useinbandfec, + cbr: other.cbr, + max_fr: other.max_fr, + maxplaybackrate: other.maxplaybackrate, + maxaveragebitrate: other.maxaveragebitrate, + ptime: other.ptime, + minptime: other.minptime, + maxptime: other.maxptime, + dtmf_tones: StringView::from(other.dtmf_tones.as_str()), + rtx, + encodings: &other.encodings, + unknown_tokens: &other.unknown_tokens, + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeFmtp { + pub payload_type: u8, + pub codec_name: StringView, + pub parameters: RustSdpAttributeFmtpParameters, +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_fmtp_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Fmtp) +} + +fn find_payload_type(attributes: &[SdpAttribute], payload_type: u8) -> Option<&SdpAttributeRtpmap> { + attributes + .iter() + .filter_map(|x| { + if let SdpAttribute::Rtpmap(ref data) = *x { + if data.payload_type == payload_type { + Some(data) + } else { + None + } + } else { + None + } + }) + .next() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_fmtp( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_fmtp: *mut RustSdpAttributeFmtp, +) -> size_t { + let fmtps = (*attributes).iter().filter_map(|x| { + if let SdpAttribute::Fmtp(ref data) = *x { + Some(data) + } else { + None + } + }); + let mut rust_fmtps = Vec::new(); + for fmtp in fmtps { + if let Some(rtpmap) = find_payload_type((*attributes).as_slice(), fmtp.payload_type) { + rust_fmtps.push(RustSdpAttributeFmtp { + payload_type: fmtp.payload_type as u8, + codec_name: StringView::from(rtpmap.codec_name.as_str()), + parameters: RustSdpAttributeFmtpParameters::from(&fmtp.parameters), + }); + } + } + let fmtps = if ret_size <= rust_fmtps.len() { + slice::from_raw_parts_mut(ret_fmtp, ret_size) + } else { + slice::from_raw_parts_mut(ret_fmtp, rust_fmtps.len()) + }; + fmtps.copy_from_slice(rust_fmtps.as_slice()); + fmtps.len() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_ptime(attributes: *const Vec<SdpAttribute>) -> i64 { + for attribute in (*attributes).iter() { + if let SdpAttribute::Ptime(time) = *attribute { + return time as i64; + } + } + -1 +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_max_msg_size(attributes: *const Vec<SdpAttribute>) -> i64 { + for attribute in (*attributes).iter() { + if let SdpAttribute::MaxMessageSize(max_msg_size) = *attribute { + return max_msg_size as i64; + } + } + -1 +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_sctp_port(attributes: *const Vec<SdpAttribute>) -> i64 { + for attribute in (*attributes).iter() { + if let SdpAttribute::SctpPort(port) = *attribute { + return port as i64; + } + } + -1 +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeFlags { + pub ice_lite: bool, + pub rtcp_mux: bool, + pub rtcp_rsize: bool, + pub bundle_only: bool, + pub end_of_candidates: bool, +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_attribute_flags( + attributes: *const Vec<SdpAttribute>, +) -> RustSdpAttributeFlags { + let mut ret = RustSdpAttributeFlags { + ice_lite: false, + rtcp_mux: false, + rtcp_rsize: false, + bundle_only: false, + end_of_candidates: false, + }; + for attribute in (*attributes).iter() { + if let SdpAttribute::IceLite = *attribute { + ret.ice_lite = true; + } else if let SdpAttribute::RtcpMux = *attribute { + ret.rtcp_mux = true; + } else if let SdpAttribute::RtcpRsize = *attribute { + ret.rtcp_rsize = true; + } else if let SdpAttribute::BundleOnly = *attribute { + ret.bundle_only = true; + } else if let SdpAttribute::EndOfCandidates = *attribute { + ret.end_of_candidates = true; + } + } + ret +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_mid( + attributes: *const Vec<SdpAttribute>, + ret: *mut StringView, +) -> nsresult { + for attribute in (*attributes).iter() { + if let SdpAttribute::Mid(ref data) = *attribute { + *ret = StringView::from(data.as_str()); + return NS_OK; + } + } + NS_ERROR_INVALID_ARG +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeMsid { + id: StringView, + appdata: StringView, +} + +impl<'a> From<&'a SdpAttributeMsid> for RustSdpAttributeMsid { + fn from(other: &SdpAttributeMsid) -> Self { + RustSdpAttributeMsid { + id: StringView::from(other.id.as_str()), + appdata: StringView::from(&other.appdata), + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_msid_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Msid) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_msids( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_msids: *mut RustSdpAttributeMsid, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Msid(ref data) = *x { + Some(RustSdpAttributeMsid::from(data)) + } else { + None + } + }) + .collect(); + let msids = slice::from_raw_parts_mut(ret_msids, ret_size); + msids.copy_from_slice(attrs.as_slice()); +} + +// TODO: Finish msid attributes once parsing is changed upstream. +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeMsidSemantic { + pub semantic: StringView, + pub msids: *const Vec<String>, +} + +impl<'a> From<&'a SdpAttributeMsidSemantic> for RustSdpAttributeMsidSemantic { + fn from(other: &SdpAttributeMsidSemantic) -> Self { + RustSdpAttributeMsidSemantic { + semantic: StringView::from(other.semantic.as_str()), + msids: &other.msids, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_msid_semantic_count( + attributes: *const Vec<SdpAttribute>, +) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::MsidSemantic) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_msid_semantics( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_msid_semantics: *mut RustSdpAttributeMsidSemantic, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::MsidSemantic(ref data) = *x { + Some(RustSdpAttributeMsidSemantic::from(data)) + } else { + None + } + }) + .collect(); + let msid_semantics = slice::from_raw_parts_mut(ret_msid_semantics, ret_size); + msid_semantics.copy_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub enum RustSdpAttributeGroupSemantic { + LipSynchronization, + FlowIdentification, + SingleReservationFlow, + AlternateNetworkAddressType, + ForwardErrorCorrection, + DecodingDependency, + Bundle, +} + +impl<'a> From<&'a SdpAttributeGroupSemantic> for RustSdpAttributeGroupSemantic { + fn from(other: &SdpAttributeGroupSemantic) -> Self { + match *other { + SdpAttributeGroupSemantic::LipSynchronization => { + RustSdpAttributeGroupSemantic::LipSynchronization + } + SdpAttributeGroupSemantic::FlowIdentification => { + RustSdpAttributeGroupSemantic::FlowIdentification + } + SdpAttributeGroupSemantic::SingleReservationFlow => { + RustSdpAttributeGroupSemantic::SingleReservationFlow + } + SdpAttributeGroupSemantic::AlternateNetworkAddressType => { + RustSdpAttributeGroupSemantic::AlternateNetworkAddressType + } + SdpAttributeGroupSemantic::ForwardErrorCorrection => { + RustSdpAttributeGroupSemantic::ForwardErrorCorrection + } + SdpAttributeGroupSemantic::DecodingDependency => { + RustSdpAttributeGroupSemantic::DecodingDependency + } + SdpAttributeGroupSemantic::Bundle => RustSdpAttributeGroupSemantic::Bundle, + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeGroup { + pub semantic: RustSdpAttributeGroupSemantic, + pub tags: *const Vec<String>, +} + +impl<'a> From<&'a SdpAttributeGroup> for RustSdpAttributeGroup { + fn from(other: &SdpAttributeGroup) -> Self { + RustSdpAttributeGroup { + semantic: RustSdpAttributeGroupSemantic::from(&other.semantics), + tags: &other.tags, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_group_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Group) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_groups( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_groups: *mut RustSdpAttributeGroup, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Group(ref data) = *x { + Some(RustSdpAttributeGroup::from(data)) + } else { + None + } + }) + .collect(); + let groups = slice::from_raw_parts_mut(ret_groups, ret_size); + groups.copy_from_slice(attrs.as_slice()); +} + +#[repr(C)] +pub struct RustSdpAttributeRtcp { + pub port: u32, + pub unicast_addr: RustExplicitlyTypedAddress, + pub has_address: bool, +} + +impl<'a> From<&'a SdpAttributeRtcp> for RustSdpAttributeRtcp { + fn from(other: &SdpAttributeRtcp) -> Self { + match other.unicast_addr { + Some(ref address) => RustSdpAttributeRtcp { + port: other.port as u32, + unicast_addr: address.into(), + has_address: true, + }, + None => RustSdpAttributeRtcp { + port: other.port as u32, + unicast_addr: RustExplicitlyTypedAddress::default(), + has_address: false, + }, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_rtcp( + attributes: *const Vec<SdpAttribute>, + ret: *mut RustSdpAttributeRtcp, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Rtcp); + if let Some(&SdpAttribute::Rtcp(ref data)) = attr { + *ret = RustSdpAttributeRtcp::from(data); + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeRtcpFb { + pub payload_type: u32, + pub feedback_type: u32, + pub parameter: StringView, + pub extra: StringView, +} + +impl<'a> From<&'a SdpAttributeRtcpFb> for RustSdpAttributeRtcpFb { + fn from(other: &SdpAttributeRtcpFb) -> Self { + RustSdpAttributeRtcpFb { + payload_type: match other.payload_type { + SdpAttributePayloadType::Wildcard => u32::max_value(), + SdpAttributePayloadType::PayloadType(x) => x as u32, + }, + feedback_type: other.feedback_type.clone() as u32, + parameter: StringView::from(other.parameter.as_str()), + extra: StringView::from(other.extra.as_str()), + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_rtcpfb_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Rtcpfb) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_rtcpfbs( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_rtcpfbs: *mut RustSdpAttributeRtcpFb, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Rtcpfb(ref data) = *x { + Some(RustSdpAttributeRtcpFb::from(data)) + } else { + None + } + }) + .collect(); + let rtcpfbs = slice::from_raw_parts_mut(ret_rtcpfbs, ret_size); + rtcpfbs.clone_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeImageAttrXyRange { + // range + pub min: u32, + pub max: u32, + pub step: u32, + + // discrete values + pub discrete_values: *const Vec<u32>, +} + +impl<'a> From<&'a SdpAttributeImageAttrXyRange> for RustSdpAttributeImageAttrXyRange { + fn from(other: &SdpAttributeImageAttrXyRange) -> Self { + match other { + &SdpAttributeImageAttrXyRange::Range(min, max, step) => { + RustSdpAttributeImageAttrXyRange { + min, + max, + step: step.unwrap_or(1), + discrete_values: ptr::null(), + } + } + &SdpAttributeImageAttrXyRange::DiscreteValues(ref discrete_values) => { + RustSdpAttributeImageAttrXyRange { + min: 0, + max: 1, + step: 1, + discrete_values, + } + } + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeImageAttrSRange { + // range + pub min: c_float, + pub max: c_float, + + // discrete values + pub discrete_values: *const Vec<c_float>, +} + +impl<'a> From<&'a SdpAttributeImageAttrSRange> for RustSdpAttributeImageAttrSRange { + fn from(other: &SdpAttributeImageAttrSRange) -> Self { + match other { + &SdpAttributeImageAttrSRange::Range(min, max) => RustSdpAttributeImageAttrSRange { + min, + max, + discrete_values: ptr::null(), + }, + &SdpAttributeImageAttrSRange::DiscreteValues(ref discrete_values) => { + RustSdpAttributeImageAttrSRange { + min: 0.0, + max: 1.0, + discrete_values, + } + } + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeImageAttrPRange { + pub min: c_float, + pub max: c_float, +} + +impl<'a> From<&'a SdpAttributeImageAttrPRange> for RustSdpAttributeImageAttrPRange { + fn from(other: &SdpAttributeImageAttrPRange) -> Self { + RustSdpAttributeImageAttrPRange { + min: other.min, + max: other.max, + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeImageAttrSet { + pub x: RustSdpAttributeImageAttrXyRange, + pub y: RustSdpAttributeImageAttrXyRange, + + pub has_sar: bool, + pub sar: RustSdpAttributeImageAttrSRange, + + pub has_par: bool, + pub par: RustSdpAttributeImageAttrPRange, + + pub q: c_float, +} + +impl<'a> From<&'a SdpAttributeImageAttrSet> for RustSdpAttributeImageAttrSet { + fn from(other: &SdpAttributeImageAttrSet) -> Self { + RustSdpAttributeImageAttrSet { + x: RustSdpAttributeImageAttrXyRange::from(&other.x), + y: RustSdpAttributeImageAttrXyRange::from(&other.y), + + has_sar: other.sar.is_some(), + sar: match other.sar { + Some(ref x) => RustSdpAttributeImageAttrSRange::from(x), + // This is just any valid value accepted by rust, + // it might as well by uninitilized + None => RustSdpAttributeImageAttrSRange::from( + &SdpAttributeImageAttrSRange::DiscreteValues(vec![]), + ), + }, + + has_par: other.par.is_some(), + par: match other.par { + Some(ref x) => RustSdpAttributeImageAttrPRange::from(x), + // This is just any valid value accepted by rust, + // it might as well by uninitilized + None => RustSdpAttributeImageAttrPRange { min: 0.0, max: 1.0 }, + }, + + q: other.q.unwrap_or(0.5), + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeImageAttrSetList { + pub sets: *const Vec<SdpAttributeImageAttrSet>, +} + +impl<'a> From<&'a SdpAttributeImageAttrSetList> for RustSdpAttributeImageAttrSetList { + fn from(other: &SdpAttributeImageAttrSetList) -> Self { + match other { + &SdpAttributeImageAttrSetList::Wildcard => { + RustSdpAttributeImageAttrSetList { sets: ptr::null() } + } + &SdpAttributeImageAttrSetList::Sets(ref sets) => { + RustSdpAttributeImageAttrSetList { sets: sets } + } + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_imageattr_get_set_count( + sets: *const Vec<SdpAttributeImageAttrSet>, +) -> size_t { + (*sets).len() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_imageattr_get_sets( + sets: *const Vec<SdpAttributeImageAttrSet>, + ret_size: size_t, + ret: *mut RustSdpAttributeImageAttrSet, +) { + let rust_sets: Vec<_> = (*sets) + .iter() + .map(RustSdpAttributeImageAttrSet::from) + .collect(); + let sets = slice::from_raw_parts_mut(ret, ret_size); + sets.clone_from_slice(rust_sets.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeImageAttr { + pub pt: u32, + pub send: RustSdpAttributeImageAttrSetList, + pub recv: RustSdpAttributeImageAttrSetList, +} + +impl<'a> From<&'a SdpAttributeImageAttr> for RustSdpAttributeImageAttr { + fn from(other: &SdpAttributeImageAttr) -> Self { + RustSdpAttributeImageAttr { + pt: match other.pt { + SdpAttributePayloadType::Wildcard => u32::max_value(), + SdpAttributePayloadType::PayloadType(x) => x as u32, + }, + send: RustSdpAttributeImageAttrSetList::from(&other.send), + recv: RustSdpAttributeImageAttrSetList::from(&other.recv), + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_imageattr_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::ImageAttr) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_imageattrs( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_attrs: *mut RustSdpAttributeImageAttr, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::ImageAttr(ref data) = *x { + Some(RustSdpAttributeImageAttr::from(data)) + } else { + None + } + }) + .collect(); + let imageattrs = slice::from_raw_parts_mut(ret_attrs, ret_size); + imageattrs.copy_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeSctpmap { + pub port: u32, + pub channels: u32, +} + +impl<'a> From<&'a SdpAttributeSctpmap> for RustSdpAttributeSctpmap { + fn from(other: &SdpAttributeSctpmap) -> Self { + RustSdpAttributeSctpmap { + port: other.port as u32, + channels: other.channels, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_sctpmap_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Sctpmap) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_sctpmaps( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_sctpmaps: *mut RustSdpAttributeSctpmap, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Sctpmap(ref data) = *x { + Some(RustSdpAttributeSctpmap::from(data)) + } else { + None + } + }) + .collect(); + let sctpmaps = slice::from_raw_parts_mut(ret_sctpmaps, ret_size); + sctpmaps.copy_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeSimulcastId { + pub id: StringView, + pub paused: bool, +} + +impl<'a> From<&'a SdpAttributeSimulcastId> for RustSdpAttributeSimulcastId { + fn from(other: &SdpAttributeSimulcastId) -> Self { + RustSdpAttributeSimulcastId { + id: StringView::from(other.id.as_str()), + paused: other.paused, + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeSimulcastVersion { + pub ids: *const Vec<SdpAttributeSimulcastId>, +} + +impl<'a> From<&'a SdpAttributeSimulcastVersion> for RustSdpAttributeSimulcastVersion { + fn from(other: &SdpAttributeSimulcastVersion) -> Self { + RustSdpAttributeSimulcastVersion { ids: &other.ids } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_simulcast_get_ids_count( + ids: *const Vec<SdpAttributeSimulcastId>, +) -> size_t { + (*ids).len() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_simulcast_get_ids( + ids: *const Vec<SdpAttributeSimulcastId>, + ret_size: size_t, + ret: *mut RustSdpAttributeSimulcastId, +) { + let rust_ids: Vec<_> = (*ids) + .iter() + .map(RustSdpAttributeSimulcastId::from) + .collect(); + let ids = slice::from_raw_parts_mut(ret, ret_size); + ids.clone_from_slice(rust_ids.as_slice()); +} + +#[repr(C)] +pub struct RustSdpAttributeSimulcast { + pub send: *const Vec<SdpAttributeSimulcastVersion>, + pub receive: *const Vec<SdpAttributeSimulcastVersion>, +} + +impl<'a> From<&'a SdpAttributeSimulcast> for RustSdpAttributeSimulcast { + fn from(other: &SdpAttributeSimulcast) -> Self { + RustSdpAttributeSimulcast { + send: &other.send, + receive: &other.receive, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_simulcast_get_version_count( + version_list: *const Vec<SdpAttributeSimulcastVersion>, +) -> size_t { + (*version_list).len() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_simulcast_get_versions( + version_list: *const Vec<SdpAttributeSimulcastVersion>, + ret_size: size_t, + ret: *mut RustSdpAttributeSimulcastVersion, +) { + let rust_versions_list: Vec<_> = (*version_list) + .iter() + .map(RustSdpAttributeSimulcastVersion::from) + .collect(); + let versions = slice::from_raw_parts_mut(ret, ret_size); + versions.clone_from_slice(rust_versions_list.as_slice()) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_simulcast( + attributes: *const Vec<SdpAttribute>, + ret: *mut RustSdpAttributeSimulcast, +) -> nsresult { + let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Simulcast); + if let Some(&SdpAttribute::Simulcast(ref data)) = attr { + *ret = RustSdpAttributeSimulcast::from(data); + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub enum RustDirection { + Recvonly, + Sendonly, + Sendrecv, + Inactive, +} + +impl<'a> From<&'a Option<SdpAttributeDirection>> for RustDirection { + fn from(other: &Option<SdpAttributeDirection>) -> Self { + match *other { + Some(ref direction) => match *direction { + SdpAttributeDirection::Recvonly => RustDirection::Recvonly, + SdpAttributeDirection::Sendonly => RustDirection::Sendonly, + SdpAttributeDirection::Sendrecv => RustDirection::Sendrecv, + }, + None => RustDirection::Inactive, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_direction(attributes: *const Vec<SdpAttribute>) -> RustDirection { + for attribute in (*attributes).iter() { + match *attribute { + SdpAttribute::Recvonly => { + return RustDirection::Recvonly; + } + SdpAttribute::Sendonly => { + return RustDirection::Sendonly; + } + SdpAttribute::Sendrecv => { + return RustDirection::Sendrecv; + } + SdpAttribute::Inactive => { + return RustDirection::Inactive; + } + _ => (), + } + } + RustDirection::Sendrecv +} + +#[repr(C)] +pub struct RustSdpAttributeRemoteCandidate { + pub component: u32, + pub address: RustAddress, + pub port: u32, +} + +impl<'a> From<&'a SdpAttributeRemoteCandidate> for RustSdpAttributeRemoteCandidate { + fn from(other: &SdpAttributeRemoteCandidate) -> Self { + RustSdpAttributeRemoteCandidate { + component: other.component, + address: RustAddress::from(&other.address), + port: other.port, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_remote_candidate_count( + attributes: *const Vec<SdpAttribute>, +) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::RemoteCandidate) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_remote_candidates( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_candidates: *mut RustSdpAttributeRemoteCandidate, +) { + let attrs = (*attributes).iter().filter_map(|x| { + if let SdpAttribute::RemoteCandidate(ref data) = *x { + Some(RustSdpAttributeRemoteCandidate::from(data)) + } else { + None + } + }); + let candidates = slice::from_raw_parts_mut(ret_candidates, ret_size); + for (source, destination) in attrs.zip(candidates) { + *destination = source + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_candidate_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Candidate) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_candidates( + attributes: *const Vec<SdpAttribute>, + _ret_size: size_t, + ret: *mut *const Vec<String>, +) { + let attr_strings: Vec<String> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Candidate(ref attr) = *x { + // The serialized attribute starts with "candidate:...", this needs to be removed + Some(attr.to_string()) + } else { + None + } + }) + .collect(); + + *ret = Box::into_raw(Box::from(attr_strings)); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeRidParameters { + pub max_width: u32, + pub max_height: u32, + pub max_fps: u32, + pub max_fs: u32, + pub max_br: u32, + pub max_pps: u32, + pub unknown: *const Vec<String>, +} + +impl<'a> From<&'a SdpAttributeRidParameters> for RustSdpAttributeRidParameters { + fn from(other: &SdpAttributeRidParameters) -> Self { + RustSdpAttributeRidParameters { + max_width: other.max_width, + max_height: other.max_height, + max_fps: other.max_fps, + max_fs: other.max_fs, + max_br: other.max_br, + max_pps: other.max_pps, + + unknown: &other.unknown, + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeRid { + pub id: StringView, + pub direction: u32, + pub formats: *const Vec<u16>, + pub params: RustSdpAttributeRidParameters, + pub depends: *const Vec<String>, +} + +impl<'a> From<&'a SdpAttributeRid> for RustSdpAttributeRid { + fn from(other: &SdpAttributeRid) -> Self { + RustSdpAttributeRid { + id: StringView::from(other.id.as_str()), + direction: other.direction.clone() as u32, + formats: &other.formats, + params: RustSdpAttributeRidParameters::from(&other.params), + depends: &other.depends, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_rid_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Rid) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_rids( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_rids: *mut RustSdpAttributeRid, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Rid(ref data) = *x { + Some(RustSdpAttributeRid::from(data)) + } else { + None + } + }) + .collect(); + let rids = slice::from_raw_parts_mut(ret_rids, ret_size); + rids.clone_from_slice(attrs.as_slice()); +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeExtmap { + pub id: u16, + pub direction_specified: bool, + pub direction: RustDirection, + pub url: StringView, + pub extension_attributes: StringView, +} + +impl<'a> From<&'a SdpAttributeExtmap> for RustSdpAttributeExtmap { + fn from(other: &SdpAttributeExtmap) -> Self { + let dir = if other.direction.is_some() { + RustDirection::from(&other.direction) + } else { + RustDirection::from(&Some(SdpAttributeDirection::Sendrecv)) + }; + RustSdpAttributeExtmap { + id: other.id as u16, + direction_specified: other.direction.is_some(), + direction: dir, + url: StringView::from(other.url.as_str()), + extension_attributes: StringView::from(&other.extension_attributes), + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_extmap_count(attributes: *const Vec<SdpAttribute>) -> size_t { + count_attribute((*attributes).as_slice(), SdpAttributeType::Extmap) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_extmaps( + attributes: *const Vec<SdpAttribute>, + ret_size: size_t, + ret_rids: *mut RustSdpAttributeExtmap, +) { + let attrs: Vec<_> = (*attributes) + .iter() + .filter_map(|x| { + if let SdpAttribute::Extmap(ref data) = *x { + Some(RustSdpAttributeExtmap::from(data)) + } else { + None + } + }) + .collect(); + let extmaps = slice::from_raw_parts_mut(ret_rids, ret_size); + extmaps.copy_from_slice(attrs.as_slice()); +} diff --git a/dom/media/webrtc/sdp/rsdparsa_capi/src/lib.rs b/dom/media/webrtc/sdp/rsdparsa_capi/src/lib.rs new file mode 100644 index 0000000000..20a13900a2 --- /dev/null +++ b/dom/media/webrtc/sdp/rsdparsa_capi/src/lib.rs @@ -0,0 +1,298 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +extern crate libc; +extern crate nserror; +extern crate rsdparsa; + +use std::ffi::CString; +use std::os::raw::c_char; +use std::ptr; + +use libc::size_t; + +use std::rc::Rc; + +use std::convert::{TryFrom, TryInto}; + +use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; +use rsdparsa::address::ExplicitlyTypedAddress; +use rsdparsa::anonymizer::{AnonymizingClone, StatefulSdpAnonymizer}; +use rsdparsa::attribute_type::SdpAttribute; +use rsdparsa::error::SdpParserError; +use rsdparsa::media_type::{SdpMediaValue, SdpProtocolValue}; +use rsdparsa::{SdpBandwidth, SdpSession, SdpTiming}; + +#[macro_use] +extern crate log; + +pub mod attribute; +pub mod media_section; +pub mod network; +pub mod types; + +use network::{ + get_bandwidth, origin_view_helper, RustAddressType, RustSdpConnection, RustSdpOrigin, +}; +pub use types::{StringView, NULL_STRING}; + +#[no_mangle] +pub unsafe extern "C" fn parse_sdp( + sdp: StringView, + fail_on_warning: bool, + session: *mut *const SdpSession, + parser_error: *mut *const SdpParserError, +) -> nsresult { + let sdp_str: String = match sdp.try_into() { + Ok(string) => string, + Err(boxed_error) => { + *session = ptr::null(); + *parser_error = Box::into_raw(Box::new(SdpParserError::Sequence { + message: format!("{}", boxed_error), + line_number: 0, + })); + return NS_ERROR_INVALID_ARG; + } + }; + + let parser_result = rsdparsa::parse_sdp(&sdp_str, fail_on_warning); + match parser_result { + Ok(mut parsed) => { + *parser_error = match parsed.warnings.len() { + 0 => ptr::null(), + _ => Box::into_raw(Box::new(parsed.warnings.remove(0))), + }; + *session = Rc::into_raw(Rc::new(parsed)); + NS_OK + } + Err(e) => { + *session = ptr::null(); + error!("Error parsing SDP in rust: {}", e); + *parser_error = Box::into_raw(Box::new(e)); + NS_ERROR_INVALID_ARG + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn create_anonymized_sdp_clone( + session: *const SdpSession, +) -> *const SdpSession { + Rc::into_raw(Rc::new( + (*session).masked_clone(&mut StatefulSdpAnonymizer::new()), + )) +} + +#[no_mangle] +pub unsafe extern "C" fn create_sdp_clone(session: *const SdpSession) -> *const SdpSession { + Rc::into_raw(Rc::new((*session).clone())) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_free_session(sdp_ptr: *mut SdpSession) { + let sdp = Rc::from_raw(sdp_ptr); + drop(sdp); +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_new_reference(session: *mut SdpSession) -> *const SdpSession { + let original = Rc::from_raw(session); + let ret = Rc::into_raw(Rc::clone(&original)); + Rc::into_raw(original); // So the original reference doesn't get dropped + ret +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_error_line_num(parser_error: *mut SdpParserError) -> size_t { + match *parser_error { + SdpParserError::Line { line_number, .. } + | SdpParserError::Unsupported { line_number, .. } + | SdpParserError::Sequence { line_number, .. } => line_number, + } +} + +#[no_mangle] +// Callee must check that a nullptr is not returned +pub unsafe extern "C" fn sdp_get_error_message(parser_error: *mut SdpParserError) -> *mut c_char { + let message = format!("{}", *parser_error); + return match CString::new(message.as_str()) { + Ok(c_char_ptr) => c_char_ptr.into_raw(), + Err(_) => 0 as *mut c_char, + }; +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_free_error_message(message: *mut c_char) { + if message != 0 as *mut c_char { + let _tmp = CString::from_raw(message); + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_free_error(parser_error: *mut SdpParserError) { + let e = Box::from_raw(parser_error); + drop(e); +} + +#[no_mangle] +pub unsafe extern "C" fn get_version(session: *const SdpSession) -> u64 { + (*session).get_version() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_origin(session: *const SdpSession) -> RustSdpOrigin { + origin_view_helper((*session).get_origin()) +} + +#[no_mangle] +pub unsafe extern "C" fn session_view(session: *const SdpSession) -> StringView { + StringView::from((*session).get_session()) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_session_has_connection(session: *const SdpSession) -> bool { + (*session).connection.is_some() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_session_connection( + session: *const SdpSession, + connection: *mut RustSdpConnection, +) -> nsresult { + match (*session).connection { + Some(ref c) => { + *connection = RustSdpConnection::from(c); + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_add_media_section( + session: *mut SdpSession, + media_type: u32, + direction: u32, + port: u16, + protocol: u32, + addr_type: u32, + address: StringView, +) -> nsresult { + let addr_type = match RustAddressType::try_from(addr_type) { + Ok(a) => a.into(), + Err(e) => { + return e; + } + }; + let address_string: String = match address.try_into() { + Ok(x) => x, + Err(boxed_error) => { + error!("Error while parsing string, description: {}", boxed_error); + return NS_ERROR_INVALID_ARG; + } + }; + let address = match ExplicitlyTypedAddress::try_from((addr_type, address_string.as_str())) { + Ok(a) => a, + Err(_) => { + return NS_ERROR_INVALID_ARG; + } + }; + + let media_type = match media_type { + 0 => SdpMediaValue::Audio, // MediaType::kAudio + 1 => SdpMediaValue::Video, // MediaType::kVideo + 3 => SdpMediaValue::Application, // MediaType::kApplication + _ => { + return NS_ERROR_INVALID_ARG; + } + }; + let protocol = match protocol { + 20 => SdpProtocolValue::RtpSavpf, // Protocol::kRtpSavpf + 21 => SdpProtocolValue::UdpTlsRtpSavp, // Protocol::kUdpTlsRtpSavp + 22 => SdpProtocolValue::TcpDtlsRtpSavp, // Protocol::kTcpDtlsRtpSavp + 24 => SdpProtocolValue::UdpTlsRtpSavpf, // Protocol::kUdpTlsRtpSavpf + 25 => SdpProtocolValue::TcpDtlsRtpSavpf, // Protocol::kTcpTlsRtpSavpf + 37 => SdpProtocolValue::DtlsSctp, // Protocol::kDtlsSctp + 38 => SdpProtocolValue::UdpDtlsSctp, // Protocol::kUdpDtlsSctp + 39 => SdpProtocolValue::TcpDtlsSctp, // Protocol::kTcpDtlsSctp + _ => { + return NS_ERROR_INVALID_ARG; + } + }; + let direction = match direction { + 1 => SdpAttribute::Sendonly, + 2 => SdpAttribute::Recvonly, + 3 => SdpAttribute::Sendrecv, + _ => { + return NS_ERROR_INVALID_ARG; + } + }; + + match (*session).add_media(media_type, direction, port as u32, protocol, address) { + Ok(_) => NS_OK, + Err(_) => NS_ERROR_INVALID_ARG, + } +} + +#[repr(C)] +#[derive(Clone)] +pub struct RustSdpTiming { + pub start: u64, + pub stop: u64, +} + +impl<'a> From<&'a SdpTiming> for RustSdpTiming { + fn from(timing: &SdpTiming) -> Self { + RustSdpTiming { + start: timing.start, + stop: timing.stop, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_session_has_timing(session: *const SdpSession) -> bool { + (*session).timing.is_some() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_session_timing( + session: *const SdpSession, + timing: *mut RustSdpTiming, +) -> nsresult { + match (*session).timing { + Some(ref t) => { + *timing = RustSdpTiming::from(t); + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_media_section_count(session: *const SdpSession) -> size_t { + (*session).media.len() +} + +#[no_mangle] +pub unsafe extern "C" fn get_sdp_bandwidth( + session: *const SdpSession, + bandwidth_type: *const c_char, +) -> u32 { + get_bandwidth(&(*session).bandwidth, bandwidth_type) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_session_bandwidth_vec( + session: *const SdpSession, +) -> *const Vec<SdpBandwidth> { + &(*session).bandwidth +} + +#[no_mangle] +pub unsafe extern "C" fn get_sdp_session_attributes( + session: *const SdpSession, +) -> *const Vec<SdpAttribute> { + &(*session).attribute +} diff --git a/dom/media/webrtc/sdp/rsdparsa_capi/src/media_section.rs b/dom/media/webrtc/sdp/rsdparsa_capi/src/media_section.rs new file mode 100644 index 0000000000..8429ab2815 --- /dev/null +++ b/dom/media/webrtc/sdp/rsdparsa_capi/src/media_section.rs @@ -0,0 +1,233 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::convert::TryInto; +use std::os::raw::c_char; +use std::ptr; + +use libc::size_t; + +use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; +use rsdparsa::attribute_type::{SdpAttribute, SdpAttributeRtpmap}; +use rsdparsa::media_type::{SdpFormatList, SdpMedia, SdpMediaValue, SdpProtocolValue}; +use rsdparsa::{SdpBandwidth, SdpSession}; + +use network::{get_bandwidth, RustSdpConnection}; +use types::StringView; + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_media_section( + session: *const SdpSession, + index: size_t, +) -> *const SdpMedia { + return match (*session).media.get(index) { + Some(m) => m, + None => ptr::null(), + }; +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub enum RustSdpMediaValue { + Audio, + Video, + Application, +} + +impl<'a> From<&'a SdpMediaValue> for RustSdpMediaValue { + fn from(val: &SdpMediaValue) -> Self { + match *val { + SdpMediaValue::Audio => RustSdpMediaValue::Audio, + SdpMediaValue::Video => RustSdpMediaValue::Video, + SdpMediaValue::Application => RustSdpMediaValue::Application, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_rust_get_media_type(sdp_media: *const SdpMedia) -> RustSdpMediaValue { + RustSdpMediaValue::from((*sdp_media).get_type()) +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub enum RustSdpProtocolValue { + RtpSavpf, + UdpTlsRtpSavp, + TcpDtlsRtpSavp, + UdpTlsRtpSavpf, + TcpDtlsRtpSavpf, + DtlsSctp, + UdpDtlsSctp, + TcpDtlsSctp, + RtpAvp, + RtpAvpf, + RtpSavp, +} + +impl<'a> From<&'a SdpProtocolValue> for RustSdpProtocolValue { + fn from(val: &SdpProtocolValue) -> Self { + match *val { + SdpProtocolValue::RtpSavpf => RustSdpProtocolValue::RtpSavpf, + SdpProtocolValue::UdpTlsRtpSavp => RustSdpProtocolValue::UdpTlsRtpSavp, + SdpProtocolValue::TcpDtlsRtpSavp => RustSdpProtocolValue::TcpDtlsRtpSavp, + SdpProtocolValue::UdpTlsRtpSavpf => RustSdpProtocolValue::UdpTlsRtpSavpf, + SdpProtocolValue::TcpDtlsRtpSavpf => RustSdpProtocolValue::TcpDtlsRtpSavpf, + SdpProtocolValue::DtlsSctp => RustSdpProtocolValue::DtlsSctp, + SdpProtocolValue::UdpDtlsSctp => RustSdpProtocolValue::UdpDtlsSctp, + SdpProtocolValue::TcpDtlsSctp => RustSdpProtocolValue::TcpDtlsSctp, + SdpProtocolValue::RtpAvp => RustSdpProtocolValue::RtpAvp, + SdpProtocolValue::RtpAvpf => RustSdpProtocolValue::RtpAvpf, + SdpProtocolValue::RtpSavp => RustSdpProtocolValue::RtpSavp, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_media_protocol( + sdp_media: *const SdpMedia, +) -> RustSdpProtocolValue { + RustSdpProtocolValue::from((*sdp_media).get_proto()) +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub enum RustSdpFormatType { + Integers, + Strings, +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_format_type(sdp_media: *const SdpMedia) -> RustSdpFormatType { + match *(*sdp_media).get_formats() { + SdpFormatList::Integers(_) => RustSdpFormatType::Integers, + SdpFormatList::Strings(_) => RustSdpFormatType::Strings, + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_format_string_vec( + sdp_media: *const SdpMedia, +) -> *const Vec<String> { + if let SdpFormatList::Strings(ref formats) = *(*sdp_media).get_formats() { + formats + } else { + ptr::null() + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_format_u32_vec(sdp_media: *const SdpMedia) -> *const Vec<u32> { + if let SdpFormatList::Integers(ref formats) = *(*sdp_media).get_formats() { + formats + } else { + ptr::null() + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_set_media_port(sdp_media: *mut SdpMedia, port: u32) { + (*sdp_media).set_port(port); +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_media_port(sdp_media: *const SdpMedia) -> u32 { + (*sdp_media).get_port() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_media_port_count(sdp_media: *const SdpMedia) -> u32 { + (*sdp_media).get_port_count() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_media_bandwidth( + sdp_media: *const SdpMedia, + bandwidth_type: *const c_char, +) -> u32 { + get_bandwidth((*sdp_media).get_bandwidth(), bandwidth_type) +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_media_bandwidth_vec( + sdp_media: *const SdpMedia, +) -> *const Vec<SdpBandwidth> { + (*sdp_media).get_bandwidth() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_media_has_connection(sdp_media: *const SdpMedia) -> bool { + (*sdp_media).get_connection().is_some() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_media_connection( + sdp_media: *const SdpMedia, + ret: *mut RustSdpConnection, +) -> nsresult { + if let &Some(ref connection) = (*sdp_media).get_connection() { + *ret = RustSdpConnection::from(connection); + return NS_OK; + } + NS_ERROR_INVALID_ARG +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_get_media_attribute_list( + sdp_media: *const SdpMedia, +) -> *const Vec<SdpAttribute> { + (*sdp_media).get_attributes() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_media_clear_codecs(sdp_media: *mut SdpMedia) { + (*sdp_media).remove_codecs() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_media_add_codec( + sdp_media: *mut SdpMedia, + pt: u8, + codec_name: StringView, + clockrate: u32, + channels: u16, +) -> nsresult { + let rtpmap = SdpAttributeRtpmap { + payload_type: pt, + codec_name: match codec_name.try_into() { + Ok(x) => x, + Err(boxed_error) => { + error!("Error while parsing string, description: {}", boxed_error); + return NS_ERROR_INVALID_ARG; + } + }, + frequency: clockrate, + channels: Some(channels as u32), + }; + + match (*sdp_media).add_codec(rtpmap) { + Ok(_) => NS_OK, + Err(_) => NS_ERROR_INVALID_ARG, + } +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_media_add_datachannel( + sdp_media: *mut SdpMedia, + name: StringView, + port: u16, + streams: u16, + message_size: u32, +) -> nsresult { + let name_str = match name.try_into() { + Ok(x) => x, + Err(_) => { + return NS_ERROR_INVALID_ARG; + } + }; + match (*sdp_media).add_datachannel(name_str, port, streams, message_size) { + Ok(_) => NS_OK, + Err(_) => NS_ERROR_INVALID_ARG, + } +} diff --git a/dom/media/webrtc/sdp/rsdparsa_capi/src/network.rs b/dom/media/webrtc/sdp/rsdparsa_capi/src/network.rs new file mode 100644 index 0000000000..970f7c8dec --- /dev/null +++ b/dom/media/webrtc/sdp/rsdparsa_capi/src/network.rs @@ -0,0 +1,266 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +extern crate nserror; + +use std::ffi::{CStr, CString}; +use std::net::IpAddr; +use std::os::raw::c_char; + +use rsdparsa::address::{Address, AddressType, AddressTyped, ExplicitlyTypedAddress}; +use rsdparsa::{SdpBandwidth, SdpConnection, SdpOrigin}; +use std::convert::TryFrom; +use types::{StringView, NULL_STRING}; + +#[repr(C)] +#[derive(Clone, Copy, PartialEq)] +pub enum RustAddressType { + IP4, + IP6, +} + +impl TryFrom<u32> for RustAddressType { + type Error = nserror::nsresult; + fn try_from(address_type: u32) -> Result<Self, Self::Error> { + match address_type { + 1 => Ok(RustAddressType::IP4), + 2 => Ok(RustAddressType::IP6), + _ => Err(nserror::NS_ERROR_INVALID_ARG), + } + } +} + +impl From<AddressType> for RustAddressType { + fn from(address_type: AddressType) -> Self { + match address_type { + AddressType::IpV4 => RustAddressType::IP4, + AddressType::IpV6 => RustAddressType::IP6, + } + } +} + +impl Into<AddressType> for RustAddressType { + fn into(self) -> AddressType { + match self { + RustAddressType::IP4 => AddressType::IpV4, + RustAddressType::IP6 => AddressType::IpV6, + } + } +} + +impl<'a> From<&'a IpAddr> for RustAddressType { + fn from(addr: &IpAddr) -> RustAddressType { + addr.address_type().into() + } +} + +pub fn get_octets(addr: &IpAddr) -> [u8; 16] { + let mut octets = [0; 16]; + match *addr { + IpAddr::V4(v4_addr) => { + let v4_octets = v4_addr.octets(); + (&mut octets[0..4]).copy_from_slice(&v4_octets); + } + IpAddr::V6(v6_addr) => { + let v6_octets = v6_addr.octets(); + octets.copy_from_slice(&v6_octets); + } + } + octets +} + +#[repr(C)] +pub struct RustAddress { + ip_address: [u8; 50], + fqdn: StringView, + is_fqdn: bool, +} + +impl<'a> From<&'a Address> for RustAddress { + fn from(address: &Address) -> Self { + match address { + Address::Ip(ip) => Self::from(ip), + Address::Fqdn(fqdn) => Self { + ip_address: [0; 50], + fqdn: fqdn.as_str().into(), + is_fqdn: true, + }, + } + } +} + +impl<'a> From<&'a IpAddr> for RustAddress { + fn from(addr: &IpAddr) -> Self { + let mut c_addr = [0; 50]; + let str_addr = format!("{}", addr); + let str_bytes = str_addr.as_bytes(); + if str_bytes.len() < 50 { + c_addr[..str_bytes.len()].copy_from_slice(&str_bytes); + } + Self { + ip_address: c_addr, + fqdn: NULL_STRING, + is_fqdn: false, + } + } +} + +#[repr(C)] +pub struct RustExplicitlyTypedAddress { + address_type: RustAddressType, + address: RustAddress, +} + +impl Default for RustExplicitlyTypedAddress { + fn default() -> Self { + Self { + address_type: RustAddressType::IP4, + address: RustAddress { + ip_address: [0; 50], + fqdn: NULL_STRING, + is_fqdn: false, + }, + } + } +} + +impl<'a> From<&'a ExplicitlyTypedAddress> for RustExplicitlyTypedAddress { + fn from(address: &ExplicitlyTypedAddress) -> Self { + match address { + ExplicitlyTypedAddress::Fqdn { domain, .. } => Self { + address_type: address.address_type().into(), + address: RustAddress { + ip_address: [0; 50], + fqdn: StringView::from(domain.as_str()), + is_fqdn: true, + }, + }, + ExplicitlyTypedAddress::Ip(ip_address) => Self { + address_type: ip_address.address_type().into(), + address: ip_address.into(), + }, + } + } +} + +// TODO @@NG remove +impl<'a> From<&'a Option<IpAddr>> for RustExplicitlyTypedAddress { + fn from(addr: &Option<IpAddr>) -> Self { + match *addr { + Some(ref x) => Self { + address_type: RustAddressType::from(x.address_type()), + address: RustAddress::from(x), + }, + None => Self::default(), + } + } +} + +#[repr(C)] +pub struct RustSdpConnection { + pub addr: RustExplicitlyTypedAddress, + pub ttl: u8, + pub amount: u64, +} + +impl<'a> From<&'a SdpConnection> for RustSdpConnection { + fn from(sdp_connection: &SdpConnection) -> Self { + let ttl = match sdp_connection.ttl { + Some(x) => x as u8, + None => 0, + }; + let amount = match sdp_connection.amount { + Some(x) => x as u64, + None => 0, + }; + RustSdpConnection { + addr: RustExplicitlyTypedAddress::from(&sdp_connection.address), + ttl: ttl, + amount: amount, + } + } +} + +#[repr(C)] +pub struct RustSdpOrigin { + username: StringView, + session_id: u64, + session_version: u64, + addr: RustExplicitlyTypedAddress, +} + +fn bandwidth_match(str_bw: &str, enum_bw: &SdpBandwidth) -> bool { + match *enum_bw { + SdpBandwidth::As(_) => str_bw == "AS", + SdpBandwidth::Ct(_) => str_bw == "CT", + SdpBandwidth::Tias(_) => str_bw == "TIAS", + SdpBandwidth::Unknown(ref type_name, _) => str_bw == type_name, + } +} + +fn bandwidth_value(bandwidth: &SdpBandwidth) -> u32 { + match *bandwidth { + SdpBandwidth::As(x) | SdpBandwidth::Ct(x) | SdpBandwidth::Tias(x) => x, + SdpBandwidth::Unknown(_, _) => 0, + } +} + +pub unsafe fn get_bandwidth(bandwidths: &Vec<SdpBandwidth>, bandwidth_type: *const c_char) -> u32 { + let bw_type = match CStr::from_ptr(bandwidth_type).to_str() { + Ok(string) => string, + Err(_) => return 0, + }; + for bandwidth in bandwidths.iter() { + if bandwidth_match(bw_type, bandwidth) { + return bandwidth_value(bandwidth); + } + } + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_serialize_bandwidth(bw: *const Vec<SdpBandwidth>) -> *mut c_char { + let mut builder = String::new(); + for bandwidth in (*bw).iter() { + match *bandwidth { + SdpBandwidth::As(val) => { + builder.push_str("b=AS:"); + builder.push_str(&val.to_string()); + builder.push_str("\r\n"); + } + SdpBandwidth::Ct(val) => { + builder.push_str("b=CT:"); + builder.push_str(&val.to_string()); + builder.push_str("\r\n"); + } + SdpBandwidth::Tias(val) => { + builder.push_str("b=TIAS:"); + builder.push_str(&val.to_string()); + builder.push_str("\r\n"); + } + SdpBandwidth::Unknown(ref name, val) => { + builder.push_str("b="); + builder.push_str(name.as_str()); + builder.push(':'); + builder.push_str(&val.to_string()); + builder.push_str("\r\n"); + } + } + } + CString::from_vec_unchecked(builder.into_bytes()).into_raw() +} + +#[no_mangle] +pub unsafe extern "C" fn sdp_free_string(s: *mut c_char) { + drop(CString::from_raw(s)); +} + +pub unsafe fn origin_view_helper(origin: &SdpOrigin) -> RustSdpOrigin { + RustSdpOrigin { + username: StringView::from(origin.username.as_str()), + session_id: origin.session_id, + session_version: origin.session_version, + addr: RustExplicitlyTypedAddress::from(&origin.unicast_addr), + } +} diff --git a/dom/media/webrtc/sdp/rsdparsa_capi/src/types.rs b/dom/media/webrtc/sdp/rsdparsa_capi/src/types.rs new file mode 100644 index 0000000000..2522c8333d --- /dev/null +++ b/dom/media/webrtc/sdp/rsdparsa_capi/src/types.rs @@ -0,0 +1,199 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use libc::size_t; +use std::boxed::Box; +use std::convert::TryInto; +use std::error::Error; +use std::ffi::CStr; +use std::{slice, str}; + +use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; + +use rsdparsa::attribute_type::SdpAttributeSsrc; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct StringView { + buffer: *const u8, + len: size_t, +} + +pub const NULL_STRING: StringView = StringView { + buffer: 0 as *const u8, + len: 0, +}; + +impl<'a> From<&'a str> for StringView { + fn from(input: &str) -> StringView { + StringView { + buffer: input.as_ptr(), + len: input.len(), + } + } +} + +impl TryInto<String> for StringView { + type Error = Box<dyn Error>; + fn try_into(self) -> Result<String, Box<dyn Error>> { + // This block must be unsafe as it converts a StringView, most likly provided from the + // C++ code, into a rust String and thus needs to operate with raw pointers. + let string_slice: &[u8]; + unsafe { + // Add one to the length as the length passed in the StringView is the length of + // the string and is missing the null terminator + string_slice = slice::from_raw_parts(self.buffer, self.len + 1 as usize); + } + + let c_str = match CStr::from_bytes_with_nul(string_slice) { + Ok(string) => string, + Err(x) => { + return Err(Box::new(x)); + } + }; + + let str_slice: &str = match str::from_utf8(c_str.to_bytes()) { + Ok(string) => string, + Err(x) => { + return Err(Box::new(x)); + } + }; + + Ok(str_slice.to_string()) + } +} + +impl<'a, T: AsRef<str>> From<&'a Option<T>> for StringView { + fn from(input: &Option<T>) -> StringView { + match *input { + Some(ref x) => StringView { + buffer: x.as_ref().as_ptr(), + len: x.as_ref().len(), + }, + None => NULL_STRING, + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn string_vec_len(vec: *const Vec<String>) -> size_t { + (*vec).len() as size_t +} + +#[no_mangle] +pub unsafe extern "C" fn string_vec_get_view( + vec: *const Vec<String>, + index: size_t, + ret: *mut StringView, +) -> nsresult { + match (*vec).get(index) { + Some(ref string) => { + *ret = StringView::from(string.as_str()); + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} + +#[no_mangle] +pub unsafe extern "C" fn free_boxed_string_vec(ptr: *mut Vec<String>) -> nsresult { + drop(Box::from_raw(ptr)); + NS_OK +} + +#[no_mangle] +pub unsafe extern "C" fn f32_vec_len(vec: *const Vec<f32>) -> size_t { + (*vec).len() +} + +#[no_mangle] +pub unsafe extern "C" fn f32_vec_get( + vec: *const Vec<f32>, + index: size_t, + ret: *mut f32, +) -> nsresult { + match (*vec).get(index) { + Some(val) => { + *ret = *val; + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} + +#[no_mangle] +pub unsafe extern "C" fn u32_vec_len(vec: *const Vec<u32>) -> size_t { + (*vec).len() +} + +#[no_mangle] +pub unsafe extern "C" fn u32_vec_get( + vec: *const Vec<u32>, + index: size_t, + ret: *mut u32, +) -> nsresult { + match (*vec).get(index) { + Some(val) => { + *ret = *val; + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} + +#[no_mangle] +pub unsafe extern "C" fn u16_vec_len(vec: *const Vec<u16>) -> size_t { + (*vec).len() +} + +#[no_mangle] +pub unsafe extern "C" fn u16_vec_get( + vec: *const Vec<u16>, + index: size_t, + ret: *mut u16, +) -> nsresult { + match (*vec).get(index) { + Some(val) => { + *ret = *val; + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} + +#[no_mangle] +pub unsafe extern "C" fn u8_vec_len(vec: *const Vec<u8>) -> size_t { + (*vec).len() +} + +#[no_mangle] +pub unsafe extern "C" fn u8_vec_get(vec: *const Vec<u8>, index: size_t, ret: *mut u8) -> nsresult { + match (*vec).get(index) { + Some(val) => { + *ret = *val; + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} + +#[no_mangle] +pub unsafe extern "C" fn ssrc_vec_len(vec: *const Vec<SdpAttributeSsrc>) -> size_t { + (*vec).len() +} + +#[no_mangle] +pub unsafe extern "C" fn ssrc_vec_get_id( + vec: *const Vec<SdpAttributeSsrc>, + index: size_t, + ret: *mut u32, +) -> nsresult { + match (*vec).get(index) { + Some(val) => { + *ret = val.id; + NS_OK + } + None => NS_ERROR_INVALID_ARG, + } +} |