CrtmpServer支持Android与IOS进行RTMP直播遇到的_checkbw问题

来源:互联网 发布:虚拟ip地址软件 编辑:程序博客网 时间:2024/06/13 11:54

原文:http://blog.csdn.net/fengyily/article/details/34422913

 在进行移动端视频直播项目时遇到的问题,手机端在推的流时的是没问题的,主要现在是IOS和安卓连接CRtmpServer后进行播放时checkBW过不了,出现异常:NetConnection.Call.Failed,但连FMS服务器时能正常播放,由于用的是VLC的库,是封装好的,确定不了是哪个环节出了问题,以下是安卓与IOS开发报出来的异常截图。




然后,决定分析下CRtmpServer的日志及原码,发现在CrtmpServer的日志中发现了一条警告:Default implementation of ProcessInvokeGeneric: Request: _checkbw。

马上在源码中找到了抛出该日志的方法

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. bool BaseRTMPAppProtocolHandler::ProcessInvokeGeneric(BaseRTMPProtocol *pFrom,  
  2.         Variant & request) {  
  3.     WARN("Default implementation of ProcessInvokeGeneric: Request: %s",  
  4.             STR(M_INVOKE_FUNCTION(request)));  
  5.     Variant response = GenericMessageFactory::GetInvokeCallFailedError(request);  
  6.     return SendRTMPMessage(pFrom, response);  
  7. }  
找到引用之处

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. bool BaseRTMPAppProtocolHandler::ProcessInvoke(BaseRTMPProtocol *pFrom,  
  2.         Variant &request) {  
  3.     //PROD_ACCESS(CreateLogEventInvoke(pFrom, request));  
  4.     string functionName = request[RM_INVOKE][RM_INVOKE_FUNCTION];  
  5.     uint32_t currentInvokeId = M_INVOKE_ID(request);  
  6.     if (currentInvokeId != 0) {  
  7.         if (_nextInvokeId[pFrom->GetId()] <= currentInvokeId) {  
  8.             _nextInvokeId[pFrom->GetId()] = currentInvokeId + 1;  
  9.         }  
  10.     }  
  11.     if (functionName == RM_INVOKE_FUNCTION_CONNECT) {  
  12.         return ProcessInvokeConnect(pFrom, request);  
  13.     } else if (functionName == RM_INVOKE_FUNCTION_CREATESTREAM) {  
  14.         return ProcessInvokeCreateStream(pFrom, request);  
  15.     } else if (functionName == RM_INVOKE_FUNCTION_PUBLISH) {  
  16.         return ProcessInvokePublish(pFrom, request);  
  17.     } else if (functionName == RM_INVOKE_FUNCTION_PLAY) {  
  18.         return ProcessInvokePlay(pFrom, request);  
  19.     } else if (functionName == RM_INVOKE_FUNCTION_PAUSERAW) {  
  20.         return ProcessInvokePauseRaw(pFrom, request);  
  21.     } else if (functionName == RM_INVOKE_FUNCTION_PAUSE) {  
  22.         return ProcessInvokePause(pFrom, request);  
  23.     } else if (functionName == RM_INVOKE_FUNCTION_SEEK) {  
  24.         return ProcessInvokeSeek(pFrom, request);  
  25.     } else if (functionName == RM_INVOKE_FUNCTION_CLOSESTREAM) {  
  26.         return ProcessInvokeCloseStream(pFrom, request);  
  27.     } else if (functionName == RM_INVOKE_FUNCTION_RELEASESTREAM) {  
  28.         return ProcessInvokeReleaseStream(pFrom, request);  
  29.     } else if (functionName == RM_INVOKE_FUNCTION_DELETESTREAM) {  
  30.         return ProcessInvokeDeleteStream(pFrom, request);  
  31.     } else if (functionName == RM_INVOKE_FUNCTION_RESULT) {  
  32.         return ProcessInvokeResult(pFrom, request);  
  33.     } else if (functionName == RM_INVOKE_FUNCTION_ERROR) {  
  34.         return ProcessInvokeResult(pFrom, request);  
  35.     } else if (functionName == RM_INVOKE_FUNCTION_ONSTATUS) {  
  36.         return ProcessInvokeOnStatus(pFrom, request);  
  37.     } else if (functionName == RM_INVOKE_FUNCTION_FCPUBLISH) {  
  38.         return ProcessInvokeFCPublish(pFrom, request);  
  39.     } else if (functionName == RM_INVOKE_FUNCTION_GETSTREAMLENGTH) {  
  40.         return ProcessInvokeGetStreamLength(pFrom, request);  
  41.     } else if (functionName == RM_INVOKE_FUNCTION_ONBWDONE) {  
  42.         return ProcessInvokeOnBWDone(pFrom, request);  
  43.     } else if (functionName == RM_INVOKE_FUNCTION_CHECKBANDWIDTH) {  
  44.         return ProcessInvokeCheckBandwidth(pFrom, request);  
  45.     } else {  
  46.         return ProcessInvokeGeneric(pFrom, request);  
  47.     }  
  48. }  
同时也将客户端连接流程进行了梳理

1、客户端与服务器连接流程
   Client---->Server,  Command Message,"Connect"
   Client<----Server,  "Window Acknowledgement size"
   Client<----Server,  "Set Peer Bandwidth",这里存在Server发送"onBWDone",客户端回应"_checkbw"消息,Server回应"_result"
   Client---->Server,  "Window Acknowledgement size"
   Client<----Server,  User Control Message ,"StreamBegin"
   Client<----Server,  Command Message,"_result connect response"
2、客户端发给服务器的命令格式: CommandName(String) + TransactionID(Number) + CommandObject(Object,av类型,如果不存在设定为Null) + StreamName(string) + start(number) + Duration(Number) + Reset(Boolean)
   服务器回应给客户端命令格式: CommandName(String) + Description(string) 
   Client---->Server,  Command Message,"play"  ,这之后可能夹杂,server发送 "onbwcheck", client回应"_result",
   Client---->Server,  set buffertime,用户事件,设定buffertimeLength= 36000000ms
   Client<----Server,  set chunk size,服务器设定块大小,
   Client<----Server,  User Control Message ,"StreamIsRecoreded"
   Client<----Server,  User Control Message ,"StreamBegin"   
   Client<----Server,  Command Message,"onStatus,play.reset"
   Client<----Server,  Command Message,"onStatus,play.start"   
   Client<----Server,  发送Command Message "RtmpSampleAccess"
   Client<----Server,  Audio Message  
   Client<----Server,  Video Message

最后将问题定格在: Client---->Server,  Command Message,"play"  ,这之后可能夹杂,server发送 "onbwcheck", client回应"_result",这一环节之上。

对比了日志与源码的处理逻辑发现,手机端发送的指令中functionName的值为"_checkbw",而源码处理逻辑中functionName只有为”checkBandwidth“,于是做了一个猜想:

1、_checkbw会不会是checkBandwidth的意思;

2、某些如Flash不需要_checkbw而某些客户端需要才能继续走下去。

即然怀疑问题出在此处,就决定试一试,在处理逻辑中增加对“_checkbw”的处理,处理逻辑与原有“checkBandwidth”相同,源码如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. bool BaseRTMPAppProtocolHandler::ProcessInvoke(BaseRTMPProtocol *pFrom,  
  2.         Variant &request) {  
  3.     //PROD_ACCESS(CreateLogEventInvoke(pFrom, request));  
  4.     string functionName = request[RM_INVOKE][RM_INVOKE_FUNCTION];  
  5.     uint32_t currentInvokeId = M_INVOKE_ID(request);  
  6.     if (currentInvokeId != 0) {  
  7.         if (_nextInvokeId[pFrom->GetId()] <= currentInvokeId) {  
  8.             _nextInvokeId[pFrom->GetId()] = currentInvokeId + 1;  
  9.         }  
  10.     }  
  11.     if (functionName == RM_INVOKE_FUNCTION_CONNECT) {  
  12.         return ProcessInvokeConnect(pFrom, request);  
  13.     } else if (functionName == RM_INVOKE_FUNCTION_CREATESTREAM) {  
  14.         return ProcessInvokeCreateStream(pFrom, request);  
  15.     } else if (functionName == RM_INVOKE_FUNCTION_PUBLISH) {  
  16.         return ProcessInvokePublish(pFrom, request);  
  17.     } else if (functionName == RM_INVOKE_FUNCTION_PLAY) {  
  18.         return ProcessInvokePlay(pFrom, request);  
  19.     } else if (functionName == RM_INVOKE_FUNCTION_PAUSERAW) {  
  20.         return ProcessInvokePauseRaw(pFrom, request);  
  21.     } else if (functionName == RM_INVOKE_FUNCTION_PAUSE) {  
  22.         return ProcessInvokePause(pFrom, request);  
  23.     } else if (functionName == RM_INVOKE_FUNCTION_SEEK) {  
  24.         return ProcessInvokeSeek(pFrom, request);  
  25.     } else if (functionName == RM_INVOKE_FUNCTION_CLOSESTREAM) {  
  26.         return ProcessInvokeCloseStream(pFrom, request);  
  27.     } else if (functionName == RM_INVOKE_FUNCTION_RELEASESTREAM) {  
  28.         return ProcessInvokeReleaseStream(pFrom, request);  
  29.     } else if (functionName == RM_INVOKE_FUNCTION_DELETESTREAM) {  
  30.         return ProcessInvokeDeleteStream(pFrom, request);  
  31.     } else if (functionName == RM_INVOKE_FUNCTION_RESULT) {  
  32.         return ProcessInvokeResult(pFrom, request);  
  33.     } else if (functionName == RM_INVOKE_FUNCTION_ERROR) {  
  34.         return ProcessInvokeResult(pFrom, request);  
  35.     } else if (functionName == RM_INVOKE_FUNCTION_ONSTATUS) {  
  36.         return ProcessInvokeOnStatus(pFrom, request);  
  37.     } else if (functionName == RM_INVOKE_FUNCTION_FCPUBLISH) {  
  38.         return ProcessInvokeFCPublish(pFrom, request);  
  39.     } else if (functionName == RM_INVOKE_FUNCTION_GETSTREAMLENGTH) {  
  40.         return ProcessInvokeGetStreamLength(pFrom, request);  
  41.     } else if (functionName == RM_INVOKE_FUNCTION_ONBWDONE) {  
  42.         return ProcessInvokeOnBWDone(pFrom, request);  
  43.     } else if (functionName == RM_INVOKE_FUNCTION_CHECKBANDWIDTH) {  
  44.         return ProcessInvokeCheckBandwidth(pFrom, request);  
  45.     } else if (functionName == "_checkbw") {  
  46.         return ProcessInvokeCheckBandwidth(pFrom, request);  
  47.     } else {  
  48.         return ProcessInvokeGeneric(pFrom, request);  
  49.     }  
  50. }  
改完后上传服务器,编译,运行,测试,还不成功。继续看日志,发现与之前有所不同,出现了另一条警告:ProcessInvokeCheckBandwidth:checkBandwidth is disabled.

马上反映过来,原来是配置中没有将checkBandwidth设为true,立马修改,重启后测试,成功。


0 0