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

在进行移动端视频直播项目时遇到的问题,手机端在推的流时的是没问题的,主要现在是IOS和安卓连接CRtmpServer后进行播放时checkBW过不了,出现异常:NetConnection.Call.Failed,但连FMS服务器时能正常播放,由于用的是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);
	}
}

同时也将客户端连接流程进行了梳理

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”相同,源码如下:

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问题

时间: 2024-08-05 15:02:49

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

IOS JPush 集成步骤(极光远程推送解决方案,支持android和iOS两个平台)

●  什么是JPush ●  一套远程推送解决方案,支持android和iOS两个平台 ●  它能够快捷地为iOS App增加推送功能,减少集成APNs需要的工作量.开发复杂 度 ●  更多的信息,可以参考JPush官方网站:https://www.jpush.cn ●  集成iOS SDK的步骤可以参考 ●  http://docs.jpush.cn/pages/viewpage.action?pageId=2621727 JPush的集成步骤 注册帐号,创建应用 填写iOS App的必要信息

支持Android、iOS系统的人脸识别技术

随着深度学习方法的应用,支持Android.iOS系统的人脸识别技术的识别率已经得到质的提升,目前我司的支持Android.iOS系统的人脸识别技术率已经达到99%.支持Android.iOS系统的人脸识别技术与其他生物特征识别技术相比,在实际应用中具有天然独到的优势:通过摄像头直接获取,可以非接触的方式完成识别过程,方便快捷.目前我司的支持Android.iOS系统的人脸识别技术已应用在金融.教育.景区.旅运.社保等领域. 支持Android.iOS系统的人脸识别技术主要分为两部分: 第一部为

.NET 开源了,Visual Studio 开始支持 Android 和 iOS 程序编写并自带 Android 模拟器【转载】

北京时间今天(2014年11月12日)凌晨的--.NET 开源.集成 Clang 和 LLVM 并且自带 Android 模拟器,这意味着 Visual Studio 这个当下最好没有之一的 IDE 正式支持编写 Android 和 iOS 程序. 微软今天宣布,在所有的主要平台上将对开发者开放 Visual Studio 和 .NET.从 Core .NET Server stack,新的免费且功能完整的 Visual Studio 版本,以及下一代 Visual Studio 和 .NET

.NET开源了,Visual Studio开始支持 Android 和 iOS 编程并自带Android模拟器

北京时间今天凌晨的大会上,多少程序员的假想成为现实..NET 开源,集成 Clang 和 LLVM 并且自带 Android 模拟器,这意味着 Visual Studio 这个当下最好没有之一的 IDE 正式支持编写 Android 和 iOS 程序. 这个开始前多次通过邮件向核心用户预告的会议果然没让人失望:Visual Studio 和 .NET 真正开始走向跨平台化.Nadella 说的“移动为先,云为先”和“找到微软最初的本质”终于连成一线,这家提供开发者工具 / 平台起家的公司在继用户

Delphi XE10 精简 支持 Android 、 IOS 跨平台开发

版本说明: 由于 XE5 时代 Delphi 安装体积急剧膨胀(完整安装接近 10G,程序文件.安装缓存超过 20G+),按照过去的方式打包,XE5 的 lite 体积 1.xG,接近 PE image 理论极限,而且当前 XE5 支持 x86.x64.osx.ios.android.等诸多平台功能,不好按照网友的口味进行裁剪(win32only.winonly....) 经多方案权衡对比,决定 v8.x 开始,只使用 inno 对 Delphi 的主体功能进行封装(完整的 x86+其他支撑组件

混合开发之DSBridge(同时支持Android和iOS)

什么是 Javascript bridge 随着h5的不断普及及优化,以及移动端对动态化的需求越来越大,开发者经常需要在app中嵌入一些网页,然后会在web和native之间进行交互,如传递数据,调用函数,而连接web与native需要一个桥梁,通常称为javascript bridge,项目中选择一个好的javascript bridge也非常重要. Javascript bridge现状 目前github上也有一些开源的,其中使用最广的非WebViewJavascriptBridge.JsB

目前国内支持Android和IOS客户端的CMS系统

LMCMS是Java领域技术最先进的开源CMS全媒体内容发布平台 后台CMS+PC官网+微官网+微信公共号+Android新闻客户端+IOS新闻客户端. 主要定位于"内容信息管理"领域,可用作企业信息管理类系统.网站后台管理类系统等.LMCMS是非常强调开发的高效性.健壮性和安全性的. LMCMS是轻量级的,简单易学,本框架以Spring Framework为核心.Spring MVC(相比Struts2更容易上手.更易用)作为模型视图控制器.Hibernate作为数据库操作层,此组合

bsd socket 简单封装。支持android、ios、mac osx

cocos2d-x官方没有封装原生socket,只提供了websocket,如果我们需要socket,不同团队有不同的造轮子的方案,其中使用Asio库的比较多,但是Asio库太过于庞大,我不太想用.其实只需要简单封装一下bsd socket就好了,几十行代码而已. 注意如果在android中测试,需要添加网络访问权限,而且不能在主线程中使用. 贴一发代码,只是简单测试了下,如果有问题再慢慢完善. 1 #ifndef __cpp_test__Socket__ 2 #define __cpp_tes

[转载]微软VS2015支持Android和iOS编程

Visual Studio 2015 Preview http://www.zhihu.com/question/26594936/answer/33397319 http://www.visualstudio.com/zh-cn/downloads/visual-studio-2015-downloads-vs