summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/sdp/rsdparsa_capi
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/sdp/rsdparsa_capi')
-rw-r--r--dom/media/webrtc/sdp/rsdparsa_capi/Cargo.toml12
-rw-r--r--dom/media/webrtc/sdp/rsdparsa_capi/src/attribute.rs1472
-rw-r--r--dom/media/webrtc/sdp/rsdparsa_capi/src/lib.rs298
-rw-r--r--dom/media/webrtc/sdp/rsdparsa_capi/src/media_section.rs233
-rw-r--r--dom/media/webrtc/sdp/rsdparsa_capi/src/network.rs266
-rw-r--r--dom/media/webrtc/sdp/rsdparsa_capi/src/types.rs199
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,
+ }
+}