
醉凝眸 2020-04-04 10.48.52 - 01.gif
序一:我看了看Xcode代碼,又看了看右上角時(shí)間,emmm,想了下就不詳細(xì)敘述了,走一遍大概邏輯以作提醒!
序二:?jiǎn)稳艘粢曨l功能實(shí)現(xiàn)依賴于GoogleWebRTC和SocketRocket框架;
序三:多人音視頻功能分mesh模式、SFU模式、MCU模式,本項(xiàng)目采用的是基于SFU模式的Kurento,框架為KurentoToolbox,相關(guān)區(qū)別請(qǐng)看鏈接:
序四:懶得麻煩········懶······
序五:因?yàn)橹恢v邏輯,不講具體實(shí)現(xiàn)代碼,所以主要記錄一些踩過的坑
一、踩過的坑
1.因?yàn)閕OS的代碼項(xiàng)目在goole上面是后進(jìn)的人發(fā)offer、先進(jìn)的人發(fā)oanswer,而常規(guī)的單人音視頻是先進(jìn)的人打個(gè)后進(jìn)的人,也就是需要先進(jìn)的人發(fā)offer、后進(jìn)的人發(fā)answer;實(shí)現(xiàn)邏輯:將peer和newPeer信令的邏輯對(duì)調(diào),A進(jìn)來收到peer信令啥事也不干,然后當(dāng)b進(jìn)來后,A收到newPeer信令后,創(chuàng)建本地流、生成peerconnection并添加本地流,發(fā)送offer;B進(jìn)來收到peer信令創(chuàng)建本地流、生成peerconnection并添加本地流;
2.和安卓端互通問題:iPhone和iPhone可以后,和安卓端聯(lián)調(diào)時(shí)候,在發(fā)送offer和answer時(shí)候回報(bào)錯(cuò)FingerPrint啥啥啥的,打印查詢sdp后發(fā)現(xiàn)原因是安卓端底層代碼此協(xié)議默認(rèn)關(guān)閉(安卓端是有個(gè)if-else,默認(rèn)走得是另外一個(gè)協(xié)議)導(dǎo)致sdp中fingerPrint不通過,解決方案移動(dòng)端統(tǒng)一增加屬性值DtlsSrtpKeyAgreement為yes;
3.斷網(wǎng)重連問題之重連實(shí)現(xiàn):整體斷網(wǎng)重連由于webSocket代碼心跳不能百分百拉回peerconnection(也就是說RTCIceConnectionState經(jīng)過斷網(wǎng)重連后不能從RTCIceConnectionStateFailed狀態(tài)切換到RTCIceConnectionStateConnected狀態(tài)),所以采用的重走流程方案,即收到didFailWithError代理回調(diào)時(shí)候,判定條件(如果rtcIsFail且非主動(dòng)掛斷且ReachabilityStatus>0),條件成立,重新初始化socket,鏈接服務(wù)器,didOpen后發(fā)送reconnect信令給服務(wù)器,然后重走peer及后續(xù)信令,重新拉回peerconnection鏈接(因?yàn)楸镜亓?、peerconnection、iceServer和RTCPeerConnectionFactory都是全局變量,而且都做了判空處理,所以整個(gè)流程其實(shí)就是相當(dāng)于重新初始化了下socket服務(wù)器,然后信令走了一遍具體信令里面的操作其實(shí)相當(dāng)于沒走);
4.斷網(wǎng)重連問題之和安卓端的適配:因?yàn)楣雀桧?xiàng)目中peerconnection是局部變量,在重連時(shí)候重走流程時(shí)候,iPhone和iPhone手機(jī)是完全沒問題的;但是和安卓就有點(diǎn)蛋疼了,因?yàn)榘沧縿?chuàng)建本地流、生成peerconnection耽誤時(shí)間,所以安卓邏輯是在進(jìn)入頁面時(shí)進(jìn)行這些操作,為了適配安卓手機(jī),iOS端把peerconnection也初始化全局,這樣子整個(gè)移動(dòng)端相當(dāng)于peerconnection都是全局變量,重連時(shí)候不需要再重新創(chuàng)建peerconnection,直接恢復(fù)已有的peerconnection!
5.斷網(wǎng)重連問題之?dāng)嗑W(wǎng)提示:手動(dòng)創(chuàng)建定時(shí)器,新建心跳heart信令發(fā)送給rtc服務(wù)器,哪方網(wǎng)絡(luò)不好時(shí)候,rtc服務(wù)器會(huì)返回給對(duì)面_poor_connection信令用來顯示對(duì)應(yīng)的網(wǎng)絡(luò)提示;
6.大坑之音視頻鏈接音頻ok視頻卻黑屏問題:經(jīng)測(cè)試,在iPhone7以下機(jī)型,音視頻ok;7以上機(jī)型,音頻ok視頻黑屏問題,嘗試過修改sdp內(nèi)容的編解碼、網(wǎng)路帶寬和碼率等;最終解決方案定位統(tǒng)一視頻分辨率!
7.多網(wǎng)絡(luò)音視頻互通:rtc服務(wù)器同學(xué)在stun打洞服務(wù)器的基礎(chǔ)上新增turn服務(wù)器,移動(dòng)端創(chuàng)建iceServer時(shí)候兩個(gè)都加上!
8.視頻橫屏問題:didChangeVideoSize代理回調(diào)中,判斷寬大于高時(shí)候調(diào)換一下,然后橫豎比按照videoView.bounds.size.height/videoFrame.size.height值對(duì)比;
9.單人音視頻前后置攝像頭切換導(dǎo)致的本地和遠(yuǎn)程視頻流鏡像問題:保持前置攝像頭鏡像(即本地視頻預(yù)覽)ok,修改后置攝像頭(即遠(yuǎn)程視頻預(yù)覽);創(chuàng)建remoteVideoView設(shè)置transform的scale為(-1,1),和安卓端適配時(shí),在點(diǎn)擊切換攝像頭時(shí)候發(fā)送change_camera信令,收到change_camera信令時(shí)候,判定如果攝像頭是back就設(shè)置遠(yuǎn)程預(yù)覽頁為Identity,如果否就設(shè)置遠(yuǎn)程預(yù)覽頁scale為(-1,1);
10.群聊音視頻的鏡像問題:因?yàn)槿毫囊粢曨l顯示在接聽頁面上的流都是放在遠(yuǎn)程預(yù)覽頁remoteVideoView上顯示的,所以跟單人音視頻一樣,將遠(yuǎn)程預(yù)覽頁的transform的scale設(shè)置為(-1,1)即可!
11.emmmmm··················,忘了,想起來了有緣在寫,下班了,溜了溜了!
二、代碼實(shí)現(xiàn)
1.CocoaPods導(dǎo)入GoogleWebRTC和SocketRocket
2.WebRTCHelper單列類引用
3.主頁面遠(yuǎn)程視頻預(yù)覽頁和本地視頻預(yù)覽頁創(chuàng)建(RTCEAGLVideoView和RTCCameraPreviewView)
4.鏈接webrtc服務(wù)器,代碼部分:
[[WebRTCHelper shareInstance] connectServer:@"rtc服務(wù)器地址" port:@"rtc服務(wù)器端口" room:@"你的房間"];
5.鏈接服務(wù)器,初始化websocket,鏈接成功,會(huì)回調(diào)webSocketDidOpen代理方法;鏈接失敗,會(huì)回調(diào)didFailWithError代理方法,并自動(dòng)調(diào)用didCloseWithCode代理;
6.鏈接成功后,后續(xù)會(huì)進(jìn)行七大常規(guī)信令交涉(join、peer、newPeer、iceCandidate、offer、answer、leave七個(gè)信令),接收此七大常規(guī)信令的方法為didReceiveMessage代理方法
7.鏈接成功后,發(fā)送join信令(表示該用戶加入房間),代碼:

圖片.png
8.用戶A join房間成功后,會(huì)收到rtc服務(wù)器返回的peer信令,此信令代表用戶自己進(jìn)入成功,每一個(gè)用戶加入房間都會(huì)收到peer信令用來表示自己加入成功;
9.加入房間后,如果此時(shí)有新用戶B進(jìn)入房間(新用戶B加入流程也是5、6、7、8步),之前加入房間的用戶A會(huì)收到newPeer信令,然后進(jìn)行創(chuàng)建本地音視頻流、生成peerconnection、peerconnection添加本地音視頻流、創(chuàng)建并發(fā)送offer,大致代碼:

圖片.png
10.新用戶B會(huì)收到rtc服務(wù)器轉(zhuǎn)發(fā)的用戶A的offer信令,接到offer信令后生成answer信令并發(fā)送,大致代碼:

圖片.png
11.用戶A會(huì)收到rtc服務(wù)器轉(zhuǎn)發(fā)的新用戶B的answer信令

圖片.png
12.在A、B兩用戶交涉過程中,會(huì)通過打洞iceServer的方式,進(jìn)行點(diǎn)與點(diǎn)的信令交涉,也就是iceCandidate信令:

圖片.png