Commit 7a216f4c by Christoph

V0.984 rc.

* Cleanup callapp for easier use * Support for async init to have video devices available from the first frame * better work with recent Chrome changes and if loaded via http / file: url’s (mediaDevices null) * Will fail now during init some WebRTC features aren’t available to avoid cryptic error messages during runtime * Added GetBufferedAmount
parent 062d45ee
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<input type="checkbox" name="audio" class="callapp_send_audio" checked autocomplete="off"> Audio <input type="checkbox" name="audio" class="callapp_send_audio" checked autocomplete="off"> Audio
<input type="checkbox" name="video" class="callapp_send_video" checked autocomplete="off"> Video <input type="checkbox" name="video" class="callapp_send_video" checked autocomplete="off"> Video
<input type= "text" class="callapp_address" autocomplete="off"> <input type= "text" class="callapp_address" autocomplete="off">
<button class="callapp_button"> Start / Stop </button> <button class="callapp_button"> Join </button>
<div class="callapp_local_video">local video</div> <div class="callapp_local_video">local video</div>
<div class="callapp_remote_video">remote video</div> <div class="callapp_remote_video">remote video</div>
</div> </div>
......
...@@ -16,14 +16,15 @@ ...@@ -16,14 +16,15 @@
<input type="checkbox" name="audio" class="callapp_send_audio" checked autocomplete="off"> Audio <input type="checkbox" name="audio" class="callapp_send_audio" checked autocomplete="off"> Audio
<input type="checkbox" name="video" class="callapp_send_video" checked autocomplete="off"> Video <input type="checkbox" name="video" class="callapp_send_video" checked autocomplete="off"> Video
<input type= "text" class="callapp_address" autocomplete="off"> <input type= "text" class="callapp_address" autocomplete="off">
<button class="callapp_button"> Start / Stop </button> <button class="callapp_button"> Join </button>
<div class="callapp_local_video">local video</div> <div class="callapp_local_video">local video</div>
<div class="callapp_remote_video">remote video</div> <div class="callapp_remote_video">remote video</div>
</div> </div>
<script> <script>
//everything below is just the callapp.ts compiled to js without the "export" key word //everything below is just the callapp.ts compiled to js via "npm run tsc -- -p src/apps"
//but without the "export" key word
//the inclusion of the ./bundle/awrtc.js above will make the interface available via //the inclusion of the ./bundle/awrtc.js above will make the interface available via
//the global variable "awrtc" //the global variable "awrtc"
class CallApp { class CallApp {
...@@ -35,7 +36,7 @@ class CallApp { ...@@ -35,7 +36,7 @@ class CallApp {
this.mLocalVideo = null; this.mLocalVideo = null;
this.mRemoteVideo = {}; this.mRemoteVideo = {};
this.mIsRunning = false; this.mIsRunning = false;
this.OnStartStopButtonClicked = () => { this.Ui_OnStartStopButtonClicked = () => {
if (this.mIsRunning) { if (this.mIsRunning) {
this.Stop(); this.Stop();
} }
...@@ -43,7 +44,7 @@ class CallApp { ...@@ -43,7 +44,7 @@ class CallApp {
this.Start(this.mAddress, this.mAudio, this.mVideo); this.Start(this.mAddress, this.mAudio, this.mVideo);
} }
}; };
this.OnUiUpdate = () => { this.Ui_OnUpdate = () => {
console.debug("OnUiUpdate"); console.debug("OnUiUpdate");
this.mAddress = this.mUiAddress.value; this.mAddress = this.mUiAddress.value;
this.mAudio = this.mUiAudio.checked; this.mAudio = this.mUiAudio.checked;
...@@ -60,46 +61,6 @@ class CallApp { ...@@ -60,46 +61,6 @@ class CallApp {
this.mNetConfig.IsConference = false; this.mNetConfig.IsConference = false;
this.mNetConfig.SignalingUrl = "wss://signaling.because-why-not.com/callapp"; this.mNetConfig.SignalingUrl = "wss://signaling.because-why-not.com/callapp";
} }
setupUi(parent) {
this.mUiAddress = parent.querySelector(".callapp_address");
this.mUiAudio = parent.querySelector(".callapp_send_audio");
this.mUiVideo = parent.querySelector(".callapp_send_video");
this.mUiUrl = parent.querySelector(".callapp_url");
this.mUiButton = parent.querySelector(".callapp_button");
this.mUiLocalVideoParent = parent.querySelector(".callapp_local_video");
this.mUiRemoteVideoParent = parent.querySelector(".callapp_remote_video");
this.mUiAudio.onclick = this.OnUiUpdate;
this.mUiVideo.onclick = this.OnUiUpdate;
this.mUiAddress.onkeyup = this.OnUiUpdate;
this.mUiButton.onclick = this.OnStartStopButtonClicked;
//set default value + make string "true"/"false" to proper booleans
this.mAudio = this.GetParameterByName("audio");
this.mAudio = this.tobool(this.mAudio, true);
this.mVideo = this.GetParameterByName("video");
this.mVideo = this.tobool(this.mVideo, true);
this.mAutostart = this.GetParameterByName("autostart");
this.mAutostart = this.tobool(this.mAutostart, false);
this.mAddress = this.GetParameterByName("a");
//if autostart is set but no address is given -> create one and reopen the page
if (this.mAddress === null && this.mAutostart == true) {
this.mAddress = this.GenerateRandomKey();
window.location.href = this.GetUrlParams();
}
else {
if (this.mAddress === null)
this.mAddress = this.GenerateRandomKey();
this.UpdateUi();
}
//used for interacting with the Unity CallApp
//current hack to get the html element delivered. by default this
//just the image is copied and given as array
//Lazy frames will be the default soon though
if (this.mAutostart) {
console.log("Starting automatically ... ");
this.Start(this.mAddress, this.mAudio, this.mVideo);
}
console.log("address: " + this.mAddress + " audio: " + this.mAudio + " video: " + this.mVideo + " autostart: " + this.mAutostart);
}
GetParameterByName(name) { GetParameterByName(name) {
var url = window.location.href; var url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&"); name = name.replace(/[\[\]]/g, "\\$&");
...@@ -117,29 +78,11 @@ class CallApp { ...@@ -117,29 +78,11 @@ class CallApp {
return false; return false;
return defaultval; return defaultval;
} }
GenerateRandomKey() {
var result = "";
for (var i = 0; i < 7; i++) {
result += String.fromCharCode(65 + Math.round(Math.random() * 25));
}
return result;
}
GetUrlParams() {
return "?a=" + this.mAddress + "&audio=" + this.mAudio + "&video=" + this.mVideo + "&" + "autostart=" + true;
}
GetUrl() {
return location.protocol + '//' + location.host + location.pathname + this.GetUrlParams();
}
UpdateUi() {
console.log("UpdateUi");
this.mUiAddress.value = this.mAddress;
this.mUiAudio.checked = this.mAudio;
this.mUiVideo.checked = this.mVideo;
this.mUiUrl.innerHTML = this.GetUrl();
}
Start(address, audio, video) { Start(address, audio, video) {
if (this.mCall != null) if (this.mCall != null)
this.Stop(); this.Stop();
this.mIsRunning = true;
this.Ui_OnStart();
console.log("start"); console.log("start");
console.log("Using signaling server url: " + this.mNetConfig.SignalingUrl); console.log("Using signaling server url: " + this.mNetConfig.SignalingUrl);
//create media configuration //create media configuration
...@@ -149,12 +92,14 @@ class CallApp { ...@@ -149,12 +92,14 @@ class CallApp {
config.IdealWidth = 640; config.IdealWidth = 640;
config.IdealHeight = 480; config.IdealHeight = 480;
config.IdealFps = 30; config.IdealFps = 30;
config.FrameUpdates = false; //For usage in HTML set FrameUpdates to false and wait for MediaUpdate to
//get the VideoElement. By default awrtc would deliver frames individually
//for use in Unity WebGL
console.log("requested config:" + JSON.stringify(config)); console.log("requested config:" + JSON.stringify(config));
//setup our high level call class. //setup our high level call class.
this.mCall = new awrtc.BrowserWebRtcCall(this.mNetConfig); this.mCall = new awrtc.BrowserWebRtcCall(this.mNetConfig);
//handle events (get triggered after Configure / Listen call) //handle events (get triggered after Configure / Listen call)
//+ugly lahmda to avoid loosing "this" reference //+ugly lambda to avoid loosing "this" reference
this.mCall.addEventListener((sender, args) => { this.mCall.addEventListener((sender, args) => {
this.OnNetworkEvent(sender, args); this.OnNetworkEvent(sender, args);
}); });
...@@ -173,91 +118,89 @@ class CallApp { ...@@ -173,91 +118,89 @@ class CallApp {
this.mCall.Listen(address); this.mCall.Listen(address);
} }
Stop() { Stop() {
this.Cleanup();
}
Cleanup() {
if (this.mCall != null) { if (this.mCall != null) {
this.mCall.Dispose(); this.mCall.Dispose();
this.mCall = null; this.mCall = null;
clearInterval(this.mIntervalId); clearInterval(this.mIntervalId);
this.mIntervalId = -1; this.mIntervalId = -1;
this.mIsRunning = false;
this.mLocalVideo = null;
this.mRemoteVideo = {};
} }
this.Ui_OnCleanup();
} }
Update() { Update() {
if (this.mCall != null) if (this.mCall != null)
this.mCall.Update(); this.mCall.Update();
} }
OnNetworkEvent(sender, args) { OnNetworkEvent(sender, args) {
//User gave access to requiested camera/ micrphone //User gave access to requested camera/ microphone
if (args.Type == awrtc.CallEventType.ConfigurationComplete) { if (args.Type == awrtc.CallEventType.ConfigurationComplete) {
console.log("configuration complete"); console.log("configuration complete");
} }
/*
else if (args.Type == awrtc.CallEventType.FrameUpdate) {
//frame updated. For unity this needs to be called every frame to deliver
//the byte array but for the browser we get the internally used video element
//for now. (this system will probably change in the future)
let frameUpdateArgs = args as awrtc.FrameUpdateEventArgs;
var lazyFrame = frameUpdateArgs.Frame as LazyFrame;
if (this.mLocalVideo == null && frameUpdateArgs.ConnectionId == awrtc.ConnectionId.INVALID) {
let videoElement = lazyFrame.FrameGenerator.VideoElement;
this.mLocalVideo = videoElement;
this.mUiLocalVideoParent.appendChild(videoElement);
console.log("local video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
}
else if (frameUpdateArgs.ConnectionId != awrtc.ConnectionId.INVALID && this.mRemoteVideo[frameUpdateArgs.ConnectionId.id] == null) {
var videoElement = lazyFrame.FrameGenerator.VideoElement;
this.mRemoteVideo[frameUpdateArgs.ConnectionId.id] = videoElement;
this.mUiRemoteVideoParent.appendChild(videoElement);
console.log("remote video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
}
}
*/
else if (args.Type == awrtc.CallEventType.MediaUpdate) { else if (args.Type == awrtc.CallEventType.MediaUpdate) {
let margs = args; let margs = args;
if (this.mLocalVideo == null && margs.ConnectionId == awrtc.ConnectionId.INVALID) { if (this.mLocalVideo == null && margs.ConnectionId == awrtc.ConnectionId.INVALID) {
var videoElement = margs.VideoElement; var videoElement = margs.VideoElement;
this.mLocalVideo = videoElement; this.mLocalVideo = videoElement;
this.mUiLocalVideoParent.appendChild(videoElement); this.Ui_OnLocalVideo(videoElement);
console.log("local video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??"); console.log("local video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
} }
else if (margs.ConnectionId != awrtc.ConnectionId.INVALID && this.mRemoteVideo[margs.ConnectionId.id] == null) { else if (margs.ConnectionId != awrtc.ConnectionId.INVALID && this.mRemoteVideo[margs.ConnectionId.id] == null) {
var videoElement = margs.VideoElement; var videoElement = margs.VideoElement;
this.mRemoteVideo[margs.ConnectionId.id] = videoElement; this.mRemoteVideo[margs.ConnectionId.id] = videoElement;
this.mUiRemoteVideoParent.appendChild(videoElement); this.Ui_OnRemoteVideo(videoElement, margs.ConnectionId);
console.log("remote video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??"); console.log("remote video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
} }
} }
else if (args.Type == awrtc.CallEventType.ListeningFailed) { else if (args.Type == awrtc.CallEventType.ListeningFailed) {
//First attempt of this example is to try to listen on a certain address //First attempt of this example is to try to listen on a certain address
//for confernce calls this should always work (expect the internet is dead) //for conference calls this should always work (expect the internet is dead)
if (this.mNetConfig.IsConference == false) { if (this.mNetConfig.IsConference == false) {
//no conference call and listening failed? someone might have claimed the address. //no conference call and listening failed? someone might have claimed the address.
//Try to connect to existing call //Try to connect to existing call
this.mCall.Call(this.mAddress); this.mCall.Call(this.mAddress);
} }
else { else {
console.error("Listening failed. Server dead?"); let errorMsg = "Listening failed. Offline? Server dead?";
console.error(errorMsg);
this.Ui_OnError(errorMsg);
this.Cleanup();
return;
} }
} }
else if (args.Type == awrtc.CallEventType.ConnectionFailed) { else if (args.Type == awrtc.CallEventType.ConnectionFailed) {
//Outgoing call failed entirely. This can mean there is no address to connect to, //Outgoing call failed entirely. This can mean there is no address to connect to,
//server is offline, internet is dead, firewall blocked access, ... //server is offline, internet is dead, firewall blocked access, ...
alert("connection failed"); let errorMsg = "Connection failed. Offline? Server dead? ";
console.error(errorMsg);
this.Ui_OnError(errorMsg);
this.Cleanup();
return;
} }
else if (args.Type == awrtc.CallEventType.CallEnded) { else if (args.Type == awrtc.CallEventType.CallEnded) {
//call endet or was disconnected //call ended or was disconnected
var callEndedEvent = args; var callEndedEvent = args;
console.log("call ended with id " + callEndedEvent.ConnectionId.id); console.log("call ended with id " + callEndedEvent.ConnectionId.id);
//document.body.removeChild(mRemoteVideo[callEndedEvent.ConnectionId.id]); delete this.mRemoteVideo[callEndedEvent.ConnectionId.id];
//remove properly this.Ui_OnLog("Disconnected from user with id " + callEndedEvent.ConnectionId.id);
this.mRemoteVideo[callEndedEvent.ConnectionId.id] = null; //check if this was the last user
if (this.mNetConfig.IsConference == false && Object.keys(this.mRemoteVideo).length == 0) {
//1 to 1 call and only user left -> quit
this.Cleanup();
return;
}
} }
else if (args.Type == awrtc.CallEventType.Message) { else if (args.Type == awrtc.CallEventType.Message) {
//no ui for this yet. simply echo messages for testing
let messageArgs = args; let messageArgs = args;
this.mCall.Send(messageArgs.Content, messageArgs.Reliable, messageArgs.ConnectionId); this.mCall.Send(messageArgs.Content, messageArgs.Reliable, messageArgs.ConnectionId);
} }
else if (args.Type == awrtc.CallEventType.DataMessage) { else if (args.Type == awrtc.CallEventType.DataMessage) {
//no ui for this yet. simply echo messages for testing
let messageArgs = args; let messageArgs = args;
this.mCall.SendData(messageArgs.Content, messageArgs.Reliable, messageArgs.ConnectionId); this.mCall.SendData(messageArgs.Content, messageArgs.Reliable, messageArgs.ConnectionId);
} }
...@@ -265,6 +208,92 @@ class CallApp { ...@@ -265,6 +208,92 @@ class CallApp {
console.log("Unhandled event: " + args.Type); console.log("Unhandled event: " + args.Type);
} }
} }
setupUi(parent) {
this.mUiAddress = parent.querySelector(".callapp_address");
this.mUiAudio = parent.querySelector(".callapp_send_audio");
this.mUiVideo = parent.querySelector(".callapp_send_video");
this.mUiUrl = parent.querySelector(".callapp_url");
this.mUiButton = parent.querySelector(".callapp_button");
this.mUiLocalVideoParent = parent.querySelector(".callapp_local_video");
this.mUiRemoteVideoParent = parent.querySelector(".callapp_remote_video");
this.mUiAudio.onclick = this.Ui_OnUpdate;
this.mUiVideo.onclick = this.Ui_OnUpdate;
this.mUiAddress.onkeyup = this.Ui_OnUpdate;
this.mUiButton.onclick = this.Ui_OnStartStopButtonClicked;
//set default value + make string "true"/"false" to proper booleans
this.mAudio = this.GetParameterByName("audio");
this.mAudio = this.tobool(this.mAudio, true);
this.mVideo = this.GetParameterByName("video");
this.mVideo = this.tobool(this.mVideo, true);
this.mAutostart = this.GetParameterByName("autostart");
this.mAutostart = this.tobool(this.mAutostart, false);
this.mAddress = this.GetParameterByName("a");
//if autostart is set but no address is given -> create one and reopen the page
if (this.mAddress === null && this.mAutostart == true) {
this.mAddress = this.GenerateRandomKey();
window.location.href = this.GetUrlParams();
}
else {
if (this.mAddress === null)
this.mAddress = this.GenerateRandomKey();
this.Ui_Update();
}
//used for interacting with the Unity CallApp
//current hack to get the html element delivered. by default this
//just the image is copied and given as array
//Lazy frames will be the default soon though
if (this.mAutostart) {
console.log("Starting automatically ... ");
this.Start(this.mAddress, this.mAudio, this.mVideo);
}
console.log("address: " + this.mAddress + " audio: " + this.mAudio + " video: " + this.mVideo + " autostart: " + this.mAutostart);
}
Ui_OnStart() {
this.mUiButton.textContent = "Stop";
}
Ui_OnCleanup() {
this.mUiButton.textContent = "Join";
while (this.mUiLocalVideoParent.hasChildNodes()) {
this.mUiLocalVideoParent.removeChild(this.mUiLocalVideoParent.firstChild);
}
while (this.mUiRemoteVideoParent.hasChildNodes()) {
this.mUiRemoteVideoParent.removeChild(this.mUiRemoteVideoParent.firstChild);
}
}
Ui_OnLog(msg) {
}
Ui_OnError(msg) {
}
Ui_OnLocalVideo(video) {
this.mUiLocalVideoParent.appendChild(document.createElement("br"));
this.mUiLocalVideoParent.appendChild(video);
}
Ui_OnRemoteVideo(video, id) {
this.mUiRemoteVideoParent.appendChild(document.createElement("br"));
this.mUiRemoteVideoParent.appendChild(new Text("connection " + id.id));
this.mUiRemoteVideoParent.appendChild(document.createElement("br"));
this.mUiRemoteVideoParent.appendChild(video);
}
Ui_Update() {
console.log("UpdateUi");
this.mUiAddress.value = this.mAddress;
this.mUiAudio.checked = this.mAudio;
this.mUiVideo.checked = this.mVideo;
this.mUiUrl.innerHTML = this.GetUrl();
}
GenerateRandomKey() {
var result = "";
for (var i = 0; i < 7; i++) {
result += String.fromCharCode(65 + Math.round(Math.random() * 25));
}
return result;
}
GetUrlParams() {
return "?a=" + this.mAddress + "&audio=" + this.mAudio + "&video=" + this.mVideo + "&" + "autostart=" + true;
}
GetUrl() {
return location.protocol + '//' + location.host + location.pathname + this.GetUrlParams();
}
} }
function callapp(parent) { function callapp(parent) {
let callApp; let callApp;
...@@ -277,9 +306,8 @@ function callapp(parent) { ...@@ -277,9 +306,8 @@ function callapp(parent) {
callApp = new CallApp(); callApp = new CallApp();
callApp.setupUi(parent); callApp.setupUi(parent);
} }
callapp(document.querySelector("#callapp1"));
//examples.CAPIWebRtcNetwork_minimal(); callapp(document.querySelector("#callapp1"));
</script> </script>
</body> </body>
......
...@@ -9,9 +9,8 @@ ...@@ -9,9 +9,8 @@
<button onclick="apps.BrowserMediaNetwork_frameaccess()">BrowserMediaNetwork_frameaccess</button><br> <button onclick="apps.BrowserMediaNetwork_frameaccess()">BrowserMediaNetwork_frameaccess</button><br>
<button onclick="apps.WebsocketNetwork_sharedaddress()">WebsocketNetwork_sharedaddress</button><br> <button onclick="apps.WebsocketNetwork_sharedaddress()">WebsocketNetwork_sharedaddress</button><br>
<button onclick="apps.WebsocketNetwork_test1()">WebsocketNetwork_test1</button><br> <button onclick="apps.WebsocketNetwork_test1()">WebsocketNetwork_test1</button><br>
<button onclick="apps.CAPIWebRtcNetwork_testapp()">CAPIWebRtcNetwork_testapp</button><br> <button onclick="apps.CAPI_WebRtcNetwork_testapp()">CAPI_WebRtcNetwork_testapp</button><br>
<button onclick="apps.CAPIMediaNetwork_testapp()">CAPIMediaNetwork_testapp</button><br> <button onclick="apps.CAPI_MediaNetwork_testapp()">CAPI_MediaNetwork_testapp</button><br>
<button onclick="apps.CAPIMediaStreamAPI()">CAPIMediaStreamAPI</button><br>
</head> </head>
<body> <body>
<script> <script>
......
{ {
"name": "awrtc_browser", "name": "awrtc_browser",
"version": "0.98.3", "version": "0.98.4",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
...@@ -1389,7 +1389,8 @@ ...@@ -1389,7 +1389,8 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
...@@ -1410,12 +1411,14 @@ ...@@ -1410,12 +1411,14 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
...@@ -1430,17 +1433,20 @@ ...@@ -1430,17 +1433,20 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
...@@ -1557,7 +1563,8 @@ ...@@ -1557,7 +1563,8 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
...@@ -1569,6 +1576,7 @@ ...@@ -1569,6 +1576,7 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
...@@ -1583,6 +1591,7 @@ ...@@ -1583,6 +1591,7 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
...@@ -1590,12 +1599,14 @@ ...@@ -1590,12 +1599,14 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.2.4", "version": "2.2.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"yallist": "^3.0.0" "yallist": "^3.0.0"
...@@ -1614,6 +1625,7 @@ ...@@ -1614,6 +1625,7 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
...@@ -1694,7 +1706,8 @@ ...@@ -1694,7 +1706,8 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
...@@ -1706,6 +1719,7 @@ ...@@ -1706,6 +1719,7 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
...@@ -1791,7 +1805,8 @@ ...@@ -1791,7 +1805,8 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.1", "version": "5.1.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
...@@ -1827,6 +1842,7 @@ ...@@ -1827,6 +1842,7 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
...@@ -1846,6 +1862,7 @@ ...@@ -1846,6 +1862,7 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
...@@ -1889,12 +1906,14 @@ ...@@ -1889,12 +1906,14 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.2", "version": "3.0.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
} }
} }
}, },
......
{ {
"name": "awrtc_browser", "name": "awrtc_browser",
"version": "0.98.3", "version": "0.98.4",
"description": "", "description": "",
"author": "because-why-not.com Limited", "author": "because-why-not.com Limited",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
......
...@@ -29,29 +29,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -29,29 +29,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import * as awrtc from "../awrtc/index" import * as awrtc from "../awrtc/index"
import { ConnectionId } from "../awrtc/index";
/**
* Main (and most complicated) example for using BrowserWebRtcCall.
* Have a look at examples.html for easier scenarios.
*
*
*
* Features:
* - Build a "Join" system on top of the regular Listen / Call model to make it easier to use.
* - basic user interface (This is for easy testing not for use as a final application!!! Write your own using the API)
* - setup to be compatible with the Unity Asset's CallApp (but without TURN server!)
* - Get parameters from the address line to configure the call
* - autostart the call (this might not work in all browsers. Mostly used for testing)
* Todo:
* - text message system (so far it sends back the same message)
* - conference call support
*
*
*/
export class CallApp export class CallApp
{ {
private mAddress; private mAddress;
private mAudio;
private mVideo;
private mAutostart;
private mNetConfig = new awrtc.NetworkConfig(); private mNetConfig = new awrtc.NetworkConfig();
private mCall : awrtc.BrowserWebRtcCall = null; private mCall : awrtc.BrowserWebRtcCall = null;
//update loop //update loop
private mIntervalId:any = -1; private mIntervalId:any = -1;
private mLocalVideo = null;
private mRemoteVideo = {};
private mUiAddress: HTMLInputElement; private mLocalVideo: HTMLVideoElement = null;
private mUiAudio: HTMLInputElement; private mRemoteVideo = {};
private mUiVideo: HTMLInputElement;
private mUiButton: HTMLButtonElement;
private mUiUrl: HTMLElement;
private mUiLocalVideoParent: HTMLElement;
private mUiRemoteVideoParent: HTMLElement;
private mIsRunning = false; private mIsRunning = false;
...@@ -68,59 +76,6 @@ export class CallApp ...@@ -68,59 +76,6 @@ export class CallApp
this.mNetConfig.SignalingUrl = "wss://signaling.because-why-not.com/callapp"; this.mNetConfig.SignalingUrl = "wss://signaling.because-why-not.com/callapp";
} }
public setupUi(parent : HTMLElement)
{
this.mUiAddress = parent.querySelector<HTMLInputElement>(".callapp_address");
this.mUiAudio = parent.querySelector<HTMLInputElement>(".callapp_send_audio");
this.mUiVideo = parent.querySelector<HTMLInputElement>(".callapp_send_video");
this.mUiUrl = parent.querySelector<HTMLParagraphElement>(".callapp_url");
this.mUiButton = parent.querySelector<HTMLInputElement>(".callapp_button");
this.mUiLocalVideoParent = parent.querySelector<HTMLParagraphElement>(".callapp_local_video");
this.mUiRemoteVideoParent = parent.querySelector<HTMLParagraphElement>(".callapp_remote_video");
this.mUiAudio.onclick = this.OnUiUpdate;
this.mUiVideo.onclick = this.OnUiUpdate;
this.mUiAddress.onkeyup = this.OnUiUpdate;
this.mUiButton.onclick = this.OnStartStopButtonClicked;
//set default value + make string "true"/"false" to proper booleans
this.mAudio = this.GetParameterByName("audio");
this.mAudio = this.tobool(this.mAudio , true)
this.mVideo = this.GetParameterByName("video");
this.mVideo = this.tobool(this.mVideo , true);
this.mAutostart = this.GetParameterByName("autostart");
this.mAutostart = this.tobool(this.mAutostart, false);
this.mAddress = this.GetParameterByName("a");
//if autostart is set but no address is given -> create one and reopen the page
if (this.mAddress === null && this.mAutostart == true) {
this.mAddress = this.GenerateRandomKey();
window.location.href = this.GetUrlParams();
}
else
{
if(this.mAddress === null)
this.mAddress = this.GenerateRandomKey();
this.UpdateUi();
}
//used for interacting with the Unity CallApp
//current hack to get the html element delivered. by default this
//just the image is copied and given as array
//Lazy frames will be the default soon though
if(this.mAutostart)
{
console.log("Starting automatically ... ")
this.Start(this.mAddress, this.mAudio , this.mVideo );
}
console.log("address: " + this.mAddress + " audio: " + this.mAudio + " video: " + this.mVideo + " autostart: " + this.mAutostart);
}
private GetParameterByName(name) { private GetParameterByName(name) {
...@@ -146,53 +101,14 @@ export class CallApp ...@@ -146,53 +101,14 @@ export class CallApp
private GenerateRandomKey() {
var result = "";
for (var i = 0; i < 7; i++) {
result += String.fromCharCode(65 + Math.round(Math.random() * 25));
}
return result;
}
private GetUrlParams() {
return "?a=" + this.mAddress + "&audio=" + this.mAudio + "&video=" + this.mVideo + "&" + "autostart=" + true;
}
private GetUrl() {
return location.protocol + '//' + location.host + location.pathname + this.GetUrlParams();
}
public OnStartStopButtonClicked = ()=>{
if(this.mIsRunning) {
this.Stop();
}else{
this.Start(this.mAddress, this.mAudio, this.mVideo);
}
}
public OnUiUpdate = ()=>
{
console.debug("OnUiUpdate");
this.mAddress = this.mUiAddress.value;
this.mAudio = this.mUiAudio.checked;
this.mVideo = this.mUiVideo.checked;
this.mUiUrl.innerHTML = this.GetUrl();
}
public UpdateUi() : void
{
console.log("UpdateUi");
this.mUiAddress.value = this.mAddress;
this.mUiAudio.checked = this.mAudio ;
this.mUiVideo.checked = this.mVideo ;
this.mUiUrl.innerHTML = this.GetUrl();
}
public Start(address, audio, video) : void public Start(address, audio, video) : void
{ {
if(this.mCall != null) if(this.mCall != null)
this.Stop(); this.Stop();
this.mIsRunning = true;
this.Ui_OnStart()
console.log("start"); console.log("start");
console.log("Using signaling server url: " + this.mNetConfig.SignalingUrl); console.log("Using signaling server url: " + this.mNetConfig.SignalingUrl);
...@@ -203,14 +119,16 @@ export class CallApp ...@@ -203,14 +119,16 @@ export class CallApp
config.IdealWidth = 640; config.IdealWidth = 640;
config.IdealHeight = 480; config.IdealHeight = 480;
config.IdealFps = 30; config.IdealFps = 30;
config.FrameUpdates = false;
//For usage in HTML set FrameUpdates to false and wait for MediaUpdate to
//get the VideoElement. By default awrtc would deliver frames individually
//for use in Unity WebGL
console.log("requested config:" + JSON.stringify(config)); console.log("requested config:" + JSON.stringify(config));
//setup our high level call class. //setup our high level call class.
this.mCall = new awrtc.BrowserWebRtcCall(this.mNetConfig); this.mCall = new awrtc.BrowserWebRtcCall(this.mNetConfig);
//handle events (get triggered after Configure / Listen call) //handle events (get triggered after Configure / Listen call)
//+ugly lahmda to avoid loosing "this" reference //+ugly lambda to avoid loosing "this" reference
this.mCall.addEventListener((sender, args)=>{ this.mCall.addEventListener((sender, args)=>{
this.OnNetworkEvent(sender, args); this.OnNetworkEvent(sender, args);
}); });
...@@ -240,13 +158,22 @@ export class CallApp ...@@ -240,13 +158,22 @@ export class CallApp
public Stop(): void public Stop(): void
{ {
this.Cleanup();
}
private Cleanup():void{
if(this.mCall != null) if(this.mCall != null)
{ {
this.mCall.Dispose(); this.mCall.Dispose();
this.mCall = null; this.mCall = null;
clearInterval(this.mIntervalId); clearInterval(this.mIntervalId);
this.mIntervalId = -1; this.mIntervalId = -1;
this.mIsRunning = false;
this.mLocalVideo = null;
this.mRemoteVideo = {};
} }
this.Ui_OnCleanup();
} }
private Update():void private Update():void
...@@ -257,34 +184,10 @@ export class CallApp ...@@ -257,34 +184,10 @@ export class CallApp
private OnNetworkEvent(sender: any, args: awrtc.CallEventArgs):void{ private OnNetworkEvent(sender: any, args: awrtc.CallEventArgs):void{
//User gave access to requiested camera/ micrphone //User gave access to requested camera/ microphone
if (args.Type == awrtc.CallEventType.ConfigurationComplete){ if (args.Type == awrtc.CallEventType.ConfigurationComplete){
console.log("configuration complete"); console.log("configuration complete");
} }
/*
else if (args.Type == awrtc.CallEventType.FrameUpdate) {
//frame updated. For unity this needs to be called every frame to deliver
//the byte array but for the browser we get the internally used video element
//for now. (this system will probably change in the future)
let frameUpdateArgs = args as awrtc.FrameUpdateEventArgs;
var lazyFrame = frameUpdateArgs.Frame as LazyFrame;
if (this.mLocalVideo == null && frameUpdateArgs.ConnectionId == awrtc.ConnectionId.INVALID) {
let videoElement = lazyFrame.FrameGenerator.VideoElement;
this.mLocalVideo = videoElement;
this.mUiLocalVideoParent.appendChild(videoElement);
console.log("local video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
}
else if (frameUpdateArgs.ConnectionId != awrtc.ConnectionId.INVALID && this.mRemoteVideo[frameUpdateArgs.ConnectionId.id] == null) {
var videoElement = lazyFrame.FrameGenerator.VideoElement;
this.mRemoteVideo[frameUpdateArgs.ConnectionId.id] = videoElement;
this.mUiRemoteVideoParent.appendChild(videoElement);
console.log("remote video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
}
}
*/
else if (args.Type == awrtc.CallEventType.MediaUpdate) { else if (args.Type == awrtc.CallEventType.MediaUpdate) {
let margs = args as awrtc.MediaUpdatedEventArgs; let margs = args as awrtc.MediaUpdatedEventArgs;
...@@ -292,50 +195,63 @@ export class CallApp ...@@ -292,50 +195,63 @@ export class CallApp
var videoElement = margs.VideoElement; var videoElement = margs.VideoElement;
this.mLocalVideo = videoElement; this.mLocalVideo = videoElement;
this.mUiLocalVideoParent.appendChild(videoElement); this.Ui_OnLocalVideo(videoElement);
console.log("local video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??"); console.log("local video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
} }
else if (margs.ConnectionId != awrtc.ConnectionId.INVALID && this.mRemoteVideo[margs.ConnectionId.id] == null) { else if (margs.ConnectionId != awrtc.ConnectionId.INVALID && this.mRemoteVideo[margs.ConnectionId.id] == null) {
var videoElement = margs.VideoElement; var videoElement = margs.VideoElement;
this.mRemoteVideo[margs.ConnectionId.id] = videoElement; this.mRemoteVideo[margs.ConnectionId.id] = videoElement;
this.mUiRemoteVideoParent.appendChild(videoElement); this.Ui_OnRemoteVideo(videoElement, margs.ConnectionId);
console.log("remote video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??"); console.log("remote video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
} }
} }
else if (args.Type == awrtc.CallEventType.ListeningFailed) { else if (args.Type == awrtc.CallEventType.ListeningFailed) {
//First attempt of this example is to try to listen on a certain address //First attempt of this example is to try to listen on a certain address
//for confernce calls this should always work (expect the internet is dead) //for conference calls this should always work (expect the internet is dead)
if (this.mNetConfig.IsConference == false) { if (this.mNetConfig.IsConference == false) {
//no conference call and listening failed? someone might have claimed the address. //no conference call and listening failed? someone might have claimed the address.
//Try to connect to existing call //Try to connect to existing call
this.mCall.Call(this.mAddress); this.mCall.Call(this.mAddress);
} }
else { else {
console.error("Listening failed. Server dead?"); let errorMsg = "Listening failed. Offline? Server dead?";
console.error(errorMsg);
this.Ui_OnError(errorMsg);
this.Cleanup();
return;
} }
} }
else if (args.Type == awrtc.CallEventType.ConnectionFailed) { else if (args.Type == awrtc.CallEventType.ConnectionFailed) {
//Outgoing call failed entirely. This can mean there is no address to connect to, //Outgoing call failed entirely. This can mean there is no address to connect to,
//server is offline, internet is dead, firewall blocked access, ... //server is offline, internet is dead, firewall blocked access, ...
alert("connection failed"); let errorMsg = "Connection failed. Offline? Server dead? ";
console.error(errorMsg);
this.Ui_OnError(errorMsg);
this.Cleanup();
return;
} }
else if (args.Type == awrtc.CallEventType.CallEnded) { else if (args.Type == awrtc.CallEventType.CallEnded) {
//call endet or was disconnected //call ended or was disconnected
var callEndedEvent = args as awrtc.CallEndedEventArgs; var callEndedEvent = args as awrtc.CallEndedEventArgs;
console.log("call ended with id " + callEndedEvent.ConnectionId.id); console.log("call ended with id " + callEndedEvent.ConnectionId.id);
//document.body.removeChild(mRemoteVideo[callEndedEvent.ConnectionId.id]); delete this.mRemoteVideo[callEndedEvent.ConnectionId.id];
//remove properly this.Ui_OnLog("Disconnected from user with id " + callEndedEvent.ConnectionId.id);
this.mRemoteVideo[callEndedEvent.ConnectionId.id] = null; //check if this was the last user
if(this.mNetConfig.IsConference == false && Object.keys(this.mRemoteVideo).length == 0)
{
//1 to 1 call and only user left -> quit
this.Cleanup();
return;
}
} }
else if (args.Type == awrtc.CallEventType.Message) { else if (args.Type == awrtc.CallEventType.Message) {
//no ui for this yet. simply echo messages for testing
let messageArgs = args as awrtc.MessageEventArgs; let messageArgs = args as awrtc.MessageEventArgs;
this.mCall.Send(messageArgs.Content, messageArgs.Reliable, messageArgs.ConnectionId); this.mCall.Send(messageArgs.Content, messageArgs.Reliable, messageArgs.ConnectionId);
} }
else if (args.Type == awrtc.CallEventType.DataMessage) { else if (args.Type == awrtc.CallEventType.DataMessage) {
//no ui for this yet. simply echo messages for testing
let messageArgs = args as awrtc.DataMessageEventArgs; let messageArgs = args as awrtc.DataMessageEventArgs;
this.mCall.SendData(messageArgs.Content, messageArgs.Reliable, messageArgs.ConnectionId); this.mCall.SendData(messageArgs.Content, messageArgs.Reliable, messageArgs.ConnectionId);
} }
...@@ -344,6 +260,145 @@ export class CallApp ...@@ -344,6 +260,145 @@ export class CallApp
} }
} }
//UI calls. should be moved out into its own class later
private mAudio;
private mVideo;
private mAutostart;
private mUiAddress: HTMLInputElement;
private mUiAudio: HTMLInputElement;
private mUiVideo: HTMLInputElement;
private mUiButton: HTMLButtonElement;
private mUiUrl: HTMLElement;
private mUiLocalVideoParent: HTMLElement;
private mUiRemoteVideoParent: HTMLElement;
public setupUi(parent : HTMLElement)
{
this.mUiAddress = parent.querySelector<HTMLInputElement>(".callapp_address");
this.mUiAudio = parent.querySelector<HTMLInputElement>(".callapp_send_audio");
this.mUiVideo = parent.querySelector<HTMLInputElement>(".callapp_send_video");
this.mUiUrl = parent.querySelector<HTMLParagraphElement>(".callapp_url");
this.mUiButton = parent.querySelector<HTMLInputElement>(".callapp_button");
this.mUiLocalVideoParent = parent.querySelector<HTMLParagraphElement>(".callapp_local_video");
this.mUiRemoteVideoParent = parent.querySelector<HTMLParagraphElement>(".callapp_remote_video");
this.mUiAudio.onclick = this.Ui_OnUpdate;
this.mUiVideo.onclick = this.Ui_OnUpdate;
this.mUiAddress.onkeyup = this.Ui_OnUpdate;
this.mUiButton.onclick = this.Ui_OnStartStopButtonClicked;
//set default value + make string "true"/"false" to proper booleans
this.mAudio = this.GetParameterByName("audio");
this.mAudio = this.tobool(this.mAudio , true)
this.mVideo = this.GetParameterByName("video");
this.mVideo = this.tobool(this.mVideo , true);
this.mAutostart = this.GetParameterByName("autostart");
this.mAutostart = this.tobool(this.mAutostart, false);
this.mAddress = this.GetParameterByName("a");
//if autostart is set but no address is given -> create one and reopen the page
if (this.mAddress === null && this.mAutostart == true) {
this.mAddress = this.GenerateRandomKey();
window.location.href = this.GetUrlParams();
}
else
{
if(this.mAddress === null)
this.mAddress = this.GenerateRandomKey();
this.Ui_Update();
}
//used for interacting with the Unity CallApp
//current hack to get the html element delivered. by default this
//just the image is copied and given as array
//Lazy frames will be the default soon though
if(this.mAutostart)
{
console.log("Starting automatically ... ")
this.Start(this.mAddress, this.mAudio , this.mVideo );
}
console.log("address: " + this.mAddress + " audio: " + this.mAudio + " video: " + this.mVideo + " autostart: " + this.mAutostart);
}
private Ui_OnStart(){
this.mUiButton.textContent = "Stop";
}
private Ui_OnCleanup()
{
this.mUiButton.textContent = "Join";
while (this.mUiLocalVideoParent.hasChildNodes()) {
this.mUiLocalVideoParent.removeChild(this.mUiLocalVideoParent.firstChild);
}
while (this.mUiRemoteVideoParent.hasChildNodes()) {
this.mUiRemoteVideoParent.removeChild(this.mUiRemoteVideoParent.firstChild);
}
}
private Ui_OnLog(msg:string){
}
private Ui_OnError(msg:string){
}
private Ui_OnLocalVideo(video : HTMLVideoElement){
this.mUiLocalVideoParent.appendChild( document.createElement("br"));
this.mUiLocalVideoParent.appendChild(video);
}
private Ui_OnRemoteVideo(video : HTMLVideoElement, id: ConnectionId){
this.mUiRemoteVideoParent.appendChild( document.createElement("br"));
this.mUiRemoteVideoParent.appendChild(new Text("connection " + id.id));
this.mUiRemoteVideoParent.appendChild( document.createElement("br"));
this.mUiRemoteVideoParent.appendChild(video);
}
public Ui_OnStartStopButtonClicked = ()=>{
if(this.mIsRunning) {
this.Stop();
}else{
this.Start(this.mAddress, this.mAudio, this.mVideo);
}
}
public Ui_OnUpdate = ()=>
{
console.debug("OnUiUpdate");
this.mAddress = this.mUiAddress.value;
this.mAudio = this.mUiAudio.checked;
this.mVideo = this.mUiVideo.checked;
this.mUiUrl.innerHTML = this.GetUrl();
}
public Ui_Update() : void
{
console.log("UpdateUi");
this.mUiAddress.value = this.mAddress;
this.mUiAudio.checked = this.mAudio ;
this.mUiVideo.checked = this.mVideo ;
this.mUiUrl.innerHTML = this.GetUrl();
}
private GenerateRandomKey() {
var result = "";
for (var i = 0; i < 7; i++) {
result += String.fromCharCode(65 + Math.round(Math.random() * 25));
}
return result;
}
private GetUrlParams() {
return "?a=" + this.mAddress + "&audio=" + this.mAudio + "&video=" + this.mVideo + "&" + "autostart=" + true;
}
private GetUrl() {
return location.protocol + '//' + location.host + location.pathname + this.GetUrlParams();
}
} }
......
...@@ -125,7 +125,7 @@ interface IRemoteVideoDict { ...@@ -125,7 +125,7 @@ interface IRemoteVideoDict {
class MinimalCall class MinimalCall
{ {
//just a number we give each local call to //just a number we give each local call to
//identify the output of each indivudal call //identify the output of each individual call
mId:number = -1; mId:number = -1;
mCall: awrtc.BrowserWebRtcCall = null; mCall: awrtc.BrowserWebRtcCall = null;
mLocalVideo: HTMLVideoElement = null; mLocalVideo: HTMLVideoElement = null;
...@@ -172,7 +172,8 @@ class MinimalCall ...@@ -172,7 +172,8 @@ class MinimalCall
if (args.Type == awrtc.CallEventType.ConfigurationComplete) { if (args.Type == awrtc.CallEventType.ConfigurationComplete) {
console.log("configuration complete"); console.log("configuration complete");
this.mCall.Listen(this.mAddress); this.mCall.Listen(this.mAddress);
} else if (args.Type == awrtc.CallEventType.FrameUpdate) { }/* Old system. not used anymore
else if (args.Type == awrtc.CallEventType.FrameUpdate) {
let frameUpdateArgs = args as awrtc.FrameUpdateEventArgs; let frameUpdateArgs = args as awrtc.FrameUpdateEventArgs;
if (this.mLocalVideo == null && frameUpdateArgs.ConnectionId == awrtc.ConnectionId.INVALID) { if (this.mLocalVideo == null && frameUpdateArgs.ConnectionId == awrtc.ConnectionId.INVALID) {
...@@ -190,7 +191,28 @@ class MinimalCall ...@@ -190,7 +191,28 @@ class MinimalCall
this.mRemoteVideo[frameUpdateArgs.ConnectionId.id] = lazyFrame.FrameGenerator.VideoElement; this.mRemoteVideo[frameUpdateArgs.ConnectionId.id] = lazyFrame.FrameGenerator.VideoElement;
this.mDiv.appendChild(this.mRemoteVideo[frameUpdateArgs.ConnectionId.id]); this.mDiv.appendChild(this.mRemoteVideo[frameUpdateArgs.ConnectionId.id]);
} }
} else if (args.Type == awrtc.CallEventType.ListeningFailed) { }*/
else if (args.Type == awrtc.CallEventType.MediaUpdate) {
let margs = args as awrtc.MediaUpdatedEventArgs;
if (this.mLocalVideo == null && margs.ConnectionId == awrtc.ConnectionId.INVALID) {
var videoElement = margs.VideoElement;
this.mLocalVideo = videoElement;
this.mDiv.innerHTML += "local video: " + "<br>";
this.mDiv.appendChild(videoElement);
console.log("local video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
}
else if (margs.ConnectionId != awrtc.ConnectionId.INVALID && this.mRemoteVideo[margs.ConnectionId.id] == null) {
var videoElement = margs.VideoElement;
this.mRemoteVideo[margs.ConnectionId.id] = videoElement;
this.mDiv.innerHTML += "remote " + this.mId + "<br>";
this.mDiv.appendChild(videoElement);
console.log("remote video added resolution:" + videoElement.videoWidth + videoElement.videoHeight + " fps: ??");
}
}else if (args.Type == awrtc.CallEventType.ListeningFailed) {
if (this.mNetConfig.IsConference == false) { if (this.mNetConfig.IsConference == false) {
//in 1 to 1 calls there is a listener and a caller //in 1 to 1 calls there is a listener and a caller
...@@ -242,9 +264,11 @@ export function BrowserWebRtcCall_minimal() { ...@@ -242,9 +264,11 @@ export function BrowserWebRtcCall_minimal() {
let mediaConfigSender = new awrtc.MediaConfig(); let mediaConfigSender = new awrtc.MediaConfig();
mediaConfigSender.Video = true; mediaConfigSender.Video = true;
mediaConfigSender.Audio = true; mediaConfigSender.Audio = true;
mediaConfigSender.FrameUpdates = false;
let mediaConfigReceiver = new awrtc.MediaConfig(); let mediaConfigReceiver = new awrtc.MediaConfig();
mediaConfigReceiver.Video = false; mediaConfigReceiver.Video = false;
mediaConfigReceiver.Audio = false; mediaConfigReceiver.Audio = false;
mediaConfigReceiver.FrameUpdates = false;
//random key so we don't mistakenly connect //random key so we don't mistakenly connect
//to another user //to another user
......
...@@ -37,7 +37,7 @@ import { DeviceApi, DeviceInfo } from "../awrtc/index"; ...@@ -37,7 +37,7 @@ import { DeviceApi, DeviceInfo } from "../awrtc/index";
//testapp to run a full connection test using the CAPI //testapp to run a full connection test using the CAPI
//which is used by the unity WebGL plugin //which is used by the unity WebGL plugin
export function CAPIWebRtcNetwork_testapp() { export function CAPI_WebRtcNetwork_testapp() {
console.log("test1"); console.log("test1");
var testMessage = "test1234"; var testMessage = "test1234";
...@@ -46,26 +46,26 @@ export function CAPIWebRtcNetwork_testapp() { ...@@ -46,26 +46,26 @@ export function CAPIWebRtcNetwork_testapp() {
//var configuration = "{ \"signaling\" : { \"class\": \"WebsocketNetwork\", \"param\" : \"ws://localhost:12776\"}, \"iceServers\":[\"stun:stun.l.google.com:19302\"]}"; //var configuration = "{ \"signaling\" : { \"class\": \"WebsocketNetwork\", \"param\" : \"ws://localhost:12776\"}, \"iceServers\":[\"stun:stun.l.google.com:19302\"]}";
var configuration = "{ \"signaling\" : { \"class\": \"LocalNetwork\", \"param\" : null}, \"iceServers\":[{\"urls\": \"stun:stun.l.google.com:19302\"}]}"; var configuration = "{ \"signaling\" : { \"class\": \"LocalNetwork\", \"param\" : null}, \"iceServers\":[{\"urls\": \"stun:stun.l.google.com:19302\"}]}";
var srv = awrtc.CAPIWebRtcNetworkCreate(configuration); var srv = awrtc.CAPI_WebRtcNetwork_Create(configuration);
awrtc.CAPIWebRtcNetworkStartServer(srv, "Room1"); awrtc.CAPI_WebRtcNetwork_StartServer(srv, "Room1");
var clt = awrtc.CAPIWebRtcNetworkCreate(configuration); var clt = awrtc.CAPI_WebRtcNetwork_Create(configuration);
setInterval(() => { setInterval(() => {
awrtc.CAPIWebRtcNetworkUpdate(srv); awrtc.CAPI_WebRtcNetwork_Update(srv);
var evt = null; var evt = null;
while (evt = awrtc.CAPIWebRtcNetworkDequeue(srv)) { while (evt = awrtc.CAPI_WebRtcNetwork_Dequeue(srv)) {
console.log("server inc: " + evt.toString()); console.log("server inc: " + evt.toString());
if (evt.Type == awrtc.NetEventType.ServerInitialized) { if (evt.Type == awrtc.NetEventType.ServerInitialized) {
console.log("server started. Address " + evt.Info); console.log("server started. Address " + evt.Info);
awrtc.CAPIWebRtcNetworkConnect(clt, evt.Info); awrtc.CAPI_WebRtcNetwork_Connect(clt, evt.Info);
} else if (evt.Type == awrtc.NetEventType.ServerInitFailed) { } else if (evt.Type == awrtc.NetEventType.ServerInitFailed) {
console.error("server start failed"); console.error("server start failed");
...@@ -74,21 +74,21 @@ export function CAPIWebRtcNetwork_testapp() { ...@@ -74,21 +74,21 @@ export function CAPIWebRtcNetwork_testapp() {
} else if (evt.Type == awrtc.NetEventType.Disconnected) { } else if (evt.Type == awrtc.NetEventType.Disconnected) {
console.log("server peer disconnected"); console.log("server peer disconnected");
console.log("server shutdown"); console.log("server shutdown");
awrtc.CAPIWebRtcNetworkShutdown(srv); awrtc.CAPI_WebRtcNetwork_Shutdown(srv);
} else if (evt.Type == awrtc.NetEventType.ReliableMessageReceived) { } else if (evt.Type == awrtc.NetEventType.ReliableMessageReceived) {
//srv.SendData(evt.ConnectionId, evt.MessageData, true); //srv.SendData(evt.ConnectionId, evt.MessageData, true);
awrtc.CAPIWebRtcNetworkSendData(srv, evt.ConnectionId.id, evt.MessageData, true); awrtc.CAPI_WebRtcNetwork_SendData(srv, evt.ConnectionId.id, evt.MessageData, true);
} else if (evt.Type == awrtc.NetEventType.UnreliableMessageReceived) { } else if (evt.Type == awrtc.NetEventType.UnreliableMessageReceived) {
//srv.SendData(evt.ConnectionId, evt.MessageData, false); //srv.SendData(evt.ConnectionId, evt.MessageData, false);
awrtc.CAPIWebRtcNetworkSendData(srv, evt.ConnectionId.id, evt.MessageData, false); awrtc.CAPI_WebRtcNetwork_SendData(srv, evt.ConnectionId.id, evt.MessageData, false);
} }
} }
//srv.Flush(); //srv.Flush();
awrtc.CAPIWebRtcNetworkFlush(srv); awrtc.CAPI_WebRtcNetwork_Flush(srv);
//clt.Update(); //clt.Update();
awrtc.CAPIWebRtcNetworkUpdate(clt); awrtc.CAPI_WebRtcNetwork_Update(clt);
while (evt = awrtc.CAPIWebRtcNetworkDequeue(clt)) { while (evt = awrtc.CAPI_WebRtcNetwork_Dequeue(clt)) {
console.log("client inc: " + evt.toString()); console.log("client inc: " + evt.toString());
...@@ -97,7 +97,7 @@ export function CAPIWebRtcNetwork_testapp() { ...@@ -97,7 +97,7 @@ export function CAPIWebRtcNetwork_testapp() {
let buff = awrtc.Encoding.UTF16.GetBytes(testMessage); let buff = awrtc.Encoding.UTF16.GetBytes(testMessage);
//clt.SendData(evt.ConnectionId, buff, true); //clt.SendData(evt.ConnectionId, buff, true);
awrtc.CAPIWebRtcNetworkSendData(clt, evt.ConnectionId.id, buff, true); awrtc.CAPI_WebRtcNetwork_SendData(clt, evt.ConnectionId.id, buff, true);
} else if (evt.Type == awrtc.NetEventType.ReliableMessageReceived) { } else if (evt.Type == awrtc.NetEventType.ReliableMessageReceived) {
//check last message //check last message
...@@ -110,7 +110,7 @@ export function CAPIWebRtcNetwork_testapp() { ...@@ -110,7 +110,7 @@ export function CAPIWebRtcNetwork_testapp() {
let buff = awrtc.Encoding.UTF16.GetBytes(testMessage); let buff = awrtc.Encoding.UTF16.GetBytes(testMessage);
//clt.SendData(evt.ConnectionId, buff, false); //clt.SendData(evt.ConnectionId, buff, false);
awrtc.CAPIWebRtcNetworkSendData(clt, evt.ConnectionId.id, buff, false); awrtc.CAPI_WebRtcNetwork_SendData(clt, evt.ConnectionId.id, buff, false);
} else if (evt.Type == awrtc.NetEventType.UnreliableMessageReceived) { } else if (evt.Type == awrtc.NetEventType.UnreliableMessageReceived) {
let str = awrtc.Encoding.UTF16.GetString(evt.MessageData); let str = awrtc.Encoding.UTF16.GetString(evt.MessageData);
if (str != testMessage) { if (str != testMessage) {
...@@ -119,49 +119,49 @@ export function CAPIWebRtcNetwork_testapp() { ...@@ -119,49 +119,49 @@ export function CAPIWebRtcNetwork_testapp() {
console.log("client disconnecting"); console.log("client disconnecting");
//clt.Disconnect(evt.ConnectionId); //clt.Disconnect(evt.ConnectionId);
awrtc.CAPIWebRtcNetworkDisconnect(clt, evt.ConnectionId.id); awrtc.CAPI_WebRtcNetwork_Disconnect(clt, evt.ConnectionId.id);
console.log("client shutting down"); console.log("client shutting down");
//clt.Shutdown(); //clt.Shutdown();
awrtc.CAPIWebRtcNetworkShutdown(clt); awrtc.CAPI_WebRtcNetwork_Shutdown(clt);
} }
} }
//clt.Flush(); //clt.Flush();
awrtc.CAPIWebRtcNetworkFlush(clt); awrtc.CAPI_WebRtcNetwork_Flush(clt);
}, 100); }, 100);
} }
//for testing the media API used by the unity plugin //for testing the media API used by the unity plugin
export function CAPIMediaNetwork_testapp() export function CAPI_MediaNetwork_testapp()
{ {
awrtc.BrowserMediaStream.DEBUG_SHOW_ELEMENTS = true; awrtc.BrowserMediaStream.DEBUG_SHOW_ELEMENTS = true;
var signalingUrl : string = DefaultValues.Signaling; var signalingUrl : string = DefaultValues.Signaling;
let lIndex = awrtc.CAPIMediaNetwork_Create("{\"IceUrls\":[\"stun:stun.l.google.com:19302\"], \"SignalingUrl\":\"ws://because-why-not.com:12776\"}"); let lIndex = awrtc.CAPI_MediaNetwork_Create("{\"IceUrls\":[\"stun:stun.l.google.com:19302\"], \"SignalingUrl\":\"ws://because-why-not.com:12776\"}");
let configDone = false; let configDone = false;
awrtc.CAPIMediaNetwork_Configure(lIndex, true, true, 160, 120, 640, 480, 640, 480, -1, -1, -1); awrtc.CAPI_MediaNetwork_Configure(lIndex, true, true, 160, 120, 640, 480, 640, 480, -1, -1, -1);
console.log(awrtc.CAPIMediaNetwork_GetConfigurationState(lIndex)); console.log(awrtc.CAPI_MediaNetwork_GetConfigurationState(lIndex));
let startTime = new Date().getTime(); let startTime = new Date().getTime();
let mainLoop = function () { let mainLoop = function () {
awrtc.CAPIWebRtcNetworkUpdate(lIndex); awrtc.CAPI_WebRtcNetwork_Update(lIndex);
if (awrtc.CAPIMediaNetwork_GetConfigurationState(lIndex) == (awrtc.MediaConfigurationState.Successful as number) && configDone == false) { if (awrtc.CAPI_MediaNetwork_GetConfigurationState(lIndex) == (awrtc.MediaConfigurationState.Successful as number) && configDone == false) {
configDone = true; configDone = true;
console.log("configuration done"); console.log("configuration done");
} }
if (awrtc.CAPIMediaNetwork_GetConfigurationState(lIndex) == (awrtc.MediaConfigurationState.Failed as number)) { if (awrtc.CAPI_MediaNetwork_GetConfigurationState(lIndex) == (awrtc.MediaConfigurationState.Failed as number)) {
alert("configuration failed"); alert("configuration failed");
} }
if (configDone == false) if (configDone == false)
console.log(awrtc.CAPIMediaNetwork_GetConfigurationState(lIndex)); console.log(awrtc.CAPI_MediaNetwork_GetConfigurationState(lIndex));
if ((new Date().getTime() - startTime) < 15000) { if ((new Date().getTime() - startTime) < 15000) {
window.requestAnimationFrame(mainLoop); window.requestAnimationFrame(mainLoop);
} else { } else {
console.log("shutting down"); console.log("shutting down");
awrtc.CAPIWebRtcNetworkRelease(lIndex); awrtc.CAPI_WebRtcNetwork_Release(lIndex);
} }
} }
window.requestAnimationFrame(mainLoop); window.requestAnimationFrame(mainLoop);
...@@ -412,7 +412,7 @@ class FpsCounter ...@@ -412,7 +412,7 @@ class FpsCounter
} }
//Sends video data between two peers within the same browser window //Sends video data between two peers within the same browser window
//and accesses the resultung frame data directly //and accesses the resulting frame data directly
export function BrowserMediaNetwork_frameaccess() { export function BrowserMediaNetwork_frameaccess() {
......
...@@ -138,7 +138,7 @@ export class BrowserMediaNetwork extends WebRtcNetwork implements IMediaNetwork ...@@ -138,7 +138,7 @@ export class BrowserMediaNetwork extends WebRtcNetwork implements IMediaNetwork
//user requested specific device? get it now to properly add it to the //user requested specific device? get it now to properly add it to the
//constraints alter //constraints later
let deviceId:string = null; let deviceId:string = null;
if(config.Video && config.VideoDeviceName && config.VideoDeviceName !== "") if(config.Video && config.VideoDeviceName && config.VideoDeviceName !== "")
{ {
...@@ -184,6 +184,8 @@ export class BrowserMediaNetwork extends WebRtcNetwork implements IMediaNetwork ...@@ -184,6 +184,8 @@ export class BrowserMediaNetwork extends WebRtcNetwork implements IMediaNetwork
constraints.video = video; constraints.video = video;
SLog.L("calling GetUserMedia. Media constraints: " + JSON.stringify(constraints)); SLog.L("calling GetUserMedia. Media constraints: " + JSON.stringify(constraints));
if(navigator && navigator.mediaDevices)
{
let promise = navigator.mediaDevices.getUserMedia(constraints); let promise = navigator.mediaDevices.getUserMedia(constraints);
promise.then((stream) => { //user gave permission promise.then((stream) => { //user gave permission
...@@ -208,6 +210,13 @@ export class BrowserMediaNetwork extends WebRtcNetwork implements IMediaNetwork ...@@ -208,6 +210,13 @@ export class BrowserMediaNetwork extends WebRtcNetwork implements IMediaNetwork
SLog.LE(err.name + ": " + err.message); SLog.LE(err.name + ": " + err.message);
this.OnConfigurationFailed(err.message); this.OnConfigurationFailed(err.message);
}); });
}else{
//no access to media device -> fail
let error = "Configuration failed. navigator.mediaDevices is unedfined. The browser might not allow media access." +
"Is the page loaded via http or file URL? Some browsers only support https!";
SLog.LE(error);
this.OnConfigurationFailed(error);
}
} else { } else {
this.OnConfigurationSuccess(); this.OnConfigurationSuccess();
} }
......
...@@ -53,6 +53,17 @@ export class DeviceApi ...@@ -53,6 +53,17 @@ export class DeviceApi
return DeviceApi.sLastUpdate > 0; return DeviceApi.sLastUpdate > 0;
} }
private static sIsPending = false;
public static get IsPending(){
return DeviceApi.sIsPending;
}
private static sLastError:string = null;
private static get LastError()
{
return this.sLastError;
}
private static sDeviceInfo: { [id: string] : DeviceInfo; } = {}; private static sDeviceInfo: { [id: string] : DeviceInfo; } = {};
private static sVideoDeviceCounter = 1; private static sVideoDeviceCounter = 1;
...@@ -87,6 +98,7 @@ export class DeviceApi ...@@ -87,6 +98,7 @@ export class DeviceApi
private static InternalOnEnum = (devices:MediaDeviceInfo[])=> private static InternalOnEnum = (devices:MediaDeviceInfo[])=>
{ {
DeviceApi.sIsPending = false;
DeviceApi.sLastUpdate = new Date().getTime(); DeviceApi.sLastUpdate = new Date().getTime();
let newDeviceInfo: { [id: string] : DeviceInfo; } = {}; let newDeviceInfo: { [id: string] : DeviceInfo; } = {};
...@@ -141,7 +153,10 @@ export class DeviceApi ...@@ -141,7 +153,10 @@ export class DeviceApi
if(DeviceApi.sAccessStream) if(DeviceApi.sAccessStream)
{ {
DeviceApi.sAccessStream.stop(); var tracks = DeviceApi.sAccessStream.getTracks();
for (var i = 0; i < tracks.length; i++) {
tracks[i].stop();
}
DeviceApi.sAccessStream = null; DeviceApi.sAccessStream = null;
} }
DeviceApi.TriggerChangedEvent(); DeviceApi.TriggerChangedEvent();
...@@ -158,11 +173,21 @@ export class DeviceApi ...@@ -158,11 +173,21 @@ export class DeviceApi
DeviceApi.sDeviceInfo = {}; DeviceApi.sDeviceInfo = {};
DeviceApi.sVideoDeviceCounter = 1; DeviceApi.sVideoDeviceCounter = 1;
DeviceApi.sAccessStream = null; DeviceApi.sAccessStream = null;
DeviceApi.sLastError = null;
DeviceApi.sIsPending = false;
} }
private static InternalOnError = (err:DOMError)=> private static InternalOnErrorCatch = (err:DOMError)=>
{
let txt :string = err.toString();
DeviceApi.InternalOnErrorString(txt);
}
private static InternalOnErrorString = (err:string)=>
{ {
DeviceApi.sIsPending = false;
DeviceApi.sLastError = err;
SLog.LE(err); SLog.LE(err);
DeviceApi.TriggerChangedEvent();
} }
private static InternalOnStream = (stream:MediaStream)=> private static InternalOnStream = (stream:MediaStream)=>
...@@ -173,24 +198,48 @@ export class DeviceApi ...@@ -173,24 +198,48 @@ export class DeviceApi
/**Updates the device list based on the current /**Updates the device list based on the current
* access. Given devices numbers if the name isn't known. * access. Gives the devices numbers if the name isn't known.
*/ */
public static Update():void public static Update():void
{ {
DeviceApi.sLastError = null;
if(DeviceApi.IsApiAvailable())
{
DeviceApi.sIsPending = true;
navigator.mediaDevices.enumerateDevices() navigator.mediaDevices.enumerateDevices()
.then(DeviceApi.InternalOnEnum) .then(DeviceApi.InternalOnEnum)
.catch(DeviceApi.InternalOnError); .catch(DeviceApi.InternalOnErrorCatch);
}else{
DeviceApi.InternalOnErrorString("Can't access mediaDevices or enumerateDevices");
}
}
/**Checks if the API is available in the browser.
* false - browser doesn't support this API
* true - browser supports the API (might still refuse to give
* us access later on)
*/
public static IsApiAvailable():boolean
{
if(navigator && navigator.mediaDevices && navigator.mediaDevices.enumerateDevices)
return true;
return false;
} }
/**Asks the user for access first to get the full /**Asks the user for access first to get the full
* device names. * device names.
*/ */
public static RequestUpdate():void public static RequestUpdate():void
{ {
DeviceApi.sLastError = null;
if(DeviceApi.IsApiAvailable())
{
DeviceApi.sIsPending = true;
let constraints = {video:true}; let constraints = {video:true};
navigator.mediaDevices.getUserMedia(constraints) navigator.mediaDevices.getUserMedia(constraints)
.then(DeviceApi.InternalOnStream) .then(DeviceApi.InternalOnStream)
.catch(DeviceApi.InternalOnError); .catch(DeviceApi.InternalOnErrorCatch);
}else{
DeviceApi.InternalOnErrorString("Can't access mediaDevices or enumerateDevices");
}
} }
......
...@@ -127,8 +127,10 @@ export class MediaPeer extends WebRtcDataPeer ...@@ -127,8 +127,10 @@ export class MediaPeer extends WebRtcDataPeer
} }
else{ else{
for(let v of stream.getTracks()) for(let v of stream.getTracks())
{
this.mPeer.addTrack(v, stream); this.mPeer.addTrack(v, stream);
} }
}
} }
......
...@@ -196,27 +196,39 @@ export class SLog { ...@@ -196,27 +196,39 @@ export class SLog {
{ {
SLog.sLogLevel = level; SLog.sLogLevel = level;
} }
public static RequestLogLevel(level: SLogLevel)
{
if(level > SLog.sLogLevel)
SLog.sLogLevel = level;
}
public static L(msg: any): void { public static L(msg: any, tag?:string): void {
SLog.Log(msg); SLog.Log(msg, tag);
} }
public static LW(msg: any): void { public static LW(msg: any, tag?:string): void {
SLog.LogWarning(msg); SLog.LogWarning(msg, tag);
} }
public static LE(msg: any): void { public static LE(msg: any, tag?:string): void {
SLog.LogError(msg); SLog.LogError(msg, tag);
} }
public static Log(msg: any): void { public static Log(msg: any, tag?:string): void {
if(!tag)
tag = "";
if(SLog.sLogLevel >= SLogLevel.Info) if(SLog.sLogLevel >= SLogLevel.Info)
console.log(msg); console.log(msg, tag);
} }
public static LogWarning(msg: any): void { public static LogWarning(msg: any, tag?:string): void {
if(!tag)
tag = "";
if(SLog.sLogLevel >= SLogLevel.Warnings) if(SLog.sLogLevel >= SLogLevel.Warnings)
console.warn(msg); console.warn(msg, tag);
} }
public static LogError(msg: any) { public static LogError(msg: any, tag?:string) {
if(!tag)
tag = "";
if(SLog.sLogLevel >= SLogLevel.Errors) if(SLog.sLogLevel >= SLogLevel.Errors)
console.error(msg); console.error(msg, tag);
} }
} }
\ No newline at end of file
...@@ -49,7 +49,23 @@ export enum NetEventType { ...@@ -49,7 +49,23 @@ export enum NetEventType {
Disconnected = 8,//a connection was disconnected Disconnected = 8,//a connection was disconnected
FatalError = 100, //not yet used FatalError = 100, //not yet used
Warning = 101,//not yet used Warning = 101,//not yet used
Log = 102 //not yet used Log = 102, //not yet used
/// <summary>
/// This value and higher are reserved for other uses.
/// Should never get to the user and should be filtered out.
/// </summary>
ReservedStart = 200,
/// <summary>
/// Reserved.
/// Used by protocols that forward NetworkEvents
/// </summary>
MetaVersion = 201,
/// <summary>
/// Reserved.
/// Used by protocols that forward NetworkEvents.
/// </summary>
MetaHeartbeat = 202
} }
export enum NetEventDataType { export enum NetEventDataType {
Null = 0, Null = 0,
...@@ -330,6 +346,7 @@ export interface IBasicNetwork extends INetwork { ...@@ -330,6 +346,7 @@ export interface IBasicNetwork extends INetwork {
Connect(address: string): ConnectionId; Connect(address: string): ConnectionId;
} }
export interface IWebRtcNetwork extends IBasicNetwork { export interface IWebRtcNetwork extends IBasicNetwork {
GetBufferedAmount(id: ConnectionId, reliable:boolean): number;
} }
//export {NetEventType, NetworkEvent, ConnectionId, INetwork, IBasicNetwork}; //export {NetEventType, NetworkEvent, ConnectionId, INetwork, IBasicNetwork};
...@@ -151,9 +151,19 @@ export class WebRtcNetwork implements IBasicNetwork { ...@@ -151,9 +151,19 @@ export class WebRtcNetwork implements IBasicNetwork {
SLog.LogWarning("unknown connection id"); SLog.LogWarning("unknown connection id");
return false; return false;
} }
}
public GetBufferedAmount(id: ConnectionId, reliable: boolean): number {
let peer = this.mIdToConnection[id.id];
if (peer) {
return peer.GetBufferedAmount(reliable);
} else {
SLog.LogWarning("unknown connection id");
return -1;
}
} }
public Disconnect(id: ConnectionId): void { public Disconnect(id: ConnectionId): void {
let peer = this.mIdToConnection[id.id]; let peer = this.mIdToConnection[id.id];
if (peer) { if (peer) {
......
...@@ -551,6 +551,27 @@ export class WebRtcDataPeer extends AWebRtcPeer { ...@@ -551,6 +551,27 @@ export class WebRtcDataPeer extends AWebRtcPeer {
} }
return sentSuccessfully; return sentSuccessfully;
} }
public GetBufferedAmount(reliable: boolean): number {
let result = -1;
try {
if (reliable) {
if (this.mReliableDataChannel.readyState === "open")
{
result = this.mReliableDataChannel.bufferedAmount;
}
}
else {
if (this.mUnreliableDataChannel.readyState === "open")
{
result = this.mUnreliableDataChannel.bufferedAmount;
}
}
} catch (e) {
SLog.LogError("Exception while trying to access GetBufferedAmount: " + e);
}
return result;
}
public DequeueEvent(/*out*/ ev: Output<NetworkEvent>): boolean { public DequeueEvent(/*out*/ ev: Output<NetworkEvent>): boolean {
//lock(mEvents) //lock(mEvents)
......
...@@ -45,10 +45,13 @@ export enum WebsocketServerStatus { ...@@ -45,10 +45,13 @@ export enum WebsocketServerStatus {
ShuttingDown ShuttingDown
} }
//TODO: handle errors if the socket connection failed //TODO: handle errors if the socket connection failed
//+ send back failed events for connected / serverstart events that are buffered //+ send back failed events for connected / serverstart events that are buffered
export class WebsocketNetwork implements IBasicNetwork { export class WebsocketNetwork implements IBasicNetwork {
public static readonly LOGTAG = "WebsocketNetwork";
//websocket. //websocket.
private mSocket: WebSocket; private mSocket: WebSocket;
...@@ -73,13 +76,40 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -73,13 +76,40 @@ export class WebsocketNetwork implements IBasicNetwork {
//next free connection id //next free connection id
private mNextOutgoingConnectionId = new ConnectionId(1); private mNextOutgoingConnectionId = new ConnectionId(1);
/// <summary>
/// Version of the protocol implemented here
/// </summary>
public static readonly PROTOCOL_VERSION = 2;
/// <summary>
/// Minimal protocol version that is still supported.
/// V 1 servers won't understand heartbeat and version
/// messages but would just log an unknown message and
/// continue normally.
/// </summary>
public static readonly PROTOCOL_VERSION_MIN = 1;
/// <summary>
/// Assume 1 until message received
/// </summary>
private mRemoteProtocolVersion = 1;
private mUrl: string = null; private mUrl: string = null;
private mConfig: WebsocketNetwork.Configuration;
private mLastHeartbeat: number;
private mHeartbeatReceived = true;
private mIsDisposed = false; private mIsDisposed = false;
public constructor(url: string) { public constructor(url: string, configuration?:WebsocketNetwork.Configuration) {
this.mUrl = url; this.mUrl = url;
this.mStatus = WebsocketConnectionStatus.NotConnected; this.mStatus = WebsocketConnectionStatus.NotConnected;
this.mConfig = configuration;
if(!this.mConfig)
this.mConfig = new WebsocketNetwork.Configuration();
this.mConfig.Lock();
} }
private WebsocketConnect(): void { private WebsocketConnect(): void {
...@@ -90,7 +120,6 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -90,7 +120,6 @@ export class WebsocketNetwork implements IBasicNetwork {
this.mSocket.onerror = (error) => { this.OnWebsocketOnError(error); }; this.mSocket.onerror = (error) => { this.OnWebsocketOnError(error); };
this.mSocket.onmessage = (e) => { this.OnWebsocketOnMessage(e); }; this.mSocket.onmessage = (e) => { this.OnWebsocketOnMessage(e); };
this.mSocket.onclose = (e) => { this.OnWebsocketOnClose(e); }; this.mSocket.onclose = (e) => { this.OnWebsocketOnClose(e); };
//js websockets connect automatically after creation?
} }
private WebsocketCleanup() : void { private WebsocketCleanup() : void {
this.mSocket.onopen = null; this.mSocket.onopen = null;
...@@ -114,7 +143,33 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -114,7 +143,33 @@ export class WebsocketNetwork implements IBasicNetwork {
this.WebsocketConnect(); this.WebsocketConnect();
} }
} }
private UpdateHeartbeat():void{
if(this.mStatus == WebsocketConnectionStatus.Connected && this.mConfig.Heartbeat > 0)
{
let diff = Date.now() - this.mLastHeartbeat;
if(diff > (this.mConfig.Heartbeat * 1000))
{
//We trigger heatbeat timeouts only for protocol V2
//protocol 1 can receive the heatbeats but
//won't send a reply
//(still helpful to trigger TCP ACK timeout)
if(this.mRemoteProtocolVersion > 1
&& this.mHeartbeatReceived == false)
{
this.TriggerHeartbeatTimeout();
return;
}
this.mLastHeartbeat = Date.now();
this.mHeartbeatReceived = false;
this.SendHeartbeat();
}
}
}
private TriggerHeartbeatTimeout(){
SLog.L("Closing due to heartbeat timeout. Server didn't respond in time.", WebsocketNetwork.LOGTAG);
this.Cleanup();
}
private CheckSleep() : void private CheckSleep() : void
{ {
if (this.mStatus == WebsocketConnectionStatus.Connected if (this.mStatus == WebsocketConnectionStatus.Connected
...@@ -131,11 +186,13 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -131,11 +186,13 @@ export class WebsocketNetwork implements IBasicNetwork {
private OnWebsocketOnOpen() { private OnWebsocketOnOpen() {
SLog.L('onWebsocketOnOpen'); SLog.L('onWebsocketOnOpen', WebsocketNetwork.LOGTAG);
this.mStatus = WebsocketConnectionStatus.Connected; this.mStatus = WebsocketConnectionStatus.Connected;
this.mLastHeartbeat = Date.now();
this.SendVersion();
} }
private OnWebsocketOnClose(event: CloseEvent) { private OnWebsocketOnClose(event: CloseEvent) {
SLog.L('Closed: ' + JSON.stringify(event)); SLog.L('Closed: ' + JSON.stringify(event), WebsocketNetwork.LOGTAG);
if(event.code != 1000) if(event.code != 1000)
{ {
...@@ -154,10 +211,9 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -154,10 +211,9 @@ export class WebsocketNetwork implements IBasicNetwork {
|| this.mStatus == WebsocketConnectionStatus.NotConnected) || this.mStatus == WebsocketConnectionStatus.NotConnected)
return; return;
//browsers will have ArrayBuffer in event.data -> change to byte array //browsers will have ArrayBuffer in event.data -> change to byte array
let evt = NetworkEvent.fromByteArray(new Uint8Array(event.data)); let msg = new Uint8Array(event.data);
this.HandleIncomingEvent(evt); this.ParseMessage(msg);
} }
private OnWebsocketOnError(error) { private OnWebsocketOnError(error) {
//the error event doesn't seem to have any useful information? //the error event doesn't seem to have any useful information?
//browser is expected to call OnClose after this //browser is expected to call OnClose after this
...@@ -244,6 +300,31 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -244,6 +300,31 @@ export class WebsocketNetwork implements IBasicNetwork {
this.mConnections.splice(index, 1); this.mConnections.splice(index, 1);
} }
} }
private ParseMessage(msg:Uint8Array):void{
if(msg.length == 0)
{
}else if(msg[0] == NetEventType.MetaVersion)
{
if (msg.length > 1)
{
this.mRemoteProtocolVersion = msg[1];
}
else
{
SLog.LW("Received an invalid MetaVersion header without content.");
}
}else if(msg[0] == NetEventType.MetaHeartbeat)
{
this.mHeartbeatReceived = true;
}else
{
let evt = NetworkEvent.fromByteArray(msg);
this.HandleIncomingEvent(evt);
}
}
private HandleIncomingEvent(evt: NetworkEvent) { private HandleIncomingEvent(evt: NetworkEvent) {
if (evt.Type == NetEventType.NewConnection) { if (evt.Type == NetEventType.NewConnection) {
...@@ -283,12 +364,37 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -283,12 +364,37 @@ export class WebsocketNetwork implements IBasicNetwork {
while (this.mOutgoingQueue.length > 0) { while (this.mOutgoingQueue.length > 0) {
var evt = this.mOutgoingQueue.shift(); var evt = this.mOutgoingQueue.shift();
//var msg = NetworkEvent.toString(evt); this.SendNetworkEvent(evt);
var msg = NetworkEvent.toByteArray(evt); }
this.mSocket.send(msg); }
private SendHeartbeat() : void
{
let msg = new Uint8Array(1);
msg[0] = NetEventType.MetaHeartbeat;
this.InternalSend(msg);
} }
private SendVersion() :void
{
let msg = new Uint8Array(2);
msg[0] = NetEventType.MetaVersion;
msg[1] = WebsocketNetwork.PROTOCOL_VERSION;
this.InternalSend(msg);
} }
private SendNetworkEvent(evt: NetworkEvent):void
{
var msg = NetworkEvent.toByteArray(evt);
this.InternalSend(msg);
}
private InternalSend(msg: Uint8Array): void
{
this.mSocket.send(msg);
}
private NextConnectionId(): ConnectionId { private NextConnectionId(): ConnectionId {
var result = this.mNextOutgoingConnectionId; var result = this.mNextOutgoingConnectionId;
...@@ -321,8 +427,10 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -321,8 +427,10 @@ export class WebsocketNetwork implements IBasicNetwork {
} }
public Update(): void { public Update(): void {
this.UpdateHeartbeat();
this.CheckSleep(); this.CheckSleep();
} }
public Flush(): void { public Flush(): void {
//ideally we buffer everything and then flush when it is connected as //ideally we buffer everything and then flush when it is connected as
//websockets aren't suppose to be used for realtime communication anyway //websockets aren't suppose to be used for realtime communication anyway
...@@ -395,6 +503,34 @@ export class WebsocketNetwork implements IBasicNetwork { ...@@ -395,6 +503,34 @@ export class WebsocketNetwork implements IBasicNetwork {
} }
} }
export namespace WebsocketNetwork{
export class Configuration{
mHeartbeat:number = 30;
get Heartbeat():number
{
return this.mHeartbeat;
}
set Heartbeat(value:number){
if(this.mLocked)
{
throw new Error("Can't change configuration once used.");
}
this.mHeartbeat = value;
}
mLocked = false;
Lock():void
{
this.mLocked = true;
}
}
}
//Below tests only. Move out later //Below tests only. Move out later
function bufferToString(buffer: Uint8Array): string { function bufferToString(buffer: Uint8Array): string {
......
...@@ -32,23 +32,107 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -32,23 +32,107 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import {SLog, WebRtcNetwork, SignalingConfig, NetworkEvent, ConnectionId, LocalNetwork, WebsocketNetwork} from "../network/index" import {SLog, WebRtcNetwork, SignalingConfig, NetworkEvent, ConnectionId, LocalNetwork, WebsocketNetwork} from "../network/index"
import { MediaConfigurationState, NetworkConfig, MediaConfig } from "../media/index"; import { MediaConfigurationState, NetworkConfig, MediaConfig } from "../media/index";
import { BrowserMediaStream, BrowserMediaNetwork, DeviceApi } from "../media_browser/index"; import { BrowserMediaStream, BrowserMediaNetwork, DeviceApi, BrowserWebRtcCall } from "../media_browser/index";
var CAPI_InitMode = {
//Original mode. Devices will be unknown after startup
Default: 0,
//Waits for the desvice info to come in
//names might be missing though (browser security thing)
WaitForDevices: 1,
//Asks the user for camera / audio access to be able to
//get accurate device information
RequestAccess: 2
};
var CAPI_InitState = {
Uninitialized: 0,
Initializing: 1,
Initialized: 2,
Failed: 3
};
var gCAPI_InitState = CAPI_InitState.Uninitialized;
export function CAPI_InitAsync(initmode)
{
console.debug("CAPI_InitAsync mode: " + initmode);
gCAPI_InitState = CAPI_InitState.Initializing;
let hasDevApi = DeviceApi.IsApiAvailable();
if( hasDevApi && initmode == CAPI_InitMode.WaitForDevices)
{
DeviceApi.Update();
}else if(hasDevApi && initmode == CAPI_InitMode.RequestAccess)
{
DeviceApi.RequestUpdate();
}else{
//either no device access available or not requested. Switch
//to init state immediately without device info
gCAPI_InitState = CAPI_InitState.Initialized;
if(hasDevApi == false)
{
console.debug("Initialized without accessible DeviceAPI");
}
}
}
export function CAPI_PollInitState()
{
//keep checking if the DeviceApi left pending state
//Once completed init is finished.
//Later we might do more here
if(DeviceApi.IsPending == false && gCAPI_InitState == CAPI_InitState.Initializing)
{
gCAPI_InitState = CAPI_InitState.Initialized;
console.debug("Init completed.");
}
return gCAPI_InitState;
}
/**
*
* @param loglevel
* None = 0,
* Errors = 1,
* Warnings = 2,
* Verbose = 3
*/
export function CAPI_SLog_SetLogLevel(loglevel:number)
{
if(loglevel < 0 || loglevel > 3)
{
SLog.LogError("Invalid log level " + loglevel);
return;
}
SLog.SetLogLevel(loglevel);
}
var gCAPIWebRtcNetworkInstances: { [id: number]: WebRtcNetwork }= {}; var gCAPI_WebRtcNetwork_Instances: { [id: number]: WebRtcNetwork }= {};
var gCAPIWebRtcNetworkInstancesNextIndex = 1; var gCAPI_WebRtcNetwork_InstancesNextIndex = 1;
export function CAPIWebRtcNetworkIsAvailable() { export function CAPI_WebRtcNetwork_IsAvailable() {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) //used by C# component to check if this plugin is loaded.
//can only go wrong due to programming error / packaging
if(WebRtcNetwork && WebsocketNetwork)
return true;
return false;
}
export function CAPI_WebRtcNetwork_IsBrowserSupported()
{
if (RTCPeerConnection && RTCDataChannel)
return true; return true;
SLog.LE("Browser doesn't seem to support a modern WebRTC API");
return false; return false;
} }
export function CAPIWebRtcNetworkCreate(lConfiguration: string) {
var lIndex = gCAPIWebRtcNetworkInstancesNextIndex;
gCAPIWebRtcNetworkInstancesNextIndex++; export function CAPI_WebRtcNetwork_Create(lConfiguration: string) {
var lIndex = gCAPI_WebRtcNetwork_InstancesNextIndex;
gCAPI_WebRtcNetwork_InstancesNextIndex++;
var signaling_class = "LocalNetwork"; var signaling_class = "LocalNetwork";
var signaling_param: any = null; var signaling_param: any = null;
...@@ -90,83 +174,87 @@ export function CAPIWebRtcNetworkCreate(lConfiguration: string) { ...@@ -90,83 +174,87 @@ export function CAPIWebRtcNetworkCreate(lConfiguration: string) {
let rtcConfiguration: RTCConfiguration = { iceServers: iceServers }; let rtcConfiguration: RTCConfiguration = { iceServers: iceServers };
gCAPIWebRtcNetworkInstances[lIndex] = new WebRtcNetwork(signalingConfig, rtcConfiguration); gCAPI_WebRtcNetwork_Instances[lIndex] = new WebRtcNetwork(signalingConfig, rtcConfiguration);
} else { } else {
SLog.LogWarning("Parsing configuration failed. Configuration: " + lConfiguration); SLog.LogWarning("Parsing configuration failed. Configuration: " + lConfiguration);
return -1; return -1;
} }
} }
//gCAPIWebRtcNetworkInstances[lIndex].OnLog = function (lMsg) { //gCAPI_WebRtcNetwork_Instances[lIndex].OnLog = function (lMsg) {
// console.debug(lMsg); // console.debug(lMsg);
//}; //};
return lIndex; return lIndex;
} }
export function CAPIWebRtcNetworkRelease(lIndex: number) { export function CAPI_WebRtcNetwork_Release(lIndex: number) {
if (lIndex in gCAPIWebRtcNetworkInstances) { if (lIndex in gCAPI_WebRtcNetwork_Instances) {
gCAPIWebRtcNetworkInstances[lIndex].Dispose(); gCAPI_WebRtcNetwork_Instances[lIndex].Dispose();
delete gCAPIWebRtcNetworkInstances[lIndex]; delete gCAPI_WebRtcNetwork_Instances[lIndex];
} }
} }
export function CAPIWebRtcNetworkConnect(lIndex: number, lRoom: string) { export function CAPI_WebRtcNetwork_Connect(lIndex: number, lRoom: string) {
return gCAPIWebRtcNetworkInstances[lIndex].Connect(lRoom); return gCAPI_WebRtcNetwork_Instances[lIndex].Connect(lRoom);
} }
export function CAPIWebRtcNetworkStartServer(lIndex: number, lRoom: string) { export function CAPI_WebRtcNetwork_StartServer(lIndex: number, lRoom: string) {
gCAPIWebRtcNetworkInstances[lIndex].StartServer(lRoom); gCAPI_WebRtcNetwork_Instances[lIndex].StartServer(lRoom);
} }
export function CAPIWebRtcNetworkStopServer(lIndex: number) { export function CAPI_WebRtcNetwork_StopServer(lIndex: number) {
gCAPIWebRtcNetworkInstances[lIndex].StopServer(); gCAPI_WebRtcNetwork_Instances[lIndex].StopServer();
} }
export function CAPIWebRtcNetworkDisconnect(lIndex: number, lConnectionId: number) { export function CAPI_WebRtcNetwork_Disconnect(lIndex: number, lConnectionId: number) {
gCAPIWebRtcNetworkInstances[lIndex].Disconnect(new ConnectionId(lConnectionId)); gCAPI_WebRtcNetwork_Instances[lIndex].Disconnect(new ConnectionId(lConnectionId));
} }
export function CAPIWebRtcNetworkShutdown(lIndex: number) { export function CAPI_WebRtcNetwork_Shutdown(lIndex: number) {
gCAPIWebRtcNetworkInstances[lIndex].Shutdown(); gCAPI_WebRtcNetwork_Instances[lIndex].Shutdown();
} }
export function CAPIWebRtcNetworkUpdate(lIndex: number) { export function CAPI_WebRtcNetwork_Update(lIndex: number) {
gCAPIWebRtcNetworkInstances[lIndex].Update(); gCAPI_WebRtcNetwork_Instances[lIndex].Update();
} }
export function CAPIWebRtcNetworkFlush(lIndex: number) { export function CAPI_WebRtcNetwork_Flush(lIndex: number) {
gCAPIWebRtcNetworkInstances[lIndex].Flush(); gCAPI_WebRtcNetwork_Instances[lIndex].Flush();
} }
export function CAPIWebRtcNetworkSendData(lIndex: number, lConnectionId: number, lUint8ArrayData: Uint8Array, lReliable: boolean) { export function CAPI_WebRtcNetwork_SendData(lIndex: number, lConnectionId: number, lUint8ArrayData: Uint8Array, lReliable: boolean) {
gCAPIWebRtcNetworkInstances[lIndex].SendData(new ConnectionId(lConnectionId), lUint8ArrayData, lReliable); gCAPI_WebRtcNetwork_Instances[lIndex].SendData(new ConnectionId(lConnectionId), lUint8ArrayData, lReliable);
} }
//helper for emscripten //helper for emscripten
export function CAPIWebRtcNetworkSendDataEm(lIndex: number, lConnectionId: number, lUint8ArrayData: Uint8Array, lUint8ArrayDataOffset: number, lUint8ArrayDataLength: number, lReliable: boolean) { export function CAPI_WebRtcNetwork_SendDataEm(lIndex: number, lConnectionId: number, lUint8ArrayData: Uint8Array, lUint8ArrayDataOffset: number, lUint8ArrayDataLength: number, lReliable: boolean) {
//console.debug("SendDataEm: " + lReliable + " length " + lUint8ArrayDataLength + " to " + lConnectionId); //console.debug("SendDataEm: " + lReliable + " length " + lUint8ArrayDataLength + " to " + lConnectionId);
var arrayBuffer = new Uint8Array(lUint8ArrayData.buffer, lUint8ArrayDataOffset, lUint8ArrayDataLength); var arrayBuffer = new Uint8Array(lUint8ArrayData.buffer, lUint8ArrayDataOffset, lUint8ArrayDataLength);
return gCAPIWebRtcNetworkInstances[lIndex].SendData(new ConnectionId(lConnectionId), arrayBuffer, lReliable); return gCAPI_WebRtcNetwork_Instances[lIndex].SendData(new ConnectionId(lConnectionId), arrayBuffer, lReliable);
}
export function CAPI_WebRtcNetwork_GetBufferedAmount(lIndex: number, lConnectionId: number, lReliable: boolean) {
return gCAPI_WebRtcNetwork_Instances[lIndex].GetBufferedAmount(new ConnectionId(lConnectionId), lReliable);
} }
export function CAPIWebRtcNetworkDequeue(lIndex: number): NetworkEvent { export function CAPI_WebRtcNetwork_Dequeue(lIndex: number): NetworkEvent {
return gCAPIWebRtcNetworkInstances[lIndex].Dequeue(); return gCAPI_WebRtcNetwork_Instances[lIndex].Dequeue();
} }
export function CAPIWebRtcNetworkPeek(lIndex: number): NetworkEvent { export function CAPI_WebRtcNetwork_Peek(lIndex: number): NetworkEvent {
return gCAPIWebRtcNetworkInstances[lIndex].Peek(); return gCAPI_WebRtcNetwork_Instances[lIndex].Peek();
} }
/**Allows to peek into the next event to figure out its length and allocate /**Allows to peek into the next event to figure out its length and allocate
* the memory needed to store it before calling * the memory needed to store it before calling
* CAPIWebRtcNetworkDequeueEm * CAPI_WebRtcNetwork_DequeueEm
* *
* @param {type} lIndex * @param {type} lIndex
* @returns {Number} * @returns {Number}
*/ */
export function CAPIWebRtcNetworkPeekEventDataLength(lIndex) { export function CAPI_WebRtcNetwork_PeekEventDataLength(lIndex) {
var lNetEvent = gCAPIWebRtcNetworkInstances[lIndex].Peek(); var lNetEvent = gCAPI_WebRtcNetwork_Instances[lIndex].Peek();
return CAPIWebRtcNetworkCheckEventLength(lNetEvent); return CAPI_WebRtcNetwork_CheckEventLength(lNetEvent);
} }
//helper //helper
export function CAPIWebRtcNetworkCheckEventLength(lNetEvent: NetworkEvent) { export function CAPI_WebRtcNetwork_CheckEventLength(lNetEvent: NetworkEvent) {
if (lNetEvent == null) { if (lNetEvent == null) {
//invalid event //invalid event
return -1; return -1;
...@@ -185,7 +273,7 @@ export function CAPIWebRtcNetworkCheckEventLength(lNetEvent: NetworkEvent) { ...@@ -185,7 +273,7 @@ export function CAPIWebRtcNetworkCheckEventLength(lNetEvent: NetworkEvent) {
return lNetEvent.RawData.length; return lNetEvent.RawData.length;
} }
} }
export function CAPIWebRtcNetworkEventDataToUint8Array(data: any, dataUint8Array: Uint8Array, dataOffset: number, dataLength: number) { export function CAPI_WebRtcNetwork_EventDataToUint8Array(data: any, dataUint8Array: Uint8Array, dataOffset: number, dataLength: number) {
//data can be null, string or Uint8Array //data can be null, string or Uint8Array
//return value will be the length of data we used //return value will be the length of data we used
if (data == null) { if (data == null) {
...@@ -211,8 +299,8 @@ export function CAPIWebRtcNetworkEventDataToUint8Array(data: any, dataUint8Array ...@@ -211,8 +299,8 @@ export function CAPIWebRtcNetworkEventDataToUint8Array(data: any, dataUint8Array
//Version for emscripten or anything that doesn't have a garbage collector. //Version for emscripten or anything that doesn't have a garbage collector.
// The memory for everything needs to be allocated before the call. // The memory for everything needs to be allocated before the call.
export function CAPIWebRtcNetworkDequeueEm(lIndex: number, lTypeIntArray: Int32Array, lTypeIntIndex: number, lConidIntArray: Int32Array, lConidIndex: number, lDataUint8Array: Uint8Array, lDataOffset: number, lDataLength: number, lDataLenIntArray: Int32Array, lDataLenIntIndex: number) { export function CAPI_WebRtcNetwork_DequeueEm(lIndex: number, lTypeIntArray: Int32Array, lTypeIntIndex: number, lConidIntArray: Int32Array, lConidIndex: number, lDataUint8Array: Uint8Array, lDataOffset: number, lDataLength: number, lDataLenIntArray: Int32Array, lDataLenIntIndex: number) {
var nEvt = CAPIWebRtcNetworkDequeue(lIndex); var nEvt = CAPI_WebRtcNetwork_Dequeue(lIndex);
if (nEvt == null) if (nEvt == null)
return false; return false;
...@@ -220,13 +308,13 @@ export function CAPIWebRtcNetworkDequeueEm(lIndex: number, lTypeIntArray: Int32A ...@@ -220,13 +308,13 @@ export function CAPIWebRtcNetworkDequeueEm(lIndex: number, lTypeIntArray: Int32A
lConidIntArray[lConidIndex] = nEvt.ConnectionId.id; lConidIntArray[lConidIndex] = nEvt.ConnectionId.id;
//console.debug("event" + nEvt.netEventType); //console.debug("event" + nEvt.netEventType);
var length = CAPIWebRtcNetworkEventDataToUint8Array(nEvt.RawData, lDataUint8Array, lDataOffset, lDataLength); var length = CAPI_WebRtcNetwork_EventDataToUint8Array(nEvt.RawData, lDataUint8Array, lDataOffset, lDataLength);
lDataLenIntArray[lDataLenIntIndex] = length; //return the length if so the user knows how much of the given array is used lDataLenIntArray[lDataLenIntIndex] = length; //return the length if so the user knows how much of the given array is used
return true; return true;
} }
export function CAPIWebRtcNetworkPeekEm(lIndex: number, lTypeIntArray: Int32Array, lTypeIntIndex: number, lConidIntArray: Int32Array, lConidIndex: number, lDataUint8Array: Uint8Array, lDataOffset: number, lDataLength: number, lDataLenIntArray: Int32Array, lDataLenIntIndex: number) { export function CAPI_WebRtcNetwork_PeekEm(lIndex: number, lTypeIntArray: Int32Array, lTypeIntIndex: number, lConidIntArray: Int32Array, lConidIndex: number, lDataUint8Array: Uint8Array, lDataOffset: number, lDataLength: number, lDataLenIntArray: Int32Array, lDataLenIntIndex: number) {
var nEvt = CAPIWebRtcNetworkPeek(lIndex); var nEvt = CAPI_WebRtcNetwork_Peek(lIndex);
if (nEvt == null) if (nEvt == null)
return false; return false;
...@@ -234,7 +322,7 @@ export function CAPIWebRtcNetworkPeekEm(lIndex: number, lTypeIntArray: Int32Arra ...@@ -234,7 +322,7 @@ export function CAPIWebRtcNetworkPeekEm(lIndex: number, lTypeIntArray: Int32Arra
lConidIntArray[lConidIndex] = nEvt.ConnectionId.id; lConidIntArray[lConidIndex] = nEvt.ConnectionId.id;
//console.debug("event" + nEvt.netEventType); //console.debug("event" + nEvt.netEventType);
var length = CAPIWebRtcNetworkEventDataToUint8Array(nEvt.RawData, lDataUint8Array, lDataOffset, lDataLength); var length = CAPI_WebRtcNetwork_EventDataToUint8Array(nEvt.RawData, lDataUint8Array, lDataOffset, lDataLength);
lDataLenIntArray[lDataLenIntIndex] = length; //return the length if so the user knows how much of the given array is used lDataLenIntArray[lDataLenIntIndex] = length; //return the length if so the user knows how much of the given array is used
return true; return true;
...@@ -242,22 +330,30 @@ export function CAPIWebRtcNetworkPeekEm(lIndex: number, lTypeIntArray: Int32Arra ...@@ -242,22 +330,30 @@ export function CAPIWebRtcNetworkPeekEm(lIndex: number, lTypeIntArray: Int32Arra
export function CAPIMediaNetwork_IsAvailable() : boolean{ export function CAPI_MediaNetwork_IsAvailable() : boolean{
if(BrowserMediaNetwork && BrowserWebRtcCall)
return true;
return false;
}
export function CAPI_MediaNetwork_HasUserMedia() : boolean{
if(navigator && navigator.mediaDevices)
return true; return true;
return false;
} }
export function CAPIMediaNetwork_Create(lJsonConfiguration):number { export function CAPI_MediaNetwork_Create(lJsonConfiguration):number {
let config = new NetworkConfig(); let config = new NetworkConfig();
config = JSON.parse(lJsonConfiguration); config = JSON.parse(lJsonConfiguration);
let mediaNetwork = new BrowserMediaNetwork(config); let mediaNetwork = new BrowserMediaNetwork(config);
var lIndex = gCAPIWebRtcNetworkInstancesNextIndex; var lIndex = gCAPI_WebRtcNetwork_InstancesNextIndex;
gCAPIWebRtcNetworkInstancesNextIndex++; gCAPI_WebRtcNetwork_InstancesNextIndex++;
gCAPIWebRtcNetworkInstances[lIndex] = mediaNetwork; gCAPI_WebRtcNetwork_Instances[lIndex] = mediaNetwork;
return lIndex; return lIndex;
} }
...@@ -268,7 +364,7 @@ export function CAPIMediaNetwork_Create(lJsonConfiguration):number { ...@@ -268,7 +364,7 @@ export function CAPIMediaNetwork_Create(lJsonConfiguration):number {
//Configure(config: MediaConfig): void; //Configure(config: MediaConfig): void;
export function CAPIMediaNetwork_Configure(lIndex:number, audio: boolean, video: boolean, export function CAPI_MediaNetwork_Configure(lIndex:number, audio: boolean, video: boolean,
minWidth: number, minHeight: number, minWidth: number, minHeight: number,
maxWidth: number, maxHeight: number, maxWidth: number, maxHeight: number,
idealWidth: number, idealHeight: number, idealWidth: number, idealHeight: number,
...@@ -292,38 +388,38 @@ export function CAPIMediaNetwork_Configure(lIndex:number, audio: boolean, video: ...@@ -292,38 +388,38 @@ export function CAPIMediaNetwork_Configure(lIndex:number, audio: boolean, video:
config.FrameUpdates = true; config.FrameUpdates = true;
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
mediaNetwork.Configure(config); mediaNetwork.Configure(config);
} }
//GetConfigurationState(): MediaConfigurationState; //GetConfigurationState(): MediaConfigurationState;
export function CAPIMediaNetwork_GetConfigurationState(lIndex: number): number{ export function CAPI_MediaNetwork_GetConfigurationState(lIndex: number): number{
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
return mediaNetwork.GetConfigurationState() as number; return mediaNetwork.GetConfigurationState() as number;
} }
//Note: not yet glued to the C# version! //Note: not yet glued to the C# version!
//GetConfigurationError(): string; //GetConfigurationError(): string;
export function CAPIMediaNetwork_GetConfigurationError(lIndex: number): string { export function CAPI_MediaNetwork_GetConfigurationError(lIndex: number): string {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
return mediaNetwork.GetConfigurationError(); return mediaNetwork.GetConfigurationError();
} }
//ResetConfiguration(): void; //ResetConfiguration(): void;
export function CAPIMediaNetwork_ResetConfiguration(lIndex: number) : void { export function CAPI_MediaNetwork_ResetConfiguration(lIndex: number) : void {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
return mediaNetwork.ResetConfiguration(); return mediaNetwork.ResetConfiguration();
} }
//TryGetFrame(id: ConnectionId): RawFrame; //TryGetFrame(id: ConnectionId): RawFrame;
export function CAPIMediaNetwork_TryGetFrame(lIndex: number, lConnectionId: number, export function CAPI_MediaNetwork_TryGetFrame(lIndex: number, lConnectionId: number,
lWidthInt32Array: Int32Array, lWidthIntArrayIndex: number, lWidthInt32Array: Int32Array, lWidthIntArrayIndex: number,
lHeightInt32Array: Int32Array, lHeightIntArrayIndex: number, lHeightInt32Array: Int32Array, lHeightIntArrayIndex: number,
lBufferUint8Array: Uint8Array, lBufferUint8ArrayOffset: number, lBufferUint8ArrayLength: number): boolean lBufferUint8Array: Uint8Array, lBufferUint8ArrayOffset: number, lBufferUint8ArrayLength: number): boolean
{ {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
let frame = mediaNetwork.TryGetFrame(new ConnectionId(lConnectionId)); let frame = mediaNetwork.TryGetFrame(new ConnectionId(lConnectionId));
if (frame == null || frame.Buffer == null) { if (frame == null || frame.Buffer == null) {
...@@ -343,8 +439,8 @@ export function CAPIMediaNetwork_TryGetFrame(lIndex: number, lConnectionId: numb ...@@ -343,8 +439,8 @@ export function CAPIMediaNetwork_TryGetFrame(lIndex: number, lConnectionId: numb
} }
//Returns the frame buffer size or -1 if no frame is available //Returns the frame buffer size or -1 if no frame is available
export function CAPIMediaNetwork_TryGetFrameDataLength(lIndex: number, connectionId: number) : number { export function CAPI_MediaNetwork_TryGetFrameDataLength(lIndex: number, connectionId: number) : number {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
let frame = mediaNetwork.PeekFrame(new ConnectionId(connectionId)); let frame = mediaNetwork.PeekFrame(new ConnectionId(connectionId));
let length: number = -1; let length: number = -1;
...@@ -358,32 +454,32 @@ export function CAPIMediaNetwork_TryGetFrameDataLength(lIndex: number, connectio ...@@ -358,32 +454,32 @@ export function CAPIMediaNetwork_TryGetFrameDataLength(lIndex: number, connectio
//SLog.L("data length:" + length); //SLog.L("data length:" + length);
return length; return length;
} }
export function CAPIMediaNetwork_SetVolume(lIndex: number, volume: number, connectionId: number) : void { export function CAPI_MediaNetwork_SetVolume(lIndex: number, volume: number, connectionId: number) : void {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
mediaNetwork.SetVolume(volume, new ConnectionId(connectionId)); mediaNetwork.SetVolume(volume, new ConnectionId(connectionId));
} }
export function CAPIMediaNetwork_HasAudioTrack(lIndex: number, connectionId: number): boolean export function CAPI_MediaNetwork_HasAudioTrack(lIndex: number, connectionId: number): boolean
{ {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
return mediaNetwork.HasAudioTrack(new ConnectionId(connectionId)); return mediaNetwork.HasAudioTrack(new ConnectionId(connectionId));
} }
export function CAPIMediaNetwork_HasVideoTrack(lIndex: number, connectionId: number): boolean { export function CAPI_MediaNetwork_HasVideoTrack(lIndex: number, connectionId: number): boolean {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
return mediaNetwork.HasVideoTrack(new ConnectionId(connectionId)); return mediaNetwork.HasVideoTrack(new ConnectionId(connectionId));
} }
export function CAPIMediaNetwork_SetMute(lIndex: number, value: boolean) export function CAPI_MediaNetwork_SetMute(lIndex: number, value: boolean)
{ {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
mediaNetwork.SetMute(value); mediaNetwork.SetMute(value);
} }
export function CAPIMediaNetwork_IsMute(lIndex: number) export function CAPI_MediaNetwork_IsMute(lIndex: number)
{ {
let mediaNetwork = gCAPIWebRtcNetworkInstances[lIndex] as BrowserMediaNetwork; let mediaNetwork = gCAPI_WebRtcNetwork_Instances[lIndex] as BrowserMediaNetwork;
return mediaNetwork.IsMute(); return mediaNetwork.IsMute();
} }
...@@ -417,20 +513,3 @@ export function CAPI_DeviceApi_Devices_Get(index:number):string{ ...@@ -417,20 +513,3 @@ export function CAPI_DeviceApi_Devices_Get(index:number):string{
return ""; return "";
} }
} }
\ No newline at end of file
/**
*
* @param loglevel
* None = 0,
* Errors = 1,
* Warnings = 2,
* Verbose = 3
*/
export function CAPI_SLog_SetLogLevel(loglevel:number)
{
if(loglevel < 0 || loglevel > 3)
{
SLog.LogError("Invalid log level " + loglevel);
return;
}
SLog.SetLogLevel(loglevel);
}
\ No newline at end of file
...@@ -74,7 +74,9 @@ describe("BrowserApiTest_MediaStreamApi", () => { ...@@ -74,7 +74,9 @@ describe("BrowserApiTest_MediaStreamApi", () => {
console.log(device.kind + ": " + device.label + console.log(device.kind + ": " + device.label +
" id = " + device.deviceId); " id = " + device.deviceId);
}); });
gStream.stop(); gStream.getTracks().forEach(t => {
t.stop();
});
done(); done();
}) })
.catch(function(err) { .catch(function(err) {
...@@ -109,7 +111,9 @@ describe("BrowserApiTest_MediaStreamApi", () => { ...@@ -109,7 +111,9 @@ describe("BrowserApiTest_MediaStreamApi", () => {
console.log(device.kind + ": " + device.label + console.log(device.kind + ": " + device.label +
" id = " + device.deviceId); " id = " + device.deviceId);
}); });
gStream.stop(); gStream.getTracks().forEach(t => {
t.stop();
});
done(); done();
}) })
.catch(function(err) { .catch(function(err) {
......
...@@ -31,6 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -31,6 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import {DeviceApi, CAPI_DeviceApi_Update, import {DeviceApi, CAPI_DeviceApi_Update,
CAPI_DeviceApi_RequestUpdate, CAPI_DeviceApi_Devices_Length, CAPI_DeviceApi_RequestUpdate, CAPI_DeviceApi_Devices_Length,
CAPI_DeviceApi_Devices_Get} from "../awrtc/index" CAPI_DeviceApi_Devices_Get} from "../awrtc/index"
export function DeviceApiTest_export() export function DeviceApiTest_export()
{ {
...@@ -97,7 +98,7 @@ describe("DeviceApiTest", () => { ...@@ -97,7 +98,7 @@ describe("DeviceApiTest", () => {
//should have original label now //should have original label now
expect(devices2[key1].label).not.toBe("videodevice 1"); expect(devices2[key1].label).not.toBe("videodevice 1");
//and not be guessed anymore //and not be guessed anymore
expect(devices2[key1].isLabelGuessed).toBe(false); expect(devices2[key1].isLabelGuessed).toBe(false, "Chrome fails this now. Likely due to file://. Check for better test setup");
update2complete = true; update2complete = true;
DeviceApi.Reset(); DeviceApi.Reset();
......
...@@ -30,7 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -30,7 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import { WebsocketTest } from "WebsocketNetworkTest"; import { WebsocketTest } from "WebsocketNetworkTest";
import { IBasicNetworkTest } from "helper/IBasicNetworkTest"; import { IBasicNetworkTest } from "helper/IBasicNetworkTest";
import { NetworkEvent, IBasicNetwork, NetEventType, WebsocketNetwork, import { NetworkEvent, IBasicNetwork, NetEventType, WebsocketNetwork,
ConnectionId, SignalingConfig, LocalNetwork, WebRtcNetwork } ConnectionId, SignalingConfig, LocalNetwork, WebRtcNetwork, IWebRtcNetwork }
from "../awrtc/index"; from "../awrtc/index";
export class WebRtcNetworkTest extends IBasicNetworkTest { export class WebRtcNetworkTest extends IBasicNetworkTest {
...@@ -56,6 +56,46 @@ export class WebRtcNetworkTest extends IBasicNetworkTest { ...@@ -56,6 +56,46 @@ export class WebRtcNetworkTest extends IBasicNetworkTest {
this.mUrl = WebsocketTest.sUrl; this.mUrl = WebsocketTest.sUrl;
this.mUseWebsockets = WebRtcNetworkTest.mAlwaysUseWebsockets; this.mUseWebsockets = WebRtcNetworkTest.mAlwaysUseWebsockets;
}) })
it("GetBufferedAmount", (done) => {
var srv: IWebRtcNetwork;
var address: string;
var srvToCltId: ConnectionId;
var clt: IWebRtcNetwork;
var cltToSrvId: ConnectionId;
var evt: NetworkEvent;
this.thenAsync((finished) => {
this._CreateServerClient((rsrv, raddress, rsrvToCltId, rclt, rcltToSrvId) => {
srv = rsrv as IWebRtcNetwork;
address = raddress;
srvToCltId = rsrvToCltId;
clt = rclt as IWebRtcNetwork;
cltToSrvId = rcltToSrvId;
finished();
});
});
this.then(() => {
//TODO: more detailed testing by actually triggering the buffer to fill?
//might be tricky as this is very system dependent
let buf:number;
buf = srv.GetBufferedAmount(srvToCltId, false);
expect(buf).toBe(0);
buf = srv.GetBufferedAmount(srvToCltId, true);
expect(buf).toBe(0);
buf = clt.GetBufferedAmount(cltToSrvId, false);
expect(buf).toBe(0);
buf = clt.GetBufferedAmount(cltToSrvId, true);
expect(buf).toBe(0);
done();
});
this.start();
});
it("SharedAddress", (done) => { it("SharedAddress", (done) => {
//turn off websockets and use shared websockets for this test as local network doesn't support shared mode //turn off websockets and use shared websockets for this test as local network doesn't support shared mode
......
...@@ -40,6 +40,7 @@ export class WebsocketTest extends IBasicNetworkTest { ...@@ -40,6 +40,7 @@ export class WebsocketTest extends IBasicNetworkTest {
//public static sUrl = 'ws://localhost:12776/test'; //public static sUrl = 'ws://localhost:12776/test';
//public static sUrlShared = 'ws://localhost:12776/testshared'; //public static sUrlShared = 'ws://localhost:12776/testshared';
public static sUrl = 'ws://signaling.because-why-not.com'; public static sUrl = 'ws://signaling.because-why-not.com';
//public static sUrl = 'ws://192.168.1.3:12776';
public static sUrlShared = 'ws://signaling.because-why-not.com/testshared'; public static sUrlShared = 'ws://signaling.because-why-not.com/testshared';
//any url to simulate offline server //any url to simulate offline server
public static sBadUrl = 'ws://localhost:13776'; public static sBadUrl = 'ws://localhost:13776';
...@@ -54,6 +55,42 @@ export class WebsocketTest extends IBasicNetworkTest { ...@@ -54,6 +55,42 @@ export class WebsocketTest extends IBasicNetworkTest {
this.mUrl = WebsocketTest.sUrl; this.mUrl = WebsocketTest.sUrl;
}); });
//can only be done manually so far
xit("Timeout", (done) => {
//this needs to be a local test server
//that can be disconnected to test the timeout
this.mUrl = "ws://192.168.1.3:12776";
var evt: NetworkEvent;
var srv: WebsocketNetwork;
var address;
this.thenAsync((finished) => {
this._CreateServerNetwork((rsrv, raddress) => {
srv = rsrv;
address = raddress;
finished();
});
});
this.thenAsync((finished) => {
console.log("Server ready at " + address);
expect(srv).not.toBeNull();
expect(address).not.toBeNull();
console.debug("Waiting for timeout");
this.waitForEvent(srv, finished, 120000);
});
this.then(() => {
console.log("Timeout over");
evt = srv.Dequeue();
expect(evt).not.toBeNull();
expect(evt.Type).toBe(NetEventType.ServerClosed);
expect(srv.getStatus()).toBe(WebsocketConnectionStatus.NotConnected);
done();
});
this.start();
}, 130000);
it("SharedAddress", (done) => { it("SharedAddress", (done) => {
this.mUrl = WebsocketTest.sUrlShared; this.mUrl = WebsocketTest.sUrlShared;
......
...@@ -28,7 +28,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ...@@ -28,7 +28,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import { BasicNetworkTestBase, Task } from "./BasicNetworkTestBase"; import { BasicNetworkTestBase, Task } from "./BasicNetworkTestBase";
import { IBasicNetwork, NetworkEvent, NetEventType, ConnectionId, Encoding } from "../../awrtc/network/index"; import { IBasicNetwork, NetworkEvent, NetEventType, ConnectionId, Encoding, SLog, SLogLevel } from "../../awrtc/network/index";
export abstract class IBasicNetworkTest extends BasicNetworkTestBase { export abstract class IBasicNetworkTest extends BasicNetworkTestBase {
...@@ -36,10 +36,12 @@ export abstract class IBasicNetworkTest extends BasicNetworkTestBase { ...@@ -36,10 +36,12 @@ export abstract class IBasicNetworkTest extends BasicNetworkTestBase {
super.setup(); super.setup();
let originalTimeout = 5000; let originalTimeout = 5000;
beforeEach(() => { beforeEach(() => {
SLog.RequestLogLevel(SLogLevel.Info);
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = this.mDefaultWaitTimeout + 5000; jasmine.DEFAULT_TIMEOUT_INTERVAL = this.mDefaultWaitTimeout + 5000;
}); });
afterEach(() => { afterEach(() => {
console.debug("Test shutting down ...");
this.ShutdownAll(); this.ShutdownAll();
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = this.mDefaultWaitTimeout + 5000; jasmine.DEFAULT_TIMEOUT_INTERVAL = this.mDefaultWaitTimeout + 5000;
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
"WebRtcNetworkTest.ts", "WebRtcNetworkTest.ts",
"CallTest.ts", "CallTest.ts",
"LocalNetworkTest.ts", "LocalNetworkTest.ts",
"MediaNetworkTest.ts" "MediaNetworkTest.ts",
"DeviceApiTest.ts",
"BrowserApiTest.ts"
] ]
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment