視頻服務器(10) Kurento[5] 瀏覽器無法播放問題

目錄

一、安裝 TURN server(嘗試失敗)。

二、使用免費TURN

三、Chrome不能播放WebRtc視頻的問題

3.1 服務端分析

3.2 客戶端分析

3.3 解決方案


前面碰到的公網,firefox無法播放視頻的問題,提示

ICE failed, add a TURN server and see about:webrtc for more details

現在測試環境是:有兩個服務器,一個有外圍ip,一個只有內網ip的。

現在的問題是純js客戶端(沒有放在http服務器上的html文件),firefox情況下,連接外網或者內網的kurento服務器都是ice faild的。chrome連接內網,能夠播放,連接外網,第一次能播放,後面就不行了。

其實可以先把unity部署到springboot中,不用純js客戶端的方式連接試試。

---------------------------------------------------------------------

一、安裝 TURN server(嘗試失敗)。

查到的資料都是安裝coturn,實際操作一下看看。

參考:coturn穿透服務器搭建

git clone https://github.com/coturn/coturn
cd coturn 
./configure

不按照步驟先安裝libevent的話,會提示

我的系統是ubuntu18.4,不能用yum安裝,

參考:Ubuntu18.04安裝Openssl-1.1.1進行安裝,

安裝過程中出現 Authentication failure,參考:Linux下切換root用戶提示Authentication failure錯誤的解決方法

回到上面的coturn,在生成密鑰時碰到問題,輸入指令openssl req -x509 ....,後提示,req:Use -help for summary,好像這個語句有問題。

其他教程沒有這個,是拷貝的文件的,參考:Ubuntu下安裝配置coturn

------------------------------------------

另外還有個教程提示要安裝,sqlite,參考:webrtc筆記(1): 基於coturn項目的stun/turn服務器搭建

這個教程裏面提示直接用apt-get安裝libevent,參考:Ubuntu 下 coturn 配置實現 TURN 中繼傳輸媒體數據

好吧,不同的環境,不同的教程,我一開始可能就不應該參考那個centos環境下的。

----------------------------------------

另外可以用網上免費的stun服務器,參考:webrtc之三 iceServer

https://gist.github.com/yetithefoot/7592580裏面的

{
	url: 'turn:numb.viagenie.ca',
	credential: 'muazkh',
	username: '[email protected]'
}

似乎能使用,進入http://numb.viagenie.ca/,發現

 

-------------------------------------------

查一下openssl -req 的信息,參考:OpenSSL指令---req

用裏面的最後的例子,可以的

產生一個自簽名的根證書: openssl req -x509 -newkey rsa:1024 -keyout key.pem -out req.pem

至少第一次時會要求

Enter PEM pass phrase

 隨便輸入了一個123456,後面的其他信息也隨便輸入。

在這個基礎上改成

sudo openssl req -x509 -newkey rsa:2048 -keyout /etc/turn_server_pkey.pem -out /etc/turn_server_cert.pem -days 99999 –nodes

難道是拷貝的和手動輸入的不一樣嗎.....

繼續吧。

--------------------------------------------------------------

內網電腦配置:

relay-device=enp6s0   #與前ifconfig查到的網卡名稱一致
listening-ip=192.168.6.16    #內網IP
listening-port=3478
tls-listening-port=5349
relay-ip=192.168.6.16 #內網IP
external-ip=192.168.6.16    #公網IP
relay-threads=50
lt-cred-mech
cert=/etc/turn_server_cert.pem
pkey=/etc/turn_server_pkey.pem
pidfile="/var/run/turnserver.pid"
min-port=49152
max-port=65535
user=cww:123456    #用戶名密碼,創建IceServer時用

#創建IceServer
IceServer turnIceServer = new IceServer("turn:192.168.6.16:3478","cww","123456");
IceServer stunIceServer = new IceServer("stun:47.107.110.212:19302","","");

vim無法複製粘貼,手動輸入了,但是因爲沒有外圍ip,不知道怎麼測試。

--------------------------------------------------------------------

用免費的在https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/做了下測試,和https://www.cnblogs.com/yjmyzz/p/how-to-install-coturn-on-ubuntu.html的最後的結果一樣,接下來用那個來配置一下kurento先吧,從看到的資料,turn應該是安裝在某個公網電腦上的。

{
	url: 'turn:numb.viagenie.ca',
	credential: 'muazkh',
	username: '[email protected]'
}

接下來要設置kurento,發現官網(https://doc-kurento.readthedocs.io/en/6.12.0/user/installation.html#stun-and-turn-servers)也是推薦用numb和Coturn的。

還有Coturn的安裝說明(https://doc-kurento.readthedocs.io/en/6.12.0/user/faq.html

---------------------------------------------------------------------------

二、使用免費TURN

1.在服務器上加上turn設置

[email protected]:[email protected]:3478

說實話不知道有沒有用,有兩個@ .....

2.在客戶端的kurento-player的js代碼中加上turn的設置:

    var iceservers={
        "iceServers":[
            {url:'stun:stun.xten.com'},
            {
                url: 'turn:numb.viagenie.ca',
                credential: 'muazkh',
                username: '[email protected]'
            }
        ]
    }
    var options = {
        remoteVideo : video,
        mediaConstraints : userMediaConstraints,
        onicecandidate : onIceCandidate,
        configuration: iceservers
    }

結果還是出不來:

ICE failed, see about:webrtc for more details

纔想到這個【about:webrtc】和chrome的【chrome://webrtc-internals/】一樣,是個調試界面。。。。

從html文件打開:

而從網頁打開並播放時是

我的電腦是雙網卡的,192.168.1.16連接內網,192.168.6.12連接外網。

從網頁打開時Websocket連接的是內網的"ws://192.168.1.150:8444/player",似乎它居然用6.12的ip去連接1.150。1.16呢,幹嘛不用1.16嘗試?

把外圍網卡網線拔了,果然,html也能播放了。插上還是不行。

chrome沒有這個問題,說明chrome對多網卡的處理比firefox好一些?

chrome也有自己的的問題(外圍時服務端的addicecandidate要5s)。

嘗試用html連接192.168.6.16(是192.168.1.150電腦的內網ip),能夠播放。

神奇的是這時再用html去連接192.168.1.150,也能播放。而且連接的是兩個6網段的ip,而不是1網段的。

好像有學習能力一樣的。不是學習到自己有1網段的ip,去連接對方的1網段,而是學習都有6網段的ip。

我原本還想看看代碼,能不能讓它在有兩個網卡的情況下從1連接1,結果它自己轉到6了。

重啓一下電腦,還是可以,換一臺電腦,也是可以。

奇怪了,最早的問題(用6網段連接1網段)又是怎麼回事呢。

-----------------------------------------------------------------------------

連接外網服務器,http://60.191.23.20:8443/#,可以

這個115.204.230.177應該是我們這個局域網的對外網關ip了吧。

將webgl部署到bootstrap上,也就是kurento所在電腦上,用網頁打開,firefox可以播放視頻。

三、Chrome不能播放WebRtc視頻的問題

3.1 服務端分析

客戶端提示的原因是ICE_ADD_CANDIDATE_ERROR,服務端對應的代碼是

  private void onIceCandidate(String sessionId, JsonObject jsonMessage) {
    UserSession user = users.get(sessionId);

    if (user != null) {
      JsonObject jsonCandidate = jsonMessage.get("candidate").getAsJsonObject();
      IceCandidate candidate =
              new IceCandidate(jsonCandidate.get("candidate").getAsString(), jsonCandidate
                      .get("sdpMid").getAsString(), jsonCandidate.get("sdpMLineIndex").getAsInt());
      user.getWebRtcEndpoint().addIceCandidate(candidate);
    }
  }

這裏的addIceCandidate部分會出異常。

加入打印語句

發現start和end之間的時間有問題

在Firefox裏面播放時是很快的直接就一起的

而在Chrome裏面則是無論是否有異常,start和end之間都查了5s。addIceCandidate裏面用時5s。

而且很奇怪的是打印時間裏的秒都是5的倍數。

另外就是Chrome的發送的sdpOffer很長要16310,而Firefox的只有2083。看來下sdpOffer的內容,chrome的有4個mid。

具體內容,完全看不懂。

參考:WebRTC56版本SDP詳細解析WebRTC 中的 SDP 協議(這個還有對應的騰訊視頻課程)

-------------------------------------------------------------------------------------

3.2 客戶端分析

查資料過程中發現,在使用代理的情況下,chrome播放視頻16s,沒有代理31s,沒代理時可能播放不了,啓動代理的情況下基本都能播放。

-------------------------------------------------------------------------------------

試着把Firefox的candidate保存起來(手動一個個保存起來),在Chrome環境下發送,結果可以播放,也很快,3s左右,說明是candidate的問題。

註釋掉sendMessage裏面的發送部分,在不發送任何消息的情況下,查看chrome的oncandidate的內容,發現

1.沒有使用turn的情況下,只有2個

視頻出不來的。

2.使用turn的情況下,有6個,最後兩個裏面的158.69.221.198是numb.viagenie.ca的ip。

3.曾經在沒有使用turn,開着代理的情況下。

有時能出來4個,那種情況下,視頻是能出來的,16s左右。

另外把這些candidate手動保存下來後,不發送前兩個(包含20e66a9b-b883-43c4-b8c2-1fb6a8de9cab.local),的情況下,3s,左右視頻就出來了,發送的話16s,同時服務端addCandidate時會報錯,就是前面兩個的錯誤。

3.3 解決方案

1.添加turn iceServers

        var iceservers={
            "iceServers":[
                {url:'stun:stun.xten.com'},
                {
                    url: 'turn:numb.viagenie.ca',
                    credential: 'muazkh',
                    username: '[email protected]'
                }
            ]
        }
        var options = {
            remoteVideo : player.video,
            mediaConstraints : userMediaConstraints,
            //....
            configuration: iceservers
        }
        player.webRtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options,
            function(error) {
                if (error)
                    return console.error(error);
                player.webRtcPeer.generateOffer(function(error, offerSdp){
                    player.onOffer(error,offerSdp);
                });
            });

2.緩存發送offer和candidate,同時要過濾.local的candidate

KurentoPlayer.prototype.onOffer=function(error, offerSdp) {
        console.info("******************************* onOffer",this);
        if (error)
            return console.error('Error generating the offer');
        console.info('Invoking SDP offer callback function ' + location.host);
        var message = {
            id : 'start',
            sdpOffer : offerSdp,
            videourl : this.config.videoUrl
        }
        //this.sendMessage(message);
        this.pushBUfferMessage(message);//緩存起來,到oncandidategatheringdone時一起發送出去
    }
    KurentoPlayer.prototype.onIceCandidate=function(candidate) {
        var player=this;
        player.candidateCount++;
        console.error('['+player.candidateCount+'][onIceCandidate : Local candidate]',JSON.stringify(candidate)); 
        player.sendCandidate(candidate);
    };
    KurentoPlayer.prototype.sendCandidate=function(candidate) {
        var isLocal=candidate.candidate.indexOf('.local');
        if(isLocal!=-1){//過濾,不發送
            console.error("sendCandidate isLocal",candidate,isLocal);
            return;
        }
        var message = {
            id : 'onIceCandidate',
            candidate : candidate
        }
        //this.sendMessage(message);
        this.pushBUfferMessage(message);
    };

3.在oncandidategatheringdone一起發送

       var options = {
            //...
            oncandidategatheringdone:function(evt){
                console.error("oncandidategatheringdone",evt);
                player.flushBUfferMessage();//一起發送
            },
            configuration: iceservers
        }

注意如果不緩存offer,只是緩存candidate,一起發送後服務端會出錯,最終導致playEnd。

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