1前面基于awrtc.js连接kurento的unity客户端,能播放出来了,但是在某些环境下会有问题。
一、现状整理
1.kurento-player的前端页面在不同浏览器都能运行。
不过在IE里面它自己会弹出一个要求安装插件的提示,安装后就和其他浏览器一样能够播放了。这是不是说明IE目前没有原生支持WebRTC?
“用IE打开页面,提示需要安装 Temasys WebRTC Plugin插件,下载、安装、刷新,可以播放。”
2.基于awrtc.js的html客户端页面,只有在Chrome里面能播放,Firefox、IE、Edge里面不能播放。
Firefox里面有到显示Video的地方,但是没有播放视频;
IE里面直接说没有RTCPeerConnection;
Edge里面则是没有createDataChannel,说明也不支持。
但是,awrtc.js里面有看到对WebRTC相关的实现代码啊。奇怪。
3.我测试用的打包好的webgl页面,在Chrome里面能够播放,在Firefox里面不能播放。
4.给别人接手,放到一个Demo项目里面的WebGL打包,连接的是另一个摄像头,在Chrome里面不能播放,在Firefox里面能够播放。
这里是为了给别人演示,放到了一个能外网访问的电脑上,电脑是双网卡,有个内网ip和外网ip,摄像头是在内网上的。访问的电脑(也就是我的电脑是无法直接访问那个摄像头的)。
Firefox上播放正常,Chrome上播放结果是:
偶尔有几次,就算有上面的错误Chrome也能正常播放。
但是手机上的:Chrome播放又是正常的,Firefox正常播放;默认的自带浏览器则不能播放,一直在那里转圈;UC浏览器姑且试了一下,点击Start没反应。
现在的问题是我计划的WebGL的推荐用户使用浏览器是 1.Chrome 2.Firefox 3.IE ,至少Chrome和Firefox都要正常使用
5.用纯js客户端方式连接外网电脑,Firefox也无法播放视频。
提示:ICE failed, add a TURN server and see about:webrtc for more details
这个看来需要把TURN server弄起来了
---------------------------------------------------------------------------------------------
现在有两条路走,1.找到不能播放的原因;2.改kurento-player的前端代码,放到unity里面。
都挺花时间的,考虑先做第二种试试吧。其实kurento-player的前端代码比awrtc封装的好,也比较灵活。
不能播放的问题的具体研究放到另外一篇文章(视频服务器(10) Kurento[5] ICE问题)里面吧。
二、kurento-player js客户端2
相当于是对《视频服务器(7) Kurento[2] js客户端》的后续,这次相当于要把kurento-player-js的代码和unity结合起来。本来在《视频服务器(8) Kurento[3] unity客户端 》里面已经用awrtc.js插件把视频播放出来了,换一个外网环境,chrome就播放不出来了。总之继续弄吧,本来就是一个未完成的任务。
2.1 Unity和Html交互接口
参考之前的awrtc.js,写一个新的接口,和html中的js代码交互。为了提高调试效率,具体js代码,就不放在unity里面,直接放在另一个外部js文件中。相关的引用添加到webgl的打包模板中。
2.1.1 Unity调用外部js代码
在Unity里面获取相应的配置信息(videoUrl,serverUrl,uiInfo),发送给外部的js代码,进行视频播放和调试。
1.Unity调用接口代码(KurentoClient.cs)
public void Connect()
{
Debug.Log("KurentoClient.Connect");
Config.ui = GetUIInfo();
string jsonConfig = JsonUtility.ToJson(Config);
Debug.Log(jsonConfig);
#if UNITY_WEBGL && !UNITY_EDITOR
var jsonResult=KurentoClientJS.Unity_Kurento_Connect(jsonConfig);
Debug.Log("jsonResult:" + jsonResult);
Id = JsonUtility.FromJson<ConnectId>(jsonResult);
Debug.Log(Id);
Debug.Log(Id.id);
#endif
if (KurentoManager.Instance)
{
KurentoManager.Instance.AddClient(this);
}
}
2.接口代码Unity部分
public static class KurentoClientJS
{
[DllImport("__Internal")]//开始播放
public static extern string Unity_Kurento_Connect(string config);
[DllImport("__Internal")]//暂时没用
public static extern int Unity_Kurento_Update(string e);
[DllImport("__Internal")]//停止、暂停、显示界面、移动界面等指令
public static extern string Unity_Kurento_Command(string config);
}
2.接口代码jslib部分(kurento_unity.jslib)
Unity_Kurento_Connect:function(pconfig){
var configJson=Pointer_stringify(pconfig);//转换为字符串
console.log("------- Unity_Kurento_Connect",configJson,this);
var config=JSON.parse(configJson);//转换为对象
console.log("------- config",config);
var client=kurento;//kurento_client.jspre里面的kurento模块
var result= client.CAPI_Kurento_Connect(config);//具体
console.log("------- result",result);
//转换为字符串
var returnStr=JSON.stringify(result);
console.log("------- returnStr",returnStr);
var bufferSize = lengthBytesUTF8(returnStr) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(returnStr, buffer, bufferSize);
console.log("------- buffer",buffer);
return buffer;
}
3.接口代码jspre部分(kurento_client.jspre)
var kurentoClient=null;
if(unityTool!=null&&unityTool.kurentoClient!=null){
kurentoClient=unityTool.kurentoClient;//对接到外部js文件,提高开发调试效率
}
else{
kurentoClient=new KurentoClientClass();
}
function func_CAPI_Kurento_Connect(config){
console.log("------- func_CAPI_Kurento_Connect",config,this);
if(kurentoClient){
return kurentoClient.Connect(config);
}
return {id:-2};
}
4.外部js代码
KurentoClient.prototype.Connect = function (config) {
//var player
config.devId="dev1";
config.serverUrl="ws://60.191.23.20:8443/player";
config.videoUrl="rtsp://admin:admin12345@192.168.1.56/h264/ch1/main/av_strema";
console.log(tag + ".Connect", config, this);
var player=this.players.find(function(item){
return item.devId==config.devId;
});
if(player==null){//第一次播放
this.currentId++;
//动态创建Video并播放
this.CreateVideo(config);
player=new KurentoPlayerClass(config);
player.id=this.currentId;
player.devId=config.devId;
player.start();
//保存起来
this.players.push(player);
}
else{
this.stopPlayers.splice($.inArray(player,this.stopPlayers),1);
var $ele=$(player.video);
this.ShowHtmlElementEx($ele, config.ui);//调整位置
}
return {id: this.currentId};
};
//unityTool是个事先创建好的对象
unityTool.kurentoClient=null;
unityTool.kurentoClient=new KurentoClientClass();
unityTool.kurentoClient.StartRemovePlayerTimer();
2.1.2 js代码发送信息给Unity
一些html事件触发后通知unity,或者发送数据给unity。
现在用于在页面大小发生变化时(最大化,还原)让unity重新发送一下界面信息。
1.js代码部分
$(window).resize(function(){//自动调整
console.info("client windowresize");
//....
console.info("setTimeout1",new Date(),this);
var t=setTimeout(function(){
console.info("setTimeout2",new Date(),this);
var evt={vid:0,type:1,data:"window_resize"};
var s=JSON.stringify(evt);
unityInstance.SendMessage('KurentoManager', 'ReceiveEvent',s);
},100);//这里要延迟执行,立刻执行的话,比例不对,unity里面的大小还没变。
});
2.unity代码部分
KurentoManager.js,脚本,在场景中挂在一个叫“KurentoManager"的空对象上。
public void ReceiveEvent(string evt)
{
Debug.Log("KurentoMananger.ReceiveEvent:" + evt);
KurentoEvent ke = JsonUtility.FromJson<KurentoEvent>(evt);
Debug.Log("ke:" + ke);
Debug.Log("type:" + ke.type);
Debug.Log("vid:" + ke.vid);
Debug.Log("data:" + ke.data);
Debug.Log("(ke.data == window_resize):" + (ke.data == "window_resize"));
Debug.Log("clients:" + clients.Count);
if (ke.vid == 0)//全部
{
foreach (KeyValuePair<int, KurentoClient> pair in clients)
{
pair.Value.DoEvent(ke);
}
}
else
{
KurentoClient client = GetClient(ke.vid);
if (client != null)
{
client.DoEvent(ke);
}
Debug.Log("client:" + client);
Debug.Log("id:" + client.Id.id);
}
}
KurentoClient.cs
public void DoEvent(KurentoEvent ke)
{
if (ke == null)
{
Debug.LogError("KurentoClient.DoEvent ke == null");
return;
}
if (ke.data == "window_resize")
{
MoveWnd(null);
}
}
2.2 kurento-player封装
对kurento-player例子的index.js文件进行一下封装,把相关的变量、方法都放到一个类里面;这样子可以把多个摄像头的变量分类开来。(说实话javascript不是很精通,会用,能看得懂,但是具体的类啊,继承啊,只会模仿现成的代码。)
2.3 Unity和Html界面同步
unity部分,获取界面信息,现在支持ScaleWithScreenSize了。
前面的坐标转换(UnityWebGL调研(5) 和网页交互)需要Canvas上面的CanvsScaler是Constant Pixel Szie。
public UIInfo GetUIInfo()
{
UIInfo info = new UIInfo();
CanvasScaler canvasScaler = VideoImage.GetComponentInParent<CanvasScaler>();
if (canvasScaler)
{
if (canvasScaler.uiScaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize)
{
info.mode = 1;//默认是ConstantPixelSize,是0
}
}
//获取相对于最外层Canvas的坐标
var posEx = Vector2.zero;
RectTransform[] pRects=VideoImage.GetComponentsInParent<RectTransform>();
for (int i = 0; i < pRects.Length; i++)
{
RectTransform rec = pRects[i];
RectTransform recP = null;
if (i < pRects.Length - 1)
{
recP = pRects[i + 1];
var p = rec.anchoredPosition;
if (rec.anchorMin.x == 1 && rec.anchorMax.x == 1)
{
p.x += recP.rect.width / 2;
}
posEx += p;
}
else
{
info.swidth = rec.rect.width;
info.sheight = rec.rect.height;
}
Debug.Log("rec:" + rec.anchoredPosition + "," + rec.rect + ",|" + rec.anchorMin + "," + rec.anchorMax + "," + rec + "," + recP);
}
var pos = posEx;
var rect = VideoImage.rect;
info.id = "video1";
info.x = pos.x;
info.y = pos.y;
info.height = rect.height;
info.width = rect.width;
return info;
}
js部分
KurentoClient.prototype.ShowHtmlElement=function($ele,posX, posY,sizeX,sizeY,padding){
"use strict"
if(this.screenSizeX==null){
this.screenSizeX=$("#unityContainer").css("width").replace("px","");
}
if(this.screenSizeY==null){
this.screenSizeY=$("#unityContainer").css("height").replace("px","");
}
var width=sizeX-padding;
var height=sizeY-padding;
$ele.css("width",width);
$ele.css("height",height);
var x=this.screenSizeX/2+posX-sizeX/2+padding/2+1;
var y=this.screenSizeY/2-posY-sizeY/2+padding/2;
$ele.css("left",x);
$ele.css("top",y);
$ele.show();
};
KurentoClient.prototype.ShowHtmlElementEx=function($ele,ui){
"use strict"
if(this.unityContainer==null){
this.unityContainer=$("#unityContainer");
}
this.screenSizeX=this.unityContainer.css("width").replace("px","");
this.screenSizeY=this.unityContainer.css("height").replace("px","");
var scale=1;
if(ui.mode==1){//Unity里面的CanvasScaler.uiScaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize,并且Match=0.5
scale=this.screenSizeX/ui.swidth;
}
console.error("ui",ui,ui.swidth/ui.sheight);
console.error("==>SetScreenInfo",this.screenSizeX,this.screenSizeY);
console.error("scale",scale);
this.ShowHtmlElement($ele, ui.x * scale, ui.y* scale, ui.width* scale, ui.height* scale,this.padding* scale);//调整位置
};
KurentoClient.prototype.Command = function (cmd) {
console.info(tag + ".Command", cmd, this);
if(cmd==null){
console.error("cmd==null");
return {success:false};
}
var player=this.players.find(function(item){
return item.id==cmd.vid;
});
if(player==null){
console.error("no find player",cmd);
return {success:false};
}
switch (cmd.cid) {
case "resume":
player.resume();
break;
//....
case "moveWnd":
//player.moveWnd();
var data=cmd.data;
if(data=="end"){
}else if(data=="begin"){
}
else{
var ui=cmd.data;
player.config.ui=ui;
ui.id="video_element_"+cmd.vid;
//var video=this.SetupVideoElement();//动态创建元素
var $ele=$(player.video);
this.ShowHtmlElementEx($ele, ui);//调整位置
}
break;
default:
break;
}
return {success:true};
};
html部分
<body>
<div class="webgl-content">
<div id="unityContainer" style="width: 960px; height: 600px"></div>
<div id="videoContainer" style="width:100%;height:100%;position:absolute;left:0px;top:0px;pointer-events: none;"></div>
</body>
2.4 效果
从结论上看,可以,而且,在网页里面播放视频,不勉强放到unity里面显示的话,播放效果更好,也不影响unity的性能。
在Unity里面拖动界面,视频Video也能跟随过去。
手机上的Chrome和Firefox能够正常播放,PC上的Firefox能够正常播放。
2.5 Unity中显示图片
暂时先不做