一、分析一個(gè)模塊的源碼步驟
- 1、首先應(yīng)該看
SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load);也就是要從mod_conference_load函數(shù)中,看到這個(gè)模塊中寫了哪些可供外部調(diào)用的api或app。
SWITCH_ADD_API(api_interface, "conference", "Conference module commands", conf_api_main, p);
SWITCH_ADD_APP(app_interface, global_app_name, global_app_name, NULL, conference_function, NULL, SAF_NONE);
SWITCH_ADD_APP(app_interface, "conference_set_auto_outcall", "conference_set_auto_outcall", NULL, conference_auto_function, NULL, SAF_NONE);
SWITCH_ADD_CHAT(chat_interface, CONF_CHAT_PROTO, chat_send);
- 2、再找到要詳細(xì)分析的api或app的函數(shù),根據(jù)調(diào)用參數(shù)和返回結(jié)果情況去尋找匹配的源碼。
- 3、模塊中其他的函數(shù)基本上都是供api或app函數(shù)調(diào)用的,因此可以在看到被調(diào)用后再去詳細(xì)分析。
二、詳細(xì)分析conference api
-
SWITCH_STANDARD_API(conf_api_main);即為該api函數(shù)。 - 每個(gè)api實(shí)際傳入的參數(shù)是輸入?yún)?shù)cmd,作用的會(huì)話session,輸出流stream。
- 先將傳入的參數(shù)cmd通過strdup函數(shù)復(fù)制到lbuf字符串保存好,然后將該字符串用空格分割后存入字符串?dāng)?shù)組argv,并得到字符串統(tǒng)計(jì)數(shù)argc。
- conference后接的第一個(gè)參數(shù)是argv[0],接下來就是根據(jù)這第一個(gè)參數(shù)去進(jìn)行字符串匹配,然后執(zhí)行相應(yīng)的動(dòng)作。
- 若是argv[0]是一個(gè)會(huì)議室號(hào)碼,則表示要對(duì)特殊的會(huì)議室進(jìn)行操作;否則就是對(duì)所有的會(huì)議進(jìn)行操作或者普通的api命令使用。
-
conference_find函數(shù),傳入會(huì)議室name號(hào)碼,返回該會(huì)議室結(jié)構(gòu)體對(duì)象conference_obj_t,以便后續(xù)操作。 - 找到對(duì)應(yīng)的會(huì)議室結(jié)構(gòu)體對(duì)象后,轉(zhuǎn)到實(shí)際的執(zhí)行api命令的函數(shù)
conf_api_dispatch。該函數(shù)中,利用api_command_t conf_api_sub_commands[]這樣一個(gè)命令參數(shù)匹配結(jié)構(gòu)體數(shù)組,找到匹配的子命令以及回調(diào)函數(shù)。 - 比如vid-floor子命令的結(jié)構(gòu)體數(shù)據(jù)為
{"vid-floor", (void_fn_t) & conf_api_sub_vid_floor, CONF_API_SUB_MEMBER_TARGET, "vid-floor", "<member_id|last> [force]"}。要想了解這個(gè)子命令的詳細(xì)執(zhí)行過程,可以轉(zhuǎn)到回調(diào)函數(shù)conf_api_sub_vid_floor。force可強(qiáng)制設(shè)定某個(gè)成員一直獲取vid_floor,即一直顯示該成員的畫面。 -
conference_set_floor_holder函數(shù)將某成員設(shè)為臨時(shí)擁有vid_floor,然后還是自動(dòng)根據(jù)聲音大小切換。 -
conference_set_video_floor_holder函數(shù)強(qiáng)制使某成員一直擁有vid_floor。conference的一個(gè)狀態(tài)值CFLAG_VID_FLOOR_LOCK標(biāo)記該vid_floor擁有者鎖住不可自動(dòng)變。 - 以上都是通過成員對(duì)象即member結(jié)構(gòu)體對(duì)象來操作,而成員對(duì)象是對(duì)應(yīng)于一個(gè)會(huì)議的加入順序設(shè)定的鏈表中的id值,通過該member對(duì)象獲取channel號(hào)碼的方式是使用函數(shù)
switch_channel_get_name(member->channel);此外還可以通過member->session獲取到該會(huì)話。 -
member_update_status_field(member)函數(shù)將對(duì)應(yīng)member對(duì)象的狀態(tài)改為TALKING和VIDEO (FLOOR),即有權(quán)講話和展示視頻的狀態(tài)。 -
switch_core_session_refresh_video(member->session);函數(shù)更新該session的msg狀態(tài)SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ,然后調(diào)用switch_core_session_receive_message(session, &msg)更新會(huì)話接收消息的策略。(后面跟蹤不到對(duì)應(yīng)狀態(tài)會(huì)干什么了。。。) -
conference_loop_fn_vid_floor_toggle函數(shù)切換(toggle)vid_floor,放在一個(gè)結(jié)構(gòu)體數(shù)組中struct _mapping control_mappings[19]
三、發(fā)起一個(gè)會(huì)議的流程
conference_app中通過參數(shù)或其他方式傳入一個(gè)會(huì)議室號(hào)碼,然后先檢查該會(huì)議室是否存在并返回一個(gè)會(huì)議室對(duì)象conference=conference_find(conf_name, NULL);,如果不存在的話則創(chuàng)建一個(gè)conference = conference_new(conf_name, xml_cfg, session, NULL);
1)然后為這個(gè)會(huì)議室開啟一個(gè)線程運(yùn)行launch_conference_thread(conference);。該線程調(diào)用一個(gè)執(zhí)行函數(shù)conference_thread_run,內(nèi)部有一個(gè)while循環(huán)去處理會(huì)議成員之間的通信數(shù)據(jù)包。
2)視頻會(huì)議會(huì)創(chuàng)建一個(gè)特別的視頻線程launch_conference_video_thread(conference_obj_t *conference);,然后調(diào)用執(zhí)行函數(shù)conference_video_thread_run,并修改會(huì)議對(duì)象視頻狀態(tài)conference->video_running = 1;。該函數(shù)內(nèi)部有一個(gè)while循環(huán),會(huì)一直通過switch_core_session_read_video_frame(session, &vid_frame, SWITCH_IO_FLAG_NONE, 0);函數(shù)讀取每個(gè)vid_floor_hold成員的視頻幀vid_frame,根據(jù)一個(gè)for循環(huán)遍歷所有的成員并通過switch_core_session_write_video_frame(imember->session, vid_frame, SWITCH_IO_FLAG_NONE, 0);函數(shù)將該vid_frame轉(zhuǎn)發(fā)給所有成員。
3)兩個(gè)會(huì)議成員之間的視頻轉(zhuǎn)發(fā)流程
-
launch_conference_video_bridge_thread(conference_member_t *member_a, conference_member_t *member_b)函數(shù)傳入兩個(gè)會(huì)議成員對(duì)象,函數(shù)內(nèi)調(diào)用兩個(gè)線程,分別執(zhí)行a到b的視頻幀轉(zhuǎn)發(fā)launch_thread_detached(conference_video_bridge_thread_run, pool, &conference->vh[0]);,和b到a的視頻幀轉(zhuǎn)發(fā)launch_thread_detached(conference_video_bridge_thread_run, pool, &conference->vh[1]);。然后都轉(zhuǎn)到線程調(diào)用的函數(shù)conference_video_bridge_thread_run,該函數(shù)內(nèi)有個(gè)while循環(huán)并通過函數(shù)switch_core_session_read_video_frame和switch_core_session_write_video_frame來進(jìn)行視頻幀的轉(zhuǎn)發(fā)。
四、1.6版本通過relate api設(shè)置成員之間的聯(lián)系,使一個(gè)成員可以綁定看另一個(gè)成員的視頻
-
conference 3000 relate 1 2 sendvideo即將成員1視頻發(fā)給成員2,不管成員1是否已獲得vid_floor