视频服务器(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了。

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