Linphone_android jni下音視頻流、初始化流程分析

本來流程順序上面做了排版(函數內部的流程,加了tab縮進的)方便理解, 但是發表之後,還是亂了。
流程順序基本理清了,可以複製到notepad++,手動加下縮進吧。
主流程是序號 1、2、...
函數內部流程,簡單點的標“=>”表示下,複雜的就安裝節序號標了。

入口在linphonecall.c中,linphone_call_init_media_streams(call),函數內部包含三個函數:
	void linphone_call_init_media_streams(LinphoneCall *call){
   		linphone_call_init_audio_stream(call);
   		linphone_call_init_video_stream(call);
   		linphone_call_init_text_stream(call);
	}

A、 linphone_call_init_audio_stream(call) 音頻流的初始化
1、char* rtcp_tool = linphone_core_get_user_agent(lc)
=>sal_get_user_agent(lc->sal),定義在sal.h,實現在sal_impl.c中;
=>belle_sip_header_user_agent_get_products_as_string(sal->user_agent, char[] user_agent,254),實現在belle_sip_headers_impl.c中;
=>list* list = user_agent->produtcts,
遍歷list,將list->data的數據存在char[] user_agent中,並返回user_agent。
2、if call->audiostream !=null , call有問題,return;
3、if (call->sessions[call->main_audio_stream_index].rtp_session = null )
{
3.1、SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalStreamType:SalAudio) :明確我發在通話中的角色(字面理解)
=> 檢查call->op是否構建。
SalMediaDescription remotedesc = sal_call_get_remote_media_description(call->op),實現在sal_op_call.c中
=> return SalOp->base.remote_media;
SalMediaDescription localdesc = call->localdesc;
如果localDesc和remotedesc都不存在,且call的dir是outgoing,
繼續判斷, 如果外面的入參SalStreamType是SalAudio,且call->params->audio_multicast_enable 爲true
則multicast_role 爲SalMulticastSender;
else 如果localldesc存在,且(remotedesc不存在 或 sal_call_is_offerer(call->op)爲true),感覺像是別人發起的call,且sdp_offering爲ture
其中的sal_call_is_offerer 只是return call->op->sdp_offering;
找到本地支持的最優媒體流,stream_desc = sal_media_description_find_best_stream(localdesc,type)實現在sal.c中;
else 如果remotedesc存在,但sal_call_is_offerer(call->op)爲false;
3.2、找到對方支持的最優媒體流,stream_desc = sal_media_description_find_best_stream(remotedesc, type); <==else結束
3.3、如果stream_desc存在,從它裏面獲取multicast_role;
3.4、外部繼續做了remotedesc = sal_call_get_remote_media_description(call->op);
3.5、如果remotedesc存在,從中獲取最優流媒體配置 :stream_desc = sal_media_description_find_best_stream(remotedesc, SalAudio);
3.6、初始化call的音頻流屬性call->audiostream=audiostream=audio_stream_new2() ,定義在mediastream.h,實現在audiostream.c
call->audiostream=audiostream=audio_stream_new2(lc->factory,linphone_call_get_bind_ip_for_stream(call,call->main_audio_stream_index),
multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_audio_stream_index].rtp_port,
multicast_role == SalMulticastReceiver ?0/*disabled for now*/: call->media_ports[call->main_audio_stream_index].rtcp_port);
{
//其中第二個參數 :linphone_call_get_bind_ip_for_stream(call,call->main_audio_stream_index);
該函數主要功能是從call->core->config中找出“rtp”session下的“bind_address”值。如果沒有的話,再根據發送\接收者的身份分別從call->media_ports中找PortConfig的multicast_ip值;
分析audio_stream_new2();實現在audiostream.c中;
第一步,構建MSMediaStreamSessions
session.rtp_session= ms_create_duplex_rtp_session(xxx),定義在mediastream.h,實現在mediastream.c;
=> rtp_session_new(RTP_SESSION_SENDRECV)。創建一個可收發的RtpSession,實現在rtpsession.c;
然後設置了一堆RtpSession的屬性;
第二步,根據factory和session構建AudioStream: audio_stream_new_with_sessions(factory, &sessions);
=> a、先 new AudioStream: stream;
b、MSFilterDesc *ec_desc=ms_factory_lookup_filter_by_name(factory,"MSWebRTCAEC"),實現在msfactory.c;
第二個參數是過濾器的名字。
=> 主要功能是從遍歷factory->desc_list,取item->data,如果與過濾器名字一致,則返回這個item->data;
c、指定OrtpRtcpXR的回調:rtcp_xr_media_cbs。stream初始化完了會用到。
d、初始化mediastream :media_stream_init(&stream->ms,factory, sessions); 實現在mediastream.c
主要設置stream的屬性,包括event_dispatcher、event_queue、factory,並且註冊rtpsession到event_queue;
e、設置factory的屬性:enable_statistics,並reset statistics;
frtp_session_resync(rtpsession),同步化rtpsession,用於當接收的rtp stream時間戳不連續時進行同步;
g、繼續設置stream的屬性:包括:
stream->ms.rtpsend=ms_factory_create_filter(factory, MS_RTP_SEND_ID);
stream->ms.ice_check_list=NULL;
stream->ms.qi=ms_quality_indicator_new(stream->ms.sessions.rtp_session);
ms_quality_indicator_set_label(stream->ms.qi,"audio");
stream->ms.process_rtcp=audio_stream_process_rtcp;
if (ec_desc!=NULL){
stream->ec=ms_factory_create_filter_from_desc(factory, ec_desc);
}else{
stream->ec=ms_factory_create_filter(factory, MS_SPEEX_EC_ID );
}
stream->play_dtmfs=TRUE;
stream->use_gc=FALSE;
stream->use_agc=FALSE;
stream->use_ng=FALSE;
stream->features=AUDIO_STREAM_FEATURE_ALL;
h、rtp_session_set_rtcp_xr_media_callbacks(rtpsession,rtcp_xr_media_cbs),實現在rtcp_xr.c中;應該是給RtpSession設置監聽回調;
} //,audio_stream初始化完成;
3.7、如果multicast_role == SalMulticastReceiver =》linphone_call_join_multicast_group():處理是不是需要加入會話組
3.8、繼續,rtp_session_enable_network_simulation() 實現在netsim.c中。貌似是想打開網絡;
3.9、audio_stream_set_rtcp_information(),設置audiostream中的RtpSession的源信息;實現在mediastream.c中;
3.10、rtp_session_set_symmetric_rtp(RtpSession,linphone_core_symmetric_rtp_enabled(lc)),實現在rtpsession.c,設置rtpsession的均衡性?
第二個參數:主要檢查lc->config中"rtp"的session,下的"symmetric"值,默認給1;
3.11、setup_dtls_params(call,stream),如果call的媒體加密方式是DTLS的時候,設置stream的加密方式;
3.12、如果lc支持ZRTP的加密方式,又對Call和audiostream做了些處理
setZrtpCryptoTypesParameters(&params,call->core);設置params上
linphone_core_get_srtp_crypto_suites(lc);從lc中讀取些srtp_suites,遍歷其item,並設置屬性到params上;
audio_stream_enable_zrtp(call->audiostream,&params);設置到audioStream是session.zrtp_context上
3.13、media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[call->main_audio_stream_index]); 把audioStream的session信息拷貝到call的session裏面;
}
4、如果call->media_ports[].rtp_port 沒有設置,調用port_config_set_random_choosed(),將audiostream下RtpSession的loc_port值設置給call。
5、檢查lc->config下“rtp”session的“audio_dscp”字段值,如果有值的話,將其設置到audiostream上,audio_stream_set_dscp(audiostream,dscp);實現在mediastream.h
6、檢查lc->sound_conf.ea如果爲真:獲取lc->config下"sound" section下的 "el_type"字段值。並根據不同類型,調用audio_stream_enable_echo_limiter(),感覺是設置聲音門限的。
7、檢查lc->config下"sound"下section的"eq_location"字段值,來設置audiostream->eq_loc爲 MSEqualizerMic 或 MSEqualizerHP; (均衡器位置)
8、audio_stream_enable_gain_control(audiostream,true)。開啓audiostream的增益控制,stream->use_gc = true:
9、檢查lc->config下"sound"下section的"noisegate"的門限開關。並設置到audiostream,audio_stream_enable_noise_gate();
10、從lc中獲取audio_features,並設置到audiostream,audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));第二個參數在misc.c下;
11、如果lc->rtptf存在:
rtp_session_get_transports(RtpSession,&,&),在rtpsession_inet.c下,從RtpSession中讀取rtp.gs.tr和rtcp.gs.tr;
分別設置rtp和rtcp的transport endpoint到對應的steam.rtp_port和stream.rtcp_port;
12、新建一個ortp的event_queue,call->audiostream_app_evq = ortp_ev_queue_new();
13、將audiostream的session.rtp_session註冊到event_quere中。rtp_session_register_event_queue();
14、最後調用 _linphone_call_prepare_ice_for_stream(call,call->main_audio_stream_index,FALSE);
如果call->core的firewall_policy是UseIce、並且call->ice_session不爲空時才做的處理。


B、linphone_call_init_video_stream(LinphoneCall *call)
先檢查VIDEO_ENABLED宏標籤是否爲True,如果false就直接退出了。
如果call->vediostream == null的時候,創建videostream,否則退出了;
1、獲取lc->config中的"video"對應的section下的"recv_buf_size";
2、獲取video_dscp,linphone_core_get_video_dscp(lc);在lc->config中的"rtp"對應的section的"video_dspc";
3、獲取display_filter,linphone_core_get_video_display_filter(lc),在misc.c中;在lc->config中的"video"對應的section中的"displaytype";
4、如果call->sessions[call->main_video_stream_index].rtp_session==NULL
4.1、先明確我方在call中的multicast_role;同audio_stream的初始化流程一樣;
4.2、如果multicast_role是receiver,linphone_call_join_multicast_group
4.3、如果if(call->op)存在,獲取對方的remotedesc = sal_call_get_remote_media_description(call->op);實際是返回op->base.remote_media;函數實現在sal_op_call.c
4.4、如果remotedesc存在,獲取stream_desc = sal_media_description_find_best_stream(remotedesc, SalVideo);根據remotedesc查找支持的最優協議;實現在sal.c
4.5、實例化videostream, video_stream_new2();實現在videostream.c中;
第一步:ms_create_duplex_rtp_session,創建video的RtpSession,實現在mediastream.c中
流程與audio_stream_new2()一樣;
第二步:video_stream_new_with_sessions(factory,&session),實現在videostream.c中;
a、直接新建一個VideoStream,
b、構建 OrtpRtcpXr的流媒體回調;
c、設置stream的ms.type和ms.sessions;
d、初始化mediastream :media_stream_init(&stream->ms,factory, sessions); 實現在mediastream.c
主要設置stream的屬性,包括event_dispatcher、event_queue、factory,並且註冊rtpsession到event_queue;
e、rtp_session_resync(rtpsession),同步化rtpsession,用於當接收的rtp stream時間戳不連續時進行同步;
f、繼續設置stream的屬性:包括:
stream->ms.rtpsend=ms_factory_create_filter(factory, MS_RTP_SEND_ID);
stream->ms.ice_check_list=NULL;
stream->ms.qi=ms_quality_indicator_new(stream->ms.sessions.rtp_session);
ms_quality_indicator_set_label(stream->ms.qi,"video");
MS_VIDEO_SIZE_ASSIGN(stream->sent_vsize, CIF);
stream->fps=0;
stream->dir=MediaStreamSendRecv;
stream->display_filter_auto_rotate_enabled=0;
stream->freeze_on_error = FALSE;
stream->source_performs_encoding = FALSE;
stream->output_performs_decoding = FALSE;
choose_display_name(stream);
stream->ms.process_rtcp=video_stream_process_rtcp;
if(ms_factory_lookup_filter_by_id(stream->ms.factory, MS_MKV_RECORDER_ID)){
stream->tee3=ms_factory_create_filter(stream->ms.factory, MS_TEE_ID);
stream->recorder_output=ms_factory_create_filter(stream->ms.factory, MS_ITC_SINK_ID);
}
g、rtp_session_set_rtcp_xr_media_callbacks(stream->ms.sessions.rtp_session, &rtcp_xr_media_cbs);實現在rtcp_xr.c中;應該是給RtpSession設置監聽回調
stream->staticimage_webcam_fps_optimization = TRUE;
4.6、如果multicast_role是receiver;linphone_call_join_multicast_group();處理是否需要加入會話組;
4.7、rtp_session_enable_network_simulation(),同init_audio_stream中的一樣;
4.8、video_stream_set_rtcp_information();設置videostream中的RtpSession的源信息
4.9、rtp_session_set_symmetric_rtp(RtpSession,linphone_core_symmetric_rtp_enabled(lc));將lc->config下"rtp"對應的section下"symmetric"值設置到RtpSession->symmetric_rtp;
4.10、setup_dtls_params()如果call的媒體加密方式是DTLS的時候,設置stream的加密方式;
4.11、如果媒體加密方式是ZRTP時,video_stream_enable_zrtpcall->videostream, call->audiostream),根據已創建的audiostream中的信息激活video_stream中的ZRTP能力;
4.12、media_stream_reclaim_sessions(&videostream->ms, &call->sessions[call->main_video_stream_index]); 把videostream的session信息拷貝到call的session裏面;
5、如果call->media_ports[].rtp_port 沒有設置,調用port_config_set_random_choosed(),將audiostream下RtpSession的loc_port值設置給call。
6、如果上面第2步獲得的dscp存在,將其設置到videostream上,video_stream_set_dscp(audiostream,dscp);實現在mediastream.h
7、video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));實現在videostream.c中;
根據lc->config中的"video"-》"display_fileter_auto_rotate"值,設置到videostream->display_filter_auto_rotato_enabled上;
8、設置video_recv_buf_size;
9、如果第3步中的display_filter不爲空,video_stream_set_display_filter_name(); videostream->display_name = display_filter;
10、video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
第二個參數是個函數名,給videoStream設置回調;
11、如果lc->rtptf存在:
rtp_session_get_transports(RtpSession,&,&),在rtpsession_inet.c下,從RtpSession中讀取rtp.gs.tr和rtcp.gs.tr;
分別設置rtp和rtcp的transport endpoint到對應的steam.rtp_port和stream.rtcp_port;
12、新建一個ortp的event_queue,call->videostream_app_evq = ortp_ev_queue_new();
13、將videostream的session.rtp_session註冊到event_quere中。rtp_session_register_event_queue();
14、最後調用 _linphone_call_prepare_ice_for_stream(call,call->main_video_stream_index,FALSE);
如果call->core的firewall_policy是UseIce、並且call->ice_session不爲空時才做的處理。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章