目錄
之前的項目是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從入門到放棄
---------------------------------------------------------------------
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。
在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了。