視頻服務器(7) Kurento[2] js客戶端

目錄

一、獲取js文件

二、通信

1.跨域問題

2.java.io.EOFException:null

3.websocket發送文本長度問題

4.wss問題

5.websocket連接還沒建立就點擊Start按鈕

三、頁面修改


之前的項目是java的,我需要的是純前端的js客戶端,通過js客戶端播放視頻,然後用unity打包的webgl和js客戶端交互,實現在unity的webgl中播放視頻的效果。

之前的demo是:https://github.com/Kurento/kurento-tutorial-java裏面的kurento-player,能夠實現在網頁裏面播放rtsp視頻,通過webrtc的方式播放的。

另外還有一套js的demo:https://github.com/Kurento/kurento-tutorial-js

一、獲取js文件

但是我現在的問題是無論是java的還是js的,相關的js引用文件弄不到。

java的:

<link rel="stylesheet"
	href="webjars/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet"
	href="webjars/ekko-lightbox/dist/ekko-lightbox.min.css">
<link rel="stylesheet" href="webjars/demo-console/index.css">
<link rel="stylesheet" href="css/kurento.css">

<script src="webjars/jquery/dist/jquery.min.js"></script>
<script src="webjars/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="webjars/ekko-lightbox/dist/ekko-lightbox.min.js"></script>
<script src="/webjars/webrtc-adapter/release/adapter.js"></script>
<script src="webjars/demo-console/index.js"></script>

<script src="js/kurento-utils.js"></script>
<script src="js/index.js"></script>

js的:

    <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="bower_components/demo-console/index.css">
    <link rel="stylesheet" href="bower_components/ekko-lightbox/dist/ekko-lightbox.min.css">
    <link rel="stylesheet" href="css/kurento.css">

    <script src="bower_components/jquery/dist/jquery.min.js"></script>
    <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
    <script src="bower_components/demo-console/index.js"></script>
    <script src="bower_components/ekko-lightbox/dist/ekko-lightbox.min.js"></script>
    <script src="bower_components/ekko-lightbox/dist/ekko-lightbox.min.js"></script>
    <script src="bower_components/webrtc-adapter/release/adapter.js"></script>

    <script src="bower_components/kurento-client/js/kurento-client.js"></script>
    <script src="bower_components/kurento-utils/js/kurento-utils.js"></script>

    <script src="js/index.js"></script>

沒有這方面的知識啊。

雖然前面的kurento-player在idea中啓動後,能打開網頁。

在Sources裏面能夠看到這些文件,但是不知道怎麼拷貝出來。

用笨辦法,手動把這些文件一個個創建,拷貝內容出來。其他都好辦,就幾個文件,boostrap的css裏面好多文件

查了一些webjars的資料,大概知道這個是什麼東西,但是還是拷貝不出來。

搜索到了個https://jar-download.com/artifacts/org.webjars/bootstrap,能夠下載bootstrap-3.3.6.jar文件(因爲前面的Sources裏面的bootstrap是3.3.6)

直接解壓jar文件,能夠得到具體的內容:

拷貝到手動創建的webjars裏面的bootstrap/dist文件夾裏面

在chrome裏面打卡index.html

有兩個adapter.js文件找不到,分別在index.html和kurento-utils.js裏面,發現都是

/webjars/webrtc-adapter/release/adapter.js

改成

webjars/webrtc-adapter/release/adapter.js

再打開,就沒有找不到文件的情況了。

tutorial-js裏面的kurento-client-js是從https://github.com/Kurento/kurento-client-bower/tree/master/js拿到的。雖然最後沒用了。

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

二、通信

啓動後,發現通信地址有問題

修改index.js

var host=location.host;
if(host===""){
	host="127.0.0.1:8444";
}
console.log("host",host);
var ws = new WebSocket('wss://' + host + '/player');
ws.onerror=function(error){
	console.error("onerror",error);
}
ws.onopen=function(msg){
	console.log("onopen",msg);
}

結果

後端打印信息:

也就是說,不能從文件連接

把文件放到iis裏面,修改代碼

var host=location.host;
//if(host==="")
{
	host="127.0.0.1:8444";
}
console.log("host",host);
var ws = new WebSocket('wss://' + host + '/player');

也是一樣的

沒有專業知識,這個時候我只能先自己猜測嘗試了。

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

wss改成ws

application.properties改成,去掉ssl部分。

server.port=8444
#server.ssl.key-store=classpath:keystore.jks
#server.ssl.key-store-password=kurento
#server.ssl.key-store-type=JKS
#server.ssl.key-alias=kurento-selfsigned

前端的wss改成ws。

進入頁面不用https。

可以正常播放。

在另一臺電腦上的ubuntu中,運行kurento,在其他電腦上登陸播放。

1.wss,https://192.168.1.150:8443/#,其他電腦,可以播放

2.ws,http://192.168.1.150:8444/#,其他電腦不能播放,自己電腦可以播放。

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

不過,從kurento-player-js裏面啓動也還是一樣的。

好吧。看看https://github.com/Kurento/kurento-tutorial-js怎麼弄的。

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

1.跨域問題

wss情況下,修改Player.java

  @Override
  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(handler(), "/player")
            .setAllowedOrigins("*")//支持跨域
            //.withSockJS()//這個加上的話原來的頁面,視頻出不來,SockJS是一個前端js庫
    ;
  }

參考:Spring Boot WebSocket從入門到放棄

參考:SpringBoot配置WebSocket

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

2.java.io.EOFException:null

想到原來的kurento-rtsp2webrtc結合現狀的java服務端是否可以,試了一下,結果出現個java.io.EOFException:null問題。

發現是前端WebSocket初始化時用了'binary'參數的話會導致該問題。

kWebsocket = new WebSocket(kaddress.value, 'binary');

改成

kWebsocket = new WebSocket(kaddress.value);

繼續改回用現在的kurento-player-js測試。

3.websocket發送文本長度問題

將kurento-player-js放到iis裏面,連接另一臺ubunto電腦的kurento的java服務端,能連接上,短文本發送測試可以("{id:1}"),但是長文本就會出錯,並導致websocket關閉,無法發送後續文本。

The decoded text message was too big for the output buffer and the endpoint does not support partial messages

和原來的網頁對比一下,原來只發送了5942個,純17359個。先處理文本長度限制問題,不行再看看差異。

查資料,首先會查到,設置org.apache.tomcat.websocket.textBufferSize。

參考:springboot框架中使用websocket傳輸內容過長的問題解決

試了,不行。還試着在application.properties裏面設置org.apache.tomcat.websocket.textBufferSize=1024000。

然後會查到,設置configureWebSocketTransport,參考:Spring Stomp over Websocket: Message/Buffer/Cache/Stream limits

但是代碼裏面的基類不是AbstractWebSocketMessageBrokerConfigurer ,而是TextWebSocketHandler。

TextWebSocketHandler裏面只有一個handleBinaryMessage

public class TextWebSocketHandler extends AbstractWebSocketHandler {
    public TextWebSocketHandler() {
    }

    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
        try {
            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("Binary messages not supported"));
        } catch (IOException var4) {
        }

    }
}

再往上是AbstractWebSocketHandler

public abstract class AbstractWebSocketHandler implements WebSocketHandler {
    public AbstractWebSocketHandler() {
    }

    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    }

    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        if (message instanceof TextMessage) {
            this.handleTextMessage(session, (TextMessage)message);
        } else if (message instanceof BinaryMessage) {
            this.handleBinaryMessage(session, (BinaryMessage)message);
        } else {
            if (!(message instanceof PongMessage)) {
                throw new IllegalStateException("Unexpected WebSocket message type: " + message);
            }

            this.handlePongMessage(session, (PongMessage)message);
        }

    }

    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    }

    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
    }

    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
    }

    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
    }

    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    }

    public boolean supportsPartialMessages() {
        return false;
    }
}

發現個supportsPartialMessages,這個正好和提示的後半部分一致“the endpoint does not support partial messages”。

這裏是false,改成true。

參考:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/socket/handler/AbstractWebSocketHandler.html#supportsPartialMessages--

在PlayerHandler裏面加上supportsPartialMessages

  @Override
  public boolean supportsPartialMessages(){
    log.info("supportsPartialMessages true !!!!!!!!!!!!!!!!!!!!!!");
    return true;
  }

再測試,服務端能夠收到信息了,但是因爲被分成幾次發送了,需要處理一下。

在PlayerHandler裏面加上GetJsonMessage

 private String lastText="";
  private JsonObject GetJsonMessage( TextMessage message){
    try {

      JsonObject jsonMessage=null;

      log.info("[TextMessage]: "+message.toString());
      String text=message.getPayload();
      log.info(String.format("[Payload]: %b,%b,%d,%s",
              text.startsWith("{"),text.endsWith("}"),text.length(),text));

      if(text.startsWith("{")&&text.endsWith("}")){
        jsonMessage = gson.fromJson(text, JsonObject.class);
        log.info("[JsonObject1]: "+jsonMessage.toString());
      }
      else{
        lastText+=text;
        if(lastText.endsWith("}")){
          jsonMessage = gson.fromJson(lastText, JsonObject.class);
          log.info("[JsonObject2]: "+jsonMessage.toString());
          lastText="";
        }
        else{
          log.info("[wait form json end]");
        }
      }
      return jsonMessage;
    }
    catch (Exception ex){
      log.error(ex.toString());
      return null;
    }
  }

  @Override
  public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    log.info(">> PlayerHandler.handleTextMessage");
    JsonObject jsonMessage=GetJsonMessage(message);
    if(jsonMessage==null)return;
    String sessionId = session.getId();
    log.debug("Incoming message {} from sessionId", jsonMessage, sessionId);
//..................
}

(就這部分是純原創的,可能寫的差了點,能達到效果)

調試結果,正常能夠收到消息後,網頁裏面視頻就能出來了!哈哈哈!!!!

代碼整理一下,上傳git,包括服務端和客戶端(前端)部分

https://github.com/llhswwha/kurento-player-rtsp2webrtc-jsclient

我這有點雜了,前端雖然是js的,但是需要連接java服務端。而kurento-tutorial-js是直接用js連接kms服務,kurento-tutorial-java是java連接kms服務,同時是前端服務端是一個springboot項目。

經測試,前端代碼,用瀏覽器打開index.html頁面也能播放視頻成功。不需要放到iis裏面。

4.wss問題

試着在第3臺電腦訪問http://192.168.1.16/kurento-player-js/#,結果:

(第1臺電腦是ubuntu,ip是192.168.1.150,運行kurento和java服務端;第2臺電腦是windows,ip是192.168.1.16,運行iis)

WebSocket connection to 'wss://192.168.1.150:8443/player' failed: Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID

查了一下ERR_CERT_AUTHORITY_INVALID,是證書問題,也就是ssl的問題。

因爲之前測試都是在16電腦上連接150的,而最開始連接150的頁面時,有從網頁上選擇“繼續訪問不安全網頁”,所以後續的訪問都沒有限制。

把java服務端改一下,不用ssl。

結果,可以!!

單獨的html文件拷貝過去,也能打開播放視頻。

5.websocket連接還沒建立就點擊Start按鈕

現在先根據

Uncaught DOMException: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.

修改一下index.js,判斷ws是否連接,沒有連接上的話,等連接上後在播放。

var isStartPlayAfterOpen=false;

function start() {
	// Disable start button
	setState(I_AM_STARTING);
	showSpinner(video);

	isClickStart=true;
	console.log("start",ws.readyState);
	if(ws.readyState==0){
		//alert("網絡正在連接中,請稍後。")
		console.log("網絡正在連接中,請稍後。",ws.readyState);
		isStartPlayAfterOpen=true;
		return;
	}

	var mode = $('input[name="mode"]:checked').val();
    //.............
}
var ws = new WebSocket('ws://' + host + '/player');
ws.onerror=function(error){
	console.error("onerror",error);
}
ws.onopen=function(msg){
	console.log("onopen",msg,this);
	this.send("{id:1}");//測試服務端代碼
	if(isStartPlayAfterOpen){//websocket連接上後就播放
		start();
	}
}

三、頁面修改

把index.js裏面的websocket地址播放,放到網頁裏面,可以在頁面上修改。不然wss和ws切換啊,都要改代碼。

index.html修改

				<div class="row">
					<div class="col-md-12">
						<input type="text" id="serverurl"
							   value="ws://192.168.1.150:8444/player"
							   style="width: 100%">
					</div>
				</div>
				<div class="row">
					<div class="col-md-12">
						<input type="text" id="videourl"
							   value="rtsp://iom:[email protected]:554/cam/realmonitor?channel=1&subtype=0"
							   style="width: 100%">
					</div>
				</div>

index.js修改

var ws=null;
function intWebSocket(url){
	if(ws!=null&&ws.url===url){
		console.log("intWebSocket same url",url);
		return;
	}
	console.log("intWebSocket",url);
	ws = new WebSocket(url);
	ws.onerror=function(error){
		console.error("onerror",error);
	}
	ws.onopen=function(msg){
		console.log("onopen",msg,this);
		this.send("{id:1}");//測試服務端代碼
		if(isStartPlayAfterOpen){//websocket連接上後就播放
			start();
		}
	}
	ws.onclose=function(msg){
		console.error("onclose",msg);
	}
	ws.onmessage = function(message) {
    //......
    }
}
function start() {

	var serverurl = document.getElementById('serverurl').value;
	intWebSocket(serverurl);

	// Disable start button
	setState(I_AM_STARTING);
	showSpinner(video);
    //....
}

好了,代碼更新上去,接下來要用結合unity了。

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