Commit dad25b72 by Christoph

V0.9852

* added width / height to the callapp ui for testing * third party dependencies updated * added sdp munging example in WebRtcPeer.ts (inactive by default)
parent 1690d7cc
...@@ -16,6 +16,11 @@ ...@@ -16,6 +16,11 @@
<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">
<div class="resolution">
width: <input type="text" class="callapp_width" size="4" value="1280"> </input>
height:<input type="text" class="callapp_height" size="4" value="720"> </input>
</div>
<button class="callapp_button"> Join </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>
......
{ {
"name": "awrtc_browser", "name": "awrtc_browser",
"version": "1.985.1", "version": "1.985.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"version": "1.985.1", "version": "1.985.2",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"devDependencies": { "devDependencies": {
"@types/jasmine": "^2.8.17", "@types/jasmine": "^2.8.17",
......
{ {
"name": "awrtc_browser", "name": "awrtc_browser",
"version": "1.985.1", "version": "1.985.2",
"description": "Compatible browser implementation to the Unity asset WebRTC Video Chat. Try examples in build folder", "description": "Compatible browser implementation to the Unity asset WebRTC Video Chat. Try examples in build folder",
"author": "because-why-not.com Limited", "author": "because-why-not.com Limited",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
......
...@@ -29,6 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -29,6 +29,7 @@ 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 { MediaConfig } from "../awrtc/index";
/** /**
* Main (and most complicated) example for using BrowserWebRtcCall. * Main (and most complicated) example for using BrowserWebRtcCall.
...@@ -98,10 +99,9 @@ export class CallApp ...@@ -98,10 +99,9 @@ export class CallApp
} }
public Start(address, audio, video) : void public Start(address: string) : void
{ {
if(this.mCall != null) if(this.mCall != null)
this.Stop(); this.Stop();
...@@ -112,11 +112,7 @@ export class CallApp ...@@ -112,11 +112,7 @@ export class CallApp
console.log("Using signaling server url: " + this.mNetConfig.SignalingUrl); console.log("Using signaling server url: " + this.mNetConfig.SignalingUrl);
//create media configuration //create media configuration
var config = new awrtc.MediaConfig(); var config = this.mMediaConfig;
config.Audio = audio;
config.Video = video;
config.IdealWidth = 640;
config.IdealHeight = 480;
config.IdealFps = 30; config.IdealFps = 30;
//For usage in HTML set FrameUpdates to false and wait for MediaUpdate to //For usage in HTML set FrameUpdates to false and wait for MediaUpdate to
...@@ -268,12 +264,13 @@ export class CallApp ...@@ -268,12 +264,13 @@ export class CallApp
//UI calls. should be moved out into its own class later //UI calls. should be moved out into its own class later
private mAudio; private mMediaConfig : MediaConfig;
private mVideo;
private mAutostart; private mAutostart;
private mUiAddress: HTMLInputElement; private mUiAddress: HTMLInputElement;
private mUiAudio: HTMLInputElement; private mUiAudio: HTMLInputElement;
private mUiVideo: HTMLInputElement; private mUiVideo: HTMLInputElement;
private mUiWidth: HTMLInputElement;
private mUiHeight: HTMLInputElement;
private mUiButton: HTMLButtonElement; private mUiButton: HTMLButtonElement;
private mUiUrl: HTMLElement; private mUiUrl: HTMLElement;
private mUiLocalVideoParent: HTMLElement; private mUiLocalVideoParent: HTMLElement;
...@@ -281,9 +278,13 @@ export class CallApp ...@@ -281,9 +278,13 @@ export class CallApp
public setupUi(parent : HTMLElement) public setupUi(parent : HTMLElement)
{ {
this.mMediaConfig = new MediaConfig();
this.mUiAddress = parent.querySelector<HTMLInputElement>(".callapp_address"); this.mUiAddress = parent.querySelector<HTMLInputElement>(".callapp_address");
this.mUiAudio = parent.querySelector<HTMLInputElement>(".callapp_send_audio"); this.mUiAudio = parent.querySelector<HTMLInputElement>(".callapp_send_audio");
this.mUiVideo = parent.querySelector<HTMLInputElement>(".callapp_send_video"); this.mUiVideo = parent.querySelector<HTMLInputElement>(".callapp_send_video");
this.mUiWidth = parent.querySelector<HTMLInputElement>(".callapp_width");
this.mUiHeight = parent.querySelector<HTMLInputElement>(".callapp_height");
this.mUiUrl = parent.querySelector<HTMLParagraphElement>(".callapp_url"); this.mUiUrl = parent.querySelector<HTMLParagraphElement>(".callapp_url");
this.mUiButton = parent.querySelector<HTMLInputElement>(".callapp_button"); this.mUiButton = parent.querySelector<HTMLInputElement>(".callapp_button");
this.mUiLocalVideoParent = parent.querySelector<HTMLParagraphElement>(".callapp_local_video"); this.mUiLocalVideoParent = parent.querySelector<HTMLParagraphElement>(".callapp_local_video");
...@@ -292,17 +293,9 @@ export class CallApp ...@@ -292,17 +293,9 @@ export class CallApp
this.mUiVideo.onclick = this.Ui_OnUpdate; this.mUiVideo.onclick = this.Ui_OnUpdate;
this.mUiAddress.onkeyup = this.Ui_OnUpdate; this.mUiAddress.onkeyup = this.Ui_OnUpdate;
this.mUiButton.onclick = this.Ui_OnStartStopButtonClicked; 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.UI_ParameterToUi();
this.mAutostart = this.tobool(this.mAutostart, false); this.UI_UiToValues();
this.mAddress = this.GetParameterByName("a");
//if autostart is set but no address is given -> create one and reopen the page //if autostart is set but no address is given -> create one and reopen the page
...@@ -314,7 +307,7 @@ export class CallApp ...@@ -314,7 +307,7 @@ export class CallApp
{ {
if(this.mAddress === null) if(this.mAddress === null)
this.mAddress = this.GenerateRandomKey(); this.mAddress = this.GenerateRandomKey();
this.Ui_Update(); this.Ui_ValuesToUi();
} }
//used for interacting with the Unity CallApp //used for interacting with the Unity CallApp
...@@ -327,10 +320,10 @@ export class CallApp ...@@ -327,10 +320,10 @@ export class CallApp
if(this.mAutostart) if(this.mAutostart)
{ {
console.log("Starting automatically ... ") console.log("Starting automatically ... ")
this.Start(this.mAddress, this.mAudio , this.mVideo ); this.Start(this.mAddress);
} }
console.log("address: " + this.mAddress + " audio: " + this.mAudio + " video: " + this.mVideo + " autostart: " + this.mAutostart); console.log("address: " + this.mAddress + " audio: " + this.mMediaConfig.Audio + " video: " + this.mMediaConfig.Video + " autostart: " + this.mAutostart);
} }
private Ui_OnStart(){ private Ui_OnStart(){
this.mUiButton.textContent = "Stop"; this.mUiButton.textContent = "Stop";
...@@ -365,30 +358,77 @@ export class CallApp ...@@ -365,30 +358,77 @@ export class CallApp
} }
public Ui_OnStartStopButtonClicked = ()=>{ public Ui_OnStartStopButtonClicked = ()=>{
this.UI_UiToValues();
if(this.mIsRunning) { if(this.mIsRunning) {
this.Stop(); this.Stop();
}else{ }else{
this.Start(this.mAddress, this.mAudio, this.mVideo); this.Start(this.mAddress);
} }
} }
private UI_ParameterToUi() {
this.mUiAudio.checked = this.tobool(this.GetParameterByName("audio") , true)
this.mUiVideo.checked = this.tobool(this.GetParameterByName("video") , true);
let width = this.GetParameterByName("width");
if(width)
this.mUiWidth.value = width;
let height = this.GetParameterByName("height");
if(height)
this.mUiHeight.value = height;
this.mUiAddress.value = this.GetParameterByName("a");
this.mAutostart = this.GetParameterByName("autostart");
this.mAutostart = this.tobool(this.mAutostart, false);
}
//UI to values
public Ui_OnUpdate = ()=> public Ui_OnUpdate = ()=>
{ {
console.debug("OnUiUpdate"); console.debug("OnUiUpdate");
this.mAddress = this.mUiAddress.value; this.UI_UiToValues();
this.mAudio = this.mUiAudio.checked; }
this.mVideo = this.mUiVideo.checked;
this.mUiUrl.innerHTML = this.GetUrl();
private UI_ParseRes(element: HTMLInputElement){
if(element)
{
let val = Math.floor(element.value as any);
if(val > 0)
return val;
}
return -1;
} }
private UI_UiToValues(){
this.mAddress = this.mUiAddress.value;
this.mMediaConfig.Audio = this.mUiAudio.checked;
this.mMediaConfig.Video = this.mUiVideo.checked;
this.mMediaConfig.IdealWidth = this.UI_ParseRes(this.mUiWidth);
this.mMediaConfig.IdealHeight = this.UI_ParseRes(this.mUiHeight);
public Ui_Update() : void this.mUiUrl.innerHTML = this.ValuesToParameter();
}
//Values to UI
public Ui_ValuesToUi() : void
{ {
console.log("UpdateUi"); console.log("UpdateUi");
this.mUiAddress.value = this.mAddress; this.mUiAddress.value = this.mAddress;
this.mUiAudio.checked = this.mAudio ; this.mUiAudio.checked = this.mMediaConfig.Audio;
this.mUiVideo.checked = this.mVideo ; this.mUiVideo.checked = this.mMediaConfig.Video;
this.mUiUrl.innerHTML = this.GetUrl(); this.mUiWidth.value = "";
if(this.mMediaConfig.IdealWidth > 0)
this.mUiWidth.value = ""+this.mMediaConfig.IdealWidth;
this.mUiHeight.value = "";
if(this.mMediaConfig.IdealHeight > 0)
this.mUiHeight.value = ""+this.mMediaConfig.IdealHeight;
this.mUiUrl.innerHTML = this.ValuesToParameter();
} }
...@@ -400,9 +440,9 @@ export class CallApp ...@@ -400,9 +440,9 @@ export class CallApp
return result; return result;
} }
private GetUrlParams() { private GetUrlParams() {
return "?a=" + this.mAddress + "&audio=" + this.mAudio + "&video=" + this.mVideo + "&" + "autostart=" + true; return "?a=" + this.mAddress + "&audio=" + this.mMediaConfig.Audio + "&video=" + this.mMediaConfig.Video + "&" + "autostart=" + false;
} }
private GetUrl() { private ValuesToParameter() {
return location.protocol + '//' + location.host + location.pathname + this.GetUrlParams(); return location.protocol + '//' + location.host + location.pathname + this.GetUrlParams();
} }
} }
......
...@@ -531,7 +531,6 @@ export class BrowserMediaStream { ...@@ -531,7 +531,6 @@ export class BrowserMediaStream {
videoElement.width = 320; videoElement.width = 320;
videoElement.height = 240; videoElement.height = 240;
videoElement.controls = true; videoElement.controls = true;
//TODO: update typescript
videoElement.setAttribute("playsinline", ""); videoElement.setAttribute("playsinline", "");
videoElement.id = "awrtc_mediastream_video_" + this.mInstanceId; videoElement.id = "awrtc_mediastream_video_" + this.mInstanceId;
......
...@@ -369,16 +369,19 @@ export abstract class AWebRtcPeer { ...@@ -369,16 +369,19 @@ export abstract class AWebRtcPeer {
let createOfferPromise = this.mPeer.createOffer(this.mOfferOptions); let createOfferPromise = this.mPeer.createOffer(this.mOfferOptions);
createOfferPromise.then((desc: RTCSessionDescription) => { createOfferPromise.then((desc_in: RTCSessionDescription) => {
let msg: string = JSON.stringify(desc); let desc_out = this.ProcLocalSdp(desc_in);
let msg: string = JSON.stringify(desc_out);
let setDescPromise = this.mPeer.setLocalDescription(desc_in);
let setDescPromise = this.mPeer.setLocalDescription(desc);
setDescPromise.then(() => { setDescPromise.then(() => {
this.RtcSetSignalingStarted(); this.RtcSetSignalingStarted();
this.EnqueueOutgoing(msg); this.EnqueueOutgoing(msg);
}); });
setDescPromise.catch((error: DOMError) => { setDescPromise.catch((error: DOMError) => {
Debug.LogError(error); Debug.LogError(error);
Debug.LogError("Error during setLocalDescription with sdp: " + JSON.stringify(desc_in));
this.RtcSetSignalingFailed(); this.RtcSetSignalingFailed();
}); });
}); });
...@@ -386,19 +389,135 @@ export abstract class AWebRtcPeer { ...@@ -386,19 +389,135 @@ export abstract class AWebRtcPeer {
Debug.LogError(error); Debug.LogError(error);
this.RtcSetSignalingFailed(); this.RtcSetSignalingFailed();
}); });
} }
//Gives a specific codec priority over the others
private EditCodecs(lines: string[]){
let prefCodec = "H264";
console.warn("sdp munging: prioritizing codec " + prefCodec);
//index and list of all video codec id's
//e.g.: m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 121 127 120 125 107 108 109 35 36 124 119 123 118 114 115 116
let vcodecs_line_index;
let vcodecs_line_split: string[];
let vcodecs_list : string[];
for(let i = 0; i < lines.length; i++){
let line = lines[i];
if(line.startsWith("m=video")){
vcodecs_line_split= line.split(" ");
vcodecs_list= vcodecs_line_split.slice(3, vcodecs_line_split.length);
vcodecs_line_index = i;
//console.log(vcodecs_list);
break;
}
}
//list of video codecs positioned based on our priority list
let vcodecs_list_new : string[] = [] ;
//start below the the m=video line
for(let i = vcodecs_line_index + 1; i < lines.length; i++){
let line = lines[i];
let prefix = "a=rtpmap:";
if(line.startsWith(prefix)){
let subline = line.substr(prefix.length);
let split = subline.split(" ");
let codecId = split[0];
let codecDesc = split[1];
let codecSplit= codecDesc.split("/");
let codecName = codecSplit[0];
//sanity check. is this a video codec?
if(vcodecs_list.includes(codecId)){
if(codecName === prefCodec){
vcodecs_list_new.unshift(codecId);
}else{
vcodecs_list_new.push(codecId);
}
}
}
}
//first 3 elements remain the same
let vcodecs_line_new = vcodecs_line_split[0] + " " + vcodecs_line_split[1] + " " + vcodecs_line_split[2];
//add new codec list after it
vcodecs_list_new.forEach((x)=>{vcodecs_line_new = vcodecs_line_new + " " + x});
//replace old line
lines[vcodecs_line_index] = vcodecs_line_new;
}
//Replaces H264 profile levels
//iOS workaround. Streaming from iOS to browser currently fails without this if
//resolution is above 720p and h264 is active
private EditProfileLevel(lines: string[]){
//TODO: Make sure we only edit H264. There could be other codecs in the future
//that look identical
console.warn("sdp munging: replacing h264 profile-level with 2a");
let vcodecs_line_index;
let vcodecs_line_split: string[];
let vcodecs_list : string[];
for(let i = 0; i < lines.length; i++){
let line = lines[i];
if(line.startsWith("a=fmtp:"))
{
//looking for profile-level-id=42001f
//we replace the 1f
let searchString = "profile-level-id=";
let sublines = line.split(";");
let updateLine = false;
for(let k = 0; k < sublines.length; k++){
let subline = sublines[k];
if(subline.startsWith(searchString)){
let len = searchString.length + 4;
sublines[k] = sublines[k].substr(0, len) + "2a";
updateLine = true;
break;
}
}
if(updateLine){
lines[i] = sublines.join(";");
}
}
}
}
static MUNGE_SDP = false;
private ProcLocalSdp(desc: RTCSessionDescription) :RTCSessionDescription {
if(AWebRtcPeer.MUNGE_SDP === false)
return desc
console.warn("sdp munging active");
let sdp_in = desc.sdp;
let sdp_out = "";
let lines = sdp_in.split("\r\n");
this.EditCodecs(lines);
//this.EditProfileLevel(lines);
sdp_out = lines.join("\r\n");
let desc_out = {type: desc.type, sdp: sdp_out} as RTCSessionDescription;
return desc_out;
}
private ProcRemoteSdp(desc: RTCSessionDescription) : RTCSessionDescription{
if(AWebRtcPeer.MUNGE_SDP === false)
return desc;
//console.warn("sdp munging active");
return desc;
}
private CreateAnswer(offer: RTCSessionDescription): void { private CreateAnswer(offer: RTCSessionDescription): void {
Debug.Log("CreateAnswer"); Debug.Log("CreateAnswer");
offer = this.ProcRemoteSdp(offer);
let remoteDescPromise = this.mPeer.setRemoteDescription(offer); let remoteDescPromise = this.mPeer.setRemoteDescription(offer);
remoteDescPromise.then(() => { remoteDescPromise.then(() => {
this.StartIce(); this.StartIce();
let createAnswerPromise = this.mPeer.createAnswer(); let createAnswerPromise = this.mPeer.createAnswer();
createAnswerPromise.then((desc: RTCSessionDescription) => { createAnswerPromise.then((desc_in: RTCSessionDescription) => {
let msg: string = JSON.stringify(desc); let desc_out = this.ProcLocalSdp(desc_in);
let msg: string = JSON.stringify(desc_out);
let localDescPromise = this.mPeer.setLocalDescription(desc); let localDescPromise = this.mPeer.setLocalDescription(desc_in);
localDescPromise.then(() => { localDescPromise.then(() => {
this.RtcSetSignalingStarted(); this.RtcSetSignalingStarted();
this.EnqueueOutgoing(msg); this.EnqueueOutgoing(msg);
...@@ -424,6 +543,7 @@ export abstract class AWebRtcPeer { ...@@ -424,6 +543,7 @@ export abstract class AWebRtcPeer {
private RecAnswer(answer: RTCSessionDescription): void { private RecAnswer(answer: RTCSessionDescription): void {
Debug.Log("RecAnswer"); Debug.Log("RecAnswer");
answer = this.ProcRemoteSdp(answer);
let remoteDescPromise = this.mPeer.setRemoteDescription(answer); let remoteDescPromise = this.mPeer.setRemoteDescription(answer);
remoteDescPromise.then(() => { remoteDescPromise.then(() => {
//all done //all done
......
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