RTSP客户端在会话完全设置(发出PLAY命令)之前发送$ -delimited数据,导致405方法不允许错误

时间:2013-08-30 05:57:42

标签: rtsp rtp live555 rtsp-client rtcp

我有一个基于live555的自定义RTSP客户端和服务器实现。我正在使用Live555的16/08/2013版本。我使用Interleaved RTP-OVER-TCP进行流式传输,因为我们将使用的防火墙不允许我们使用UDP。 (换句话说,RTP,RTCP和RTSP数据都将通过TCP发送)。在部署应用程序时,在我的本地网络上,流式传输完美无缺。但是,在有轻微延迟的WAN上,我从服务器收到“405 Method Not Allowed”错误。我已经能够通过限制带宽来模拟我的本地主机上的数据,以便数据流速稍慢。如果我限制网络,我得到“405方法不允许”错误,如果我没有限制它,我没有得到这个错误,流媒体工作正常。我使用网络流量检查器来观察客户端发送和接收的数据,我注意到在我收到错误的情况下,客户端在PLAY命令之前发送$ -delimited数据,然后发送一些额外的二进制数据发行。我认为这会混淆服务器,因为服务器可能希望仅在会话建立并发出PLAY命令后才接收此类数据。

我已手动尝试过滤掉“不需要的”消息,直到发出PLAY命令为止。如果我这样做,流实际上开始,我能够渲染一个或两个帧,之后视频流似乎“冻结”。然而,当检查网络流量时,似乎流确实在常规视频流中在后台流动,但是我在SETUP期间丢弃了“不合适”数据的事实导致视频流不呈现超过前几微秒。

我很清楚$ -delimited消息代表RTP或RTCP数据包。然而,在RTSP命令完成设置流会话并开始播放之前,我没想到客户端会开始发送此类数据包。

有人可能会协助向我解释这些“无序”RTP / RTCP数据包是什么以及客户端发送它们的原因?我该如何解决这个问题?

作为参考,我包括显示来自客户端的消息的日志,表示错误:

##Client Sends:##
DESCRIBE rtsp://127.0.0.1:8554/ RTSP/1.0
CSeq: 2
User-Agent: LIVE555 Streaming Media v2013.08.16
Accept: application/sdp

##Client Receives:##
RTSP/1.0 200 OK
CSeq: 2
Date: Thu, Aug 29 2013 06:18:42 GMT
Content-Base: rtsp://127.0.0.1:8554/nurv/
Content-Type: application/sdp
Content-Length: 449

v=0
o=- 1377757120235695 1 IN IP4 192.168.56.1
s=MyVideo Streaming Session
i=nurv
t=0 0
a=tool:LIVE555 Streaming Media v2013.08.16
a=type:broadcast
a=control:*
a=range:npt=0-
a=x-qt-text-nam:MyVideo Streaming Session
a=x-qt-text-inf:nurv
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:3750
a=rtpmap:96 H264/90000
a=control:track1
m=audio 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:84602240
a=rtpmap:96 PCMU/48000/2
a=control:track2

##Client Sends:##
SETUP rtsp://127.0.0.1:8554/nurv/track1 RTSP/1.0
CSeq: 3
User-Agent: LIVE555 Streaming Media v2013.08.16
Transport: RTP/AVP/TCP;unicast;interleaved=0-1

##Client Receives:##
RTSP/1.0 200 OK
CSeq: 3
Date: Thu, Aug 29 2013 06:18:43 GMT
Transport: RTP/AVP/TCP;unicast;destination=127.0.0.1;source=127.0.0.1;interleaved=0-1
Session: 32A854D4

##Client Sends:##
SETUP rtsp://127.0.0.1:8554/nurv/track2 RTSP/1.0
CSeq: 4
User-Agent: LIVE555 Streaming Media v2013.08.16
Transport: RTP/AVP/TCP;unicast;interleaved=2-3
Session: 32A854D4

##THIS IS THE "OUT-OF-SEQUENCE DATA THAT CAUSES THE PROBLEM. THIS SECTION IS ONLY SENT WHEN NETWORK HAS SOME LATENCY AND DOES NOT APPEAR WHEN STREAMING WORKS.##
##Client Sends:##
00000000  24 01 00 20                                        $..             

00000000  80 C9 00 01 23 7A EB 1D 81 CA 00 05 23 7A EB 1D    ....#z......#z..
00000010  6C 61 70 74 6F 70 6E 61 6D 65 0D 0A 00 00 00 00    ..LaptopName....
##END OF SECTION THAT SHOWS THE "OUT-OF-SEQUENCE" DATA.##

##Client Receives:##
RTSP/1.0 200 OK
CSeq: 4
Date: Thu, Aug 29 2013 06:18:47 GMT
Transport: RTP/AVP/TCP;unicast;destination=127.0.0.1;source=127.0.0.1;interleaved=2-3
Session: 32A854D4

##Client Sends:##
PLAY rtsp://127.0.0.1:8554/nurv/ RTSP/1.0
CSeq: 5
User-Agent: LIVE555 Streaming Media v2013.08.16
Session: 32A854D4
Range: npt=0.000-

##THIS IS THE ERROR RECEIVED FROM THE SERVER. IN CASES WHERE STREAMING WORKS, THIS ERROR IS NOT RECEIVED BUT WE RATHER START RECEIVING RTP AND RTCP PACKETS (DATA) FROM THE SERVER.##
##Client Receives:##
RTSP/1.0 405 Method Not Allowed
CSeq: 5
Date: Thu, Aug 29 2013 06:18:48 GMT
Allow: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER

##Client Sends:##
TEARDOWN rtsp://127.0.0.1:8554/nurv/ RTSP/1.0
CSeq: 6
User-Agent: LIVE555 Streaming Media v2013.08.16
Session: 32A854D4

1 个答案:

答案 0 :(得分:0)

在对Live555本身进行一些深入调试后,我发现它包含一个bug。 $ -delimited数据基本上是在发出PLAY命令之前错误地发送的RTCP“RR”数据包(它应该仅在发出PLAY之后发生)。 Live555的2012/10/04版本似乎包含一个“EnableRTCPReports”标志,用于指示是否可以继续发送“RR”,并且此值设置为仅在PLAY发布后才允许发送这些报告。 / p>

但是,在实际执行发送的代码中,存在一个条件,在该条件下,在发送“RR”报告之前不会检查此标志。这是我发现的错误。此错误报告已与修复程序一起提交到Live555项目,但我同时也将修复程序放在此处,以及在此期间遇到此问题的任何人:

livemedia / include / RTSPSource.hh 中,我们有enableRTCPReports函数来返回fEnableRTCPReports。但是,这不能被const对象调用(这是我们需要做的),因此只需声明一个非常相似的函数,但要使它成为const并且安全:

...
Boolean& enableRTCPReports() { return fEnableRTCPReports; }
//****The following function is part of the fix. The same as enableRTCPReports except that it is "const" and "safe" for const object references to call, which means we can call this from RTCPInstance using the fSource object there.
Boolean constAccessibleEnableRTCPReports() const { return fEnableRTCPReports; } 
...

在livemedia / RTCP.cpp中:

...
Boolean RTCPInstance::addReport(Boolean alwaysAdd) {
  // Include a SR or a RR, depending on whether we have an associated sink or source:
  if (fSink != NULL) {
    if (!alwaysAdd) {
      if (!fSink->enableRTCPReports()) return False;

      // Hack: Don't send a SR during those (brief) times when the timestamp of the
      // next outgoing RTP packet has been preset, to ensure that that timestamp gets
      // used for that outgoing packet. (David Bertrand, 2006.07.18)
      if (fSink->nextTimestampHasBeenPreset()) return False;
    }

    addSR();
  } else if (fSource != NULL) {
     //****The following IF-statement is the fix. As in the case of the Sink Node above (but using our "const-accessible" function), we first check the value of EnableRTCPReports before we do addRR().
    if (!fSource->constAccessibleEnableRTCPReports()) return false;
    addRR();
  }

  return True;
}
...