pub async fn play(mut self, policy: PlayOptions) -> Result<Session<Playing>, Error> {
        let inner = self.0.as_mut().project();
        let conn = inner
            .conn
            .as_mut()
            .ok_or_else(|| wrap!(ErrorInt::FailedPrecondition("no connection".into())))?;
        let session = inner.session.as_ref().ok_or_else(|| {
            wrap!(ErrorInt::FailedPrecondition(
                "must SETUP before PLAY".into()
            ))
        })?;
        if let Some(tool) = inner.presentation.tool.as_deref() {
            if matches!(inner.options.transport, Transport::Tcp) && *inner.has_live555_tcp_bug {
                warn!(
                    "Connecting via TCP to known-broken RTSP server {:?}. \
                       See <https://github.com/scottlamb/retina/issues/17>. \
                       Consider using UDP instead!",
                    tool
                );
            }
        }

        trace!("PLAY with channel mappings: {:#?}", &conn.channels);
        *inner.maybe_playing = true;
        let (msg_ctx, cseq, response) = conn
            .send(
                ResponseMode::Play,
                &inner.options,
                inner.requested_auth,
                &mut rtsp_types::Request::builder(Method::Play, rtsp_types::Version::V1_0)
                    .request_uri(inner.presentation.control.clone())
                    .header(rtsp_types::headers::SESSION, &*session.id)
                    .header(rtsp_types::headers::RANGE, "npt=0.000-".to_owned())
                    .build(Bytes::new()),
            )
            .await?;
        parse::parse_play(&response, inner.presentation).map_err(|description| {
            wrap!(ErrorInt::RtspResponseError {
                conn_ctx: *conn.inner.ctx(),
                msg_ctx,
                method: rtsp_types::Method::Play,
                cseq,
                status: response.status(),
                description,
            })
        })?;

        // Count how many streams have been setup (not how many are in the presentation).
        let setup_streams = inner
            .presentation
            .streams
            .iter()
            .filter(|s| matches!(s.state, StreamState::Init(_)))
            .count();

        let all_have_time = inner.presentation.streams.iter().all(|s| match s.state {
            StreamState::Init(StreamStateInit {
                initial_rtptime, ..
            }) => initial_rtptime.is_some(),
            _ => true,
        });

        // Move all streams that have been set up from Init to Playing state. Check that required
        // parameters are present while doing so.
        for (i, s) in inner.presentation.streams.iter_mut().enumerate() {
            match s.state {
                StreamState::Init(StreamStateInit {
                    initial_rtptime,
                    initial_seq,
                    ssrc,
                    ..
                }) => {
                    let initial_rtptime = match policy.initial_timestamp {
                        InitialTimestampPolicy::Require | InitialTimestampPolicy::Default
                            if setup_streams > 1 =>
                        {
                            if initial_rtptime.is_none() {
                                bail!(ErrorInt::RtspResponseError {
                                    conn_ctx: *conn.inner.ctx(),
                                    msg_ctx,
                                    method: rtsp_types::Method::Play,
                                    cseq,
                                    status: response.status(),
                                    description: format!(
                                        "Expected rtptime on PLAY with mode {:?}, missing on \
                                             stream {} ({:?}). Consider setting initial timestamp \
                                             mode permissive.",
                                        policy.initial_timestamp, i, &s.control
                                    ),
                                });
                            }
                            initial_rtptime
                        }
                        InitialTimestampPolicy::Permissive
                            if setup_streams > 1 && all_have_time =>
                        {
                            initial_rtptime
                        }
                        _ => None,
                    };
                    let initial_seq = match initial_seq {
                        Some(0) if policy.ignore_zero_seq => {
                            log::info!("Ignoring seq=0 on stream {}", i);
                            None
                        }
                        o => o,
                    };
                    let conn_ctx = conn.inner.ctx();
                    s.state = StreamState::Playing {
                        timeline: Timeline::new(
                            initial_rtptime,
                            s.clock_rate,
                            policy.enforce_timestamps_with_max_jump_secs,
                        )
                        .map_err(|description| {
                            wrap!(ErrorInt::RtspResponseError {
                                conn_ctx: *conn_ctx,
                                msg_ctx,
                                method: rtsp_types::Method::Play,
                                cseq,
                                status: response.status(),
                                description,
                            })
                        })?,
                        rtp_handler: rtp::InorderParser::new(ssrc, initial_seq),
                    };
                }
                StreamState::Uninit => {}
                StreamState::Playing { .. } => unreachable!(),
            };
        }
        *inner.keepalive_timer = Some(Box::pin(tokio::time::sleep(KEEPALIVE_DURATION)));
        Ok(Session(self.0, Playing(())))
    }
/// Sends a `PLAY` request for the entire presentation.
///
/// The presentation must support aggregate control, as defined in [RFC 2326
/// section 1.3](https://tools.ietf.org/html/rfc2326#section-1.3).
Sends a `PLAY` request for the entire presentation.
The presentation must support aggregate control, as defined in [RFC 2326
section 1.3].
Sends a ` PLAY ` request for the entire presentation . The presentation must support aggregate control as defined in [ RFC 2326 section 1 . 3 ] .
pub async fn play(mut self, policy: PlayOptions) -> Result<Session<Playing>, Error> {
        let inner = self.0.as_mut().project();
        let conn = inner
            .conn
            .as_mut()
            .ok_or_else(|| wrap!(ErrorInt::FailedPrecondition("no connection".into())))?;
        let session = inner.session.as_ref().ok_or_else(|| {
            wrap!(ErrorInt::FailedPrecondition(
                "must SETUP before PLAY".into()
            ))
        })?;
        if let Some(tool) = inner.presentation.tool.as_deref() {
            if matches!(inner.options.transport, Transport::Tcp) && *inner.has_live555_tcp_bug {
                warn!(
                    "Connecting via TCP to known-broken RTSP server {:?}. \
                       See <https://github.com/scottlamb/retina/issues/17>. \
                       Consider using UDP instead!",
                    tool
                );
            }
        }
        trace!("PLAY with channel mappings: {:#?}", &conn.channels);
        *inner.maybe_playing = true;
        let (msg_ctx, cseq, response) = conn
            .send(
                ResponseMode::Play,
                &inner.options,
                inner.requested_auth,
                &mut rtsp_types::Request::builder(Method::Play, rtsp_types::Version::V1_0)
                    .request_uri(inner.presentation.control.clone())
                    .header(rtsp_types::headers::SESSION, &*session.id)
                    .header(rtsp_types::headers::RANGE, "npt=0.000-".to_owned())
                    .build(Bytes::new()),
            )
            .await?;
        parse::parse_play(&response, inner.presentation).map_err(|description| {
            wrap!(ErrorInt::RtspResponseError {
                conn_ctx: *conn.inner.ctx(),
                msg_ctx,
                method: rtsp_types::Method::Play,
                cseq,
                status: response.status(),
                description,
            })
        })?;
        // Count how many streams have been setup (not how many are in the presentation).
        let setup_streams = inner
            .presentation
            .streams
            .iter()
            .filter(|s| matches!(s.state, StreamState::Init(_)))
            .count();
        let all_have_time = inner.presentation.streams.iter().all(|s| match s.state {
            StreamState::Init(StreamStateInit {
                initial_rtptime, ..
            }) => initial_rtptime.is_some(),
            _ => true,
        });
        // Move all streams that have been set up from Init to Playing state. Check that required
        // parameters are present while doing so.
        for (i, s) in inner.presentation.streams.iter_mut().enumerate() {
            match s.state {
                StreamState::Init(StreamStateInit {
                    initial_rtptime,
                    initial_seq,
                    ssrc,
                    ..
                }) => {
                    let initial_rtptime = match policy.initial_timestamp {
                        InitialTimestampPolicy::Require | InitialTimestampPolicy::Default
                            if setup_streams > 1 =>
                        {
                            if initial_rtptime.is_none() {
                                bail!(ErrorInt::RtspResponseError {
                                    conn_ctx: *conn.inner.ctx(),
                                    msg_ctx,
                                    method: rtsp_types::Method::Play,
                                    cseq,
                                    status: response.status(),
                                    description: format!(
                                        "Expected rtptime on PLAY with mode {:?}, missing on \
                                             stream {} ({:?}). Consider setting initial timestamp \
                                             mode permissive.",
                                        policy.initial_timestamp, i, &s.control
                                    ),
                                });
                            }
                            initial_rtptime
                        }
                        InitialTimestampPolicy::Permissive
                            if setup_streams > 1 && all_have_time =>
                        {
                            initial_rtptime
                        }
                        _ => None,
                    };
                    let initial_seq = match initial_seq {
                        Some(0) if policy.ignore_zero_seq => {
                            log::info!("Ignoring seq=0 on stream {}", i);
                            None
                        }
                        o => o,
                    };
                    let conn_ctx = conn.inner.ctx();
                    s.state = StreamState::Playing {
                        timeline: Timeline::new(
                            initial_rtptime,
                            s.clock_rate,
                            policy.enforce_timestamps_with_max_jump_secs,
                        )
                        .map_err(|description| {
                            wrap!(ErrorInt::RtspResponseError {
                                conn_ctx: *conn_ctx,
                                msg_ctx,
                                method: rtsp_types::Method::Play,
                                cseq,
                                status: response.status(),
                                description,
                            })
                        })?,
                        rtp_handler: rtp::InorderParser::new(ssrc, initial_seq),
                    };
                }
                StreamState::Uninit => {}
                StreamState::Playing { .. } => unreachable!(),
            };
        }
        *inner.keepalive_timer = Some(Box::pin(tokio::time::sleep(KEEPALIVE_DURATION)));
        Ok(Session(self.0, Playing(())))
    }
pub async fn play ( mut self , policy : PlayOptions ) -> Result < Session < Playing > , Error > { let inner = self . 0 . as_mut ( ) . project ( ) ; let conn = inner . conn . as_mut ( ) . ok_or_else ( | | wrap ! ( ErrorInt FailedPrecondition ( " " into ( ) ) ) ) ? ; let session = inner . session . as_ref ( ) . ok_or_else ( | | { wrap ! ( ErrorInt FailedPrecondition ( " " into ( ) ) ) } ) ? ; if let Some ( tool ) = inner . presentation . tool . as_deref ( ) { if matches ! ( inner options transport Transport Tcp ) && * inner . has_live555_tcp_bug { warn ! ( " \
 \
 " tool ) ; } } trace ! ( " " conn channels ) ; * inner . maybe_playing = true ; let ( msg_ctx , cseq , response ) = conn . send ( ResponseMode :: Play , & inner . options , inner . requested_auth , & mut rtsp_types :: Request :: builder ( Method :: Play , rtsp_types :: Version :: V1_0 ) . request_uri ( inner . presentation . control . clone ( ) ) . header ( rtsp_types :: headers :: SESSION , & * session . id ) . header ( rtsp_types :: headers :: RANGE , " " . to_owned ( ) ) . build ( Bytes :: new ( ) ) , ) . await ? ; parse :: parse_play ( & response , inner . presentation ) . map_err ( | description | { wrap ! ( ErrorInt RtspResponseError { conn_ctx conn inner ctx ( ) msg_ctx method rtsp_types Method Play cseq status response status ( ) description } ) } ) ? ; // Count how many streams have been setup (not how many are in the presentation). let setup_streams = inner . presentation . streams . iter ( ) . filter ( | s | matches ! ( s state StreamState Init ( ) ) ) . count ( ) ; let all_have_time = inner . presentation . streams . iter ( ) . all ( | s | match s . state { StreamState :: Init ( StreamStateInit { initial_rtptime , .. } ) => initial_rtptime . is_some ( ) , _ => true , } ) ; // Move all streams that have been set up from Init to Playing state. Check that required // parameters are present while doing so. for ( i , s ) in inner . presentation . streams . iter_mut ( ) . enumerate ( ) { match s . state { StreamState :: Init ( StreamStateInit { initial_rtptime , initial_seq , ssrc , .. } ) => { let initial_rtptime = match policy . initial_timestamp { InitialTimestampPolicy :: Require | InitialTimestampPolicy :: Default if setup_streams > 1 => { if initial_rtptime . is_none ( ) { bail ! ( ErrorInt RtspResponseError { conn_ctx conn inner ctx ( ) msg_ctx method rtsp_types Method Play cseq status response status ( ) description format ( " \
 \
 " policy initial_timestamp i s control ) } ) ; } initial_rtptime } InitialTimestampPolicy :: Permissive if setup_streams > 1 && all_have_time => { initial_rtptime } _ => None , } ; let initial_seq = match initial_seq { Some ( 0 ) if policy . ignore_zero_seq => { log :: info ! ( " " i ) ; None } o => o , } ; let conn_ctx = conn . inner . ctx ( ) ; s . state = StreamState :: Playing { timeline : Timeline :: new ( initial_rtptime , s . clock_rate , policy . enforce_timestamps_with_max_jump_secs , ) . map_err ( | description | { wrap ! ( ErrorInt RtspResponseError { conn_ctx conn_ctx msg_ctx method rtsp_types Method Play cseq status response status ( ) description } ) } ) ? , rtp_handler : rtp :: InorderParser :: new ( ssrc , initial_seq ) , } ; } StreamState :: Uninit => { } StreamState :: Playing { .. } => unreachable ! ( ) , } ; } * inner . keepalive_timer = Some ( Box :: pin ( tokio :: time :: sleep ( KEEPALIVE_DURATION ) ) ) ; Ok ( Session ( self . 0 , Playing ( ( ) ) ) ) }
Sends a `PLAY` request for the entire presentation.
Sends a ` PLAY ` request for the entire presentation .
mut self
policy
PlayOptions