<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 14 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";
        mso-fareast-language:EN-US;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
p.MsoPlainText, li.MsoPlainText, div.MsoPlainText
        {mso-style-priority:99;
        mso-style-link:"Nur Text Zchn";
        margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";
        mso-fareast-language:EN-US;}
span.E-MailFormatvorlage17
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
span.NurTextZchn
        {mso-style-name:"Nur Text Zchn";
        mso-style-priority:99;
        mso-style-link:"Nur Text";
        font-family:"Calibri","sans-serif";}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri","sans-serif";
        mso-fareast-language:EN-US;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:70.85pt 70.85pt 2.0cm 70.85pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=DE link=blue vlink=purple><div class=WordSection1><p class=MsoNormal>Hi Ross,<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>thank you for your quick reply.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>My second topic was (and still is):<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoPlainText>>> On client-side I use the method "MediaSubsession::getNormalPlayTime". All works fine for the first play-command. But after the send of a second play-command the method returns wrong values with the receive of a new RTCP "SR" packet. Whats going wrong?<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>> I don't know, because you haven't provided nearly enough information.  Do both the RTSP client and the RTSP server use our code, or just the RTSP client?  Please provide the complete RTSP protocol exchange (including both "PLAY" commands) between your client and your server, up to the point at which you believe the call to "getNormalPlayTime()" returns an incorrect result.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>On both sides I use live555.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>Protocol exchange (only client side):<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>1.) pRtspClient->sendPlayCommand(*m_pMediaSession, continueAfterPLAY, 0.0, -1.0, 1.0, m_pAuthenticator);<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Sending Request: PLAY xxx<o:p></o:p></p><p class=MsoNormal>CSeq: xx<o:p></o:p></p><p class=MsoNormal>User-Agent: xx<o:p></o:p></p><p class=MsoNormal>Session: xxx<o:p></o:p></p><p class=MsoNormal>Range: npt=0.000-<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Received a complete PLAY response<o:p></o:p></p><p class=MsoNormal>RTSP/1.0 200 OK<o:p></o:p></p><p class=MsoNormal>CSeq: xx<o:p></o:p></p><p class=MsoNormal>Date: xxx<o:p></o:p></p><p class=MsoNormal>Range: npt=0.000-<o:p></o:p></p><p class=MsoNormal>Session: xxx<o:p></o:p></p><p class=MsoNormal>RTP-Info: xxx<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>2.) pRtspClient->sendPauseCommand(*m_pMediaSession, continueAfterPAUSE, m_pAuthenticator);<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Sending Request: PAUSE xxx<o:p></o:p></p><p class=MsoNormal>CSeq: xx<o:p></o:p></p><p class=MsoNormal>User-Agent: xx<o:p></o:p></p><p class=MsoNormal>Session: xxx<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Received a complete PAUSE response<o:p></o:p></p><p class=MsoNormal>RTSP/1.0 200 OK<o:p></o:p></p><p class=MsoNormal>CSeq: xx<o:p></o:p></p><p class=MsoNormal>Date: xxx<o:p></o:p></p><p class=MsoNormal>Session: xxx<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>------> all o.k.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>3.) pRtspClient->sendPlayCommand(*m_pMediaSession, continueAfterPLAY, -1.0, -1.0, 1.0, m_pAuthenticator);<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Sending Request: PLAY xxx<o:p></o:p></p><p class=MsoNormal>CSeq: xx<o:p></o:p></p><p class=MsoNormal>User-Agent: xx<o:p></o:p></p><p class=MsoNormal>Session: xxx<o:p></o:p></p><p class=MsoNormal>Range: npt=0.000-<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Received a complete PLAY response<o:p></o:p></p><p class=MsoNormal>RTSP/1.0 200 OK<o:p></o:p></p><p class=MsoNormal>CSeq: xx<o:p></o:p></p><p class=MsoNormal>Date: xxx<o:p></o:p></p><p class=MsoNormal>Range: npt=0.000-<o:p></o:p></p><p class=MsoNormal>Session: xxx<o:p></o:p></p><p class=MsoNormal>RTP-Info: xxx<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>------> all o.k. until a RTCP "SR" packet sets the rtpTimestamp in "RTPReceptionStats::noteIncomingSR"<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Example: (after second PLAY command)<o:p></o:p></p><p class=MsoNormal>...<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>presentationTime before NPT: 13469992513654<o:p></o:p></p><p class=MsoNormal>presentationTime after NPT:     10000000<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>presentationTime before NPT: 13469993513654<o:p></o:p></p><p class=MsoNormal>presentationTime after NPT:     1100000<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>presentationTime before NPT: 13469994513654<o:p></o:p></p><p class=MsoNormal>presentationTime after NPT:     1200000<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>presentationTime before NPT: 13469995513654<o:p></o:p></p><p class=MsoNormal>presentationTime after NPT:     1300000<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>...<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>new incoming "SR" packet ---> change the "<span style='color:#020002'>fSyncTimestamp" in " RTPReceptionStats</span>::<span style='color:#020002'>noteIncomingSR"</span><o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>presentationTime before NPT: 13468215331451<o:p></o:p></p><p class=MsoNormal>presentationTime after NPT:     -123045<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>...<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>It seems that the "fNPT_PTS_Offset" in "MediaSubsession::getNormalPlayTime" has a wrong value after the setting of "fSyncTimestamp"!<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>double MediaSubsession::getNormalPlayTime(struct timeval const& presentationTime) {<o:p></o:p></p><p class=MsoNormal>…<o:p></o:p></p><p class=MsoNormal>   if (rtpInfo.infoIsNew) {<o:p></o:p></p><p class=MsoNormal>      // This is the first time we've been called with a synchronized presentation time since the "rtpInfo"<o:p></o:p></p><p class=MsoNormal>      // structure was last filled in.  Use this "presentationTime" to compute "fNPT_PTS_Offset":<o:p></o:p></p><p class=MsoNormal>      if (seqNumLT(rtpSource()->curPacketRTPSeqNum(), rtpInfo.seqNum)) return -0.1; // sanity check; ignore old packets<o:p></o:p></p><p class=MsoNormal>      u_int32_t timestampOffset = rtpSource()->curPacketRTPTimestamp() - rtpInfo.timestamp;<o:p></o:p></p><p class=MsoNormal>      double nptOffset = (timestampOffset/(double)(rtpSource()->timestampFrequency()))*scale();<o:p></o:p></p><p class=MsoNormal>      double npt = playStartTime() + nptOffset;<o:p></o:p></p><p class=MsoNormal>      fNPT_PTS_Offset = npt - ptsDouble*scale();<o:p></o:p></p><p class=MsoNormal>      rtpInfo.infoIsNew = False; // for next time<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>      return npt;<o:p></o:p></p><p class=MsoNormal>    } else {<o:p></o:p></p><p class=MsoNormal>      // Use the precomputed "fNPT_PTS_Offset" to compute the NPT from the PTS:<o:p></o:p></p><p class=MsoNormal>      if (fNPT_PTS_Offset == 0.0) return 0.0; // error: The "rtpInfo" structure was apparently never filled in<o:p></o:p></p><p class=MsoNormal>      return (double)(ptsDouble*scale() + fNPT_PTS_Offset);<o:p></o:p></p><p class=MsoNormal>    }<o:p></o:p></p><p class=MsoNormal>…<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>If I change the expression from "if (rtpInfo.infoIsNew)" to "if (True)" then "MediaSubsession::getNormalPlayTime" returns always the right value.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal style='text-autospace:none'><span style='color:#020002'>Thanks in advance<o:p></o:p></span></p><p class=MsoNormal style='text-autospace:none'><span style='color:#020002'><o:p> </o:p></span></p><p class=MsoNormal style='text-autospace:none'><span style='color:#020002'>Matthias Meding</span><o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p></div></body></html>