• 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,编译,执行,測试。还不成功。继续看日志。发现与之前有所不同,出现了还有一条警告:ProcessInvokeCheckBandcheckBandwidth is disabled.

    立即反映过来。原来是配置中没有将checkBandwidth设为true,立刻改动,重新启动后測试。成功。



  • 相关阅读:
    经典SQL问题: 行转列,列转行
    RocketMQ之三:RocketMQ集群环境搭建
    mysql函数之五:group_concat mysql 把结果集中的一列数据用指定分隔符转换成一行
    并发编程之五--ThreadLocal
    RocketMQ之三:nameserver源码解析
    Spring之3:BeanFactory、ApplicationContext、ApplicationContextAware区别
    spring中InitializingBean接口使用理解
    ES之四:Elasticsearch Mapping类型映射概述与元字段类型
    spring容器启动的三种方式
    java的reflection和introspector
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6812495.html
Copyright © 2020-2023  润新知