linphone视频开发不能打开视频

lp05310204 2016-08-26 02:38:24
最近使用linphone进行二次开发,目前遇到一个非常郁闷的问题想请教一下:

我们开发这里视频会议已经调试通了,但是测试方哪里总是不能从普通会议切换到视频模式
(设备都一样,他的一个android专用设备,一个手机都一样存在异常,我们的手机,同样的专用设备就都正常了,我们在不同的城市,其他暂时想不到有什么区别了···)

我们测试视频的时候,在state == State.StreamsRunning,LinphonePreferences.instance().isVideoEnabled()为true,call.getCurrentParamsCopy().getVideoEnabled()返回状态也为true,此时,我们切换到视频界面,一切正常。

但是在测试方那边,LinphonePreferences.instance().isVideoEnabled()为true(说明我们已经设置正确),但是call.getCurrentParamsCopy().getVideoEnabled()返回却为false,

其他说明:在语音会议模式下,切换视频调用LinphoneManager.getInstance().addVideo();,
这个调用跟踪下来都是正常的,都已经切换过去了,shouldInitiateVideoCall(),shouldAutomaticallyAcceptVideoRequests()都为true。

麻烦高手给一个思路,实在是不知道哪里问题了,先谢谢了?
...全文
1367 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
bobo928843007 2018-04-14
  • 打赏
  • 举报
回复
linphone不支持视频会议,要实现修改的内容挺多的,首先要看懂音频会议的流程,底层C的。然后结合音频会议把视频会议加上去。我年前做过多路视频分发,但没做视频会议,视频会议要实现多路视频混合,软件实现压力很大吧。不过好像linphone 官方sip服务器flexisip也有个会议模块功能,不知道支不支持视频会议。
lp05310204 2016-09-21
  • 打赏
  • 举报
回复
目前使用了一种解决方法,每次都发起视频呼叫,但是在初始化的时候默认隐藏显示界面(界面隐藏时也没有视频数据上传),打开摄像头时只是把显示界面打开· 关于那个SDP包问题,有时间在跟一下
lp05310204 2016-09-20
  • 打赏
  • 举报
回复
前段时间由于不太紧急,也加上没有太多思路,先搁置了一段时间 最近通过vpn代理方式(不知道是不是通常显现),复现了测试方的情况,这样就好调试多了 在打了更详细的debug日志 有问题(先通过vpn)的时候报错,注意红色部分顺序 09-20 00:47:03.771: I/trunkedin(18240): [org.antlr.runtime.MismatchedTokenException] reason [IS_TOKEN(a)] 09-20 00:47:03.772: I/trunkedin(18240): [org.antlr.runtime.MismatchedTokenException] reason [IS_TOKEN(a)] 09-20 00:47:03.773: I/trunkedin(18240): [org.antlr.runtime.MismatchedTokenException] reason [IS_TOKEN(a)] 09-20 00:47:03.774: E/trunkedin(18240): session_description parser error for [v=0 09-20 00:47:03.774: E/trunkedin(18240): o=FreeSWITCH 1474273302 1474273304 IN IP4 139.196.27.52 09-20 00:47:03.774: E/trunkedin(18240): s=FreeSWITCH 09-20 00:47:03.774: E/trunkedin(18240): c=IN IP4 139.196.27.52 09-20 00:47:03.774: E/trunkedin(18240): t=0 0 09-20 00:47:03.774: E/trunkedin(18240): m=audio 30318 RTP/AVP 96 101 09-20 00:47:03.774: E/trunkedin(18240): a=rtpmap:96 opus/48000/2 09-20 00:47:03.774: E/trunkedin(18240): a=fmtp:96 useinbandfec=1 09-20 00:47:03.774: E/trunkedin(18240): a=rtpmap:101 telephone-event/48000 09-20 00:47:03.774: E/trunkedin(18240): a=fmtp:101 0-16 09-20 00:47:03.774: E/trunkedin(18240): a=ptime:20 09-20 00:47:03.774: E/trunkedin(18240): a=sendrecv 09-20 00:47:03.774: E/trunkedin(18240): m=video 22068 RTP/AVP 96 09-20 00:47:03.774: E/trunkedin(18240): a=rtpmap:96 VP8/90000 09-20 00:47:03.774: E/trunkedin(18240): b=AS:1024 09-20 00:47:03.774: E/trunkedin(18240): ] 09-20 00:47:03.774: E/trunkedin(18240): Failed to parse SDP message. 而没问题的时候(不通过vpn),此包最后部分为 09-20 00:48:02.781: I/trunkedin(19789): m=video 20022 RTP/AVP 96 09-20 00:48:02.781: I/trunkedin(19789): b=AS:1024 09-20 00:48:02.781: I/trunkedin(19789): a=rtpmap:96 VP8/90000 两种情况下b和a的顺序不一样,查看别人总结 sdp文件详细总结 Media description m= (media name and transport address) i=* (media title) c=* (connection information - optionalif included at session-level) b=* (bandwidth information) k=* (encryption key) a=* (zero or more media attributelines) 上面的有些行是必需有的,有些行是可选的。可选的行有*号标记。必需的是v,o,s,t,m(这是对于会话级描述和媒体及描述总体而言的,对于媒体级描述而言只有m=是必须的)。注意所有的描述项必须按照上面的顺序给出。 看sdp解析器中media_description attribute描述副基本证实了这一点(不知道这个语法,看样子不像有循环的) attribute returns [belle_sdp_attribute_t* ret] scope {int has_value;} @init {$ret=NULL;} : {IS_TOKEN(a)}?alpha_num EQUAL attribute_content{$ret=$attribute_content.ret;}; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { ANTLR3_LOG_EXCEPTION(); if ($ret) belle_sip_object_unref($ret); $ret=NULL; } media_description returns [belle_sdp_media_description_t* ret] scope { belle_sdp_media_description_t* current; } @init {$media_description::current = belle_sdp_media_description_new(); $ret=$media_description::current; } : media CR LF {belle_sdp_media_description_set_media($media_description::current,$media.ret);} (info {belle_sdp_media_description_set_info($media_description::current,$info.ret);} CR LF)? (connection { belle_sdp_media_description_set_connection($media_description::current,$connection.ret);} CR LF)? (bandwidth {belle_sdp_media_description_add_bandwidth($media_description::current,$bandwidth.ret);} CR LF)* (key_field CR LF)? (attribute {if ($attribute.ret)belle_sdp_media_description_add_attribute($media_description::current,$attribute.ret);} CR LF)*; 但是尼玛,抓的服务器包,对比过,顺序都是m a b这种顺序,但是到客户端就不一样了·· 这个该如何处理···
sd276608 2016-08-31
  • 打赏
  • 举报
回复
操蛋的规则,换个号继续 看了哈sdp协议,这个包没问题呢··,为撒会报这个错··还有源码里面找不到belle_sdp_session_description_parse这个函数实现···

        if (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0
			&& strcmp("sdp",belle_sip_header_content_type_get_subtype(content_type))==0) {
			*session_desc=belle_sdp_session_description_parse(body);
			if (*session_desc==NULL) {
				ms_error("Failed to parse SDP message.");
				*error=SalReasonNotAcceptable;
				return -1;
			}
		}else{
			*error=SalReasonUnsupportedContent;
			return -1;
		}
lp05310204 2016-08-31
  • 打赏
  • 举报
回复
belle_sip_internal.h中找到了这个函数··
#define BELLE_SDP_PARSE(object_type) \
belle_sdp_##object_type##_t* belle_sdp_##object_type##_parse (const char* value) { \
	pANTLR3_INPUT_STREAM           input; \
	pbelle_sdpLexer               lex; \
	pANTLR3_COMMON_TOKEN_STREAM    tokens; \
	pbelle_sdpParser              parser; \
	belle_sdp_##object_type##_t* l_parsed_object; \
	input  = ANTLR_STREAM_NEW(object_type, value,strlen(value));\
	lex    = belle_sdpLexerNew                (input);\
	tokens = antlr3CommonTokenStreamSourceNew  (ANTLR3_SIZE_HINT, TOKENSOURCE(lex));\
	parser = belle_sdpParserNew               (tokens);\
	l_parsed_object = parser->object_type(parser).ret;\
	parser ->free(parser);\
	tokens ->free(tokens);\
	lex    ->free(lex);\
	input  ->close(input);\
	if (l_parsed_object == NULL) belle_sip_error(#object_type" parser error for [%s]",value);\
	return l_parsed_object;\
}
lp05310204 2016-08-29
  • 打赏
  • 举报
回复
更新,切换的时候看到一个这个错误·· 08-28 23:04:45.728: E/trunkedin(4257): session_description parser error for [v=0 08-28 23:04:45.728: E/trunkedin(4257): o=FreeSWITCH 1472368717 1472368719 IN IP4 139.196.27.52 08-28 23:04:45.728: E/trunkedin(4257): s=FreeSWITCH 08-28 23:04:45.728: E/trunkedin(4257): c=IN IP4 139.196.27.52 08-28 23:04:45.728: E/trunkedin(4257): t=0 0 08-28 23:04:45.728: E/trunkedin(4257): m=audio 27890 RTP/AVP 96 101 08-28 23:04:45.728: E/trunkedin(4257): a=rtpmap:96 opus/48000/2 08-28 23:04:45.728: E/trunkedin(4257): a=fmtp:96 useinbandfec=1 08-28 23:04:45.728: E/trunkedin(4257): a=rtpmap:101 telephone-event/48000 08-28 23:04:45.728: E/trunkedin(4257): a=fmtp:101 0-16 08-28 23:04:45.728: E/trunkedin(4257): a=ptime:20 08-28 23:04:45.728: E/trunkedin(4257): a=sendrecv 08-28 23:04:45.728: E/trunkedin(4257): m=video 24284 RTP/AVP 96 08-28 23:04:45.728: E/trunkedin(4257): a=rtpmap:96 VP8/90000 08-28 23:04:45.728: E/trunkedin(4257): b=AS:1024 08-28 23:04:45.728: E/trunkedin(4257): ] 08-28 23:04:45.728: E/trunkedin(4257): Failed to parse SDP message.
lp05310204 2016-08-28
  • 打赏
  • 举报
回复
最近进展: 在音频会议模式时,要切换视频会议,关键调用下面函数 LinphoneManager.getInstance().addVideo(); 正常机器能够正常切换,异常机器通话State.StreamsRunning后,仍然在音频通话模式(call.getCurrentParamsCopy().getVideoEnabled()为false),然而在设置界面,[b]勾选一次打开摄像头就正常了,但是不能每次都去手动打开一次,点击打开摄像头代码如下(mPrefs.enableVideo(enable);这个我也试着在打开的时候调用mPrefs.enableVideo(true);,也没有效果

        findPreference(getString(R.string.pref_video_enable_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
			@Override
			public boolean onPreferenceChange(Preference preference, Object newValue) {
				boolean enable = (Boolean) newValue;
				mPrefs.enableVideo(enable);
				return true;
			}
		});
也试着初始化就进入视频模式,然后嗲用关闭逻辑

LinphoneCallParams params = call.getCurrentParamsCopy();
params.setVideoEnabled(false);
LinphoneManager.getLc().updateCall(call, params);
发现异常机器点击关闭视频,调用上面的关闭代码,然后在callState状态通知时,在收到State.StreamsRunning的时候,call.getCurrentParamsCopy().getVideoEnabled()还是为true jni的代码准备看了,不过不太熟悉,看了主流程,不过还是没有找到原因 看到 submodules/linphone/coreapi/linphonecore.c 文件 linphone_core_update_call函数

int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
	int err=0;
	LinphoneCallState nextstate, initial_state;

#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
	bool_t has_video = FALSE;
#endif

	switch(initial_state=call->state){
		case LinphoneCallIncomingReceived:
		case LinphoneCallIncomingEarlyMedia:
		case LinphoneCallOutgoingRinging:
		case LinphoneCallOutgoingEarlyMedia:
			nextstate=LinphoneCallEarlyUpdating;
			break;
		case LinphoneCallStreamsRunning:
		case LinphoneCallPaused:
		case LinphoneCallPausedByRemote:
			nextstate=LinphoneCallUpdating;
			break;
		default:
		ms_error("linphone_core_update_call() is not allowed in [%s] state",linphone_call_state_to_string(call->state));
		return -1;
	}
	
	linphone_call_check_ice_session(call, IR_Controlling, TRUE);

	if (params!=NULL){
		call->broken = FALSE;
		linphone_call_set_state(call,nextstate,"Updating call");
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
		has_video = call->params->has_video;

		// Video removing
		if((call->videostream != NULL) && !params->has_video) {
			if(call->upnp_session != NULL) {
				if (linphone_core_update_upnp(lc, call)<0) {
					/* uPnP port mappings failed, proceed with the call anyway. */
					linphone_call_delete_upnp_session(call);
				}
			}

		}
#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */
		linphone_call_set_new_params(call,params);
		err=linphone_call_prepare_ice(call,FALSE);
		if (err==1) {
			ms_message("Defer call update to gather ICE candidates");
			return 0;
		}

#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
		// Video adding
		if (!has_video && call->params->has_video) {
			if(call->upnp_session != NULL) {
				ms_message("Defer call update to add uPnP port mappings");
				video_stream_prepare_video(call->videostream);
				if (linphone_core_update_upnp(lc, call)<0) {
					/* uPnP port mappings failed, proceed with the call anyway. */
					linphone_call_delete_upnp_session(call);
				} else {
					return err;
				}
			}
		}
#endif //defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
		if ((err = linphone_core_start_update_call(lc, call)) && call->state!=initial_state) {
			/*Restore initial state*/
			linphone_call_set_state(call,initial_state,"Restore initial state");
		}

	}else{
#ifdef VIDEO_ENABLED
		if ((call->videostream != NULL) && (call->state == LinphoneCallStreamsRunning)) {
			video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
			video_stream_set_fps(call->videostream, linphone_core_get_preferred_framerate(lc));
			if (call->camera_enabled && call->videostream->cam!=lc->video_conf.device){
				video_stream_change_camera(call->videostream, lc->video_conf.device);
			}else video_stream_update_video_params(call->videostream);
		}
#endif
	}

	return err;
}
网易云捕 2016-08-26
  • 打赏
  • 举报
回复
贴下崩溃堆栈看看
lp05310204 2016-08-26
  • 打赏
  • 举报
回复
没有崩溃,只是无法切换到视频模式
lp05310204 2016-08-26
  • 打赏
  • 举报
回复
补充一下,是在wifi状态

80,472

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧