pub(super) async fn generate_matched_sdp(
        &self,
        mut local_transceivers: Vec<Arc<RTCRtpTransceiver>>,
        use_identity: bool,
        include_unmatched: bool,
        connection_role: ConnectionRole,
        sdp_semantics: RTCSdpSemantics,
    ) -> Result<SessionDescription> {
        let d = SessionDescription::new_jsep_session_description(use_identity);

        let ice_params = self.ice_gatherer.get_local_parameters().await?;
        let candidates = self.ice_gatherer.get_local_candidates().await?;

        let remote_description = {
            let pending_remote_description = self.pending_remote_description.lock().await;
            if pending_remote_description.is_some() {
                pending_remote_description.clone()
            } else {
                let current_remote_description = self.current_remote_description.lock().await;
                current_remote_description.clone()
            }
        };

        let detected_plan_b = description_is_plan_b(remote_description.as_ref())?;
        let mut media_sections = vec![];
        let mut already_have_application_media_section = false;
        if let Some(remote_description) = remote_description.as_ref() {
            if let Some(parsed) = &remote_description.parsed {
                for media in &parsed.media_descriptions {
                    if let Some(mid_value) = get_mid_value(media) {
                        if mid_value.is_empty() {
                            return Err(Error::ErrPeerConnRemoteDescriptionWithoutMidValue);
                        }

                        if media.media_name.media == MEDIA_SECTION_APPLICATION {
                            media_sections.push(MediaSection {
                                id: mid_value.to_owned(),
                                data: true,
                                ..Default::default()
                            });
                            already_have_application_media_section = true;
                            continue;
                        }

                        let kind = RTPCodecType::from(media.media_name.media.as_str());
                        let direction = get_peer_direction(media);
                        if kind == RTPCodecType::Unspecified
                            || direction == RTCRtpTransceiverDirection::Unspecified
                        {
                            continue;
                        }

                        if sdp_semantics == RTCSdpSemantics::PlanB
                            || (sdp_semantics == RTCSdpSemantics::UnifiedPlanWithFallback
                                && detected_plan_b)
                        {
                            if !detected_plan_b {
                                return Err(Error::ErrIncorrectSDPSemantics);
                            }
                            // If we're responding to a plan-b offer, then we should try to fill up this
                            // media entry with all matching local transceivers
                            let mut media_transceivers = vec![];
                            loop {
                                // keep going until we can't get any more
                                if let Some(t) = satisfy_type_and_direction(
                                    kind,
                                    direction,
                                    &mut local_transceivers,
                                )
                                .await
                                {
                                    if let Some(sender) = t.sender().await {
                                        sender.set_negotiated();
                                    }
                                    media_transceivers.push(t);
                                } else {
                                    if media_transceivers.is_empty() {
                                        let t = RTCRtpTransceiver::new(
                                            None,
                                            None,
                                            RTCRtpTransceiverDirection::Inactive,
                                            kind,
                                            vec![],
                                            Arc::clone(&self.media_engine),
                                        )
                                        .await;
                                        media_transceivers.push(t);
                                    }
                                    break;
                                }
                            }
                            media_sections.push(MediaSection {
                                id: mid_value.to_owned(),
                                transceivers: media_transceivers,
                                ..Default::default()
                            });
                        } else if sdp_semantics == RTCSdpSemantics::UnifiedPlan
                            || sdp_semantics == RTCSdpSemantics::UnifiedPlanWithFallback
                        {
                            if detected_plan_b {
                                return Err(Error::ErrIncorrectSDPSemantics);
                            }
                            if let Some(t) = find_by_mid(mid_value, &mut local_transceivers).await {
                                if let Some(sender) = t.sender().await {
                                    sender.set_negotiated();
                                }
                                let media_transceivers = vec![t];
                                media_sections.push(MediaSection {
                                    id: mid_value.to_owned(),
                                    transceivers: media_transceivers,
                                    rid_map: get_rids(media),
                                    ..Default::default()
                                });
                            } else {
                                return Err(Error::ErrPeerConnTranscieverMidNil);
                            }
                        }
                    } else {
                        return Err(Error::ErrPeerConnRemoteDescriptionWithoutMidValue);
                    }
                }
            }
        }

        // If we are offering also include unmatched local transceivers
        if include_unmatched {
            if !detected_plan_b {
                for t in &local_transceivers {
                    if let Some(sender) = t.sender().await {
                        sender.set_negotiated();
                    }
                    media_sections.push(MediaSection {
                        id: t.mid().await,
                        transceivers: vec![Arc::clone(t)],
                        ..Default::default()
                    });
                }
            }

            if self
                .sctp_transport
                .data_channels_requested
                .load(Ordering::SeqCst)
                != 0
                && !already_have_application_media_section
            {
                if detected_plan_b {
                    media_sections.push(MediaSection {
                        id: "data".to_owned(),
                        data: true,
                        ..Default::default()
                    });
                } else {
                    media_sections.push(MediaSection {
                        id: format!("{}", media_sections.len()),
                        data: true,
                        ..Default::default()
                    });
                }
            }
        }

        if sdp_semantics == RTCSdpSemantics::UnifiedPlanWithFallback && detected_plan_b {
            log::info!("Plan-B Offer detected; responding with Plan-B Answer");
        }

        let dtls_fingerprints = if let Some(cert) = self.dtls_transport.certificates.first() {
            cert.get_fingerprints()?
        } else {
            return Err(Error::ErrNonCertificate);
        };

        let params = PopulateSdpParams {
            is_plan_b: detected_plan_b,
            media_description_fingerprint: self.setting_engine.sdp_media_level_fingerprints,
            is_icelite: self.setting_engine.candidates.ice_lite,
            connection_role,
            ice_gathering_state: self.ice_gathering_state(),
        };
        populate_sdp(
            d,
            &dtls_fingerprints,
            &self.media_engine,
            &candidates,
            &ice_params,
            &media_sections,
            params,
        )
        .await
    }
/// generate_matched_sdp generates a SDP and takes the remote state into account
/// this is used everytime we have a remote_description
generate_matched_sdp generates a SDP and takes the remote state into account
this is used everytime we have a remote_description
generate_matched_sdp generates a SDP and takes the remote state into account this is used everytime we have a remote_description
pub(super) async fn generate_matched_sdp(
        &self,
        mut local_transceivers: Vec<Arc<RTCRtpTransceiver>>,
        use_identity: bool,
        include_unmatched: bool,
        connection_role: ConnectionRole,
        sdp_semantics: RTCSdpSemantics,
    ) -> Result<SessionDescription> {
        let d = SessionDescription::new_jsep_session_description(use_identity);
        let ice_params = self.ice_gatherer.get_local_parameters().await?;
        let candidates = self.ice_gatherer.get_local_candidates().await?;
        let remote_description = {
            let pending_remote_description = self.pending_remote_description.lock().await;
            if pending_remote_description.is_some() {
                pending_remote_description.clone()
            } else {
                let current_remote_description = self.current_remote_description.lock().await;
                current_remote_description.clone()
            }
        };
        let detected_plan_b = description_is_plan_b(remote_description.as_ref())?;
        let mut media_sections = vec![];
        let mut already_have_application_media_section = false;
        if let Some(remote_description) = remote_description.as_ref() {
            if let Some(parsed) = &remote_description.parsed {
                for media in &parsed.media_descriptions {
                    if let Some(mid_value) = get_mid_value(media) {
                        if mid_value.is_empty() {
                            return Err(Error::ErrPeerConnRemoteDescriptionWithoutMidValue);
                        }
                        if media.media_name.media == MEDIA_SECTION_APPLICATION {
                            media_sections.push(MediaSection {
                                id: mid_value.to_owned(),
                                data: true,
                                ..Default::default()
                            });
                            already_have_application_media_section = true;
                            continue;
                        }
                        let kind = RTPCodecType::from(media.media_name.media.as_str());
                        let direction = get_peer_direction(media);
                        if kind == RTPCodecType::Unspecified
                            || direction == RTCRtpTransceiverDirection::Unspecified
                        {
                            continue;
                        }
                        if sdp_semantics == RTCSdpSemantics::PlanB
                            || (sdp_semantics == RTCSdpSemantics::UnifiedPlanWithFallback
                                && detected_plan_b)
                        {
                            if !detected_plan_b {
                                return Err(Error::ErrIncorrectSDPSemantics);
                            }
                            // If we're responding to a plan-b offer, then we should try to fill up this
                            // media entry with all matching local transceivers
                            let mut media_transceivers = vec![];
                            loop {
                                // keep going until we can't get any more
                                if let Some(t) = satisfy_type_and_direction(
                                    kind,
                                    direction,
                                    &mut local_transceivers,
                                )
                                .await
                                {
                                    if let Some(sender) = t.sender().await {
                                        sender.set_negotiated();
                                    }
                                    media_transceivers.push(t);
                                } else {
                                    if media_transceivers.is_empty() {
                                        let t = RTCRtpTransceiver::new(
                                            None,
                                            None,
                                            RTCRtpTransceiverDirection::Inactive,
                                            kind,
                                            vec![],
                                            Arc::clone(&self.media_engine),
                                        )
                                        .await;
                                        media_transceivers.push(t);
                                    }
                                    break;
                                }
                            }
                            media_sections.push(MediaSection {
                                id: mid_value.to_owned(),
                                transceivers: media_transceivers,
                                ..Default::default()
                            });
                        } else if sdp_semantics == RTCSdpSemantics::UnifiedPlan
                            || sdp_semantics == RTCSdpSemantics::UnifiedPlanWithFallback
                        {
                            if detected_plan_b {
                                return Err(Error::ErrIncorrectSDPSemantics);
                            }
                            if let Some(t) = find_by_mid(mid_value, &mut local_transceivers).await {
                                if let Some(sender) = t.sender().await {
                                    sender.set_negotiated();
                                }
                                let media_transceivers = vec![t];
                                media_sections.push(MediaSection {
                                    id: mid_value.to_owned(),
                                    transceivers: media_transceivers,
                                    rid_map: get_rids(media),
                                    ..Default::default()
                                });
                            } else {
                                return Err(Error::ErrPeerConnTranscieverMidNil);
                            }
                        }
                    } else {
                        return Err(Error::ErrPeerConnRemoteDescriptionWithoutMidValue);
                    }
                }
            }
        }
        // If we are offering also include unmatched local transceivers
        if include_unmatched {
            if !detected_plan_b {
                for t in &local_transceivers {
                    if let Some(sender) = t.sender().await {
                        sender.set_negotiated();
                    }
                    media_sections.push(MediaSection {
                        id: t.mid().await,
                        transceivers: vec![Arc::clone(t)],
                        ..Default::default()
                    });
                }
            }
            if self
                .sctp_transport
                .data_channels_requested
                .load(Ordering::SeqCst)
                != 0
                && !already_have_application_media_section
            {
                if detected_plan_b {
                    media_sections.push(MediaSection {
                        id: "data".to_owned(),
                        data: true,
                        ..Default::default()
                    });
                } else {
                    media_sections.push(MediaSection {
                        id: format!("{}", media_sections.len()),
                        data: true,
                        ..Default::default()
                    });
                }
            }
        }
        if sdp_semantics == RTCSdpSemantics::UnifiedPlanWithFallback && detected_plan_b {
            log::info!("Plan-B Offer detected; responding with Plan-B Answer");
        }
        let dtls_fingerprints = if let Some(cert) = self.dtls_transport.certificates.first() {
            cert.get_fingerprints()?
        } else {
            return Err(Error::ErrNonCertificate);
        };
        let params = PopulateSdpParams {
            is_plan_b: detected_plan_b,
            media_description_fingerprint: self.setting_engine.sdp_media_level_fingerprints,
            is_icelite: self.setting_engine.candidates.ice_lite,
            connection_role,
            ice_gathering_state: self.ice_gathering_state(),
        };
        populate_sdp(
            d,
            &dtls_fingerprints,
            &self.media_engine,
            &candidates,
            &ice_params,
            &media_sections,
            params,
        )
        .await
    }
pub ( super ) async fn generate_matched_sdp ( & self , mut local_transceivers : Vec < Arc < RTCRtpTransceiver > > , use_identity : bool , include_unmatched : bool , connection_role : ConnectionRole , sdp_semantics : RTCSdpSemantics , ) -> Result < SessionDescription > { let d = SessionDescription :: new_jsep_session_description ( use_identity ) ; let ice_params = self . ice_gatherer . get_local_parameters ( ) . await ? ; let candidates = self . ice_gatherer . get_local_candidates ( ) . await ? ; let remote_description = { let pending_remote_description = self . pending_remote_description . lock ( ) . await ; if pending_remote_description . is_some ( ) { pending_remote_description . clone ( ) } else { let current_remote_description = self . current_remote_description . lock ( ) . await ; current_remote_description . clone ( ) } } ; let detected_plan_b = description_is_plan_b ( remote_description . as_ref ( ) ) ? ; let mut media_sections = vec ! [ ] ; let mut already_have_application_media_section = false ; if let Some ( remote_description ) = remote_description . as_ref ( ) { if let Some ( parsed ) = & remote_description . parsed { for media in & parsed . media_descriptions { if let Some ( mid_value ) = get_mid_value ( media ) { if mid_value . is_empty ( ) { return Err ( Error :: ErrPeerConnRemoteDescriptionWithoutMidValue ) ; } if media . media_name . media == MEDIA_SECTION_APPLICATION { media_sections . push ( MediaSection { id : mid_value . to_owned ( ) , data : true , .. Default :: default ( ) } ) ; already_have_application_media_section = true ; continue ; } let kind = RTPCodecType :: from ( media . media_name . media . as_str ( ) ) ; let direction = get_peer_direction ( media ) ; if kind == RTPCodecType :: Unspecified || direction == RTCRtpTransceiverDirection :: Unspecified { continue ; } if sdp_semantics == RTCSdpSemantics :: PlanB || ( sdp_semantics == RTCSdpSemantics :: UnifiedPlanWithFallback && detected_plan_b ) { if ! detected_plan_b { return Err ( Error :: ErrIncorrectSDPSemantics ) ; } // If we're responding to a plan-b offer, then we should try to fill up this // media entry with all matching local transceivers let mut media_transceivers = vec ! [ ] ; loop { // keep going until we can't get any more if let Some ( t ) = satisfy_type_and_direction ( kind , direction , & mut local_transceivers , ) . await { if let Some ( sender ) = t . sender ( ) . await { sender . set_negotiated ( ) ; } media_transceivers . push ( t ) ; } else { if media_transceivers . is_empty ( ) { let t = RTCRtpTransceiver :: new ( None , None , RTCRtpTransceiverDirection :: Inactive , kind , vec ! [ ] , Arc :: clone ( & self . media_engine ) , ) . await ; media_transceivers . push ( t ) ; } break ; } } media_sections . push ( MediaSection { id : mid_value . to_owned ( ) , transceivers : media_transceivers , .. Default :: default ( ) } ) ; } else if sdp_semantics == RTCSdpSemantics :: UnifiedPlan || sdp_semantics == RTCSdpSemantics :: UnifiedPlanWithFallback { if detected_plan_b { return Err ( Error :: ErrIncorrectSDPSemantics ) ; } if let Some ( t ) = find_by_mid ( mid_value , & mut local_transceivers ) . await { if let Some ( sender ) = t . sender ( ) . await { sender . set_negotiated ( ) ; } let media_transceivers = vec ! [ t ] ; media_sections . push ( MediaSection { id : mid_value . to_owned ( ) , transceivers : media_transceivers , rid_map : get_rids ( media ) , .. Default :: default ( ) } ) ; } else { return Err ( Error :: ErrPeerConnTranscieverMidNil ) ; } } } else { return Err ( Error :: ErrPeerConnRemoteDescriptionWithoutMidValue ) ; } } } } // If we are offering also include unmatched local transceivers if include_unmatched { if ! detected_plan_b { for t in & local_transceivers { if let Some ( sender ) = t . sender ( ) . await { sender . set_negotiated ( ) ; } media_sections . push ( MediaSection { id : t . mid ( ) . await , transceivers : vec ! [ Arc clone ( t ) ] , .. Default :: default ( ) } ) ; } } if self . sctp_transport . data_channels_requested . load ( Ordering :: SeqCst ) != 0 && ! already_have_application_media_section { if detected_plan_b { media_sections . push ( MediaSection { id : " " . to_owned ( ) , data : true , .. Default :: default ( ) } ) ; } else { media_sections . push ( MediaSection { id : format ! ( " " media_sections len ( ) ) , data : true , .. Default :: default ( ) } ) ; } } } if sdp_semantics == RTCSdpSemantics :: UnifiedPlanWithFallback && detected_plan_b { log :: info ! ( " " ) ; } let dtls_fingerprints = if let Some ( cert ) = self . dtls_transport . certificates . first ( ) { cert . get_fingerprints ( ) ? } else { return Err ( Error :: ErrNonCertificate ) ; } ; let params = PopulateSdpParams { is_plan_b : detected_plan_b , media_description_fingerprint : self . setting_engine . sdp_media_level_fingerprints , is_icelite : self . setting_engine . candidates . ice_lite , connection_role , ice_gathering_state : self . ice_gathering_state ( ) , } ; populate_sdp ( d , & dtls_fingerprints , & self . media_engine , & candidates , & ice_params , & media_sections , params , ) . await }
generate_matched_sdp generates a SDP and takes the remote state into account
this is used everytime we have a remote_description
generate_matched_sdp generates a SDP and takes the remote state into account this is used everytime we have a remote_description
&self
local_transceivers
Vec<Arc<RTCRtpTransceiver>>
use_identity
bool
include_unmatched
bool
connection_role
ConnectionRole
sdp_semantics
RTCSdpSemantics