Bug 1379265 - Add C API for rsdparsa; r=rillian draft
authorPaul Ellenbogen <pe5@cs.princeton.edu>
Fri, 30 Jun 2017 12:54:12 -0700
changeset 756279 797c024526a3ea11bb9a1e29c673b53d68c14a25
parent 752258 d96082ff0c0cac81811d91915add960e330cb5b8
child 756280 a58577b52f5db3ef7afde0b7384da1d76ceb7b24
push id99458
push userbmo:dminor@mozilla.com
push dateFri, 16 Feb 2018 19:57:29 +0000
reviewersrillian
bugs1379265
milestone60.0a1
Bug 1379265 - Add C API for rsdparsa; r=rillian MozReview-Commit-ID: FdhpTT5wzwI
media/webrtc/signaling/src/sdp/rsdparsa_capi/Cargo.toml
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/network.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/types.rs
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
toolkit/library/rust/shared/Cargo.toml
toolkit/library/rust/shared/lib.rs
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "rsdparsa_capi"
+version = "0.1.0"
+authors = ["Paul Ellenbogen <pe5@cs.princeton.edu>",
+	   "Nils Ohlmeier <github@ohlmeier.org>"]
+
+[dependencies]
+libc = "^0.2.0"
+log = "^0.3"
+rsdparsa = {version = "0.1.0", path = "../rsdparsa"}
+nserror = { path = "../../../../../../xpcom/rust/nserror" }
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs
@@ -0,0 +1,752 @@
+use std::slice;
+use libc::{size_t, uint8_t, uint16_t, uint32_t, int64_t};
+
+use rsdparsa::SdpSession;
+use rsdparsa::attribute_type::{SdpAttribute, SdpAttributeFingerprint, SdpAttributeSetup, SdpAttributeSsrc, SdpAttributeRtpmap, SdpAttributeMsid, SdpAttributeMsidSemantic, SdpAttributeGroupSemantic, SdpAttributeGroup, SdpAttributeRtcp, SdpAttributeSctpmap, SdpAttributeRemoteCandidate, SdpAttributeExtmap, SdpAttributeDirection};
+use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG};
+
+use types::StringView;
+use network::RustIpAddr;
+
+#[repr(C)]
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum RustSdpAttributeType {
+    BundleOnly,
+    Candidate,
+    EndOfCandidates,
+    Extmap,
+    Fingerprint,
+    Fmtp,
+    Group,
+    IceLite,
+    IceMismatch,
+    IceOptions,
+    IcePwd,
+    IceUfrag,
+    Identity,
+    ImageAttr,
+    Inactive,
+    Label,
+    MaxMessageSize,
+    MaxPtime,
+    Mid,
+    Msid,
+    MsidSemantic,
+    Ptime,
+    Rid,
+    Recvonly,
+    RemoteCandidate,
+    Rtpmap,
+    Rtcp,
+    Rtcpfb,
+    RtcpMux,
+    RtcpRsize,
+    Sctpmap,
+    SctpPort,
+    Sendonly,
+    Sendrecv,
+    Setup,
+    Simulcast,
+    Ssrc,
+    SsrcGroup,
+}
+
+impl<'a> From<&'a SdpAttribute> for RustSdpAttributeType {
+    fn from(other: &SdpAttribute) -> Self {
+        match *other {
+            SdpAttribute::BundleOnly{..} => RustSdpAttributeType::BundleOnly,
+            SdpAttribute::Candidate{..} => RustSdpAttributeType::Candidate,
+            SdpAttribute::EndOfCandidates{..} => RustSdpAttributeType::EndOfCandidates,
+            SdpAttribute::Extmap{..} => RustSdpAttributeType::Extmap,
+            SdpAttribute::Fingerprint{..} => RustSdpAttributeType::Fingerprint,
+            SdpAttribute::Fmtp{..} => RustSdpAttributeType::Fmtp,
+            SdpAttribute::Group{..} => RustSdpAttributeType::Group,
+            SdpAttribute::IceLite{..} => RustSdpAttributeType::IceLite,
+            SdpAttribute::IceMismatch{..} => RustSdpAttributeType::IceMismatch,
+            SdpAttribute::IceOptions{..} => RustSdpAttributeType::IceOptions,
+            SdpAttribute::IcePwd{..} => RustSdpAttributeType::IcePwd,
+            SdpAttribute::IceUfrag{..} => RustSdpAttributeType::IceUfrag,
+            SdpAttribute::Identity{..} => RustSdpAttributeType::Identity,
+            SdpAttribute::ImageAttr{..} => RustSdpAttributeType::ImageAttr,
+            SdpAttribute::Inactive{..} => RustSdpAttributeType::Inactive,
+            SdpAttribute::Label{..} => RustSdpAttributeType::Label,
+            SdpAttribute::MaxMessageSize{..} => RustSdpAttributeType::MaxMessageSize,
+            SdpAttribute::MaxPtime{..} => RustSdpAttributeType::MaxPtime,
+            SdpAttribute::Mid{..} => RustSdpAttributeType::Mid,
+            SdpAttribute::Msid{..} => RustSdpAttributeType::Msid,
+            SdpAttribute::MsidSemantic{..} => RustSdpAttributeType::MsidSemantic,
+            SdpAttribute::Ptime{..} => RustSdpAttributeType::Ptime,
+            SdpAttribute::Rid{..} => RustSdpAttributeType::Rid,
+            SdpAttribute::Recvonly{..} => RustSdpAttributeType::Recvonly,
+            SdpAttribute::RemoteCandidate{..} => RustSdpAttributeType::RemoteCandidate,
+            SdpAttribute::Rtcp{..} => RustSdpAttributeType::Rtcp,
+            SdpAttribute::Rtcpfb{..} => RustSdpAttributeType::Rtcpfb,
+            SdpAttribute::RtcpMux{..} => RustSdpAttributeType::RtcpMux,
+            SdpAttribute::RtcpRsize{..} => RustSdpAttributeType::RtcpRsize,
+            SdpAttribute::Rtpmap{..} => RustSdpAttributeType::Rtpmap,
+            SdpAttribute::Sctpmap{..} => RustSdpAttributeType::Sctpmap,
+            SdpAttribute::SctpPort{..} => RustSdpAttributeType::SctpPort,
+            SdpAttribute::Sendonly{..} => RustSdpAttributeType::Sendonly,
+            SdpAttribute::Sendrecv{..} => RustSdpAttributeType::Sendrecv,
+            SdpAttribute::Setup{..} => RustSdpAttributeType::Setup,
+            SdpAttribute::Simulcast{..} => RustSdpAttributeType::Simulcast,
+            SdpAttribute::Ssrc{..} => RustSdpAttributeType::Ssrc,
+            SdpAttribute::SsrcGroup{..} => RustSdpAttributeType::SsrcGroup
+        }
+    }
+}
+
+#[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: RustSdpAttributeType) -> usize {
+    let mut count = 0;
+    for attribute in (*attributes).iter() {
+        if RustSdpAttributeType::from(attribute) == search {
+            count += 1;
+        }
+    }
+    count
+}
+
+fn argsearch(attributes: &[SdpAttribute], attribute_type: RustSdpAttributeType) -> Option<usize> {
+    for (i, attribute) in (*attributes).iter().enumerate() {
+        if RustSdpAttributeType::from(attribute) == attribute_type {
+            return Some(i);
+        }
+    }
+    None
+}
+
+pub unsafe fn has_attribute(attributes: *const Vec<SdpAttribute>, attribute_type: RustSdpAttributeType) -> bool {
+    argsearch((*attributes).as_slice(), attribute_type).is_some()
+}
+
+fn get_attribute(attributes: &[SdpAttribute], attribute_type: RustSdpAttributeType) -> Option<&SdpAttribute> {
+    argsearch(attributes, attribute_type).map(|i| &attributes[i])
+}
+
+#[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(), RustSdpAttributeType::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(), RustSdpAttributeType::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(), RustSdpAttributeType::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(), RustSdpAttributeType::IceOptions);
+    if let Some(&SdpAttribute::IceOptions(ref options)) = attr {
+        *ret = options;
+        return NS_OK;
+    }
+    NS_ERROR_INVALID_ARG
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct RustSdpAttributeFingerprint {
+    hash_algorithm: StringView,
+    fingerprint: StringView
+}
+
+impl<'a> From<&'a SdpAttributeFingerprint> for RustSdpAttributeFingerprint {
+    fn from(other: &SdpAttributeFingerprint) -> Self {
+        RustSdpAttributeFingerprint {
+            hash_algorithm: StringView::from(other.hash_algorithm.as_str()),
+            fingerprint: StringView::from(other.fingerprint.as_str())
+        }
+    }
+}
+
+
+
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_fingerprint_count(attributes: *const Vec<SdpAttribute>) -> size_t {
+    count_attribute((*attributes).as_slice(), RustSdpAttributeType::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(), RustSdpAttributeType::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: uint32_t,
+    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(), RustSdpAttributeType::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());
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct RustSdpAttributeRtpmap {
+    pub payload_type: uint8_t,
+    pub codec_name: StringView,
+    pub frequency: uint32_t,
+    pub channels: uint32_t,
+}
+
+impl<'a> From<&'a SdpAttributeRtpmap> for RustSdpAttributeRtpmap {
+    fn from(other: &SdpAttributeRtpmap) -> Self {
+        RustSdpAttributeRtpmap {
+            payload_type: other.payload_type as uint8_t,
+            codec_name: StringView::from(other.codec_name.as_str()),
+            frequency: other.frequency as uint32_t,
+            channels: other.channels.unwrap_or(1)
+        }
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_rtpmap_count(attributes: *const Vec<SdpAttribute>) -> size_t {
+    count_attribute((*attributes).as_slice(), RustSdpAttributeType::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 RustSdpAttributeFmtp {
+    pub payload_type: uint8_t,
+    pub codec_name: StringView,
+    pub tokens: *const Vec<String>,
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_fmtp_count(attributes: *const Vec<SdpAttribute>) -> size_t {
+    count_attribute((*attributes).as_slice(), RustSdpAttributeType::Fmtp)
+}
+
+fn find_payload_type(attributes: &[SdpAttribute], payload_type: u32) -> 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()),
+                tokens: &fmtp.tokens
+            }
+            );
+        }
+    }
+    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>) -> int64_t {
+    for attribute in (*attributes).iter() {
+        if let SdpAttribute::Ptime(time) = *attribute {
+            return time as int64_t;
+        }
+    }
+    -1
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct RustSdpAttributeFlags {
+    pub ice_lite: bool,
+    pub rtcp_mux: 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,
+        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::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(), RustSdpAttributeType::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(), RustSdpAttributeType::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(), RustSdpAttributeType::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());
+}
+
+pub struct RustSdpAttributeRtcp {
+    pub port: uint16_t,
+    pub unicast_addr: RustIpAddr,
+}
+
+impl<'a> From<&'a SdpAttributeRtcp> for RustSdpAttributeRtcp {
+    fn from(other: &SdpAttributeRtcp) -> Self {
+        RustSdpAttributeRtcp {
+            port: other.port as u16,
+            unicast_addr: RustIpAddr::from(&other.unicast_addr)
+        }
+    }
+}
+
+#[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(), RustSdpAttributeType::Rtcp);
+    if let Some(&SdpAttribute::Rtcp(ref data)) = attr {
+        *ret = RustSdpAttributeRtcp::from(data);
+        return NS_OK;
+    }
+    NS_ERROR_INVALID_ARG
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_imageattr_count(attributes: *const Vec<SdpAttribute>) -> size_t {
+    count_attribute((*attributes).as_slice(), RustSdpAttributeType::ImageAttr)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_imageattrs(attributes: *const Vec<SdpAttribute>, ret_size: size_t, ret_groups: *mut StringView) {
+    let attrs: Vec<_> = (*attributes).iter().filter_map(|x| if let SdpAttribute::ImageAttr(ref string) = *x {
+        Some(StringView::from(string.as_str()))
+    } else {
+        None
+    }).collect();
+    let imageattrs = slice::from_raw_parts_mut(ret_groups, ret_size);
+    imageattrs.copy_from_slice(attrs.as_slice());
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct RustSdpAttributeSctpmap {
+    pub port: uint16_t,
+    pub channels: uint32_t,
+}
+
+impl<'a> From<&'a SdpAttributeSctpmap> for RustSdpAttributeSctpmap {
+    fn from(other: &SdpAttributeSctpmap) -> Self {
+        RustSdpAttributeSctpmap {
+            port: other.port as u16,
+            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(), RustSdpAttributeType::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 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: uint32_t,
+    pub address: RustIpAddr,
+    pub port: uint32_t,
+}
+
+
+impl<'a> From<&'a SdpAttributeRemoteCandidate> for RustSdpAttributeRemoteCandidate {
+    fn from(other: &SdpAttributeRemoteCandidate) -> Self {
+        RustSdpAttributeRemoteCandidate {
+            component: other.component,
+            address: RustIpAddr::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(), RustSdpAttributeType::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_rid_count(attributes: *const Vec<SdpAttribute>) -> size_t {
+    count_attribute((*attributes).as_slice(), RustSdpAttributeType::Rid)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_rids(attributes: *const Vec<SdpAttribute>, ret_size: size_t, ret_rids: *mut StringView) {
+    let attrs: Vec<_> = (*attributes).iter().filter_map(|x| if let SdpAttribute::Rid(ref string) = *x {
+        Some(StringView::from(string.as_str()))
+    } else {
+        None
+    }).collect();
+    let rids = slice::from_raw_parts_mut(ret_rids, ret_size);
+    rids.copy_from_slice(attrs.as_slice());
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct RustSdpAttributeExtmap {
+    pub id: uint16_t,
+    pub direction: RustDirection,
+    pub url: StringView,
+    pub extension_attributes: StringView
+}
+
+impl<'a> From<&'a SdpAttributeExtmap> for RustSdpAttributeExtmap {
+    fn from(other: &SdpAttributeExtmap) -> Self {
+        RustSdpAttributeExtmap {
+            id : other.id as uint16_t,
+            direction: RustDirection::from(&other.direction),
+            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(), RustSdpAttributeType::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());
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs
@@ -0,0 +1,190 @@
+extern crate rsdparsa;
+extern crate libc;
+#[macro_use] extern crate log;
+extern crate nserror;
+
+use std::ffi::CStr;
+use std::{str, slice, ptr};
+use std::os::raw::c_char;
+use std::error::Error;
+
+use libc::size_t;
+
+use std::rc::Rc;
+
+use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG};
+use rsdparsa::{SdpTiming, SdpBandwidth, SdpSession};
+use rsdparsa::error::SdpParserError;
+use rsdparsa::attribute_type::SdpAttribute;
+
+pub mod types;
+pub mod network;
+pub mod attribute;
+pub mod media_section;
+
+pub use types::{StringView, NULL_STRING};
+use network::{RustSdpOrigin, origin_view_helper, RustSdpConnection,
+              get_bandwidth};
+
+#[no_mangle]
+pub unsafe extern "C" fn parse_sdp(sdp: *const u8, length: u32,
+                                   fail_on_warning: bool,
+                                   session: *mut *const SdpSession,
+                                   error: *mut *const SdpParserError) -> nsresult {
+    // Bug 1433529 tracks fixing the TODOs in this function.
+    // TODO: Do I need to add explicit lifetime here?
+    // https://gankro.github.io/blah/only-in-rust/#honorable-mention-variance
+    let sdp_slice: &[u8] = slice::from_raw_parts(sdp, length as usize);
+    let sdp_c_str = match CStr::from_bytes_with_nul(sdp_slice) {
+        Ok(string) => string,
+        Err(_) => {
+            *session = ptr::null();
+            *error = ptr::null(); // TODO: Give more useful return value here
+            debug!("Error converting string");
+            return NS_ERROR_INVALID_ARG;
+        }
+    };
+    let sdp_buf: &[u8] = sdp_c_str.to_bytes();
+    let sdp_str_slice: &str = match str::from_utf8(sdp_buf) {
+        Ok(string) => string,
+        Err(_) => {
+            *session = ptr::null();
+            *error = ptr::null(); // TODO: Give more useful return value here
+            debug!("Error converting string to utf8");
+            return NS_ERROR_INVALID_ARG;
+        }
+    };
+    let parser_result = rsdparsa::parse_sdp(sdp_str_slice, fail_on_warning);
+    match parser_result {
+        Ok(parsed) => {
+            *session = Rc::into_raw(Rc::new(parsed));
+            *error = ptr::null();
+            NS_OK
+        },
+        Err(e) => {
+            *session = ptr::null();
+            debug!("{:?}", e);
+            debug!("Error parsing SDP in rust: {}", e.description());
+            *error = Box::into_raw(Box::new(e));
+            NS_ERROR_INVALID_ARG
+        }
+    }
+}
+
+#[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(error: *mut SdpParserError) -> size_t {
+    match *error {
+        SdpParserError::Line {line_number, ..} |
+        SdpParserError::Unsupported { line_number, ..} |
+        SdpParserError::Sequence {line_number, ..} => line_number
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_error_message(error: *mut SdpParserError) -> StringView {
+    StringView::from((*error).description())
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_free_error(error: *mut SdpParserError) {
+    let e = Box::from_raw(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().as_str())
+}
+
+#[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
+    }
+}
+
+#[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 has_timing(session: *const SdpSession) -> bool {
+    (*session).timing.is_some()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn 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
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs
@@ -0,0 +1,146 @@
+use std::ptr;
+use std::os::raw::c_char;
+
+use libc::{size_t, uint32_t};
+
+use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG};
+use rsdparsa::{SdpBandwidth, SdpSession};
+use rsdparsa::media_type::{SdpMedia, SdpMediaValue, SdpProtocolValue,
+                           SdpFormatList};
+use rsdparsa::attribute_type::SdpAttribute;
+
+use network::{get_bandwidth, RustSdpConnection};
+
+#[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,
+    UdpTlsRtpSavpf,
+    TcpTlsRtpSavpf,
+    DtlsSctp,
+    UdpDtlsSctp,
+    TcpDtlsSctp,
+}
+
+impl<'a> From<&'a SdpProtocolValue> for RustSdpProtocolValue {
+    fn from(val: &SdpProtocolValue) -> Self {
+        match *val {
+            SdpProtocolValue::RtpSavpf => RustSdpProtocolValue::RtpSavpf,
+            SdpProtocolValue::UdpTlsRtpSavpf => RustSdpProtocolValue::UdpTlsRtpSavpf,
+            SdpProtocolValue::TcpTlsRtpSavpf => RustSdpProtocolValue::TcpTlsRtpSavpf,
+            SdpProtocolValue::DtlsSctp => RustSdpProtocolValue::DtlsSctp,
+            SdpProtocolValue::UdpDtlsSctp => RustSdpProtocolValue::UdpDtlsSctp,
+            SdpProtocolValue::TcpDtlsSctp => RustSdpProtocolValue::TcpDtlsSctp,
+        }
+    }
+}
+
+#[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_get_media_port(sdp_media: *const SdpMedia) -> uint32_t {
+    (*sdp_media).get_port()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_media_port_count(sdp_media: *const SdpMedia) -> uint32_t {
+    (*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) -> uint32_t {
+    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).has_connection()
+}
+
+#[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()
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/network.rs
@@ -0,0 +1,180 @@
+use std::net::IpAddr;
+use std::os::raw::c_char;
+use std::ffi::{CStr, CString};
+
+use libc::{uint8_t, uint64_t};
+
+use rsdparsa::{SdpOrigin, SdpConnection, SdpBandwidth};
+
+use types::StringView;
+
+#[repr(C)]
+#[derive(Clone, Copy, PartialEq)]
+pub enum RustSdpAddrType {
+    None,
+    IP4,
+    IP6
+}
+
+impl<'a> From<&'a IpAddr> for RustSdpAddrType {
+    fn from(addr: &IpAddr) -> RustSdpAddrType {
+        match *addr {
+            IpAddr::V4(_) => RustSdpAddrType::IP4,
+            IpAddr::V6(_) => RustSdpAddrType::IP6
+        }
+    }
+}
+
+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 RustIpAddr {
+    addr_type: RustSdpAddrType,
+    unicast_addr: [u8; 50]
+}
+
+impl<'a> From<&'a IpAddr> for RustIpAddr {
+    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);
+        }
+        RustIpAddr {addr_type: RustSdpAddrType::from(addr),
+                    unicast_addr: c_addr }
+    }
+}
+
+impl<'a> From<&'a Option<IpAddr>> for RustIpAddr {
+    fn from(addr: &Option<IpAddr>) -> Self {
+        match *addr {
+            Some(ref x) => RustIpAddr::from(x),
+            None => RustIpAddr {
+                addr_type: RustSdpAddrType::None,
+                unicast_addr: [0; 50]
+            }
+        }
+    }
+}
+
+#[repr(C)]
+pub struct RustSdpConnection {
+    pub addr: RustIpAddr,
+    pub ttl: uint8_t,
+    pub amount: uint64_t
+}
+
+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: RustIpAddr::from(&sdp_connection.addr),
+                            ttl: ttl, amount: amount }
+    }
+}
+
+#[repr(C)]
+pub struct RustSdpOrigin {
+    username: StringView,
+    session_id: u64,
+    session_version: u64,
+    addr: RustIpAddr,
+}
+
+
+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: RustIpAddr::from(&origin.unicast_addr)
+    }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/types.rs
@@ -0,0 +1,65 @@
+use libc::{size_t, uint32_t};
+
+use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG};
+
+#[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<'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 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 uint32_t) -> nsresult {
+    match (*vec).get(index) {
+        Some(val) => {
+            *ret = *val;
+            NS_OK
+        },
+        None => NS_ERROR_INVALID_ARG
+    }
+}
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -591,16 +591,17 @@ dependencies = [
  "encoding_c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "geckoservo 0.0.1",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "mp4parse_capi 0.9.1",
  "netwerk_helper 0.0.1",
  "nserror 0.1.0",
  "nsstring 0.1.0",
+ "rsdparsa_capi 0.1.0",
  "rust_url_capi 0.0.1",
  "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "u2fhid 0.1.0",
  "webrender_bindings 0.1.0",
  "xpcom 0.1.0",
 ]
 
 [[package]]
@@ -1109,16 +1110,30 @@ dependencies = [
 ]
 
 [[package]]
 name = "regex-syntax"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "rsdparsa"
+version = "0.1.0"
+
+[[package]]
+name = "rsdparsa_capi"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nserror 0.1.0",
+ "rsdparsa 0.1.0",
+]
+
+[[package]]
 name = "runloop"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "rust_url_capi"
 version = "0.0.1"
 dependencies = [
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -589,16 +589,17 @@ dependencies = [
  "encoding_c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "geckoservo 0.0.1",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "mp4parse_capi 0.9.1",
  "netwerk_helper 0.0.1",
  "nserror 0.1.0",
  "nsstring 0.1.0",
+ "rsdparsa_capi 0.1.0",
  "rust_url_capi 0.0.1",
  "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "u2fhid 0.1.0",
  "webrender_bindings 0.1.0",
  "xpcom 0.1.0",
 ]
 
 [[package]]
@@ -1096,16 +1097,30 @@ dependencies = [
 ]
 
 [[package]]
 name = "regex-syntax"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "rsdparsa"
+version = "0.1.0"
+
+[[package]]
+name = "rsdparsa_capi"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nserror 0.1.0",
+ "rsdparsa 0.1.0",
+]
+
+[[package]]
 name = "runloop"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "rust_url_capi"
 version = "0.0.1"
 dependencies = [
--- a/toolkit/library/rust/shared/Cargo.toml
+++ b/toolkit/library/rust/shared/Cargo.toml
@@ -18,16 +18,17 @@ cubeb-pulse = { path = "../../../../medi
 cubeb-core = { path = "../../../../media/cubeb-rs/cubeb-core", optional = true }
 cubeb = { path = "../../../../media/cubeb-rs/cubeb-api", optional = true }
 cubeb-backend = { path = "../../../../media/cubeb-rs/cubeb-backend", optional = true }
 encoding_c = "0.8.0"
 encoding_glue = { path = "../../../../intl/encoding_glue" }
 audioipc-client = { path = "../../../../media/audioipc/client", version = "0.2", optional = true }
 audioipc-server = { path = "../../../../media/audioipc/server", version = "0.2", optional = true }
 u2fhid = { path = "../../../../dom/webauthn/u2f-hid-rs" }
+rsdparsa_capi = { path = "../../../../media/webrtc/signaling/src/sdp/rsdparsa_capi" }
 # We have these to enforce common feature sets for said crates.
 log = {version = "0.3", features = ["release_max_level_info"]}
 syn = { version = "0.11", features = ["full", "visit", "parsing"] }
 cose-c = { version = "0.1.5" }
 
 [features]
 default = []
 bindgen = ["geckoservo/bindgen"]
--- a/toolkit/library/rust/shared/lib.rs
+++ b/toolkit/library/rust/shared/lib.rs
@@ -20,16 +20,17 @@ extern crate encoding_glue;
 #[cfg(feature = "cubeb-remoting")]
 extern crate audioipc_client;
 #[cfg(feature = "cubeb-remoting")]
 extern crate audioipc_server;
 extern crate u2fhid;
 extern crate log;
 extern crate syn;
 extern crate cosec;
+extern crate rsdparsa_capi;
 
 use std::boxed::Box;
 use std::ffi::CStr;
 use std::os::raw::c_char;
 use std::panic;