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,立刻改动,重新启动后測试。成功。
CrtmpServer支持Android与IOS进行RTMP直播遇到的_checkbw问题的更多相关文章
- .NET 开源了,Visual Studio 开始支持 Android 和 iOS 程序编写并自带 Android 模拟器
.NET 开源了,Visual Studio 开始支持 Android 和 iOS 程序编写并自带 Android 模拟器 北京时间今天凌晨的 Connect(); 大会上,多少程序员的假想成为现实. ...
- IOS JPush 集成步骤(极光远程推送解决方案,支持android和iOS两个平台)
● 什么是JPush ● 一套远程推送解决方案,支持android和iOS两个平台 ● 它能够快捷地为iOS App增加推送功能,减少集成APNs需要的工作量.开发复杂 度 ● 更多的信息,可 ...
- [RN] React Native 图片保存到相册(支持 Android 和 ios)
React Native 图片保存到相册(支持 Android 和 ios) 原理: IOS用 RN自带的 CameraRoll, Android 使用 不成功,需要 react-native-fs ...
- 同时支持Android 和 ios 投屏到电脑的软件,Support Android and ios screen shrare to PC - 希沃授课助手
最近学校由粉笔黑板更换了智慧电子黑板,然后发现了一个好玩的软件. 感谢希沃公司的开发: 希沃授课助手,这是一款同时支持Android 和 ios 投屏和远程控制的. 效果很流畅,非常赞
- EasyRTMP实现的一套简单、高效、易用的全平台(Windows/Linux/ARM/Android/iOS)RTMP直播推送库
本文转自EasyDarwin开源团队成员Kim的博客:http://blog.csdn.net/jinlong0603/article/details/52938980 EasyRTMP介绍 Easy ...
- Android、iOS平台RTMP/RTSP播放器实时音量调节
介绍移动端RTMP.RTSP播放器实时音量调节之前,我们之前也写过,为什么windows播放端加这样的接口,windows端播放器在多窗口大屏显示的场景下尤其需要,尽管我们老早就有了实时静音接口,相对 ...
- .NET开源了,Visual Studio开始支持 Android 和 iOS 编程并自带Android模拟器
北京时间今天凌晨的大会上,多少程序员的假想成为现实..NET 开源,集成 Clang 和 LLVM 并且自带 Android 模拟器,这意味着 Visual Studio 这个当下最好没有之一的 ID ...
- 混合开发之DSBridge(同时支持Android和iOS)
什么是 Javascript bridge 随着h5的不断普及及优化,以及移动端对动态化的需求越来越大,开发者经常需要在app中嵌入一些网页,然后会在web和native之间进行交互,如传递数据,调用 ...
- nginx支持android、ios、微信扫一扫
首先做一个android下载的html页面,页面中识别微信浏览器提示在浏览器中打开,然后在nginx对ios进行识别并跳转到apple store #下载App location ^~ /appDow ...
随机推荐
- 【Mybatis】mybatis查询报错org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'areaName' in 'class java.lang.String'
mybatis查询报错: Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for pro ...
- ElasticSearch测试数据
curl命令数据 curl -XPUT http://127.0.0.1:9200/us/user/1 -d "{\"email\":\"john@smith. ...
- Shader toy (顺手写两个Gyro)(纯代码写3D)
Shader toy (A new world) 1.一个多月了,突然忘记CSDN的password了.由于每次输password的时候都要计算一遍,于是没有计算出来- 2.回头发现都过了半年了,都快 ...
- SpringMVC处理MySQL BLOB字段的下载
任务: uos.docfile的content字段是longblob类型,通过Web点击链接能下载到存储在这个字段里的文件.Web点击链接类似如下形式: http://localhost:8080/d ...
- linux系统预留内存和磁盘大小
默认情况下, Linux 会最多使用 40% 的可用内存作为文件系统缓存.当超过这个阈值后,文件系统会把将缓存中的内存全部写入磁盘, 导致后续的 IO 请求都是同步的. 将缓存写入磁盘时,有一个默认1 ...
- DB门面,查询构建器,Eloquent ORM三者的CURD
一.DB门面 1.insert DB::insert('insert into table(`name`) value(?)', ['test']); 2.update DB::update('upd ...
- Warning: isMounted(...) is deprecated in plain JavaScript React classes.
1.错误提示 警告:isMounted(…)在纯 react.js 类中被弃用. 2.原因解析 出现此错误提示的原因是源代码内有已被React舍弃的代码,但此并不影响程序运行. 在index.js 内 ...
- Oracle 字符串不为空条件
Oracle 中,空字符串存入到Oracle中会自动转换为NULL,另外VARCHAR2把空串等同于null处理. SQL from dual where null=null; 没有查到记录 SQL ...
- 编辑器未包含main类型
明明写了main函数,在运行的时候,却得到这样的结果. 解决方案: 重新建立一个项目,建立项目的过程中
- unsigned int与int相加问题
作者 : 卿笃军 一道unsigned int与int类型的相加题目.引发了我对这个问题的思考. 首先要明确两个问题: 问题一. unsigned int 和 int究竟哪个能表达出来的数上限大呢? ...