瀏覽代碼

* Video conferencing APIs

michael 5 年之前
父節點
當前提交
841b080e6c

+ 7 - 1
demo/Makefile

@@ -5,7 +5,9 @@ TARGETS=democomponents demobrowseconsole demoajax demoxhr restbridgeclient \
   chartjs_demoline chartjs_demotime chartjs_demoscriptablebubble chartjs_demoradar \
   chartjs_democustompoints chartjs_demopolararea promiseall promisestory1 \
   promisestory2 promisestory demodb demoload demorest fpcunitbrowsertest \
-  sampleda webgl1 pdfbasic hotreload dynload bootstraptable fullcalendar
+  sampleda webgl1 pdfbasic hotreload dynload bootstraptable fullcalendar \
+  jitsimeet opentok
+
 ifneq ($(SKIPWEBCOMPILER),1)
 TARGETS:=$(TARGETS) demowebcompiler
 BASEDIR=$(CURDIR)/../compiler/packages
@@ -110,3 +112,7 @@ bootstraptable: ./bootstrap/demobootstraptable.lpr
 	$(BROWSERP2JS) $<
 fullcalendar: ./fullcalendar/demofullcalendar.lpr
 	$(BROWSERP2JS) $<
+jitsimeet: ./jitsimeet/demojitsimeet.lpr
+	$(BROWSERP2JS) $<
+opentok: ./opentok/demoopentok.lpr
+	$(BROWSERP2JS) $<

+ 91 - 0
demo/jitsimeet/demojitsimeet.lpi

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="demojitsimeet"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="5">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="PasJSHTMLFile" Value="project1.html"/>
+      <Item2 Name="PasJSPort" Value="0"/>
+      <Item3 Name="PasJSWebBrowserProject" Value="1"/>
+      <Item4 Name="RunAtReady" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="demojitsimeet.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="index.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="demojitsimeet"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 142 - 0
demo/jitsimeet/demojitsimeet.lpr

@@ -0,0 +1,142 @@
+program demojitsimeet;
+
+{$mode objfpc}
+{$modeswitch externalclass}
+
+uses
+  Types, TypInfo, JS, Classes, SysUtils, Web, browserapp, libjitsimeet;
+
+Type
+
+  { TJitsiClient }
+
+  TJitsiClient = Class(TBrowserApplication)
+  Private
+    returnURL : string;
+    jitsicontainer,jitsinode,options : TJSHTMLElement;
+    svr,room,email,nick : TJSHTMLInputElement;
+    BtnConnect : TJSHtmlButtonElement;
+    BtnLeave : TJSHtmlButtonElement;
+    API : TJMExternalAPI;
+    GUIElements : Array[TJMUIElement] of TJSHTMLInputElement;
+    procedure BindElements;
+    procedure ConnectToJitsi;
+    function DoConnectClick(aEvent: TJSMouseEvent): boolean;
+    function DoDisConnectClick(aEvent: TJSMouseEvent): boolean;
+    procedure doHangup(Arg: JSValue);
+    function GetServer: String;
+  Protected
+
+    Procedure DoRun; override;
+  end;
+
+Var
+  Application : TJitsiClient;
+
+{ TJitsiClient }
+
+function TJitsiClient.DoConnectClick(aEvent: TJSMouseEvent): boolean;
+
+begin
+  Result:=True;
+  if room.value='' then
+    Window.alert('No room specified')
+  else
+    begin
+    ConnectToJitsi;
+    Options.style.cssText:='display: none;';
+    BtnLeave.disabled:=False;
+    BtnConnect.Disabled:=True;
+    end;
+end;
+
+function TJitsiClient.DoDisConnectClick(aEvent: TJSMouseEvent): boolean;
+begin
+  API.Hangup;
+end;
+
+procedure TJitsiClient.doHangup(Arg : JSValue);
+
+begin
+  BtnLeave.disabled:=True;
+  BtnConnect.Disabled:=False;
+  Options.style.cssText:='';
+  jitsinode.innerHTML:='';
+end;
+
+Function TJitsiClient.GetServer : String;
+
+begin
+  Result:=svr.value;
+  if Result='' then
+    Result:='meet.jit.si';
+end;
+
+Procedure TJitsiClient.ConnectToJitsi;
+
+var
+  opts : TJMMeetOptions;
+  user : TJMUserInfo;
+  cfg : TJMInterfaceConfig;
+  el : TJMUIElement;
+  els : TJMUIElements;
+
+begin
+  els:=[];
+  for el in TJMUIElement do
+    if GUIElements[el].checked then
+      Include(els,el);
+  opts:=TJMMeetOptions.New;
+  opts.noSSL:=False;
+  opts.parentNode:=jitsinode;
+  opts.roomName:=room.Value;
+  if (email.value<>'') then
+    begin
+    user:=TJMUserInfo.New;
+    user.email:=email.value;
+    opts.userInfo:=user;
+    end;
+  cfg:=TJMInterfaceConfig.New;
+  cfg.ToolbarButtons:=UIElementsStrings(Els);
+  opts.interfaceConfigOverwrite:=cfg;
+  API:=TJMExternalAPI.New(GetServer,opts);
+  API.on_(EventReadyToClose,@DoHangup);
+  if nick.value<>'' then
+    API.SetDisplayName(nick.value);
+end;
+
+procedure TJitsiClient.BindElements;
+
+Var
+  E : TJMUIElement;
+
+begin
+  jitsinode:=GetHTMLElement('jitsi');
+  svr:=TJSHTMLInputElement(GetHTMLElement('edtServer'));
+  room:=TJSHTMLInputElement(GetHTMLElement('edtRoom'));
+  email:=TJSHTMLInputElement(GetHTMLElement('edtEmail'));
+  nick:=TJSHTMLInputElement(GetHTMLElement('edtNick'));
+  jitsicontainer:=GetHTMLElement('jitsi-container');
+  btnConnect:=TJSHtmlButtonElement(GetHTMLElement('btnConnect'));
+  BtnLeave:=TJSHtmlButtonElement(GetHtmlElement('btnDisconnect'));
+  options:=GetHTMLElement('Options');
+  For E in TJMUIElement do
+    GUIElements[E]:=TJSHTMLInputElement(GetHTMLElement(GetEnumName(TypeInfo(TJMUIElement),Ord(E))));
+end;
+
+procedure TJitsiClient.DoRun;
+
+begin
+  Terminate;
+  BindElements;
+  ReturnURL:=window.location.href;
+  btnConnect.onclick:=@DoConnectClick;
+  btnLeave.onclick:=@DoDisConnectClick;
+end;
+
+
+begin
+  Application:=TJitsiClient.Create(Nil);
+  Application.Initialize;
+  Application.Run;
+end.

+ 225 - 0
demo/jitsimeet/index.html

@@ -0,0 +1,225 @@
+
+<!doctype html>
+<html lang="en">
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>Jitsi meet Pas2JS Demo</title>
+  <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
+  <script src="https://code.jquery.com/jquery-3.3.1.js" type="text/javascript"></script>
+  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" type="text/javascript"></script>
+  <script src='https://meet.jit.si/external_api.js'></script>
+  <script src="demojitsimeet.js"></script>
+</head>
+<style>
+  body {
+    background-color: #eee;
+    max-width: 1000px;
+    margin: auto;
+  }
+</style>
+<body>
+  <div class="container-fluid">
+    <div id="Options">
+      <div class="card">
+        <div class="card-header" id="MeetOptionsHeader">
+          <h5 class="mb-0">
+            <button class="btn btn-link" data-toggle="collapse" data-target="#MeetOptions" aria-expanded="true" aria-controls="MeetOptions">
+              Meeting options
+            </button>
+          </h5>
+        </div>
+        <div id="MeetOptions" class="collapse show" aria-labelledby="MeetOptionsHeader" data-parent="#Options">
+          <div class="card-body">
+            <div class="row" id="controls">
+              <div class="col-md-6">
+                <div class="form-group">
+                  <label for="edtServer">Jitsi Server</label>
+                  <input type="text" class="form-control" id="edtServer" aria-describedby="lblServer" placeholder="Jitsi server" value="meet.jit.si">
+                  <small id="lblServer" class="form-text text-muted">Jitsi server to contact.</small>
+                </div>
+                <div class="form-group">
+                  <label for="edtRoom">Room name</label>
+                  <input type="text" class="form-control" id="edtRoom" aria-describedby="lblRoom" placeholder="Jitsi room name" value="">
+                  <small id="lblRoom" class="form-text text-muted">Room you want to join.</small>
+                </div>
+              </div>
+              <div class="col-md-6">
+                <div class="form-group">
+                  <label for="edtEmail">Your email</label>
+                  <input type="text" class="form-control" id="edtEmail" aria-describedby="lblEmail" placeholder="Your email address" value="">
+                  <small id="lblEmail" class="form-text text-muted">Your email so people know who you are.</small>
+                </div>
+                <div class="form-group">
+                  <label for="edtNick">Your nickname</label>
+                  <input type="text" class="form-control" id="edtNick" aria-describedby="lblNick" placeholder="Your name in the room" value="">
+                  <small id="lblNick" class="form-text text-muted">Nickname to use in the room.</small>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="card">
+        <div class="card-header" id="ConnOptionsHeader">
+          <h5 class="mb-0">
+            <button class="btn btn-link" data-toggle="collapse" data-target="#ConnOptions" aria-expanded="true" aria-controls="collapseOne">
+              GUI elements
+            </button>
+          </h5>
+        </div>
+        <div id="ConnOptions" class="collapse " aria-labelledby="ConnOptionsHeader" data-parent="#Options">
+          <div class="card-body">
+            <div class="row" id="controls">
+              <div class="col-sm-6 col-md-3">
+                <div class="form-check">
+                  <input id="uieMicrophone" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieMicrophone">Microphone</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieCamera" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieCamera">Camera</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieClosedCaptions" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieClosedCaptions">Closed captions</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieDesktop" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieDesktop">Desktop</label>
+                </div>
+              </div>
+              <div class="col-sm-6 col-md-3">
+                <div class="form-check">
+                  <input id="uieFullScreen" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieFullScreen">Full Screen</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieFODeviceSelection" type="checkbox" class="form-check-input" checked >
+                  <label class="form-check-label" for="uieCamera">Device Selection</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieHangup" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieHangup">Hangup</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieChat" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieChat">Chat</label>
+                </div>
+              </div>
+              <div class="col-sm-6 col-md-3">
+                <div class="form-check">
+                  <input id="uieLiveStreaming" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieLiveStreaming">Live Streaming</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieEtherPad" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieEtherPad">Ether Pad</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieSharedVideo" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieSharedVideo">Shared Video</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieSettings" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieSettings">Settings</label>
+                </div>
+              </div>
+              <div class="col-sm-6 col-md-3">
+                <div class="form-check">
+                  <input id="uieVideoQuality" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieVideoQuality">Video Quality</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieFilmStrip" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieFilmStrip">Film strip</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieFeedBack" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieFeedBack">Shared Video</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieStats" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieStats">Stats</label>
+                </div>
+              </div>
+              <!--         uieHelp, uieMuteEveryone,
+                          uieProfile, uieInfo, uieRaiseHand, uieInvite -->
+              <div class="col-sm-6 col-md-3">
+                <div class="form-check">
+                  <input id="uieShortCuts" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieShortCuts">ShortCuts</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieTileView" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieTileView">Tile View</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieVideoBackgroundBlur" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieVideoBackgroundBlur">Video Background Blur</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieDownload" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieDownload">Download</label>
+                </div>
+              </div>
+              <div class="col-sm-6 col-md-3">
+                <div class="form-check">
+                  <input id="uieHelp" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieHelp">Help</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieMuteEveryone" type="checkbox" class="form-check-input" checked >
+                  <label class="form-check-label" for="uieMuteEveryone">Mute Everyone</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieProfile" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieProfile">Profile</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieInfo" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieInfo">Info</label>
+                </div>
+              </div>
+              <div class="col-sm-6 col-md-3">
+                <div class="form-check">
+                  <input id="uieRaiseHand" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieRaiseHand">Raise Hand</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieInvite" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieInvite">Invite</label>
+                </div>
+                <div class="form-check">
+                  <input id="uieRecording" type="checkbox" class="form-check-input"  checked>
+                  <label class="form-check-label" for="uieRecording">Recording</label>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="row mt-3" id="buttons">
+      <div class="col-6 col-sm-4 col-md-3">
+        <button class="btn btn-primary btn-block" id="btnConnect">Join Jitsi meeting</button>
+      </div>
+      <div class="col-6 col-sm-4 col-md-3">
+        <button class="btn btn-primary btn-block" id="btnDisconnect" disabled>End Jitsi meeting</button>
+      </div>
+    </div>
+    <div class="row mt-3 ml-1 text-muted">
+      Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> &nbsp;&nbsp;
+       Sources: &nbsp; <a target="new" href="demojitsimeet.lpr">Program</a>
+    </div>
+    <div class="row">
+      <div id="jitsi-container" class="col-md-12" style="height: 66vh;">
+        <div id="jitsi" style="height: 100%;">
+        </div>
+      </div>
+    </div>
+  <script>
+    window.addEventListener("load", rtl.run);
+  </script>
+</body>
+</html>

+ 35 - 0
demo/opentok/css/app.css

@@ -0,0 +1,35 @@
+/* Enter your classes/style definitions here */
+body, html {
+  background-color: #eee;
+  /* height: 100%; */
+  max-width: 1000px;
+  margin: auto;
+}
+
+#videos {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.subscriber {
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 10;
+}
+
+.publisher {
+  position: absolute;
+  width: 360px;
+  height: 240px;
+  bottom: 10px;
+  left: 10px;
+  z-index: 100;
+  border: 3px solid white;
+  border-radius: 3px;
+}

+ 87 - 0
demo/opentok/demoopentok.lpi

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="11"/>
+    <General>
+      <Flags>
+        <SaveOnlyProjectUnits Value="True"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="OpenTok API Demo"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="2">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="PasJSWebBrowserProject" Value="1"/>
+    </CustomData>
+    <BuildModes Count="1">
+      <Item1 Name="default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="0"/>
+    </RunParams>
+    <Units Count="4">
+      <Unit0>
+        <Filename Value="demoopentok.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="../libopentok.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit1>
+      <Unit2>
+        <Filename Value="index.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit2>
+      <Unit3>
+        <Filename Value="css/app.css"/>
+        <IsPartOfProject Value="True"/>
+      </Unit3>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="demoopentok"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value=".."/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 177 - 0
demo/opentok/demoopentok.lpr

@@ -0,0 +1,177 @@
+program demoopentok;
+
+{$mode objfpc}
+
+uses
+  JS, Classes, SysUtils, Web, libopentok, browserapp;
+
+Type
+
+  { TOpenTokApplication }
+
+  TOpenTokApplication = Class(TBrowserApplication)
+    EdtAPIKey : TJSHTMLInputElement;
+    EdtSession : TJSHTMLInputElement;
+    EdtToken : TJSHTMLInputElement;
+    EdtName : TJSHTMLInputElement;
+    BtnJoin : TJSHTMLButtonElement;
+    BtnLeave : TJSHTMLButtonElement;
+    OptionsEl : TJSHTMLElement;
+    cbPictureInPicture : TJSHTMLInputElement;
+    VideosEl : TJSHTMLElement;
+    PublisherEl : TJSHTMLElement;
+    SubscriberEl : TJSHTMLElement;
+  private
+    Fsession : TOTSession;
+    FPublisher : TOTPublisher;
+    function CheckInput: Boolean;
+    function DoJoinClick(aEvent: TJSMouseEvent): boolean;
+    function DoLeaveClick(aEvent: TJSMouseEvent): boolean;
+    function DoPictureInPicture(Event: TEventListenerEvent): boolean;
+    procedure handleError(error: TOTError);
+    procedure InitElements;
+    procedure initializeSession;
+  Protected
+    Procedure DoRun; override;
+  end;
+
+{ TOpenTokApplication }
+
+procedure TOpenTokApplication.InitElements;
+
+begin
+  VideosEl:=GetHTMLElement('videos');
+  PublisherEl:=GetHTMLElement('publisher');
+  SubscriberEl:=GetHTMLElement('subscriber');
+  cbPictureInPicture:=TJSHTMLInputElement(GetHTMLElement('cbPictureInPicture'));
+  EdtAPIKey :=TJSHTMLInputElement(GetHTMLElement('edtAPIKey'));
+  EdtSession := TJSHTMLInputElement(GetHTMLElement('edtSession'));
+  EdtToken := TJSHTMLInputElement(GetHTMLElement('edtToken'));
+  EdtName := TJSHTMLInputElement(GetHTMLElement('edtName'));
+  BtnJoin := TJSHTMLButtonElement(GetHTMLElement('btnJoin'));
+  BtnLeave := TJSHTMLButtonElement(GetHTMLElement('btnLeave'));
+  OptionsEl := GetHTMLElement('Options');
+  BtnJoin.OnClick:=@DoJoinClick;
+  BtnLeave.OnClick:=@DoLeaveClick;
+  cbPictureInPicture.onChange:=@DoPictureInPicture;
+end;
+
+procedure TOpenTokApplication.DoRun;
+begin
+  Terminate;
+  InitElements;
+end;
+
+Procedure TOpenTokApplication.handleError(error : TOTError);
+
+begin
+  if Assigned(error) then
+    begin
+    window.alert(error.message);
+    writeln('Error :',error.message);
+    end;
+end;
+
+function TOpenTokApplication.CheckInput : Boolean;
+
+begin
+  Result:=(EdtAPIKey.Value<>'') and (EdtSession.Value<>'') and (edtToken.Value<>'');
+  if not Result then
+    window.alert('Please fill in APIKey, Session and Token');
+
+end;
+
+function TOpenTokApplication.DoJoinClick(aEvent: TJSMouseEvent): boolean;
+begin
+  Result:=False;
+  if Not CheckInput then exit;
+  BtnJoin.disabled:=True;
+  OptionsEl.style.cssText:='display: none;';
+  InitializeSession;
+  BtnLeave.disabled:=False;
+end;
+
+function TOpenTokApplication.DoLeaveClick(aEvent: TJSMouseEvent): boolean;
+begin
+  Result:=False;
+  BtnJoin.disabled:=False;
+  OptionsEl.style.cssText:='';
+  FSession.disconnect;
+  FSession:=Nil;
+  FPublisher:=Nil;
+  BtnLeave.disabled:=True;
+end;
+
+function TOpenTokApplication.DoPictureInPicture(Event: TEventListenerEvent): boolean;
+begin
+  Result:=False;
+  if cbPictureInPicture.Checked then
+    begin
+    PublisherEl.className:='publisher';
+    SubscriberEl.className:='subscriber';
+    end
+  else
+    begin
+    PublisherEl.className:='col-6';
+    SubscriberEl.className:='col-6';
+    end
+end;
+
+Procedure TOpenTokApplication.initializeSession;
+
+  Procedure DoConnect(error : TOTError);
+
+  begin
+    if Assigned(error) then
+      handleError(error)
+    else
+      FSession.publish(FPublisher, @handleError);
+  end;
+
+  procedure DoStreamCreated(event : TJSEvent);
+
+  Var
+    S : TOTStream;
+    initSub : TOTInitSubscriberOptions;
+
+  begin
+    With TOTStreamEvent(event) do
+      S:=Stream;
+    initSub:=TOTInitSubscriberOptions.new;
+    With initSub do
+      begin
+      insertMode:='append';
+      widthstring:='100%';
+      heightString:='100%';
+      end;
+    FSession.subscribe(S, 'subscriber', InitSub,@HandleError);
+  end;
+
+var
+  initPub : TOTInitPublisherOptions;
+  n : string;
+
+begin
+  Fsession:=OpenTok.initSession(edtAPIKey.Value, edtSession.Value);
+  Fsession.on_('streamCreated', @doStreamCreated);
+  initPub:=TOTInitPublisherOptions.New;
+  initPub.insertmode:='append';
+  initPub.widthString:='100%';
+  initPub.heightString:='100%';
+  N:=edtName.Value;
+  if N='' then
+    N:='You';
+  initPub.Name:=N;
+  Fpublisher:=OpenTok.initPublisher('publisher',initPub,@HandleError);
+  // Connect to the session
+  Fsession.connect(edtToken.Value, @DoConnect);
+end;
+
+begin
+  With TOpenTokApplication.Create(Nil) do
+    begin
+    Title:='OpenTok API Demo';
+    Initialize;
+    Run;
+    end;
+end.

+ 98 - 0
demo/opentok/index.html

@@ -0,0 +1,98 @@
+
+<html>
+  <head>
+      <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+      <meta name="viewport" content="width=device-width, initial-scale=1">
+      <title>OpenTok Pas2js Demo</title>
+      <link href="css/app.css" rel="stylesheet" type="text/css">
+      <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
+      <script src="https://code.jquery.com/jquery-3.3.1.js" type="text/javascript"></script>
+      <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" type="text/javascript"></script>
+      <script src="https://static.opentok.com/v2/js/opentok.min.js"></script>
+      <script src="demoopentok.js"></script>
+  </head>
+  <body>
+    <div class="container-fluid">
+      <div id="Options">
+        <div class="card">
+          <div class="card-header" id="OpenTokOptionsHeader">
+            <h5 class="mb-0">
+              <button class="btn btn-link" data-toggle="collapse" data-target="#OpenTokOptions" aria-expanded="true" aria-controls="OpenTokOptions">
+                OpenTok Options
+              </button>
+            </h5>
+          </div>
+          <div id="OpenTokOptions" class="collapse show" aria-labelledby="OpenTokOptionsHeader" data-parent="#Options">
+            <div class="card-body">
+              <div class="row" >
+                <div class="col-12 panel panel-info">
+                  <div class="panel-body lead">
+                    You must obtain an API Key, Session ID and Token from <a href="http://www.tokbox.com">Tokbox</a>.
+                    You can get a test account for free.
+                  </div>
+                </div>
+              </div>
+              <div class="row mt-4" id="controls">
+                <div class="col-12">
+                  <div class="form-group">
+                    <label for="edtAPIKey">API Key</label>
+                    <input type="text" class="form-control" id="edtAPIKey" aria-describedby="lblAPIKey" placeholder="OpenTok API Key" value="">
+                    <small id="lblAPIKey" class="form-text text-muted">OpenTok API Key</small>
+                  </div>
+                </div>
+                <div class="col-12">
+                  <div class="form-group">
+                    <label for="edtSession">Session ID</label>
+                    <input type="text" class="form-control" id="edtSession" aria-describedby="lblSession" placeholder="OpenTok Session ID" value="">
+                    <small id="lblSession" class="form-text text-muted">Session you want to join.</small>
+                  </div>
+                </div>
+                <div class="col-12">
+                  <div class="form-group">
+                    <label for="edtToken">OpenTOK Token</label>
+                    <input type="text" class="form-control" id="edtToken" aria-describedby="lblToken" placeholder="OpenTok token" value="">
+                    <small id="lblToken" class="form-text text-muted">The OpenTok token you got from the OpenTok Server.</small>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div id="Buttons" class="row mt-4">
+        <div class="col-12">
+          <div class="form-group">
+            <label class="ml-1 text-bold" for="edtName">Display Name</label>
+            <input type="text" class="form-control" id="edtName" aria-describedby="lblName" placeholder="Your name" value="">
+            <small id="lblName" class="form-text text-muted">The name you wish people to see</small>
+          </div>
+        </div>
+        <div class="col-12  ">
+          <div class="form-check">
+            <input id="cbPictureInPicture" type="checkbox" class="form-check-input" >
+            <label class="form-check-label" for="cbPictureInPicture">Picture-in-Picture mode</label>
+          </div>
+        </div>
+        <div class="col-6 col-sm-3 mt-3 ">
+          <button class="btn btn-primary btn-block" id="btnJoin">Join</button>
+        </div>
+        <div class="col-6 col-sm-3 mt-3">
+          <button class="btn btn-secondary btn-block" id="btnLeave" disabled>Leave</button>
+        </div>
+      </div>
+      <div class="row mt-3 ml-1 text-muted">
+        Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> &nbsp;&nbsp;
+         Sources: &nbsp; <a target="new" href="demoopentok.lpr">Program</a>
+      </div>
+      <div id="videos" class="row mt-3">
+        <div id="subscriber" class="col-6"></div>
+        <div id="publisher" class="col-6"></div>
+      </div>
+    </div>
+    <script>
+      rtl.run();
+    </script>
+  
+  </body>
+  </html>
+  

+ 549 - 0
packages/jitsimeet/libjitsimeet.pp

@@ -0,0 +1,549 @@
+{
+    This file is part of the Pas2JS run time library.
+    Copyright (c) 2020 by the Pas2JS development team.
+
+    This unit defines Jitsi external meet API
+    (not to be confused with internal APIs)
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+{$mode objfpc}
+{$modeswitch externalclass}
+
+unit libjitsimeet;
+
+interface
+
+uses
+  JS, web;
+
+Const
+  // Event names
+  EventAudioAvailabilityChanged = 'audioAvailabilityChanged';
+  EventAudioMuteStatusChanged = 'audioMuteStatusChanged';
+  EventAvatarChanged = 'avatarChanged';
+  EventCameraError = 'cameraError';
+  EventDeviceListChanged = 'deviceListChanged';
+  EventDisplayNameChange = 'displayNameChange';
+  EventdominantSpeakerChanged = 'dominantSpeakerChanged';
+  EventEmailChange = 'emailChange';
+  EventEndpointTextMessageReceived = 'endpointTextMessageReceived';
+  EventFeedbackSubmitted = 'feedbackSubmitted';
+  EventFilmstripDisplayChanged = 'filmstripDisplayChanged';
+  EventIncomingMessage = 'incomingMessage';
+  EventMicError = 'micError';
+  EventOutgoingMessage = 'outgoingMessage';
+  EventParticipantJoined = 'participantJoined';
+  EventParticipantKickedOut = 'participantKickedOut';
+  EventParticipantLeft = 'participantLeft';
+  EventPasswordRequired = 'passwordRequired';
+  EventReadyToClose = 'readyToClose';
+  EventScreenSharingStatusChanged = 'screenSharingStatusChanged';
+  EventSubjectChange = 'subjectChange';
+  EventSuspendDetected = 'suspendDetected';
+  EventTileViewChanged = 'tileViewChanged';
+  EventVideoAvailabilityChanged = 'videoAvailabilityChanged';
+  EventVideoConferenceJoined = 'videoConferenceJoined';
+  EventVideoConferenceLeft = 'videoConferenceLeft';
+  EventVideoMuteStatusChanged = 'videoMuteStatusChanged';
+
+  // Command names. You can use the class helper instead.
+  CommandAvatarURL = 'avatarURL';
+  CommandDisplayName = 'displayName';
+  CommandEmail = 'email';
+  CommandHangup = 'hangup';
+  CommandPassword = 'password';
+  CommandSendEndPointTextMessage = 'sendEndpointTextMessage';
+  CommandSendTones = 'sendTones';
+  CommandSubject = 'subject';
+  CommandToggleAudio = 'toggleAudio';
+  CommandToggleChat = 'toggleChat';
+  CommandToggleFilmStrip = 'toggleFilmStrip';
+  CommandToggleTileView = 'toggleTileView';
+  CommandToggleVideo = 'toggleVideo';
+  CommandToggleShareScreen = 'toggleShareScreen';
+
+  // UI elements
+  UIMicrophone = 'microphone';
+  UICamera = 'camera';
+  UIClosedCaptions = 'closedcaptions';
+  UIDesktop = 'desktop';
+  UIFullScreen = 'fullscreen';
+  UIFODeviceSelection = 'fodeviceselection';
+  UIHangup = 'hangup';
+  UIChat = 'chat';
+  UIRecording = 'recording';
+  UILiveStreaming = 'livestreaming';
+  UIEtherPad = 'etherpad';
+  UISharedVideo = 'sharedvideo';
+  UISettings = 'settings';
+  UIVideoQuality = 'videoquality';
+  UIFilmStrip = 'filmstrip';
+  UIFeedBack = 'feedback';
+  UIStats = 'stats';
+  UIShortCuts = 'shortcuts';
+  UITileView = 'tileview';
+  UIVideoBackgroundBlur = 'videobackgroundblur';
+  UIDownload = 'download';
+  UIHelp = 'help';
+  UIMuteEveryone = 'mute-everyone';
+  UIProfile = 'profile';
+  UIInfo = 'info';
+  UIRaiseHand = 'raisehand';
+  UIInvite = 'invite';
+
+  UISettingDevices = 'devices';
+  UISettingLanguage = 'language';
+  UISettingModerator = 'moderator';
+  UISettingProfile = 'profile';
+  UISettingCalendar = 'calendar';
+
+Type
+  // Not documented or possible to define statically  :(
+
+  TJMCommands  = TJSObject;
+  TJMInvite = TJSObject;
+  TJMInviteDynArray = Array of TJMInvite;
+
+  TJMEventHandler = reference to Procedure(Arg : JSValue);
+
+  TJMInvitee = class external name 'Object' (TJSObject);
+  TJMInviteeDynArray = array of TJMInvitee;
+
+  TJMUIElement = (uieMicrophone, uieCamera, uieClosedCaptions, uieDesktop,
+    uieFullScreen, uieFODeviceSelection, uieHangup, uieChat, uieRecording,
+    uieLiveStreaming, uieEtherPad, uieSharedVideo, uieSettings, uieVideoQuality,
+    uieFilmStrip, uieFeedBack, uieStats, uieShortCuts, uieTileView,
+    uieVideoBackgroundBlur, uieDownload, uieHelp, uieMuteEveryone,
+    uieProfile, uieInfo, uieRaiseHand, uieInvite);
+  TJMUIElements = set of TJMUIElement;
+  TJMUISetting = (usDevices, usLanguage, usModerator, usProfile, usCalendar);
+  TJMUISettings = set of TJMUISetting;
+
+  { TJMDevices }
+
+  TJMDevices = class external name 'Object' (TJSObject)
+  private
+    FAudioInput: String; external name 'audioInput';
+    FAudioOutput: String; external name 'audioOutput';
+    FVideoInput: String; external name 'videoInput';
+  Public
+    Property AudioInput : String Read FAudioInput Write FAudioInput;
+    Property audioOutput : String read FAudioOutput Write FAudioOutput;
+    Property videoInput : String read FVideoInput Write FVideoInput;
+  end;
+
+  { TJMUserInfo }
+
+  TJMUserInfo = class external name 'Object' (TJSObject)
+  private
+    FEmail: String; external name 'email';
+  Public
+    Property Email : String Read FEmail Write FEmail;
+  end;
+
+  { TJMInterfaceConfig }
+
+  TJMInterfaceConfig = class external name 'Object' (TJSObject)
+  private
+    FAndroidAppPackage : string; external name 'ANDROID_APP_PACKAGE';
+    FAppName: String; external name 'APP_NAME';
+    FAppScheme : string; external name 'APP_SCHEME';
+    FAudioLevelPrimaryColor : string; external name 'AUDIO_LEVEL_PRIMARY_COLOR';
+    FAudioLevelSecondaryColor : string; external name 'AUDIO_LEVEL_SECONDARY_COLOR';
+    FAuthenticationEnable: Boolean; external name 'AUTHENTICATION_ENABLE';
+    FAutoPinLatestScreenShare : String; external name 'AUTO_PIN_LATEST_SCREEN_SHARE';
+    FBrandWaterMarkLink: String; external name 'BRAND_WATERMARK_LINK';
+    FClosePageGuestHint: String; external name 'CLOSE_PAGE_GUEST_HINT';
+    FConnectionIndicatorAutoHideEnabled : boolean; external name 'CONNECTION_INDICATOR_AUTO_HIDE_ENABLED';
+    FConnectionIndicatorAutoHideTimeout : nativeint ; external name 'CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT';
+    FConnectionIndicatorDisabled : boolean; external name 'CONNECTION_INDICATOR_DISABLED';
+    FDefaultBackground: String;  external name 'DEFAULT_BACKGROUND';
+    FDefaultLocalDisplayName: String; external name 'DEFAULT_LOCAL_DISPLAY_NAME';
+    FDefaultRemoteDisplayName: String;  external name 'DEFAULT_REMOTE_DISPLAY_NAME';
+    FDisableDominantSpeakerIndicator: Boolean; external name 'DISABLE_DOMINANT_SPEAKER_INDICATOR';
+    FDisableFocusIndicator: Boolean;  external name 'DISABLE_FOCUS_INDICATOR';
+    FDisableJoinLeaveNotifications :boolean ; external name 'DISABLE_JOIN_LEAVE_NOTIFICATIONS';
+    FDisablePresenceStatus : boolean; external name 'DISABLE_PRESENCE_STATUS';
+    FDisableRinging : Boolean; external name 'DISABLE_RINGING';
+    FDisableTranscriptionSubtitles: Boolean;  external name 'DISABLE_TRANSCRIPTION_SUBTITLES';
+    FDisableVideoBackground: Boolean; external name 'DISABLE_VIDEO_BACKGROUND';
+    FDisplayWelcomePageContent: Boolean;  external name 'DISPLAY_WELCOME_PAGE_CONTENT';
+    FDisplayWelcomePageToolbarAdditionalContent: Boolean; external name 'DISPLAY_WELCOME_PAGE_TOOLBAR_ADDITIONAL_CONTENT';
+    FEnableFeedBackAnimation: Boolean;   external name 'ENABLE_FEEDBACK_ANIMATION';
+    FEnforceNotificationAutoDismissTimeout : NativeInt; external name 'ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT';
+    FFilmStripMaxHeight: NativeInt;  external name 'FILM_STRIP_MAX_HEIGHT';
+    FFilmStripOnly: Boolean; external name 'filmStripOnly';
+    FGenerateRoomNamesOnWelcomePage: Boolean;  external name 'GENERATE_ROOMNAMES_ON_WELCOME_PAGE';
+    FInitialToolbarTimeOut: NativeInt;  external name 'INITIAL_TOOLBAR_TIMEOUT';
+    FInvitationPoweredBy: Boolean;  external name 'INVITATION_POWERED_BY';
+    FJitsiWaterMarkLink: String; external name 'JITSI_WATERMARK_LINK';
+    FLangDetection: Boolean;  external name 'LANG_DETECTION';
+    FLiveStreamingHelpLink : string; external name 'LIVE_STREAMING_HELP_LINK';
+    FLocalThumbnailRatio : double ; external name 'LOCAL_THUMBNAIL_RATIO';
+    FMaximumZoomingCoefficient : double ; external name 'MAXIMUM_ZOOMING_COEFFICIENT';
+    FMobileAppPromo :Boolean ; external name 'MOBILE_APP_PROMO';
+    FMobileDownloadLinkAndroid : string ; external name 'MOBILE_DOWNLOAD_LINK_ANDROID';
+    FMobileDownloadLinkIos : string; external name 'MOBILE_DOWNLOAD_LINK_IOS';
+    FNativeAppName: STring;  external name 'NATIVE_APP_NAME';
+    FOptimalBrowsers : TStringDynArray ; external name 'OPTIMAL_BROWSERS';
+    FPolicyLogo : string; external name 'POLICY_LOGO';
+    FProviderName: string;   external name 'PROVIDER_NAME';
+    FRandomAvatarURLPrefix: String; external name 'RANDOM_AVATAR_URL_PREFIX';
+    FRandomAvatarURLSuffix: String;   external name 'RANDOM_AVATAR_URL_SUFFIX';
+    FRecentListEnabled :boolean ; external name 'RECENT_LIST_ENABLED';
+    FRemoteThumbnailRatio : double ; external name 'REMOTE_THUMBNAIL_RATIO';
+    FSettingSections: TStringDynArray;   external name 'SETTINGS_SECTIONS';
+    FShowBrandWaterMark: Boolean; external name 'SHOW_BRAND_WATERMARK';
+    FShowChromeExtensionBanner : Boolean; external name 'SHOW_CHROME_EXTENSION_BANNER';
+    FShowDeepLinkingImage: Boolean; external name 'SHOW_DEEP_LINKING_IMAGE';
+    FShowJitsiWaterMark: Boolean;  external name 'SHOW_JITSI_WATERMARK';
+    FShowPoweredBy: Boolean;  external name 'SHOW_POWERED_BY';
+    FShowPromotionalClosePage: Boolean; external name 'SHOW_PROMOTIONAL_CLOSE_PAGE';
+    FShowWaterMarkForGuests: Boolean; external name 'SHOW_WATERMARK_FOR_GUESTS';
+    FSupportUrl : string ; external name 'SUPPORT_URL';
+    FTileViewMaxColumns : nativeint; external name 'TILE_VIEW_MAX_COLUMNS';
+    FToolbarAlwaysVisible: Boolean;  external name 'TOOLBAR_ALWAYS_VISIBLE';
+    FToolbarButtons: TStringDynArray;  external name 'TOOLBAR_BUTTONS';
+    FToolbarTimeOut: NativeInt;  external name 'TOOLBAR_TIMEOUT';
+    FUnsupportedBrowsers : TStringDynArray; external name 'UNSUPPORTED_BROWSERS';
+    FVerticalFilmStrip: Boolean; external name 'VERTICAL_FILMSTRIP';
+    FVideoLayoutFit: String; external name 'VIDEO_LAYOUT_FIT';
+    FVideoQualityLabelDisabled : boolean; external name 'VIDEO_QUALITY_LABEL_DISABLED';
+  Public
+    Property AndroidAppPackage : String Read FAndroidAppPackage write FAndroidAppPackage; //       ANDROID_APP_PACKAGE: 'org.jitsi.meet',
+    Property AppName : String Read FAppName Write FAppName; //  APP_NAME: 'Jitsi Meet',
+    Property AppScheme : String Read FAppScheme write FAppScheme; //       APP_SCHEME: 'org.jitsi.meet',
+    Property AudioLevelPrimaryColor : string  Read FAudioLevelPrimaryColor write FAudioLevelPrimaryColor; //       AUDIO_LEVEL_PRIMARY_COLOR: 'rgba(255,255,255,0.4)',
+    Property AudioLevelSecondaryColor : string Read FAudioLevelSecondaryColor write FAudioLevelSecondaryColor; //       AUDIO_LEVEL_SECONDARY_COLOR: 'rgba(255,255,255,0.2)',
+    Property AuthenticationEnable : Boolean Read FAuthenticationEnable Write FAuthenticationEnable; // AUTHENTICATION_ENABLE: true,
+    Property AutoPinLatestScreenShare : string Read FAutoPinLatestScreenShare write FAutoPinLatestScreenShare; //       AUTO_PIN_LATEST_SCREEN_SHARE: 'remote-only',
+    Property BrandWaterMarkLink : String Read FBrandWaterMarkLink Write FBrandWaterMarkLink; // BRAND_WATERMARK_LINK: '',
+    Property ClosePageGuestHint : String Read FClosePageGuestHint Write FClosePageGuestHint; // CLOSE_PAGE_GUEST_HINT
+    Property ConnectionIndicatorAutoHideEnabled : Boolean Read FConnectionIndicatorAutoHideEnabled write FConnectionIndicatorAutoHideEnabled; //       CONNECTION_INDICATOR_AUTO_HIDE_ENABLED: true,
+    Property ConnectionIndicatorAutoHideTimeout : NativeInt Read FConnectionIndicatorAutoHideTimeout write FConnectionIndicatorAutoHideTimeout; //       CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT: 5000,
+    Property ConnectionIndicatorDisabled : Boolean Read FConnectionIndicatorDisabled write FConnectionIndicatorDisabled; //       CONNECTION_INDICATOR_DISABLED: false,
+    Property DefaultBackground : String Read FDefaultBackground Write FDefaultBackground; // DEFAULT_BACKGROUND: String;
+    Property DefaultLocalDisplayName : String Read FDefaultLocalDisplayName Write FDefaultLocalDisplayName; //  DEFAULT_LOCAL_DISPLAY_NAME: 'me',
+    Property DefaultRemoteDisplayName : String Read FDefaultRemoteDisplayName Write FDefaultRemoteDisplayName; //   DEFAULT_REMOTE_DISPLAY_NAME: 'Fellow Jitster',
+    Property DisableDominantSpeakerIndicator : Boolean Read FDisableDominantSpeakerIndicator Write FDisableDominantSpeakerIndicator; // DISABLE_DOMINANT_SPEAKER_INDICATOR: false,
+    Property DisableFocusIndicator: Boolean Read FDisableFocusIndicator Write FDisableFocusIndicator; //  DISABLE_FOCUS_INDICATOR: true,
+    Property DisableJoinLeaveNotifications : boolean Read FDisableJoinLeaveNotifications write FDisableJoinLeaveNotifications; //       DISABLE_JOIN_LEAVE_NOTIFICATIONS: true
+    Property DisablePresenceStatus : boolean Read FDisablePresenceStatus write FDisablePresenceStatus; //       DISABLE_PRESENCE_STATUS: true,
+    Property DisableRinging : Boolean Read FDisableRinging write FDisableRinging; //       DISABLE_RINGING: false,
+    Property DisableTranscriptionSubtitles : Boolean Read  FDisableTranscriptionSubtitles Write FDisableTranscriptionSubtitles; // DISABLE_TRANSCRIPTION_SUBTITLES: false,
+    Property DisableVideoBackground : Boolean Read FDisableVideoBackground Write FDisableVideoBackground; //   DISABLE_VIDEO_BACKGROUND: false,
+    Property DisplayWelcomePageContent : Boolean Read FDisplayWelcomePageContent Write FDisplayWelcomePageContent; //    DISPLAY_WELCOME_PAGE_CONTENT: true,
+    Property DisplayWelcomePageToolbarAdditionalContent : Boolean Read FDisplayWelcomePageToolbarAdditionalContent Write FDisplayWelcomePageToolbarAdditionalContent; //  DISPLAY_WELCOME_PAGE_TOOLBAR_ADDITIONAL_CONTENT: false,
+    Property EnableFeedBackAnimation : Boolean Read FEnableFeedBackAnimation Write FEnableFeedBackAnimation; //  ENABLE_FEEDBACK_ANIMATION: false,
+    Property EnforceNotificationAutoDismissTimeout : Nativeint  Read FEnforceNotificationAutoDismissTimeout write FEnforceNotificationAutoDismissTimeout; //       ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT: 15000,
+    Property FilmStripMaxHeight : NativeInt Read FFilmStripMaxHeight Write FFilmStripMaxHeight; //  FILM_STRIP_MAX_HEIGHT: 120,
+    Property FilmStripOnly : Boolean Read FFilmStripOnly Write FFilmStripOnly;  // filmStripOnly: false,
+    Property GenerateRoomNamesOnWelcomePage : Boolean Read FGenerateRoomNamesOnWelcomePage Write FGenerateRoomNamesOnWelcomePage; //  GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
+    Property InitialToolbarTimeOut : NativeInt Read FInitialToolbarTimeOut Write FInitialToolbarTimeOut; //       INITIAL_TOOLBAR_TIMEOUT: 20000,
+    Property InvitationPoweredBy : Boolean Read FInvitationPoweredBy Write FInvitationPoweredBy; //  INVITATION_POWERED_BY: true,
+    Property JitsiWaterMarkLink : String Read FJitsiWaterMarkLink Write FJitsiWaterMarkLink; // JITSI_WATERMARK_LINK: 'https://jitsi.org',
+    Property LangDetection : Boolean Read FLangDetection Write FLangDetection; //   LANG_DETECTION: false, // Allow i18n to detect the system language
+    Property LiveStreamingHelpLink : string Read FLiveStreamingHelpLink write FLiveStreamingHelpLink; //       LIVE_STREAMING_HELP_LINK: 'https://jitsi.org/live',
+    Property LocalThumbnailRatio : Double Read FLocalThumbnailRatio write FLocalThumbnailRatio; //       LOCAL_THUMBNAIL_RATIO: 16 / 9, // 16:9
+    Property MaximumZoomingCoefficient : Double Read FMaximumZoomingCoefficient write FMaximumZoomingCoefficient; //       MAXIMUM_ZOOMING_COEFFICIENT: 1.3,
+    Property MobileAppPromo : Boolean Read FMobileAppPromo write FMobileAppPromo; //       MOBILE_APP_PROMO: true,
+    Property MobileDownloadLinkAndroid : String Read FMobileDownloadLinkAndroid write FMobileDownloadLinkAndroid; //       MOBILE_DOWNLOAD_LINK_ANDROID: 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
+    Property MobileDownloadLinkIos : String Read FMobileDownloadLinkIos write FMobileDownloadLinkIos; //       MOBILE_DOWNLOAD_LINK_IOS: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
+    Property NativeAppName : STring Read FNativeAppName Write FNativeAppName; //   NATIVE_APP_NAME: 'Jitsi Meet',
+    Property OptimalBrowsers : TStringDynArray Read FOptimalBrowsers write FOptimalBrowsers; //       OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'nwjs', 'electron' ],
+    Property PolicyLogo : String  Read FPolicyLogo write FPolicyLogo; //       POLICY_LOGO: null,
+    Property ProviderName : string Read FProviderName Write FProviderName; //  PROVIDER_NAME: 'Jitsi',
+    Property RandomAvatarURLPrefix : String Read FRandomAvatarURLPrefix Write FRandomAvatarURLPrefix; //  RANDOM_AVATAR_URL_PREFIX
+    Property RandomAvatarURLSuffix : String Read FRandomAvatarURLSuffix Write FRandomAvatarURLSuffix; //  RANDOM_AVATAR_URL_SUFFIX
+    Property RecentListEnabled : Boolean Read FRecentListEnabled write FRecentListEnabled; //       RECENT_LIST_ENABLED: true,
+    Property RemoteThumbnailRatio : Double Read FRemoteThumbnailRatio write FRemoteThumbnailRatio; //       REMOTE_THUMBNAIL_RATIO: 1, // 1:1
+    Property SettingSections : TStringDynArray Read FSettingSections Write FSettingSections; // SETTINGS_SECTIONS:
+    Property ShowBrandWaterMark : Boolean Read FShowBrandWaterMark Write FShowBrandWaterMark; //  SHOW_BRAND_WATERMARK: false,
+    Property ShowChromeExtensionBanner : boolean Read FShowChromeExtensionBanner write FShowChromeExtensionBanner; //       SHOW_CHROME_EXTENSION_BANNER: true,
+    Property ShowDeepLinkingImage : Boolean Read FShowDeepLinkingImage Write FShowDeepLinkingImage; //  SHOW_DEEP_LINKING_IMAGE: false,
+    Property ShowJitsiWaterMark : Boolean Read FShowJitsiWaterMark Write FShowJitsiWaterMark; //  SHOW_JITSI_WATERMARK: true,
+    Property ShowPoweredBy : Boolean Read FShowPoweredBy Write FShowPoweredBy; //   SHOW_POWERED_BY: false,
+    Property ShowPromotionalClosePage : Boolean Read FShowPromotionalClosePage Write FShowPromotionalClosePage; // SHOW_PROMOTIONAL_CLOSE_PAGE
+    Property ShowWaterMarkForGuests : Boolean Read FShowWaterMarkForGuests Write FShowWaterMarkForGuests; //   SHOW_WATERMARK_FOR_GUESTS: true,
+    Property SupportUrl : String Read FSupportUrl write FSupportUrl; //       SUPPORT_URL: 'https://github.com/jitsi/jitsi-meet/issues/new',
+    Property TileViewMaxColumns : NativeInt  Read FTileViewMaxColumns write FTileViewMaxColumns; //       TILE_VIEW_MAX_COLUMNS: 5,
+    Property ToolbarAlwaysVisible: Boolean Read FToolbarAlwaysVisible Write FToolbarAlwaysVisible; //  TOOLBAR_ALWAYS_VISIBLE: false,
+    Property ToolbarButtons : TStringDynArray Read FToolbarButtons Write FToolbarButtons; //  TOOLBAR_BUTTONS:
+    Property ToolbarTimeOut : NativeInt Read FToolbarTimeOut Write FToolbarTimeOut; //  TOOLBAR_TIMEOUT: 4000,
+    Property UnsupportedBrowsers : TStringDynArray Read FUnsupportedBrowsers write FUnsupportedBrowsers; //       UNSUPPORTED_BROWSERS: [],
+    Property VerticalFilmStrip : Boolean Read FVerticalFilmStrip Write FVerticalFilmStrip; // VERTICAL_FILMSTRIP: true,
+    Property VideoLayoutFit : String Read FVideoLayoutFit Write FVideoLayoutFit; // VIDEO_LAYOUT_FIT: 'both',
+    Property VideoQualityLabelDisabled : Boolean Read FVideoQualityLabelDisabled write FVideoQualityLabelDisabled; //       VIDEO_QUALITY_LABEL_DISABLED: false,
+  end;
+
+  TJMMeetOptions = class external name 'Object' (TJSObject)
+  Public
+    roomName : String;
+    width : Integer;
+    widthString : String; external name 'width';
+    height : Integer;
+    heightString : String; external name 'height';
+    parentNode : TJSHTMLElement;
+    configOverwrite: TJSObject;
+    interfaceConfigOverwrite: TJMInterfaceConfig;
+    noSSL : Boolean;
+    jwt : String;
+    onload : TJSRawEventHandler;
+    invitees : TJMInviteeDynArray;
+    devices : TJMDevices;
+    userInfo : TJMUserInfo;
+  end;
+
+  { TJMMediaDevice }
+
+  TJMMediaDevice = class external name 'Object' (TJSObject)
+  private
+    FDeviceID: String; external name 'deviceId';
+    FGroupID: String; external name 'groupId';
+    FKind: String; external name 'lind';
+    FLabel: String; external name 'label';
+  public
+    Property DeviceId : String Read FDeviceID;
+    Property GroupId : String Read FGroupID;
+    Property Kind : String Read FKind;
+    Property Label_ : String read FLabel;
+  end;
+  TJMMediaDeviceDynArray = Array of TJMMediaDevice;
+
+  { TJMAvailableDevicesResponse }
+
+  TJMAvailableDevicesResponse = class external name 'Object' (TJSObject)
+  private
+    FAudioInput: TJMMediaDeviceDynArray; external name 'audioInput';
+    FAudioOutput: TJMMediaDeviceDynArray; external name 'audioOutput';
+    FVideoInput: TJMMediaDeviceDynArray; external name 'videoInput';
+  Public
+    property AudioInput : TJMMediaDeviceDynArray read FAudioInput;
+    property AudioOutput : TJMMediaDeviceDynArray read FAudioOutput;
+    property VideoInput : TJMMediaDeviceDynArray Read FVideoInput;
+  end;
+
+
+  { TJMCurrentDevicesResponse }
+
+  TJMCurrentDevicesResponse = class external name 'Object' (TJSObject)
+  private
+    fAudioInput: TJMMediaDeviceDynArray; external name 'audioInput';
+    fAudioOutput: TJMMediaDeviceDynArray; external name 'audioOutput';
+    fVideoInput: TJMMediaDeviceDynArray; external name 'videoInput';
+  Public
+    property AudioInput : TJMMediaDeviceDynArray read fAudioInput;
+    property AudioOutput : TJMMediaDeviceDynArray read fAudioOutput;
+    property VideoInput : TJMMediaDeviceDynArray read fVideoInput;
+  end;
+
+  TJMEventEmitter = class external name 'Object' (TJSObject)
+  Public
+    Procedure addListener(aName : String; aCallBack : TJMEventHandler);
+    Procedure On_(aName : String; aCallBack : TJMEventHandler); external name 'on';
+    Procedure Off(aName : String; aCallBack : TJMEventHandler); external name 'off';
+    Procedure removeAllListeners(aName : String);
+    Procedure removeListener(aName : String; aCallBack : TJMEventHandler);
+  end;
+
+  TJMExternalAPI = class external name 'JitsiMeetExternalAPI' (TJMEventEmitter)
+  Public
+    Constructor new (aDomain : String; aOptions : TJMMeetOptions);
+    Procedure dispose;
+    Procedure executeCommand(aCommand : String); overload;
+    Procedure executeCommand(aCommand : String; Arg : String); overload;
+    Procedure executeCommand(aCommand : String; Arg1,Arg2 : String); overload;
+    Procedure executeCommand(aCommand : String; Options : TJSObject); overload;
+    Procedure executeCommands(commands : TJMCommands);
+    Function getAvailableDevices : TJSPromise;
+    Function getAvatarURL : String;
+    Function getCurrentDevices : TJSPromise;
+    Function getDisplayName : String;
+    Function getEmail : String;
+    Function getIFrame : TJSHTMLElement;
+    Function getNumberOfParticipants : NativeInt;
+    Function invite(aInvitees : TJMInviteDynArray): TJSPromise;
+    Function isAudioAvailable : TJSPromise;
+    Function isAudioMuted : TJSPromise;
+    Function isDeviceChangeAvailable(const aDeviceType : String) : TJSPromise;
+    Function isDeviceListAvailable : TJSPromise;
+    Function isMultipleAudioInputSupported : TJSPromise;
+    Function isVideoAvailable : TJSPromise;
+    Function isVideoMuted : TJSPromise;
+    Procedure setAudioInputDevice(const aDeviceLabel,aDeviceId : String);
+    Procedure setAudioOutputDevice(const aDeviceLabel,aDeviceId : String);
+    Procedure setVideoInputDevice(const aDeviceLabel,aDeviceId : String);
+  end;
+
+  { TJSMSendTones }
+
+  TJMSendTones = class external name 'Object' (TJSObject)
+  private
+    FDuration: NativeInt; external name 'duration';
+    FPause: NativeInt; external name 'pause';
+    FTones: String; external name 'tones';
+  Public
+    Property Tones : String Read FTones Write FTones;
+    Property Duration : NativeInt Read FDuration Write FDuration;
+    Property Pause : NativeInt Read FPause Write FPause;
+  end;
+
+  { TJMExternalAPIHelper }
+
+  TJMExternalAPIHelper = class helper for TJMExternalAPI
+  Public
+    procedure SetDisplayName (Const aName : string);
+    procedure SetPassword (Const aPassword : string);
+    procedure SendTones (aTones :TJMSendTones);
+    procedure SetSubject(Const aSubject : string);
+    procedure ToggleAudio;
+    procedure ToggleVideo;
+    procedure ToggleFilmStrip;
+    procedure ToggleChat;
+    procedure ToggleShareScreen;
+    procedure ToggleTileView;
+    procedure Hangup;
+    procedure Email(Const aEmail : string);
+    procedure AvatarURL(Const aURL : string);
+    procedure SendEndPointTextMessage(Const aParticipantID,aText : string);
+  end;
+
+function UIElementsStrings(aElements : TJMUIElements) : TStringDynArray;
+function UISettingsStrings(aUISettings : TJMUISettings) : TStringDynArray;
+
+Const
+  UIElementNames : Array[TJMUIElement] of string = (
+    UIMicrophone, UICamera, UIClosedCaptions, UIDesktop,
+    UIFullScreen, UIFODeviceSelection, UIHangup, UIChat, UIRecording,
+    UILiveStreaming, UIEtherPad, UISharedVideo, UISettings, UIVideoQuality,
+    UIFilmStrip, UIFeedBack, UIStats, UIShortCuts, UITileView,
+    UIVideoBackgroundBlur, UIDownload, UIHelp, UIMuteEveryone,
+    UIProfile, UIInfo, UIRaiseHand, UIInvite
+  );
+  UISettingNames : Array[TJMUISetting] of string =
+    (UISettingDevices,  UISettingLanguage,  UISettingModerator,  UISettingProfile,  UISettingCalendar);
+
+
+
+implementation
+
+{ TJMExternalAPIHelper }
+
+procedure TJMExternalAPIHelper.SetDisplayName(const aName: string);
+begin
+  ExecuteCommand(CommandDisplayName,aName);
+end;
+
+procedure TJMExternalAPIHelper.SetPassword(const aPassword: string);
+begin
+  ExecuteCommand(CommandPassword,aPassword);
+end;
+
+procedure TJMExternalAPIHelper.SendTones(aTones: TJMSendTones);
+begin
+  executeCommand(CommandSendTones,aTones);
+end;
+
+procedure TJMExternalAPIHelper.SetSubject(const aSubject: string);
+begin
+  ExecuteCommand(CommandSubject,aSubject);
+end;
+
+procedure TJMExternalAPIHelper.ToggleAudio;
+begin
+  ExecuteCommand(CommandToggleAudio);
+end;
+
+procedure TJMExternalAPIHelper.ToggleVideo;
+begin
+  ExecuteCommand(CommandToggleVideo);
+end;
+
+procedure TJMExternalAPIHelper.ToggleFilmStrip;
+begin
+  ExecuteCommand(CommandToggleFilmStrip);
+end;
+
+procedure TJMExternalAPIHelper.ToggleChat;
+begin
+  ExecuteCommand(CommandToggleChat);
+end;
+
+procedure TJMExternalAPIHelper.ToggleShareScreen;
+begin
+  ExecuteCommand(CommandToggleShareScreen);
+end;
+
+procedure TJMExternalAPIHelper.ToggleTileView;
+begin
+  ExecuteCommand(CommandToggleTileView);
+end;
+
+procedure TJMExternalAPIHelper.Hangup;
+begin
+  ExecuteCommand(CommandHangup);
+end;
+
+procedure TJMExternalAPIHelper.Email(const aEmail: string);
+begin
+  ExecuteCommand(commandEmail,aEmail);
+end;
+
+procedure TJMExternalAPIHelper.AvatarURL(const aURL: string);
+begin
+  ExecuteCommand(CommandAvatarURL,aURL);
+end;
+
+procedure TJMExternalAPIHelper.SendEndPointTextMessage(const aParticipantID, aText: string);
+begin
+  ExecuteCommand(CommandSendEndPointTextMessage,aParticipantID,atext);
+end;
+
+
+function UISettingsStrings(aUISettings: TJMUISettings): TStringDynArray;
+
+Var
+  Len: Integer;
+  S : TJMUISetting;
+
+begin
+  Len:=0;
+  SetLength(Result,Ord(High(TJMUISetting)));
+  For S in TJMUISetting do
+    if S in aUISettings then
+      begin
+      Result[Len]:=UISettingNames[S];
+      Inc(Len);
+      end;
+  SetLength(Result,len);
+
+end;
+
+function UIElementsStrings(aElements: TJMUIElements): TStringDynArray;
+
+Var
+  Len: Integer;
+  J : TJMUIElement;
+
+begin
+  Len:=0;
+  SetLength(Result,Ord(High(TJMUIElement)));
+  For J in TJMUIElement do
+    if J in aElements then
+      begin
+      Result[Len]:=UIElementNames[J];
+      Inc(Len);
+      end;
+  SetLength(Result,len);
+end;
+
+end.
+

+ 777 - 0
packages/opentok/libopentok.pas

@@ -0,0 +1,777 @@
+{
+    This file is part of the Pas2JS run time library.
+    Copyright (c) 2020 by Michael Van Canneyt
+
+    OpenTok.js import classes.
+
+    Actual Opentok API is copyright Tokbox/Nexmo/Vonage
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit libopentok;
+
+{$mode objfpc}
+{$modeswitch externalclass}
+
+interface
+
+uses
+  JS, web;
+
+Type
+  TJSMediaStreamTrack = class external name 'MediaStreamTrack' (TJSObject);
+
+{ ---------------------------------------------------------------------
+  Forward declarations
+  ---------------------------------------------------------------------}
+
+  TOT = Class;
+  TOTArchiveEvent = Class;
+  TOTAudioLevelUpdatedEvent = Class;
+  TOTCapabilities = Class;
+  TOTConnection = Class;
+  TOTConnectionEvent = Class;
+  TOTDevice = Class;
+  TOTError = Class;
+  TOTEvent = Class;
+  TOTEventDispatcher = Class;
+  TOTExceptionEvent = Class;
+  TOTGetDevicesResponse = Class;
+  TOTGetUserMediaOptions = Class;
+  TOTInitPublisherOptions = Class;
+  TOTInitSessionOptions = Class;
+  TOTMediaStoppedEvent = Class;
+  TOTPublisher = Class;
+  TOTPublisherStats = Class;
+  TOTPublisherStyleOptions = Class;
+  TOTScreenSharingCapabilities = Class;
+  TOTSession = Class;
+  TOTSessionConnectEvent = Class;
+  TOTSessionDisonnectEvent = Class;
+  TOTSignalEvent = Class;
+  TOTStream = Class;
+  TOTStreamEvent = Class;
+  TOTStreamPropertyChangedEvent = Class;
+  TOTSubscriber = Class;
+  TOTSubscriberStats = Class;
+  TOTSubscriberStyleOptions = Class;
+  TOTSupportedCodecsResponse = Class;
+  TOTUIStyle = Class;
+  TOTVideoElementCreatedEvent = Class;
+  TOTVideoEnabledChangedEvent = Class;
+
+  TOTConnectionDynArray = Array of TOTConnection;
+  TOTStreamDynArray = Array of TOTStream;
+
+{ ---------------------------------------------------------------------
+  Events
+  ---------------------------------------------------------------------}
+
+
+  TOTEvent = Class external name 'ArchiveEvent' (TJSEvent)
+  Public
+    Function isDefaultPrevented : Boolean;
+  end;
+
+  { TOTStreamEvent }
+
+  TOTBaseStreamEvent  = Class external name 'StreamEvent' (TOTEvent)
+  private
+    FStream: TOTStream; external name 'stream';
+  public
+    Property Stream : TOTStream read FStream;
+  end;
+
+  { TOTStreamEvent }
+
+  TOTStreamEvent  = Class external name 'StreamEvent' (TOTBaseStreamEvent)
+  private
+    Fcancelable: Boolean; external name 'cancelable';
+    FReason: string; external name 'reason';
+  Public
+    Property Cancelable : Boolean Read Fcancelable;
+    Property Reason : string read FReason;
+  end;
+
+  { TOTStreamPropertyChangedEvent }
+
+  TOTStreamPropertyChangedEvent = Class external name 'StreamPropertyChangedEvent' (TOTBaseStreamEvent)
+  Private
+    FChangedProperty: string; external name 'changedProperty';
+    FNewValue: TJSObject; external name 'newValue';
+    FOldValue: TJSObject; external name 'oldValue';
+  Public
+    Property ChangedProperty : string read FChangedProperty;
+    Property NewValue : TJSObject Read FNewValue;
+    Property OldValue : TJSObject Read FOldValue;
+  end;
+
+  { TOTSessionConnectEvent }
+
+  TOTSessionConnectEvent  = Class external name 'SessionConnect' (TOTEvent)
+  private
+    FReason: string; external name 'reason';
+  Public
+    Property Reason : string read FReason;
+  end;
+
+  { TOTSessionDisonnectEvent }
+
+  TOTSessionDisonnectEvent  = Class external name 'SessionDisconnect' (TOTEvent)
+  private
+    FConnections: TOTConnectionDynArray; external name 'connections';
+    FStreams: TOTStreamDynArray; external name 'streams';
+  Public
+    Property Connections : TOTConnectionDynArray Read FConnections;
+    Property Streams : TOTStreamDynArray Read FStreams;
+  end;
+
+  { TOTSignalEvent }
+
+  TOTSignalEvent  = Class external name 'SignalEvent' (TOTEvent)
+  private
+    FData: string; external name 'data';
+    FFrom: TOTConnection; external name 'from';
+    Ftype: string; external name 'type';
+  Public
+    Property Data : string read FData;
+    Property From : TOTConnection Read FFrom;
+    Property Type_ : string read Ftype;
+  end;
+
+  { TOTAudioLevelUpdatedEvent }
+
+  TOTAudioLevelUpdatedEvent = Class external name 'AudioLevelUpdatedEvent' (TOTEvent)
+  private
+    faudiolevel: Double;  external name 'audioLevel';
+  Public
+    Property AudioLevel : Double read faudiolevel;
+  end;
+
+  { TOTConnectionEvent }
+
+  TOTConnectionEvent = Class external name 'ConnectionEvent' (TOTEvent)
+  private
+    fconnection: TOTConnection;external name 'connection';
+    freason: string;external name 'reason';
+  Public
+    Property Connection : TOTConnection read fconnection;
+    Property Reason : string read freason;
+  end;
+
+  { TOTExceptionEvent }
+
+  TOTExceptionEvent = Class external name 'ExceptionEvent' (TOTEvent)
+  private
+    FCode: nativeint;external name 'code';
+    FMessage: string;external name 'message';
+    FTitle: string;external name 'title';
+  Public
+    Property Code : nativeint read FCode;
+    Property Message : string read FMessage;
+    Property Title : string read FTitle;
+  end;
+
+  { TOTMediaStoppedEvent }
+
+  TOTMediaStoppedEvent = Class external name 'MediaStoppedEvent' (TOTEvent)
+  private
+    FMessage: string; external name 'message';
+    FTitle: string; external name 'title';
+    FTrack: TJSMediaStreamTrack; external name 'track';
+  Public
+    Property Message : string read FMessage;
+    Property Title : string Read FTitle;
+    Property Track : TJSMediaStreamTrack Read FTrack;
+  end;
+
+  { TOTArchiveEvent }
+
+  TOTArchiveEvent = Class external name 'ArchiveEvent' (TOTEvent)
+  private
+    FID: string; external name 'id';
+    FName: string; external name 'name';
+  Public
+    Property ID : string read FID;
+    Property Name : string read FName;
+  end;
+
+  { TOTVideoElementCreatedEvent }
+
+  TOTVideoElementCreatedEvent = Class external name 'VideoElementCreatedEvent' (TOTEvent)
+  private
+    Felement: TJSHTMLElement; external name 'element';
+  Public
+    Property Element : TJSHTMLElement Read Felement;
+  end;
+
+  { TOTVideoEnabledChangedEvent }
+
+  TOTVideoEnabledChangedEvent = Class external name 'VideoEnabledChangedEvent' (TOTEvent)
+  private
+    FCancelable: Boolean; external name 'cancelable';
+    FReason: string; external name 'reason';
+    FTarget: TJSObject; external name 'target';
+    FType: string; external name 'type';
+  Public
+    Property Cancelable : Boolean Read FCancelable;
+    Property Reason : string Read FReason;
+    Property Target : TJSObject Read FTarget;
+    Property Type_ : string read FType;
+  end;
+
+  { ---------------------------------------------------------------------
+    Real classes
+    ---------------------------------------------------------------------}
+
+
+  { TOTError }
+
+  TOTError = class external name 'Error' (TJSError)
+  Private
+    FCode: nativeint;  external name 'code';
+    FName: string; external name 'name';
+  Public
+    Property Code : nativeint read FCode Write FCode;
+    Property name : string read FName Write FName;
+  end;
+  TOTErrorHandler = reference to procedure(aErr : TOTError);
+
+  { TOTEventDispatcher }
+
+  TOTEventDispatcher = Class external name 'EventDispatcher' (TJSObject)
+  Public
+    Procedure off(aType : string; aHandler : TJSEventHandler); overload;
+    Procedure off(aType : string); overload;
+    Procedure off(aTypes : TJSObject; aContext : JSValue); overload;
+    Procedure off(aTypes : TJSObject); overload;
+    Function on_(aType : string; aHandler : TJSEventHandler) : TOTEventDispatcher; overload; external name 'on';
+    Function on_(aType : string; aHandler : TJSEventHandler; aContext : JSValue): TOTEventDispatcher; overload; external name 'on';
+    Function on_(aType : string; aHandler : TJSRawEventHandler) : TOTEventDispatcher; overload; external name 'on';
+    Function on_(aType : string; aHandler : TJSRawEventHandler; aContext : JSValue): TOTEventDispatcher; overload; external name 'on';
+    Function once(aType : string; aHandler : TJSRawEventHandler) : TJSObject; overload;
+    Function once(aType : string; aHandler : TJSRawEventHandler; aContext : JSValue) : TJSObject; overload;
+    Function once(aType : string; aHandler : TJSEventHandler) : TJSObject; overload;
+    Function once(aType : string; aHandler : TJSEventHandler; aContext : JSValue) : TJSObject; overload;
+  end;
+
+  TOTConnection  = Class external name 'Connection' (TJSObject)
+  Private
+    FconnectionId : string; external name 'connectionId';
+    FcreationTime : NativeInt;  external name 'creationTime';
+    Fdata : string; external name 'data';
+  Public
+    Property connectionId : string Read FconnectionId Write FconnectionId;
+    Property creationTime : NativeInt Read FcreationTime Write FcreationTime;
+    Property data : string Read Fdata Write Fdata;
+  end;
+
+  TOTMediaResolution = Record
+    height : nativeint;
+    width : nativeint;
+  end;
+
+  { TOTStream }
+
+  TOTStream = Class external name 'Stream' (TJSObject)
+  private
+    FConnection: TOTConnection; external name 'connection';
+    FCreationTime: NativeInt; external name 'creationTime';
+    FFrameRate: NativeInt; external name 'frameRate';
+    FHasAudio: Boolean; external name 'hasAudio';
+    FHasVideo: Boolean; external name 'hasVideo';
+    FName: string; external name 'name';
+    FStreamID: string; external name 'streamId';
+    FvideoDimensions: TOTMediaResolution; external name 'videoDimensions';
+    FVideoType: string; external name 'videoType';
+  Public
+    Property Connection : TOTConnection Read FConnection;
+    Property CreationTime : NativeInt Read FCreationTime;
+    Property FrameRate : NativeInt Read FFrameRate;
+    Property HasAudio : Boolean Read FHasAudio;
+    Property HasVideo : Boolean Read FHasVideo;
+    Property Name : string Read FName;
+    Property StreamId : string Read FStreamID;
+    Property VideoDimensions : TOTMediaResolution Read FvideoDimensions;
+    Property VideoType : string Read FVideoType;
+  end;
+
+  TOTCapabilities = Class external name 'Capabilities' (TJSObject)
+  Private
+    FforceDisconnect : byte; external name 'forceDisconnect';
+    FforceUnpublish : byte; external name 'forceUnpublish';
+    Fpublish : byte; external name 'publish';
+    Fsubscribe : byte; external name 'subscribe';
+  Public
+    Property forceDisconnect : byte Read FforceDisconnect Write FforceDisconnect;
+    Property forceUnpublish : byte Read FforceUnpublish Write FforceUnpublish;
+    Property publish : byte Read Fpublish Write Fpublish;
+    Property subscribe : byte Read Fsubscribe Write Fsubscribe;
+  end;
+
+  { TOTScreenSharingCapabilities }
+
+  TOTScreenSharingCapabilities = Class external name 'Object' (TJSOBject)
+  private
+    FextensionRegistered: Boolean; external name 'extensionRegistered';
+    FextensionInstalled: boolean; external name 'extensionInstalled';
+    FextensionRequired: string; external name 'extensionRequired';
+    FSupported: boolean;external name 'supported';
+    FsupportedSources: TJSObject;external name 'supportedSources';
+  Public
+    Property extensionInstalled : boolean Read FextensionInstalled;
+    Property supported : boolean read FSupported;
+    Property supportedSources : TJSObject read FsupportedSources ; deprecated;
+    Property extensionRequired : string read FextensionRequired;
+    Property extensionRegistered : Boolean read FextensionRegistered;
+  end;
+  TOTScreenSharingCapabilityCallback = reference to Procedure (aResponse : TOTScreenSharingCapabilities);
+
+  { TOTDevice }
+
+  TOTDevice = class external name 'Object' (TJSOBject)
+  private
+    FDeviceID: string; external name 'deviceId';
+    FKind: string; external name 'kind';
+    FLabel: String; external name 'label';
+  Public
+    Property DeviceId : string read FDeviceID;
+    Property Kind : string read FKind;
+    Property Label_ : String read FLabel;
+  end;
+  TOTDeviceDynArray = Array of TOTDevice;
+
+  { TOTGetDevicesResponse }
+
+  TOTGetDevicesResponse = Class external name 'Object' (TJSOBject)
+  private
+    FDevices: TOTDeviceDynArray; external name 'devices';
+    FError: TOTError; external name 'devices';
+  Public
+    Property Devices : TOTDeviceDynArray read FDevices;
+    Property Error : TOTError read FError;
+  end;
+  TOTGetDevicesCallback = reference to Procedure (aResponse : TOTGetDevicesResponse);
+
+  { TOTSupportedCodecsResponse }
+
+  TOTSupportedCodecsResponse = class external name 'Object' (TJSObject)
+  private
+    FvideoDecoders: TStringDynArray; external name 'videoDecoders';
+    FVideoEncoders: TStringDynArray; external name 'videoEncoders';
+  public
+    Property VideoDecoders : TStringDynArray Read FvideoDecoders;
+    Property VideoEncoders : TStringDynArray read FVideoEncoders;
+  end;
+
+  TOTGetUserMediaOptions = class external name 'Object' (TJSObject)
+  Private
+    FaudioSource : JSValue; external name 'audioSource';
+    FaudioSourceString : String; external name 'audioSource';
+    FaudioSourceBoolean : boolean; external name 'audioSource';
+    FaudioSourceTrack : TJSMediaStreamTrack; external name 'audioSource';
+    FenableStereo : Boolean; external name 'enableStereo';
+    FdisableAudioProcessing : Boolean;  external name 'disableAudioProcessing';
+    FfacingMode : string; external name 'facingMode';
+    FframeRate : Byte;external name 'frameRate';
+    FmaxResolution : TOTMediaResolution; external name 'maxResolution';
+    Fresolution : string; external name 'resolution';
+    FvideoSource : JSValue; external name 'audioSource';
+    FvideoSourceString : String; external name 'audioSource';
+    FvideoSourceBoolean : boolean; external name 'audioSource';
+    FvideoSourceTrack : TJSMediaStreamTrack; external name 'audioSource';
+  Public
+    Property AudioSource : JSValue Read FaudioSource Write FaudioSource;
+    Property AudioSourceString : String Read FaudioSourceString Write FaudioSourceString;
+    Property AudioSourceBoolean : boolean Read FaudioSourceBoolean Write FaudioSourceBoolean;
+    Property AudioSourceTrack : TJSMediaStreamTrack Read FaudioSourceTrack Write FaudioSourceTrack;
+    Property DisableAudioProcessing : Boolean Read FdisableAudioProcessing Write FdisableAudioProcessing;
+    Property EnableStereo : Boolean Read FenableStereo Write FenableStereo;
+    Property FacingMode : string Read FfacingMode Write FfacingMode;
+    Property FrameRate : Byte Read FframeRate Write FframeRate;
+    Property MaxResolution : TOTMediaResolution Read FmaxResolution Write FmaxResolution;
+    Property Resolution : string Read Fresolution Write Fresolution;
+    Property VideoSource : JSValue Read FvideoSource Write FvideoSource;
+    Property VideoSourceString : String Read FvideoSourceString Write FvideoSourceString;
+    Property VideoSourceBoolean : boolean Read FvideoSourceBoolean Write FvideoSourceBoolean;
+    Property VideoSourceTrack : TJSMediaStreamTrack Read FvideoSourceTrack Write FvideoSourceTrack;
+  end;
+
+  TOTUIStyle = Class external name 'Object' (TJSObject)
+  Public
+    FarchiveStatusDisplayMode : string; external name 'archiveStatusDisplayMode';
+    FaudioLevelDisplayMode : string; external name 'audioLevelDisplayMode';
+    FbackgroundImageURI : String; external name 'backgroundImageURI';
+    FbuttonDisplayMode : String; external name 'buttonDisplayMode';
+    FnameDisplayMode : string; external name 'nameDisplayMode';
+  Public
+    Property ArchiveStatusDisplayMode : string Read FarchiveStatusDisplayMode Write FarchiveStatusDisplayMode;
+    Property AudioLevelDisplayMode : string Read FaudioLevelDisplayMode Write FaudioLevelDisplayMode;
+    Property BackgroundImageURI : String Read FbackgroundImageURI Write FbackgroundImageURI;
+    Property ButtonDisplayMode : String Read FbuttonDisplayMode Write FbuttonDisplayMode;
+    Property NameDisplayMode : string Read FnameDisplayMode Write FnameDisplayMode;
+  end;
+
+  TOTInitPublisherOptions = Class external name 'Object' (TOTGetUserMediaOptions)
+  Private
+    FaudioBitrate : Nativeint; external name 'audioBitrate';
+    FaudioFallbackEnabled : Boolean;  external name 'audioFallbackEnabled';
+    FfitMode: string; external name 'fitMode';
+    Fheight : NativeInt; external name 'height';
+    FheightString : String; external name 'height'; // Same as height but as string;
+    FinsertDefaultUI : Boolean; external name 'insertDefaultUI';
+    FinsertMode : string; external name 'insertMode';
+    Fmirror : boolean; external name 'mirror';
+    Fname : string;external name 'name';
+    FpublishAudio : Boolean; external name 'publishAudio';
+    FpublishVideo : Boolean; external name 'publishVideo';
+    FshowControls : Boolean; external name 'showControls';
+    Fstyle : TOTUIStyle; external name 'style';
+    FusePreviousDeviceSelection : Boolean;   external name 'usePreviousDeviceSelection';
+    Fwidth : NativeInt; external name 'width';
+    FwidthString : String; external name 'width'; // Same as width but as string;
+  Public
+    Property AudioBitrate : Nativeint Read FaudioBitrate Write FaudioBitrate ;
+    Property AudioFallbackEnabled : Boolean Read FaudioFallbackEnabled Write FaudioFallbackEnabled ;
+    Property FitMode: string Read FfitMode Write FfitMode ;
+    Property Height : NativeInt Read Fheight Write Fheight ;
+    Property HeightString : String Read FheightString Write FheightString ;
+    Property InsertDefaultUI : Boolean Read FinsertDefaultUI Write FinsertDefaultUI ;
+    Property InsertMode : string Read FinsertMode Write FinsertMode ;
+    Property Mirror : boolean Read Fmirror Write Fmirror ;
+    Property Name : string Read Fname Write Fname ;
+    Property PublishAudio : Boolean Read FpublishAudio Write FpublishAudio ;
+    Property PublishVideo : Boolean Read FpublishVideo Write FpublishVideo ;
+    Property ShowControls : Boolean Read FshowControls Write FshowControls ;
+    Property Style : TOTUIStyle Read Fstyle Write Fstyle ;
+    Property UsePreviousDeviceSelection : Boolean Read FusePreviousDeviceSelection Write FusePreviousDeviceSelection ;
+    Property Width : NativeInt Read Fwidth Write Fwidth ;
+    Property WidthString : String Read FwidthString Write FwidthString ;
+  end;
+
+  TOTInitPublisherCallback = TOTErrorHandler;
+
+  TOTInitSessionOptions = Class external name 'Object' (TJSObject)
+  Protected
+    FconnectionEventsSuppressed : Boolean; external name 'connectionEventsSuppressed';
+    FipWhitelist : boolean; external name 'ipWhitelist';
+    FiceConfig : TJSObject; external name 'iceConfig';
+  Public
+    Property ConnectionEventsSuppressed : Boolean Read FconnectionEventsSuppressed Write FconnectionEventsSuppressed ;
+    Property IPWhitelist : boolean Read FipWhitelist Write FipWhitelist ;
+    Property IceConfig : TJSObject Read FiceConfig Write FiceConfig ;
+  end;
+
+  TOTSubscriberAudioStats = record
+    bytesReceived : NativeInt;
+    packetsLost : NativeInt;
+    packetsReceived : NativeInt;
+  end;
+
+  TOTSubscriberVideoStats = record
+    bytesReceived : NativeInt;
+    frameRate : NativeInt;
+    packetsLost : NativeInt;
+    packetsReceived : NativeInt;
+  end;
+
+  { TOTSubscriberStats }
+
+  TOTSubscriberStats = Class external name 'Object' (TJSObject)
+  private
+    Faudio: TOTSubscriberAudioStats; external name 'audio';
+    FTimeStamp: NativeInt; external name 'timestamp';
+    Fvideo: TOTSubscriberVideoStats; external name 'video';
+  Public
+    Property audio : TOTSubscriberAudioStats Read Faudio;
+    Property timestamp : NativeInt Read FTimeStamp;
+    Property video : TOTSubscriberVideoStats Read Fvideo;
+  end;
+
+  TOTSubscriberStatsCallBack = Reference to Procedure (Error : TOTError; Stats : TOTSubscriberStats);
+
+  TOTSubscriberStyleOptions = class external name 'Object' (TJSObject)
+  Private
+    FaudioBlockedDisplayMode : string; external name 'audioBlockedDisplayMode';
+    FaudioLevelDisplayMode : string; external name 'audioLevelDisplayMode';
+    FarchiveStatusDisplayMode : string; external name 'archiveStatusDisplayMode';
+    FbackgroundImageURI : String; external name 'backgroundImageURI';
+    FbuttonDisplayMode : string; external name 'buttonDisplayMode';
+    FnameDisplayMode : string; external name 'nameDisplayMode';
+    FvideoDisabledDisplayMode : string; external name 'videoDisabledDisplayMode';
+  Public
+    Property AudioBlockedDisplayMode : string Read FaudioBlockedDisplayMode Write FaudioBlockedDisplayMode ;
+    Property AudioLevelDisplayMode : string Read FaudioLevelDisplayMode Write FaudioLevelDisplayMode ;
+    Property ArchiveStatusDisplayMode : string Read FarchiveStatusDisplayMode Write FarchiveStatusDisplayMode ;
+    Property BackgroundImageURI : String Read FbackgroundImageURI Write FbackgroundImageURI ;
+    Property ButtonDisplayMode : string Read FbuttonDisplayMode Write FbuttonDisplayMode ;
+    Property NameDisplayMode : string Read FnameDisplayMode Write FnameDisplayMode ;
+    Property VideoDisabledDisplayMode : string Read FvideoDisabledDisplayMode Write FvideoDisabledDisplayMode ;
+  end;
+
+  { TOTSubscriber }
+
+  TOTSubscriber = Class external name 'Subscriber' (TOTEventDispatcher)
+  private
+    FElement: TJSHTMLElement; external name 'element';
+    FID: String; external name 'id';
+    FStream: TOTStream; external name 'stream';
+  Public
+    Function getAudioVolume : NativeInt;
+    Function getImgData : String;
+    Procedure getStats(CallBack : TOTSubscriberStatsCallBack);
+    Function getStyle : TJSObject;
+    Function isAudioBlocked : boolean;
+    Function restrictFrameRate(aValue : Boolean) : TOTSubscriber;
+    Function setAudioVolume(aValue : NativeInt) : TOTSubscriber;
+    Procedure setPreferredFrameRate(aFrameRate : NativeInt);
+    Procedure setPreferredResolution(aResolution : TOTMediaResolution);
+    Function setStyle(aStyle : TOTSubscriberStyleOptions) : TOTSubscriber; overload;
+    Function setStyle(aProp,aValue : String): TOTSubscriber; overload;
+    Function subscribeToAudio(aValue : Boolean) : TOTSubscriber;
+    Function subscribeToVideo(aValue : Boolean) : TOTSubscriber;
+    Function videoHeight : NativeInt;
+    Function videoWidth : NativeInt;
+  Public
+    Property Element : TJSHTMLElement Read FElement;
+    Property ID : String Read FID;
+    Property Stream : TOTStream Read FStream;
+  end;
+  TOTSubscriberArray = Array of TOTSubscriber;
+
+  { TOTSession }
+
+  TOTConnectCallBack = TOTErrorHandler;
+
+  TOTSignalData = Class external name 'Object' (TJSObject)
+  Private
+    Fdata : string; external name 'data';
+    FretryAfterReconnect : Boolean;  external name 'retryAfterReconnect';
+    Fto : TOTConnection; external name 'to';
+    FType : string; external name 'type';
+  Public
+    Property Data : string Read FData Write FData;
+    Property RetryAfterReconnect : Boolean Read FretryAfterReconnect Write FretryAfterReconnect;
+    Property To_ : TOTConnection Read FTo Write FTo;
+    Property Type_ : string Read FType Write FType;
+  end;
+
+
+  { TJSSubscribeStyle }
+
+  TJSSubscribeStyle = class external name 'Object' (TJSObject)
+  Private
+    FaudioBlockedDisplayMode : string; external name 'audioBlockedDisplayMode';
+    FaudioLeveldDisplayMode : string; external name 'audioLeveldDisplayMode';
+    FbackgroundImageURI : String; external name 'backgroundImageURI';
+    FbuttonDisplayMode : string; external name 'buttonDisplayMode';
+    FnameDisplayMode : string; external name 'nameDisplayMode';
+    FvideoDisabledDisplayMode : String;  external name 'videoDisabledDisplayMode';
+  Public
+    Property AudioBlockedDisplayMode : string Read FaudioBlockedDisplayMode Write FaudioBlockedDisplayMode;
+    Property AudioLeveldDisplayMode : string Read FaudioLeveldDisplayMode Write FaudioLeveldDisplayMode;
+    Property BackgroundImageURI : String Read FbackgroundImageURI Write FbackgroundImageURI;
+    Property ButtonDisplayMode : string Read FbuttonDisplayMode Write FbuttonDisplayMode;
+    Property NameDisplayMode : string Read FnameDisplayMode Write FnameDisplayMode;
+    Property VideoDisabledDisplayMode : String Read FvideoDisabledDisplayMode Write FvideoDisabledDisplayMode;
+  end;
+
+  { TOTInitSubscriberOptions }
+
+  TOTInitSubscriberOptions = class external name 'Object' (TJSObject)
+  Private
+    FaudioVolume : Byte; external name 'audioVolume';
+    Ffitmode : string; external name 'fitmode';
+    Fheight : NativeInt; external name 'height';
+    FheightString : String; external name 'height';
+    FinsertDefaultUI : Boolean; external name 'insertDefaultUI';
+    FinsertMode : string; external name 'insertMode';
+    FpreferredFrameRate : NativeInt; external name 'preferredFrameRate';
+    FpreferredResolution : TOTMediaResolution;  external name 'preferredResolution';
+    FshowControls : Boolean; external name 'showControls';
+    Fstyle : TJSSubscribeStyle; external name 'style';
+    FsubscribeToAudio : Boolean; external name 'subscribeToAudio';
+    FsubscribeToVideo : Boolean; external name 'subscribeToVideo';
+    FtestNetwork : Boolean;  external name 'testNetwork';
+    Fwidth : NativeInt;   external name 'width';
+    FwidthString : String; external name 'width';
+  Public
+    Property AudioVolume : Byte read FaudioVolume Write FaudioVolume;
+    Property Fitmode : string read Ffitmode Write Ffitmode;
+    Property Height : NativeInt read Fheight Write Fheight;
+    Property HeightString : String read FheightString Write FheightString; // height as string;
+    Property InsertDefaultUI : Boolean read FinsertDefaultUI Write FinsertDefaultUI;
+    Property InsertMode : string read FinsertMode Write FinsertMode;
+    Property PreferredFrameRate : NativeInt read FpreferredFrameRate Write FpreferredFrameRate;
+    Property PreferredResolution : TOTMediaResolution read FpreferredResolution Write FpreferredResolution;
+    Property ShowControls : Boolean read FshowControls Write FshowControls;
+    Property Style : TJSSubscribeStyle read Fstyle Write Fstyle;
+    Property SubscribeToAudio : Boolean read FsubscribeToAudio Write FsubscribeToAudio;
+    Property SubscribeToVideo : Boolean read FsubscribeToVideo Write FsubscribeToVideo;
+    Property TestNetwork : Boolean read FtestNetwork Write FtestNetwork;
+    Property Width : NativeInt read Fwidth Write Fwidth;
+    Property WidthString : String read FwidthString Write FwidthString; //  width as string;
+  end;
+
+
+  TOTSession = Class external name 'Session' (TOTEventDispatcher)
+  private
+    FCapabilities: TOTCapabilities; external name 'capabilities';
+    FConnection: TOTConnection; external name 'connection';
+    FSessionID: string; external name 'sessionId';
+  public
+    Procedure connect(aToken : String; callback : TOTConnectCallBack);
+    Procedure disconnect;
+    Procedure forceDisconnect(aConnection : TOTConnection; callBack : TOTConnectCallBack);
+    Procedure forceUnpublish(aStream : TOTStream; callBack : TOTConnectCallBack);
+    Function getPublisherForStream(aStream : TOTStream) : TOTPublisher;
+    Function getSubscribersForStream(aStream : TOTStream) : TOTSubscriberArray;
+    Function publish(aPublisher : TOTPublisher; callBack : TOTErrorHandler) : TOTPublisher; overload;
+    Function publish(aPublisher : TOTPublisher) : TOTPublisher; overload;
+    Procedure signal(aSignal : TJSObject; callBack :TOTErrorHandler);
+    Procedure signal(aSignal : TOTSignalData; callBack :TOTErrorHandler);
+    Function subscribe(stream : TOTStream; target : TJSHTMLElement; aProperties : TOTInitSubscriberOptions; callBack : TOTErrorHandler) : TOTSubscriber; overload;
+    Function subscribe(stream : TOTStream; targetID : String; aProperties : TOTInitSubscriberOptions; callBack : TOTErrorHandler) : TOTSubscriber; overload;
+    Procedure unpublish(aPublisher : TOTPublisher);
+    Procedure unsubscribe(aSubscriber : TOTSubscriber);
+  Public
+    Property Capabilities : TOTCapabilities Read FCapabilities;
+    Property Connnection : TOTConnection Read FConnection;
+    Property SessionId : string Read FSessionID;
+  end;
+
+  TOTPublisherAudioStats = record
+    bytesSent : NativeInt;
+    packetsLost : NativeInt;
+    packetsSent : NativeInt;
+  end;
+
+  TOTPublisherVideoStats = record
+    bytesSent : NativeInt;
+    frameRate : NativeInt;
+    packetsLost : NativeInt;
+    packetsSent : NativeInt;
+  end;
+
+  TOTPublisherStatsRecord = record
+    audio : TOTPublisherAudioStats;
+    timestamp : NativeInt;
+    video : TOTPublisherVideoStats;
+  end;
+
+  { TOTPublisherStats }
+
+  TOTPublisherStats = class external name 'Object' (TJSObject)
+  private
+    FConnectionID: String; external name 'connectionId';
+    FStats: TOTPublisherStatsRecord; external name 'stats';
+    FSubscriberID: String; external name 'subscriberId';
+  Public
+    Property ConnectionId : String read FConnectionID;
+    Property Stats : TOTPublisherStatsRecord read FStats;
+    Property SubscriberId : String Read FSubscriberID;
+  end;
+  TOTPublisherStatsArray = Array of TOTPublisherStats;
+
+  TOTPublisherStatsCallback = Reference to Procedure (error : TOTError; StatsArray : TOTPublisherStatsArray);
+
+  { TOTPublisherStyleOptions }
+
+  TOTPublisherStyleOptions = class external name 'Object' (TJSObject)
+  Private
+    FarchiveStatusDisplayMode : string; external name 'archiveStatusDisplayMode';
+    FaudioLevelDisplayMode : string; external name 'audioLevelDisplayMode';
+    FbackgroundImageURI : String; external name 'backgroundImageURI';
+    FbuttonDisplayMode : string; external name 'buttonDisplayMode';
+    FnameDisplayMode : string; external name 'nameDisplayMode';
+  Public
+    Property ArchiveStatusDisplayMode : string Read FArchiveStatusDisplayMode Write FArchiveStatusDisplayMode;
+    Property AudioLevelDisplayMode : string Read FaudioLevelDisplayMode Write FaudioLevelDisplayMode;
+    Property BackgroundImageURI : String Read FbackgroundImageURI Write FbackgroundImageURI;
+    Property ButtonDisplayMode : string Read FbuttonDisplayMode Write FbuttonDisplayMode;
+    Property NameDisplayMode : string Read FnameDisplayMode Write FnameDisplayMode;
+  end;
+
+  { TOTPublisher }
+
+  TOTPublisher = Class external name 'Publisher' (TOTEventDispatcher)
+  private
+    FaccessAllowed: Boolean; external name 'accessAllowed';
+    Felement: TJSHTMLElement; external name 'element';
+    FID: string;external name 'id';
+    FSession: TOTSession;external name 'session';
+    FStream: TOTStream;external name 'stream';
+  public
+    Function cycleVideo : TJSPromise;
+    Function destroy : TOTPublisher;
+    Function getAudioSource : TJSMediaStreamTrack;
+    Function getImgData : String;
+    Procedure getStats (callback : TOTPublisherStatsCallback);
+    Function getStyle : TJSObject;
+    Procedure publishAudio(value : Boolean);
+    Procedure publishVideo(value : Boolean);
+    Function setAudioSource(aID : String) : TJSPromise; overload;
+    Function setAudioSource(aStream : TJSMediaStreamTrack) : TJSPromise; overload;
+    Function setStyle(aStyle : TOTPublisherStyleOptions) : TOTPublisher; overload;
+    Function setStyle(aProp,aValue : String): TOTPublisher; overload;
+    Function videoHeight : NativeInt;
+    Function videoWidth : NativeInt;
+  Public
+    Property AccessAllowed : Boolean read FaccessAllowed;
+    Property Element : TJSHTMLElement read Felement;
+    Property ID : string read FID;
+    Property Stream : TOTStream Read FStream;
+    Property Session : TOTSession read FSession;
+  end;
+
+{ ---------------------------------------------------------------------
+  Main class, serves as namespace.
+  ---------------------------------------------------------------------}
+
+
+  { TOT }
+
+  TOTReportIssueCallBack = reference to Procedure (err : TOTError; reportID : string);
+
+  TOT = Class external name 'OT' (TOTEventDispatcher)
+  Public
+    const NONE : Integer;
+    const ERROR : Integer;
+    const WARN : Integer;
+    const INFO : Integer;
+    const LOG_ : Integer; // Cannot use external name :(
+    const DEBUG : Integer;
+  Public
+    class Procedure checkScreenSharingCapability(callBack : TOTScreenSharingCapabilityCallback);
+    class Function checkSystemRequirements : NativeInt;
+    class Procedure getDevices(callBack : TOTGetDevicesCallback);
+    class Function getSupportedCodecs : TJSPromise;
+    class Function getUserMedia : TJSPromise;
+    class Function getUserMedia(options : TOTGetUserMediaOptions) : TJSPromise;
+    class Function initPublisher(aElement : TJSHTMLElement; properties : TOTInitPublisherOptions; CompletionHandler : TOTInitPublisherCallback) : TOTPublisher;
+    class Function initPublisher(aElementId : String; properties : TOTInitPublisherOptions; CompletionHandler : TOTInitPublisherCallback) : TOTPublisher;
+    class Function initSession(APIKey,SessionID  : String) : TOTSession; overload;
+    class Function initSession(APIKey,SessionID  : String; Options : TOTInitSessionOptions) : TOTSession; overload;
+    class Procedure log(msg : string);
+    class Procedure registerScreenSharingExtension(kind : String; id : string; version : Integer);
+    class Procedure reportIssue(aCallBack : TOTReportIssueCallBack);
+    class Procedure setLogLevel(Number : String);
+    class Procedure unblockAudio;
+    class Procedure upgradeSystemRequirements;
+   end;
+   TOTClass = Class of TOT;
+
+var
+   OpenTok : TOTClass; external name 'OT';
+
+implementation
+
+end.
+