CrtmpServer支持Android与IOS进行RTMP直播遇到的_checkbw问题
2014-09-03 11:57
447 查看
原文:http://blog.csdn.net/fengyily/article/details/34422913
在进行移动端视频直播项目时遇到的问题,手机端在推的流时的是没问题的,主要现在是IOS和安卓连接CRtmpServer后进行播放时checkBW过不了,出现异常:NetConnection.Call.Failed,但连FMS服务器时能正常播放,由于用的是VLC的库,是封装好的,确定不了是哪个环节出了问题,以下是安卓与IOS开发报出来的异常截图。
![](http://img.blog.csdn.net/20140625111109718?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmVuZ3lpbHk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140625111114031?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmVuZ3lpbHk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140625111117921?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmVuZ3lpbHk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后,决定分析下CRtmpServer的日志及原码,发现在CrtmpServer的日志中发现了一条警告:Default implementation of ProcessInvokeGeneric: Request: _checkbw。
马上在源码中找到了抛出该日志的方法
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
bool BaseRTMPAppProtocolHandler::ProcessInvokeGeneric(BaseRTMPProtocol *pFrom,
Variant & request) {
WARN("Default implementation of ProcessInvokeGeneric: Request: %s",
STR(M_INVOKE_FUNCTION(request)));
Variant response = GenericMessageFactory::GetInvokeCallFailedError(request);
return SendRTMPMessage(pFrom, response);
}
找到引用之处
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
bool BaseRTMPAppProtocolHandler::ProcessInvoke(BaseRTMPProtocol *pFrom,
Variant &request) {
//PROD_ACCESS(CreateLogEventInvoke(pFrom, request));
string functionName = request[RM_INVOKE][RM_INVOKE_FUNCTION];
uint32_t currentInvokeId = M_INVOKE_ID(request);
if (currentInvokeId != 0) {
if (_nextInvokeId[pFrom->GetId()] <= currentInvokeId) {
_nextInvokeId[pFrom->GetId()] = currentInvokeId + 1;
}
}
if (functionName == RM_INVOKE_FUNCTION_CONNECT) {
return ProcessInvokeConnect(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CREATESTREAM) {
return ProcessInvokeCreateStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PUBLISH) {
return ProcessInvokePublish(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PLAY) {
return ProcessInvokePlay(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PAUSERAW) {
return ProcessInvokePauseRaw(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PAUSE) {
return ProcessInvokePause(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_SEEK) {
return ProcessInvokeSeek(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CLOSESTREAM) {
return ProcessInvokeCloseStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_RELEASESTREAM) {
return ProcessInvokeReleaseStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_DELETESTREAM) {
return ProcessInvokeDeleteStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_RESULT) {
return ProcessInvokeResult(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ERROR) {
return ProcessInvokeResult(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ONSTATUS) {
return ProcessInvokeOnStatus(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_FCPUBLISH) {
return ProcessInvokeFCPublish(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_GETSTREAMLENGTH) {
return ProcessInvokeGetStreamLength(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ONBWDONE) {
return ProcessInvokeOnBWDone(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CHECKBANDWIDTH) {
return ProcessInvokeCheckBandwidth(pFrom, request);
} else {
return ProcessInvokeGeneric(pFrom, request);
}
}
同时也将客户端连接流程进行了梳理
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
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
bool BaseRTMPAppProtocolHandler::ProcessInvoke(BaseRTMPProtocol *pFrom,
Variant &request) {
//PROD_ACCESS(CreateLogEventInvoke(pFrom, request));
string functionName = request[RM_INVOKE][RM_INVOKE_FUNCTION];
uint32_t currentInvokeId = M_INVOKE_ID(request);
if (currentInvokeId != 0) {
if (_nextInvokeId[pFrom->GetId()] <= currentInvokeId) {
_nextInvokeId[pFrom->GetId()] = currentInvokeId + 1;
}
}
if (functionName == RM_INVOKE_FUNCTION_CONNECT) {
return ProcessInvokeConnect(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CREATESTREAM) {
return ProcessInvokeCreateStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PUBLISH) {
return ProcessInvokePublish(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PLAY) {
return ProcessInvokePlay(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PAUSERAW) {
return ProcessInvokePauseRaw(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PAUSE) {
return ProcessInvokePause(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_SEEK) {
return ProcessInvokeSeek(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CLOSESTREAM) {
return ProcessInvokeCloseStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_RELEASESTREAM) {
return ProcessInvokeReleaseStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_DELETESTREAM) {
return ProcessInvokeDeleteStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_RESULT) {
return ProcessInvokeResult(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ERROR) {
return ProcessInvokeResult(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ONSTATUS) {
return ProcessInvokeOnStatus(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_FCPUBLISH) {
return ProcessInvokeFCPublish(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_GETSTREAMLENGTH) {
return ProcessInvokeGetStreamLength(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ONBWDONE) {
return ProcessInvokeOnBWDone(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CHECKBANDWIDTH) {
return ProcessInvokeCheckBandwidth(pFrom, request);
} else if (functionName == "_checkbw") {
return ProcessInvokeCheckBandwidth(pFrom, request);
} else {
return ProcessInvokeGeneric(pFrom, request);
}
}
改完后上传服务器,编译,运行,测试,还不成功。继续看日志,发现与之前有所不同,出现了另一条警告:ProcessInvokeCheckBandwidth:checkBandwidth
is disabled.
马上反映过来,原来是配置中没有将checkBandwidth设为true,立马修改,重启后测试,成功。
在进行移动端视频直播项目时遇到的问题,手机端在推的流时的是没问题的,主要现在是IOS和安卓连接CRtmpServer后进行播放时checkBW过不了,出现异常:NetConnection.Call.Failed,但连FMS服务器时能正常播放,由于用的是VLC的库,是封装好的,确定不了是哪个环节出了问题,以下是安卓与IOS开发报出来的异常截图。
然后,决定分析下CRtmpServer的日志及原码,发现在CrtmpServer的日志中发现了一条警告:Default implementation of ProcessInvokeGeneric: Request: _checkbw。
马上在源码中找到了抛出该日志的方法
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
bool BaseRTMPAppProtocolHandler::ProcessInvokeGeneric(BaseRTMPProtocol *pFrom,
Variant & request) {
WARN("Default implementation of ProcessInvokeGeneric: Request: %s",
STR(M_INVOKE_FUNCTION(request)));
Variant response = GenericMessageFactory::GetInvokeCallFailedError(request);
return SendRTMPMessage(pFrom, response);
}
找到引用之处
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
bool BaseRTMPAppProtocolHandler::ProcessInvoke(BaseRTMPProtocol *pFrom,
Variant &request) {
//PROD_ACCESS(CreateLogEventInvoke(pFrom, request));
string functionName = request[RM_INVOKE][RM_INVOKE_FUNCTION];
uint32_t currentInvokeId = M_INVOKE_ID(request);
if (currentInvokeId != 0) {
if (_nextInvokeId[pFrom->GetId()] <= currentInvokeId) {
_nextInvokeId[pFrom->GetId()] = currentInvokeId + 1;
}
}
if (functionName == RM_INVOKE_FUNCTION_CONNECT) {
return ProcessInvokeConnect(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CREATESTREAM) {
return ProcessInvokeCreateStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PUBLISH) {
return ProcessInvokePublish(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PLAY) {
return ProcessInvokePlay(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PAUSERAW) {
return ProcessInvokePauseRaw(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PAUSE) {
return ProcessInvokePause(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_SEEK) {
return ProcessInvokeSeek(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CLOSESTREAM) {
return ProcessInvokeCloseStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_RELEASESTREAM) {
return ProcessInvokeReleaseStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_DELETESTREAM) {
return ProcessInvokeDeleteStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_RESULT) {
return ProcessInvokeResult(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ERROR) {
return ProcessInvokeResult(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ONSTATUS) {
return ProcessInvokeOnStatus(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_FCPUBLISH) {
return ProcessInvokeFCPublish(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_GETSTREAMLENGTH) {
return ProcessInvokeGetStreamLength(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ONBWDONE) {
return ProcessInvokeOnBWDone(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CHECKBANDWIDTH) {
return ProcessInvokeCheckBandwidth(pFrom, request);
} else {
return ProcessInvokeGeneric(pFrom, request);
}
}
同时也将客户端连接流程进行了梳理
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
![](https://code.csdn.net/assets/CODE_ico.png)
bool BaseRTMPAppProtocolHandler::ProcessInvoke(BaseRTMPProtocol *pFrom,
Variant &request) {
//PROD_ACCESS(CreateLogEventInvoke(pFrom, request));
string functionName = request[RM_INVOKE][RM_INVOKE_FUNCTION];
uint32_t currentInvokeId = M_INVOKE_ID(request);
if (currentInvokeId != 0) {
if (_nextInvokeId[pFrom->GetId()] <= currentInvokeId) {
_nextInvokeId[pFrom->GetId()] = currentInvokeId + 1;
}
}
if (functionName == RM_INVOKE_FUNCTION_CONNECT) {
return ProcessInvokeConnect(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CREATESTREAM) {
return ProcessInvokeCreateStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PUBLISH) {
return ProcessInvokePublish(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PLAY) {
return ProcessInvokePlay(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PAUSERAW) {
return ProcessInvokePauseRaw(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_PAUSE) {
return ProcessInvokePause(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_SEEK) {
return ProcessInvokeSeek(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CLOSESTREAM) {
return ProcessInvokeCloseStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_RELEASESTREAM) {
return ProcessInvokeReleaseStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_DELETESTREAM) {
return ProcessInvokeDeleteStream(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_RESULT) {
return ProcessInvokeResult(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ERROR) {
return ProcessInvokeResult(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ONSTATUS) {
return ProcessInvokeOnStatus(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_FCPUBLISH) {
return ProcessInvokeFCPublish(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_GETSTREAMLENGTH) {
return ProcessInvokeGetStreamLength(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_ONBWDONE) {
return ProcessInvokeOnBWDone(pFrom, request);
} else if (functionName == RM_INVOKE_FUNCTION_CHECKBANDWIDTH) {
return ProcessInvokeCheckBandwidth(pFrom, request);
} else if (functionName == "_checkbw") {
return ProcessInvokeCheckBandwidth(pFrom, request);
} else {
return ProcessInvokeGeneric(pFrom, request);
}
}
改完后上传服务器,编译,运行,测试,还不成功。继续看日志,发现与之前有所不同,出现了另一条警告:ProcessInvokeCheckBandwidth:checkBandwidth
is disabled.
马上反映过来,原来是配置中没有将checkBandwidth设为true,立马修改,重启后测试,成功。
相关文章推荐
- CrtmpServer支持Android与IOS进行RTMP直播遇到的_checkbw问题
- CrtmpServer进行RTMP直播遇到的_checkbw问题
- 打包ios&android包遇到的奇怪问题
- Ubuntu 12.04 LTS server 编译 android-4.0.4_r2.1遇到的问题和解决方法
- 使用appium进行ios测试,启动inspector时遇到的问题(一)
- 分享 Ionic 开发 Hybrid App 中遇到的问题以及后期发布 iOS/Android 的方方面面
- iOS微信支持遇到的问题:只显示一个确定按钮、onResp不回调、闪回
- 记录 cocos2dx ios&android遇到的一些注意问题
- 90%的android开发者都会遇到的问题,当sjk_daemon遇见ADB server didn't ACK
- 本文作者对iOS开发者及设计师在面试时可能会遇到的问题进行了筛选与汇总。一方面,能够帮助HR在短时间内获取更多反馈信息,以甄选合适人选,而开发者及设计师在寻找相关工作时,也可作为参考,为面试做好万全准
- cocos2d-x开发完iOS后改为Android遇到的一些问题
- iOS 制作自己的FrameWork遇到的一些问题 以及FrameWork通过包合并支持arm64 armv7 i386 架构
- 用crtmpserver搭建开源rtmp直播服务
- 记录 cocos2dx ios&android遇到的一些注意问题
- RTMP直播点播-基于开源crtmpserver
- 解决对android APK 项目进行签名过程中遇到的问题
- 使用phonegap进行移动跨平台在Android平台开发所遇到的问题
- 在Android中进行单元测试遇到的问题
- iOS之一个超赞的视频直播、第三方库,直播看这个就够了,支持RTMP推流,美颜直播
- 使用appium进行ios测试,启动inspector时遇到的问题(一)