CrtmpServer支持Android与IOS进行RTMP直播遇到的_checkbw问题
在进行移动端视频直播项目时遇到的问题。手机端在推的流时的是没问题的,主要如今是IOS和安卓连接CRtmpServer后进行播放时checkBW过不了,出现异常:NetConnection.Call.Failed,但连FMSserver时能正常播放,因为用的是VLC的库。是封装好的。确定不了是哪个环节出了问题,下面是安卓与IOS开发报出来的异常截图。
然后,决定分析下CRtmpServer的日志及原码,发如今CrtmpServer的日志中发现了一条警告:Default implementation of ProcessInvokeGeneric: Request: _checkbw。
立即在源代码中找到了抛出该日志的方法
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);
}
找到引用之处
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);
}
}
同一时候也将client连接流程进行了梳理
1、client与server连接流程
Client---->Server, Command Message,"Connect"
Client<----Server, "Window Acknowledgement size"
Client<----Server, "Set Peer Bandwidth",这里存在Server发送"onBWDone",client回应"_checkbw"消息,Server回应"_result"
Client---->Server, "Window Acknowledgement size"
Client<----Server, User Control Message ,"StreamBegin"
Client<----Server, Command Message,"_result connect response"
2、client发给server的命令格式: CommandName(String) + TransactionID(Number) + CommandObject(Object,av类型。假设不存在设定为Null) + StreamName(string) + start(number) + Duration(Number) + Reset(Boolean)
server回应给client命令格式: CommandName(String) + Description(string)
Client---->Server, Command Message,"play" ,这之后可能夹杂,server发送 "onbwcheck", client回应"_result",
Client---->Server, set buffertime,用户事件。设定buffertimeLength= 36000000ms
Client<----Server, set chunk size,server设定块大小。
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而某些client须要才干继续走下去。
即然怀疑问题出在此处。就决定试一试。在处理逻辑中添加对“_checkbw”的处理,处理逻辑与原有“checkBandwidth”同样,源代码例如以下:
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);
}
}
改完后上传server,编译,执行,測试。还不成功。继续看日志。发现与之前有所不同,出现了还有一条警告:ProcessInvokeCheckBandwidth:checkBandwidth is disabled.
立即反映过来。原来是配置中没有将checkBandwidth设为true,立刻改动,重新启动后測试。成功。
最新文章
- 手动处理datanode磁盘间使用不均的问题
- 据说练就了一指禅神功的觅闻实时手机新闻网,正以每天2000+IP的用户量递增。有智能手机的可以当场进行体验,没有的就算了哈
- java计算当前周开始日期&;结束日期
- PBAP 1.0协议翻译(Part1)
- getElementByClassName封装函数用法
- 大话设计模式(带目录完整版).pdf等
- [LeetCode#201] Bitwise AND of Numbers Range
- 《响应式Web设计&mdash;HTML5和CSS3实战》 学习记录
- SpringCloud接入EDAS——服务发现篇
- CSS布局方案
- 【SpringCloud】HystrixCommand的threadPoolKey默认值及线程池初始化
- Intel Artificial Intelligence Conference(2018.11.14)
- U3D面试题系列二
- Python中的zip()与*zip()函数详解
- Ubuntu x86-64汇编(4) 数值操作指令
- HTML6的10个高级新特性
- js隐藏表格的一行数据
- mysql 命令行导数据库
- angular2 post以“application/x-www-form-urlencoded”形式传参的解决办法
- Openssl base64命令
热门文章
- VisualStudio Shell简介 — 界面定制
- App Distribution Guide (一)
- apache只记录指定URI的日志
- 矩阵压缩写法 scipy spark.ml.linalg里都有,CRS,CCS
- Unity Dotween build error
- ElasticSearch 专业术语
- 【PA2012】【BZOJ4289】Tax
- KodExplorer介绍
- [Functional Programming] Combine State Dependent Transactions with the State ADT (composeK to replace multi chian call)
- 《Java设计模式》之调停者模式(Mediator)