aotrautils 0.0.251 → 0.0.252

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- /*utils COMMONS library associated with aotra version : «1_29072022-2359 (19/08/2022-00:31:09)»*/
3
+ /*utils COMMONS library associated with aotra version : «1_29072022-2359 (25/09/2022-16:59:58)»*/
4
4
  /*-----------------------------------------------------------------------------*/
5
5
 
6
6
 
@@ -4827,7 +4827,7 @@ AOTRAUTILS_LIB_IS_LOADED=true;
4827
4827
 
4828
4828
 
4829
4829
 
4830
- /*utils CLIENT library associated with aotra version : «1_29072022-2359 (19/08/2022-00:31:09)»*/
4830
+ /*utils CLIENT library associated with aotra version : «1_29072022-2359 (25/09/2022-16:59:58)»*/
4831
4831
  /*-----------------------------------------------------------------------------*/
4832
4832
  /* ## Utility global methods in a browser (htmljs) client environment.
4833
4833
  *
@@ -7726,11 +7726,13 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7726
7726
  // const VIDEOTAG_ID="videoElement";
7727
7727
 
7728
7728
  const DEFAULT_AUDIO_BUFFER_SIZE=4096;
7729
- const DEFAULT_WIDTH=300;
7730
- const DEFAULT_HEIGHT=300;
7729
+ // const DEFAULT_WIDTH=1920;
7730
+ // const DEFAULT_HEIGHT=1080;
7731
+ const DEFAULT_WIDTH=1280;
7732
+ const DEFAULT_HEIGHT=720;
7731
7733
 
7732
- var width=size && size.width?size.width:DEFAULT_WIDTH;
7733
- var height=size && size.height?size.height:DEFAULT_HEIGHT;
7734
+ let width=size && size.width?size.width:null;
7735
+ let height=size && size.height?size.height:null;
7734
7736
 
7735
7737
 
7736
7738
  audioBufferSize=nonull(audioBufferSize,DEFAULT_AUDIO_BUFFER_SIZE);
@@ -7799,14 +7801,13 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7799
7801
  };
7800
7802
 
7801
7803
 
7802
- const backgroundContainerDiv=document.body;
7804
+ // UNUSED : const backgroundContainerDiv=document.body;
7803
7805
 
7804
7806
 
7805
7807
  // This temporary, off-screen canvas is always used to get the image data for further use :
7806
- let canvasTag;
7807
- canvasTag=document.createElement("canvas");
7808
- canvasTag.width=width;
7809
- canvasTag.height=height;
7808
+ let canvasTag=document.createElement("canvas");
7809
+ if(width) canvasTag.width=width;
7810
+ if(height) canvasTag.height=height;
7810
7811
  //canvasTag.style.display="none";
7811
7812
 
7812
7813
 
@@ -7814,10 +7815,20 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7814
7815
  let videoTag;
7815
7816
  if(!tagConfig || !tagConfig.videoToUse){
7816
7817
  videoTag=document.createElement("video");
7818
+ videoTag.id="tmpVideoElement";
7817
7819
  videoTag.autoplay=true;
7818
7820
  videoTag.width=canvasTag.width;
7819
7821
  videoTag.height=canvasTag.height;
7820
- // videoTag.style.display="none";
7822
+ videoTag.style.width=canvasTag.width+"px";
7823
+ videoTag.style.height=canvasTag.height+"px";
7824
+
7825
+ // // UNUSEFUL (SINCE VIDEO ELEMENT IS NEVER APPENDED TO PAGE !) :
7826
+ // videoTag.style.position="absolute";
7827
+ // videoTag.style["pointer-events"]="none";
7828
+ // videoTag.style.display="none";
7829
+ // videoTag.style.display="none";
7830
+ // document.body.appendChild(videoTag);
7831
+
7821
7832
  }else{
7822
7833
  videoTag=tagConfig.videoToUse;
7823
7834
  }
@@ -7825,6 +7836,8 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7825
7836
 
7826
7837
 
7827
7838
  mediaHandler.video=videoTag;
7839
+
7840
+
7828
7841
  // UNUSED
7829
7842
  // mediaHandler.isReady=function(){
7830
7843
  //// return mediaHandler.video !== null;
@@ -7834,7 +7847,21 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7834
7847
  // 2- Method to start the media stream :
7835
7848
  const startStream=function(constraints){
7836
7849
 
7837
- if(!constraints) constraints={video: isVideo, audio: isAudio};
7850
+ if(!constraints){
7851
+ //constraints={video: (isVideo?{zoom:true,width:{ideal:nonull(width,DEFAULT_WIDTH)},height:{ideal:nonull(height,DEFAULT_HEIGHT)}}:false), audio: isAudio};
7852
+ // DBG
7853
+ constraints={video: (isVideo?
7854
+ {width:nonull(width,DEFAULT_WIDTH),height:nonull(height,DEFAULT_HEIGHT)}
7855
+ //// ALTERNATIVELY, AND MORE FINE_TUNED :
7856
+ // {zoom:true,mandatory: {
7857
+ // minWidth: 1280,
7858
+ // maxWidth: 1280,
7859
+ // minHeight: 720,
7860
+ // maxHeight: 720,
7861
+ // }
7862
+ // }
7863
+ :false), audio: isAudio};
7864
+ }
7838
7865
 
7839
7866
  // TRACE
7840
7867
  console.log("INFO : Trying to start mediaHandler stream with constraints :",JSON.stringify(constraints));
@@ -7846,6 +7873,23 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7846
7873
  // UNUSED
7847
7874
  // mediaHandler.stream=stream;
7848
7875
 
7876
+ const streamSettings = stream.getVideoTracks()[0].getSettings();
7877
+
7878
+
7879
+ // DBG
7880
+ lognow("(DEBUG) streamSettings:",streamSettings);
7881
+ lognow("(DEBUG) stream:",stream);
7882
+ lognow("(DEBUG) stream.getVideoTracks():",stream.getVideoTracks());
7883
+
7884
+
7885
+ if(streamSettings){
7886
+ if(!canvasTag.width && streamSettings.width) width=streamSettings.width;
7887
+ if(!canvasTag.height && streamSettings.height) height=streamSettings.height;
7888
+ if(!canvasTag.width && width) canvasTag.width=width;
7889
+ if(!canvasTag.height && height) canvasTag.height=height;
7890
+ }
7891
+
7892
+
7849
7893
  // Video part :
7850
7894
  if(isVideo){
7851
7895
 
@@ -7854,18 +7898,32 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7854
7898
 
7855
7899
  // We always have a video tag (to grab the video data)
7856
7900
  if(!isArray(mediaHandler.video)){
7901
+
7857
7902
  mediaHandler.video.srcObject=stream;
7903
+ // DOES NOT WORK : mediaHandler.video.src=stream;
7904
+
7858
7905
  // NO : DOES NOT WORK (CREATES A BLANK IMAGE !) mediaHandler.video.muted=true;
7859
7906
  // STUPID WORKAROUND : Because apparently, if volume==0 or video is muted, then the image data is all black !!!
7860
7907
  mediaHandler.video.volume=0.0000000000001;
7861
7908
  // mediaHandler.video.autoplay=true;
7862
- }else{
7863
- foreach(mediaHandler.video,(v)=>{
7909
+
7910
+ if(tagConfig && tagConfig.videoToUse && tagConfig.videoZoom){
7911
+ if(isNumber(tagConfig.videoZoom)){
7912
+ mediaHandler.video.style.scale=tagConfig.videoZoom;
7913
+ }
7914
+ }
7915
+
7916
+ }else{ // Audio part :
7917
+
7918
+ foreach(mediaHandler.video,(v)=>{
7919
+
7864
7920
  v.srcObject=stream;
7921
+
7865
7922
  // NO : DOES NOT WORK (CREATES A BLANK IMAGE !) v.muted=true;
7866
7923
  // STUPID WORKAROUND : Because apparently, if volume==0 or video is muted, then the image data is all black !!!
7867
7924
  v.volume=0.0000000000001;
7868
7925
  // v.autoplay=true;
7926
+
7869
7927
  });
7870
7928
  }
7871
7929
 
@@ -7906,7 +7964,7 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7906
7964
  let video=event.target;
7907
7965
  video.play();
7908
7966
  if(tagConfig.videoMuted) video.muted=true;
7909
- else delete video.muted;
7967
+ else delete video.muted;
7910
7968
  };
7911
7969
  }else{
7912
7970
  foreach(mediaHandler.video,(v)=>{
@@ -7914,7 +7972,7 @@ function filterPoints(allPoints ,ctx/*DBG*/){
7914
7972
  let video=event.target;
7915
7973
  video.play();
7916
7974
  if(tagConfig.videoMuted) video.muted=true;
7917
- else delete video.muted;
7975
+ else delete video.muted;
7918
7976
  };
7919
7977
  });
7920
7978
  }
@@ -8070,7 +8128,7 @@ drawVideoImage=function(canvas,videoImage,
8070
8128
 
8071
8129
  // We copy the data in canvas :
8072
8130
  imageData=ctx.getImageData(x, y, oldWidth, oldHeight);
8073
- // NE MARCHE PAS :
8131
+ // CAUTION : DOES NOT WORK :
8074
8132
  // var imageData=ctx.createImageData(oldWidth, oldHeight);
8075
8133
  normalizeData(videoRawImageData, imageData.data, isMessWithAlpha);
8076
8134
 
@@ -9580,6 +9638,7 @@ function offsetColorOnArea(correctionValue, x1, y1, x2, y2, data, totalWidth){
9580
9638
  function getLinearIndexForCoordinates(x, y, totalWidth, step){
9581
9639
  return Math.floor((x + y * totalWidth) * step);
9582
9640
  }
9641
+
9583
9642
  function getCoordinatesForLinearIndex(index, totalWidth, step=1){
9584
9643
  let actualIndex=index/step;
9585
9644
  let actualWidth=totalWidth;
@@ -9594,7 +9653,6 @@ function indexIsOutsideArea(indexParam, x1, y1, x2, y2, data, totalWidth, step){
9594
9653
  if (0<step)
9595
9654
  index=index / step;
9596
9655
  return (index % totalWidth<x1 || x2<index % totalWidth) || (index<x1 + y1 * totalWidth || x2 + y2 * totalWidth<index);
9597
-
9598
9656
  }
9599
9657
 
9600
9658
  function createColor(r, g, b){
@@ -11612,28 +11670,35 @@ class VNCFrame2D{
11612
11670
 
11613
11671
 
11614
11672
 
11673
+
11674
+
11675
+ // ============================================== BROWSER CLIENTS ==============================================
11676
+
11677
+
11678
+ // FUSRODA :
11679
+
11615
11680
  createFusrodaClient=function(doOnClientReady, doOnDataReception, urlParam=null, portParam=6080){
11616
11681
  // CAUTION : WORKS BETTER WHEN UNSECURE, BUT 'NEEDS CLIENT BROWSER TO ALLOW MIXED (SECURE/UNSECURE) CONTENT !
11617
11682
 
11618
11683
  const isSecure=(contains(urlParam.toLowerCase(),"https") || contains(urlParam.toLowerCase(),"wss"));
11619
11684
 
11620
11685
 
11621
- const fusrodaClient=initClient(false,true, (browserClientInstance)=>{
11686
+ const fusrodaClient=initClient(false,/*CAUTION : Fusroda Java server requires the SOcket IO websocket implementation !!*/true, /*doOnServerConnection*/(socketToServer)=>{
11622
11687
 
11623
11688
  // DBG
11624
- lognow("SETTING UP");
11689
+ lognow("FUSRODA CLIENT : SETTING UP");
11625
11690
 
11626
11691
  //0)
11627
- fusrodaClient.client.socketToServer.send("protocol", { type:"hello" });
11692
+ socketToServer.send("protocol", { type:"hello" });
11628
11693
  //1)
11629
- browserClientInstance.receive("protocolConfig", (messageConfig)=>{
11694
+ socketToServer.receive("protocolConfig", (messageConfig)=>{
11630
11695
  //2)
11631
- fusrodaClient.client.socketToServer.send("screenFrameRequest", {});
11632
- browserClientInstance.receive("imagePacket", (doOnDataReception && doOnDataReception["image"]?doOnDataReception["image"]:()=>{/*DO NOTHING*/}));
11696
+ socketToServer.send("screenFrameRequest", {});
11697
+ socketToServer.receive("imagePacket", (doOnDataReception && doOnDataReception["image"]?doOnDataReception["image"]:()=>{/*DO NOTHING*/}));
11633
11698
 
11634
11699
  //2)
11635
- fusrodaClient.client.socketToServer.send("soundSampleRequest", {});
11636
- browserClientInstance.receive("soundPacket", (doOnDataReception && doOnDataReception["sound"]?doOnDataReception["sound"]:()=>{/*DO NOTHING*/}));
11700
+ socketToServer.send("soundSampleRequest", {});
11701
+ socketToServer.receive("soundPacket", (doOnDataReception && doOnDataReception["sound"]?doOnDataReception["sound"]:()=>{/*DO NOTHING*/}));
11637
11702
 
11638
11703
 
11639
11704
  doOnClientReady(messageConfig);
@@ -11676,7 +11741,1176 @@ createFusrodaClient=function(doOnClientReady, doOnDataReception, urlParam=null,
11676
11741
 
11677
11742
 
11678
11743
 
11679
- /*utils GEOMETRY library associated with aotra version : «1_29072022-2359 (19/08/2022-00:31:09)»*/
11744
+
11745
+
11746
+
11747
+
11748
+
11749
+ // ORITA :
11750
+
11751
+
11752
+
11753
+ // ------------------------------------------------------------------------------------------
11754
+ // -------------------------------------- MAIN CLIENT --------------------------------------
11755
+ // ------------------------------------------------------------------------------------------
11756
+
11757
+ createOritaMainClient=function(
11758
+ doOnRegistered,
11759
+ treatVideoData, treatAudioData,
11760
+ doOnInputsCreated, doOnInputsUpdated, doOnOutputsCreated, doOnOutputsUpdated,
11761
+ urlParam=null, portParam=25000, ignoreHashKey=false){
11762
+
11763
+ const ORITA_HASH_STRING_NAME="oritaClientHash";
11764
+
11765
+ const isSecure=(contains(urlParam.toLowerCase(),"https") || contains(urlParam.toLowerCase(),"wss"));
11766
+
11767
+
11768
+
11769
+ const onCommunicationEventListeners=[];
11770
+
11771
+ // ---------------------------------------------------------------------
11772
+ // I/Os setup
11773
+
11774
+
11775
+ // Inputs :
11776
+
11777
+ // 2-
11778
+ onCommunicationEventListeners.push({
11779
+ condition:(message)=>message.type==="request.microClient.appendInputs",
11780
+ execute:(message)=>{
11781
+ let inputsGPIO=message.inputsGPIO;
11782
+ let microClientId=message.microClientId;
11783
+
11784
+ let microClientInfos=mainClient.oritaMainClient.microClientsInfos[microClientId];
11785
+ if(!microClientInfos) mainClient.oritaMainClient.microClientsInfos[microClientId]={};
11786
+ microClientInfos=mainClient.oritaMainClient.microClientsInfos[microClientId];
11787
+ if(microClientInfos.hasInputs) return; // (to avoid registering several times)
11788
+ microClientInfos.hasInputs=true;
11789
+
11790
+ microClientInfos.lastTime=getNow();
11791
+ mainClient.inputsGPIO=inputsGPIO;
11792
+
11793
+
11794
+ doOnInputsCreated(mainClient, microClientId, mainClient.inputsGPIO);
11795
+ },
11796
+ });
11797
+
11798
+ // 4-
11799
+ onCommunicationEventListeners.push({
11800
+ condition:(message)=>message.type==="request.microClient.updateInputsValues",
11801
+ execute:(message)=>{
11802
+
11803
+ let inputsGPIO=message.inputsGPIO;
11804
+
11805
+ // // DBG
11806
+ // console.log("updateInputsValues UPDATE VALUE ! message:",message);
11807
+ // console.log("updateInputsValues UPDATE VALUE ! inputsGPIO:",inputsGPIO);
11808
+
11809
+
11810
+ let microClientId=message.microClientId;
11811
+
11812
+ let microClientInfos=mainClient.oritaMainClient.microClientsInfos[microClientId];
11813
+ if(!microClientInfos) mainClient.oritaMainClient.microClientsInfos[microClientId]={};
11814
+ microClientInfos=mainClient.oritaMainClient.microClientsInfos[microClientId];
11815
+ microClientInfos.lastTime=getNow();
11816
+
11817
+ mainClient.inputsGPIO=inputsGPIO;
11818
+
11819
+
11820
+
11821
+ doOnInputsUpdated(mainClient, microClientId, mainClient.inputsGPIO);
11822
+ },
11823
+ });
11824
+
11825
+
11826
+
11827
+
11828
+ // Outputs :
11829
+
11830
+ // 2-
11831
+ onCommunicationEventListeners.push({
11832
+ condition:(message)=>message.type==="request.microClient.appendOutputs",
11833
+ execute:(message)=>{
11834
+ let outputsGPIOLocal=message.outputsGPIO;
11835
+ let microClientId=message.microClientId;
11836
+
11837
+ let microClientInfos=mainClient.oritaMainClient.microClientsInfos[microClientId];
11838
+ if(!microClientInfos) mainClient.oritaMainClient.microClientsInfos[microClientId]={};
11839
+ microClientInfos=mainClient.oritaMainClient.microClientsInfos[microClientId];
11840
+ if(microClientInfos.hasOutputs) return; // (to avoid registering several times)
11841
+ microClientInfos.hasOutputs=true;
11842
+
11843
+ microClientInfos.lastTime=getNow();
11844
+
11845
+ mainClient.outputsGPIO=outputsGPIOLocal;
11846
+
11847
+
11848
+ doOnOutputsCreated(mainClient, microClientId, mainClient.outputsGPIO);
11849
+
11850
+ },
11851
+ });
11852
+
11853
+ // 4-
11854
+ onCommunicationEventListeners.push({
11855
+ condition:(message)=>message.type==="response.microClient.outputChanged",
11856
+ execute:(message)=>{
11857
+
11858
+ let outputsGPIOLocal=message.outputsGPIO;
11859
+ let microClientId=message.microClientId;
11860
+
11861
+
11862
+ // // DBG
11863
+ // console.log("outputChanged UPDATE VALUE ! message:",message);
11864
+ // console.log("outputChanged UPDATE VALUE ! outputsGPIOLocal:",outputsGPIOLocal);
11865
+
11866
+ mainClient.outputsGPIO=outputsGPIOLocal;
11867
+
11868
+ doOnOutputsUpdated(microClientId, mainClient.outputsGPIO);
11869
+ },
11870
+ });
11871
+
11872
+
11873
+
11874
+
11875
+
11876
+
11877
+ const oritaClient=initClient(false, false, /*doOnServerConnection*/(socketToServer)=>{
11878
+
11879
+ // DBG
11880
+ lognow("ORITA MAIN CLIENT : SETTING UP");
11881
+
11882
+ // TRACE
11883
+ console.log("INFO : MAIN CLIENT : Sending register request...");
11884
+
11885
+
11886
+ // TRACE
11887
+ console.log("INFO : MAIN CLIENT : Checking registered client key hash...");
11888
+
11889
+ const storedHashKey=getStringFromStorage(ORITA_HASH_STRING_NAME);
11890
+ if(!storedHashKey && !ignoreHashKey){
11891
+ promptWindow("Please enter your client key :","password",null,(clearText)=>{
11892
+
11893
+ if(empty(clearText)){
11894
+ // TRACE
11895
+ lognow("ERROR : MAIN CLIENT : Client key string is empty. Cannot proceed to registration request sending to server.");
11896
+ return;
11897
+ }
11898
+
11899
+ const calculatedHash=getHashedString(clearText);// (we use the heavy treatment thing.)
11900
+
11901
+ storeString(ORITA_HASH_STRING_NAME, calculatedHash);
11902
+
11903
+ // TODO : FIXME : DUPLICATED CODE :
11904
+ socketToServer.send("protocol", "request.register:mainClient:"+calculatedHash);
11905
+
11906
+ },()=>{
11907
+ // TRACE
11908
+ lognow("WARN : MAIN CLIENT : Cannot send registration request to server if no client key is provided.");
11909
+ });
11910
+
11911
+ }else{
11912
+ // TODO : FIXME : DUPLICATED CODE :
11913
+ socketToServer.send("protocol", "request.register:mainClient:"+storedHashKey);
11914
+ }
11915
+
11916
+
11917
+
11918
+ }, urlParam, portParam, isSecure);
11919
+
11920
+
11921
+ oritaClient.microClientsInfos={};
11922
+ oritaClient.inputsGPIO={};
11923
+ oritaClient.outputsGPIO={};
11924
+
11925
+
11926
+
11927
+
11928
+
11929
+ oritaClient.client.socketToServer.receive("protocol", (message)=>{
11930
+
11931
+ // TRACE
11932
+ lognow("Mainclient received message from server:",message);
11933
+
11934
+
11935
+ if(message.type==="response.mainClient.registered"){
11936
+
11937
+ // TRACE
11938
+ log("Main client registered to server.");
11939
+
11940
+ // TRACE
11941
+ log("Starting main receiving :");
11942
+
11943
+
11944
+
11945
+
11946
+ // Main client starts receiving :
11947
+ oritaClient.client.socketToServer.receive("server.send.data", (receivedData)=>{
11948
+
11949
+
11950
+ let microClientId=receivedData.microClientId;
11951
+
11952
+ // // DEBUG
11953
+ // lognow("INFO : MAINCLIENT : MainClient received data from microClient «"+microClientId+"» :",receivedData);
11954
+
11955
+ let compression=receivedData.compression;
11956
+
11957
+ // // DBG
11958
+ // console.log("receivedData:",receivedData);
11959
+ // console.log("receivedData.compression:",compression);
11960
+
11961
+ if(receivedData.video){// -------- VIDEO :
11962
+
11963
+ if(compression){
11964
+ // Actually, only handles "LZW" uncompression, for now...
11965
+ let uncompressedData;
11966
+ if(ORITA_CONSTANTS.STRINGIFY_VIDEO_DATA) uncompressedData=arrayFromString(receivedData.video.data, compression.algorithm?true:false, compression.precision);
11967
+ else uncompressedData=receivedData.video.data;
11968
+
11969
+ receivedData.video.data=uncompressedData;
11970
+ }
11971
+
11972
+ // // DBG
11973
+ // console.log("received receivedData.length",receivedData);
11974
+
11975
+
11976
+ let microClientInfos=oritaClient.microClientsInfos[microClientId];
11977
+ if(!microClientInfos) oritaClient.microClientsInfos[microClientId]={};
11978
+ microClientInfos=oritaClient.microClientsInfos[microClientId];
11979
+ microClientInfos.hasVideo=true;
11980
+
11981
+ oritaClient.microClientsInfos[microClientId].lastTime=getNow();
11982
+
11983
+
11984
+
11985
+ treatVideoData();
11986
+
11987
+
11988
+
11989
+ }else if(receivedData.audio){// -------- AUDIO :
11990
+
11991
+ if(compression){
11992
+ // Actually, only handles "LZW" uncompression, for now...
11993
+ let uncompressedData;
11994
+ if(ORITA_CONSTANTS.STRINGIFY_VIDEO_DATA) uncompressedData=arrayFromString(receivedData.audio.data, compression.algorithm?true:false, compression.precision);
11995
+ else uncompressedData=receivedData.audio.data;
11996
+
11997
+ receivedData.audio.data=uncompressedData;
11998
+ }
11999
+
12000
+
12001
+ let microClientInfos=oritaClient.microClientsInfos[microClientId];
12002
+ if(!microClientInfos) oritaClient.microClientsInfos[microClientId]={};
12003
+ microClientInfos=oritaClient.microClientsInfos[microClientId];
12004
+ microClientInfos.hasAudio=true;
12005
+
12006
+ oritaClient.microClientsInfos[microClientId].lastTime=getNow();
12007
+
12008
+
12009
+ treatAudioData();
12010
+
12011
+
12012
+ }
12013
+
12014
+ });
12015
+
12016
+
12017
+
12018
+
12019
+
12020
+ doOnRegistered();
12021
+
12022
+ }
12023
+
12024
+
12025
+
12026
+ });
12027
+
12028
+
12029
+
12030
+ oritaClient.client.socketToServer.receive("communication", (message)=>{
12031
+
12032
+ // We execute eventual on message events listeners :
12033
+ foreach(onCommunicationEventListeners, (e)=>{
12034
+ if(!e.condition || e.condition(message)) e.execute(message);
12035
+ });
12036
+
12037
+ });
12038
+
12039
+
12040
+
12041
+
12042
+
12043
+
12044
+ return oritaClient;
12045
+ };
12046
+
12047
+
12048
+
12049
+
12050
+ // ------------------------------------------------------------------------------------------
12051
+ // -------------------------------------- MICRO CLIENT --------------------------------------
12052
+ // ------------------------------------------------------------------------------------------
12053
+
12054
+
12055
+
12056
+
12057
+ // const REFRESHING_RATE_MILLIS_AUDIO:100,
12058
+
12059
+
12060
+ // const MICRO_CLIENT_MESS_WITH_ALPHA=true;
12061
+ // const MICRO_CLIENT_MESS_WITH_ALPHA=false;
12062
+
12063
+
12064
+ const REFRESHING_RATE_MILLIS_DEFAULT = 1000;
12065
+
12066
+
12067
+ // Output constants :
12068
+ const STEPPER_DELAY_MILLIS = 1;
12069
+ const DEFAULT_STEPPER_SEQUENCE = [
12070
+ [1, 0, 0, 0],
12071
+ [0, 1, 0, 0],
12072
+ [0, 0, 1, 0],
12073
+ [0, 0, 0, 1],
12074
+ ];
12075
+ const HALF_STEP_STEPPER_SEQUENCE = [
12076
+ [0, 1, 0, 0],
12077
+ [0, 1, 0, 1],
12078
+ [0, 0, 0, 1],
12079
+ [1, 0, 0, 1],
12080
+ [1, 0, 0, 0],
12081
+ [1, 0, 1, 0],
12082
+ [0, 0, 1, 0],
12083
+ [0, 1, 1, 0],
12084
+ ];
12085
+
12086
+
12087
+
12088
+ createOritaMicroClient=function(){
12089
+
12090
+
12091
+
12092
+
12093
+
12094
+
12095
+
12096
+
12097
+
12098
+
12099
+
12100
+
12101
+
12102
+ let oritaClient={
12103
+
12104
+ onRegistrationEventListeners:[],
12105
+ onCommunicationEventListeners:[],
12106
+
12107
+ outputsGPIO:{},
12108
+ inputsGPIO:{},
12109
+
12110
+
12111
+
12112
+ };
12113
+
12114
+
12115
+
12116
+ oritaClient.start = function(mediasArg = null) {
12117
+
12118
+ const startResultPromise = new Promise((resolve, reject) => {
12119
+
12120
+
12121
+ // Other parameters :
12122
+ let allMediaParametersArray;
12123
+ if (!isNode && !mediasArg) {
12124
+ allMediaParametersArray = getMediaParametersArray(getURLParameter("medias"), getURLParameter("vr"));
12125
+ } else { // if we are in a node micro client context :
12126
+ allMediaParametersArray = getMediaParametersArray(mediasArg);
12127
+ }
12128
+ let mediaParametersArray = allMediaParametersArray.medias;
12129
+
12130
+
12131
+
12132
+
12133
+ let captureWidth = null;
12134
+ let captureHeight = null;
12135
+ let containsVideoOrAudio = false;
12136
+ foreach(mediaParametersArray, (mediasConfigElement) => {
12137
+ if (contains(["video", "audio"], mediasConfigElement.medias)) {
12138
+ containsVideoOrAudio = true;
12139
+ return "break";
12140
+ }
12141
+ });
12142
+ if (containsVideoOrAudio) {
12143
+ captureWidth = nonull(oritaClient.captureConfig.width, ORITA_CONSTANTS.DEFAULT_CAPTURE_WIDTH);
12144
+ captureHeight = nonull(oritaClient.captureConfig.height, ORITA_CONSTANTS.DEFAULT_CAPTURE_HEIGHT);
12145
+ }
12146
+
12147
+ // DBG
12148
+ lognow("INFO : MICRO CLIENT : Starting micro client...", mediasArg);
12149
+
12150
+
12151
+ const doOnStartMediaHandlerMicroClient = (selfMediaHandler = null, medias = null, videoSide = null) => {
12152
+
12153
+
12154
+ // We have to wait for the medias handler to be ready, before doing anything :
12155
+
12156
+ // TRACE
12157
+ if (selfMediaHandler) lognow("INFO : MICRO CLIENT : microClient started with mediahandler.");
12158
+ else lognow("INFO : MICRO CLIENT : microClient started without mediahandler.");
12159
+
12160
+
12161
+
12162
+
12163
+ // TODO : FIXME : Utiliser initClient(...) au lieu de directement getStatic(...) avec le paramètre isNode transmis dans l'appel)
12164
+ //oritaClient=initClient(isNode,false,doOnServerConnection=null, url, port);
12165
+
12166
+ oritaClient.client={};
12167
+ oritaClient.client.socketToServer = WebsocketImplementation.getStatic(isNode).connectToServer(url, port);
12168
+ oritaClient.client.socketToServer.onConnectionToServer(() => {
12169
+
12170
+ // TRACE
12171
+ console.log("INFO : MICRO CLIENT : Sending register request...");
12172
+
12173
+ // Only micro client determines its own id ! (to avoid multi-registration protocol bug !)
12174
+
12175
+ let microClientId = getUUID("short");
12176
+
12177
+ oritaClient.microClientId = microClientId;
12178
+
12179
+ // TRACE
12180
+ lognow("INFO : (CLIENT) Microclient will now register to server with microClientId «" + microClientId + "».");
12181
+
12182
+
12183
+ oritaClient.client.socketToServer.send("protocol", "request.register:microClient:" + microClientId);
12184
+
12185
+ });
12186
+
12187
+
12188
+
12189
+ oritaClient.client.socketToServer.receive("protocol", (message) => {
12190
+
12191
+ // TRACE
12192
+ lognow("INFO : MICRO CLIENT : Server sent a message on the protocol channel : message:", JSON.stringify(message));
12193
+
12194
+
12195
+ if (contains(message.type, "response.microClient.registered")) {
12196
+
12197
+ let microClientId = message.microClientId;
12198
+
12199
+ // To be sure this registration response does not concerns another micro client :
12200
+ if (oritaClient.microClientId !== microClientId) return;
12201
+
12202
+
12203
+ // DBG
12204
+ lognow(" MICRO CLIENT REGISTERED : message:", message);
12205
+
12206
+
12207
+ // CAUTION : ON TODAY, MICRO CLIENTS ONLY SUPPORT ONE MEDIA TO SEND AT THE TIME !!!
12208
+ if (medias === "audio" || medias === "video") {
12209
+
12210
+ // TRACE
12211
+ lognow("Starting micro client sending method for micro client microClientId «" + microClientId + "»:");
12212
+
12213
+
12214
+ // START SENDING AUDIO OR VIDEO :
12215
+ // Refreshing rate calculus :
12216
+ let refreshingRateMillis = REFRESHING_RATE_MILLIS_DEFAULT;
12217
+ if (medias === "audio") {
12218
+ // (We want millis, not seconds)
12219
+ refreshingRateMillis = Math.floor((audioBufferSize / selfMediaHandler.getAudioSampleRate()) * 1000);
12220
+ } else if (medias === "video") {
12221
+ refreshingRateMillis = nonull(oritaClient.captureConfig.refreshMillis, ORITA_CONSTANTS.DEFAULT_CAPTURE_REFRESH_MILLIS);
12222
+ }
12223
+
12224
+ // *************************
12225
+ // LOCAL SENDING LOOP :
12226
+ oritaClient.sending = setInterval(function() {
12227
+
12228
+ let data = {};
12229
+ if (medias === "video") {
12230
+
12231
+ let videoData = selfMediaHandler.getVideoData();
12232
+
12233
+
12234
+ // // DBG
12235
+ // console.log("INFO : MICRO CLIENT : videoData : ",videoData);
12236
+
12237
+ if (videoData && videoData.data) {
12238
+
12239
+ let videoRawData = videoData.data;
12240
+
12241
+
12242
+ if (videoData.format !== "base64" && videoData.messWithAlpha) {
12243
+ videoRawData = removeAlpha(videoRawData);
12244
+ }
12245
+
12246
+ // We set the Side is «left» or «right»
12247
+ if (videoSide) data.videoSide = videoSide;
12248
+
12249
+ // // TRACE
12250
+ // lognow("CLIENT : getting to send : videoRawData.length:"+videoRawData.length);
12251
+
12252
+ // Actually, only handles "LZW" compression, for now...
12253
+
12254
+ let stringToSend;
12255
+ if (ORITA_CONSTANTS.STRINGIFY_VIDEO_DATA) stringToSend = arrayToString(videoRawData, false, 1);
12256
+ else stringToSend = videoRawData;
12257
+
12258
+
12259
+
12260
+ data.video = {
12261
+ width: videoData.width,
12262
+ height: videoData.height,
12263
+ data: stringToSend,
12264
+ messWithAlpha: videoData.messWithAlpha,
12265
+ format: videoData.format,
12266
+ };
12267
+ data.compression = {
12268
+ precision: 1,
12269
+ // algorithm:"LZW"
12270
+ };
12271
+
12272
+ }
12273
+
12274
+ } else if (medias === "audio") {
12275
+
12276
+ let audioData = selfMediaHandler.getAudioData().data;
12277
+
12278
+ // // DBG
12279
+ // log("CLIENT : getting to send : audioData:"+audioData.length);
12280
+
12281
+ // Actually, only handles "LZW" compression, for now...
12282
+ // DBG
12283
+ // let stringToSend=arrayToString(audioData,false,0.001);
12284
+ // data.audio={ data: stringToSend };
12285
+ // data.compression={precision:0.001,
12286
+ // // algorithm:"LZW"
12287
+ // };
12288
+
12289
+ // DBG
12290
+ data.audio = { data: audioData };
12291
+ data.compression = {};
12292
+
12293
+ } else { // Case no medias selected
12294
+ /*DO NOTHING*/
12295
+ // // TRACE
12296
+ // lognow("WARN : MICRO CLIENT : Caution, micro client has no data to send to main clients !");
12297
+ return;
12298
+ }
12299
+
12300
+
12301
+ // // TRACE
12302
+ // lognow("CLIENT : SENDING DATA TO SERVER :");
12303
+ // // DBG
12304
+ // log("data:"+data);
12305
+
12306
+
12307
+ data.microClientId = oritaClient.microClientId;
12308
+
12309
+ // Micro client starts sending :
12310
+ oritaClient.client.socketToServer.send("microClient.send.data", data);
12311
+
12312
+
12313
+
12314
+ }
12315
+ , refreshingRateMillis); // SENDING LOOP
12316
+ // *************************
12317
+ }
12318
+
12319
+
12320
+
12321
+ // We execute eventual on registration events listeners :
12322
+ foreach(oritaClient.onRegistrationEventListeners, (e) => {
12323
+ e.execute(microClientId, message);
12324
+ });
12325
+
12326
+
12327
+ //End of startResultPromise :
12328
+ resolve(oritaClient); // CAUTION : Media handler might be ready AFTER this point !
12329
+ }
12330
+
12331
+
12332
+
12333
+
12334
+
12335
+
12336
+ });
12337
+
12338
+
12339
+
12340
+
12341
+ oritaClient.client.socketToServer.receive("communication", (message) => {
12342
+ // We execute eventual on message events listeners :
12343
+ foreach(oritaClient.onCommunicationEventListeners, (e) => {
12344
+ if (!e.condition || e.condition(message)) e.execute(message);
12345
+ });
12346
+ });
12347
+
12348
+
12349
+
12350
+
12351
+
12352
+
12353
+
12354
+
12355
+
12356
+
12357
+
12358
+ };
12359
+
12360
+
12361
+
12362
+
12363
+
12364
+
12365
+ // TODO FIXME : Now, we launch one thread loop for each media handler of this medias array,
12366
+ // instead of launching only one thread for all media handlers :
12367
+
12368
+
12369
+
12370
+ foreach(mediaParametersArray, (mediaParameters) => {
12371
+
12372
+ let mediaHandlerLocal = null;
12373
+
12374
+
12375
+ let videoSide = mediaParameters.videoSide;
12376
+ let medias = mediaParameters.medias;
12377
+ let webcamIndex = mediaParameters.webcamIndex;
12378
+ let microphoneIndex = mediaParameters.microphoneIndex;
12379
+
12380
+
12381
+
12382
+ // TRACE
12383
+ lognow("INFO : MICRO CLIENT : Microclient started :");
12384
+
12385
+ // DBG
12386
+ lognow("INFO : MICRO CLIENT : Chosen webcamIndex : " + webcamIndex);
12387
+ lognow("INFO : MICRO CLIENT : Chosen microphoneIndex : " + microphoneIndex);
12388
+
12389
+
12390
+ try {
12391
+
12392
+
12393
+
12394
+ if (!isNode) {
12395
+
12396
+ // OLD : if(webcamIndex) videoConstraints={deviceId: { exact: cameras[webcamIndex].deviceId }};
12397
+ getMediaHandler(
12398
+ medias === "video" ? { webcamIndex: webcamIndex } : null,
12399
+ medias === "audio" ? { microphoneIndex: microphoneIndex } : null,
12400
+ // CHANNELS_CONFIG,
12401
+ { width: captureWidth, height: captureHeight },
12402
+ null, /*(no need for a direct video tag possibility for micro client)*/
12403
+ audioBufferSize, 1/*(means mono audio)*/,
12404
+ (mh) => {
12405
+ //DBG
12406
+ console.log("mh:", mh); console.log("medias:", medias);
12407
+ doOnStartMediaHandlerMicroClient(mh, medias, videoSide);
12408
+ },
12409
+ (mh) => { mediaHandlerLocal = mh; });
12410
+
12411
+ } else { // Case node micro client :
12412
+
12413
+
12414
+
12415
+ // DBG
12416
+ console.log("mediaParameters", mediaParameters);
12417
+ console.log("medias", medias);
12418
+
12419
+
12420
+ const videoConfigLocal = (medias === "video" ? (webcamIndex != null ? { webcamIndex: webcamIndex } : ORITA_CONSTANTS.MOBILE_VIDEO_CONSTRAINTS) : null);
12421
+ const audioConfigLocal = (medias === "audio" ? (microphoneIndex != null ? { microphoneIndex: microphoneIndex } : {}) : null);
12422
+
12423
+ // DBG
12424
+ console.log("videoConfigLocal", videoConfigLocal);
12425
+ console.log("webcamIndex", webcamIndex);
12426
+ console.log("ORITA_CONSTANTS.MOBILE_VIDEO_CONSTRAINTS", ORITA_CONSTANTS.MOBILE_VIDEO_CONSTRAINTS);
12427
+ console.log("audioConfigLocal", audioConfigLocal);
12428
+
12429
+
12430
+ mediaHandlerLocal = getNodeMediaHandler(
12431
+ videoConfigLocal,
12432
+ audioConfigLocal,
12433
+ // CHANNELS_CONFIG,
12434
+ { width: captureWidth, height: captureHeight },
12435
+ audioBufferSize, 1/*(means mono audio)*/,
12436
+ (mh) => { doOnStartMediaHandlerMicroClient(mh, medias, videoSide); });
12437
+
12438
+
12439
+ }
12440
+
12441
+ } catch (e) {
12442
+ // TRACE
12443
+ log("ERROR : Media handler error occured while trying to be initialized for microClient:");
12444
+ log(e);
12445
+ return;
12446
+ }
12447
+
12448
+ // if(!mediaHandlerLocal){
12449
+ // // TRACE
12450
+ // log("ERROR : Media handler is null for microClient.");
12451
+ // return;
12452
+ // }
12453
+
12454
+
12455
+ });
12456
+
12457
+
12458
+ if (empty(mediaParametersArray)) doOnStartMediaHandlerMicroClient();
12459
+
12460
+ });
12461
+
12462
+
12463
+ return startResultPromise;
12464
+ };
12465
+
12466
+
12467
+
12468
+ // ******************
12469
+
12470
+ // List manager treatments :
12471
+ oritaClient.onRegistrationEventListeners.push({
12472
+ execute: (microClientId, message) => {
12473
+
12474
+ const listPosition = message.listPosition;
12475
+ if (!nothing(listPosition)) {
12476
+ // TRACE
12477
+ lognow("INFO : Client has position «" + listPosition + "» in server list.");
12478
+ oritaClient.listPosition = listPosition;
12479
+ }
12480
+ }
12481
+ });
12482
+
12483
+
12484
+ // Inputs / outputs :
12485
+ oritaClient.onRegistrationEventListeners.push({
12486
+ execute: (microClientId, message) => {
12487
+
12488
+ if (empty(oritaClient.inputsGPIO) && empty(oritaClient.outputsGPIO)) return;
12489
+
12490
+
12491
+ oritaClient.onCommunicationEventListeners.push({
12492
+ condition: (message) => message === "request.server.signalIOs",
12493
+ execute: (message) => {
12494
+
12495
+ // DBG
12496
+ lognow("SIGNALING !!!");
12497
+
12498
+
12499
+ if (!empty(oritaClient.inputsGPIO)) {
12500
+
12501
+ // DBG
12502
+ lognow("SIGNALING INPUTS");
12503
+
12504
+ oritaClient.client.socketToServer.send("communication", {
12505
+ type: "request.microClient.appendInputs",
12506
+ inputsGPIO: oritaClient.inputsGPIO,
12507
+ microClientId: oritaClient.microClientId,
12508
+ });
12509
+ }
12510
+
12511
+ if (!empty(oritaClient.outputsGPIO)) {
12512
+
12513
+ // DBG
12514
+ lognow("SIGNALING OUTPUTS");
12515
+
12516
+ oritaClient.client.socketToServer.send("communication", {
12517
+ type: "request.microClient.appendOutputs",
12518
+ outputsGPIO: oritaClient.outputsGPIO,
12519
+ microClientId: oritaClient.microClientId,
12520
+ });
12521
+ }
12522
+
12523
+ },
12524
+
12525
+ });
12526
+
12527
+
12528
+
12529
+ },
12530
+
12531
+ });
12532
+
12533
+
12534
+ // Inputs :
12535
+ oritaClient.registerInputsGPIO = (gpios, refreshRateMillis = 1000) => {
12536
+
12537
+ // 0-
12538
+ foreach(gpios, (gpioNumber, gpioId) => {
12539
+ let input = {
12540
+ gpioId: gpioId,
12541
+ gpioNumber: gpioNumber,
12542
+ state: null,
12543
+ init: () => {
12544
+ gpioUtils.open(input.gpioNumber, "in");
12545
+ input.previousState = null;
12546
+ },
12547
+ read: () => {
12548
+
12549
+ gpioUtils.read(input.gpioNumber, (state) => {
12550
+ input.previousState = input.state;
12551
+ input.state = state;
12552
+
12553
+ // // DBG
12554
+ // console.log("~~~READ STATE : ",input.state);
12555
+ });
12556
+
12557
+ },
12558
+ };
12559
+ input.init();
12560
+ oritaClient.inputsGPIO[gpioId] = input;
12561
+ });
12562
+
12563
+
12564
+ // 1-
12565
+ oritaClient.onRegistrationEventListeners.push({
12566
+ execute: (microClientId, message) => {
12567
+ oritaClient.client.socketToServer.send("communication", {
12568
+ type: "request.microClient.appendInputs",
12569
+ inputsGPIO: oritaClient.inputsGPIO,
12570
+ microClientId: oritaClient.microClientId,
12571
+ });
12572
+ },
12573
+ });
12574
+
12575
+ // 3-
12576
+ setInterval(() => {
12577
+
12578
+ let inputsGPIO = oritaClient.inputsGPIO;
12579
+
12580
+ foreach(inputsGPIO, (input) => {
12581
+ input.read();
12582
+ });
12583
+
12584
+
12585
+ oritaClient.client.socketToServer.send("communication", {
12586
+ type: "request.microClient.updateInputsValues",
12587
+ inputsGPIO: inputsGPIO,
12588
+ microClientId: oritaClient.microClientId,
12589
+ });
12590
+
12591
+
12592
+ }, refreshRateMillis);
12593
+
12594
+
12595
+ return oritaClient;
12596
+ };
12597
+
12598
+
12599
+
12600
+
12601
+ // Outputs :
12602
+ oritaClient.stepperIntervalRoutines = {};
12603
+ oritaClient.registerOutputsGPIO = (gpios) => {
12604
+
12605
+ // 0-
12606
+ foreach(gpios, (gpioInfos, gpioId) => {
12607
+
12608
+ let output = {
12609
+ gpioId: gpioId,
12610
+ gpioInfos: gpioInfos,
12611
+ state: null,
12612
+ collisionningOutputsIds: null,
12613
+ // lastPhaseIndex:null,
12614
+ // phaseIndex:0,
12615
+ sequenceIndex: 0,
12616
+ init: () => {
12617
+
12618
+ if (isNumber(output.gpioInfos)) {
12619
+ const gpioNumber = output.gpioInfos;
12620
+ gpioUtils.open(gpioNumber, "out");
12621
+
12622
+ } else {
12623
+ foreach(output.gpioInfos.phases, (phase) => {
12624
+ const gpioNumber = phase;
12625
+ gpioUtils.open(gpioNumber, "out");
12626
+
12627
+ });
12628
+ }
12629
+
12630
+ output.previousState = null;
12631
+ output.state = false;
12632
+ },
12633
+ on: (doOnEndCommand = null/*UNUSED*/) => {
12634
+
12635
+ // Other outputs exclusion :
12636
+ if (output.collisionningOutputsIds) {
12637
+ foreach(output.collisionningOutputsIds, (collisionningOutputId) => {
12638
+ const collisionningOutput = oritaClient.outputsGPIO[collisionningOutputId];
12639
+ if (!collisionningOutput) return "continue";
12640
+ collisionningOutput.off(doOnEndCommand);
12641
+ }, (collisionningOutputId) => {
12642
+ const collisionningOutput = oritaClient.outputsGPIO[collisionningOutputId];
12643
+ return collisionningOutput && collisionningOutput.state;
12644
+ });
12645
+ }
12646
+
12647
+
12648
+ if (isNumber(output.gpioInfos)) {
12649
+ // Case one single 0/1 output :
12650
+ const gpioNumber = output.gpioInfos;
12651
+
12652
+ gpioUtils.write(gpioNumber, 1, doOnEndCommand);
12653
+
12654
+
12655
+ } else {
12656
+
12657
+ // Case stepper motor output:
12658
+ const direction = nonull(output.gpioInfos.direction, 1);
12659
+ let sortedPhases;
12660
+ if (direction == -1) {
12661
+ sortedPhases = [];
12662
+ if (!empty(output.gpioInfos.phases)) {
12663
+ for (let i = output.gpioInfos.phases.length - 1; 0 <= i; i--) {
12664
+ sortedPhases.push(output.gpioInfos.phases[i]);
12665
+ }
12666
+ }
12667
+ } else {
12668
+ sortedPhases = output.gpioInfos.phases;
12669
+ }
12670
+
12671
+ const sequence = nonull(output.gpioInfos.sequence, DEFAULT_STEPPER_SEQUENCE);
12672
+ const stepDelayMillis = output.gpioInfos.stepDelayMillis;
12673
+ const stepperMethodCallback = async () => {
12674
+
12675
+ const outputSelf = stepperMethodCallback.output;
12676
+ const sortedPhasesSelf = stepperMethodCallback.sortedPhases;
12677
+
12678
+ await new Promise((resolve, reject) => setTimeout(resolve, STEPPER_DELAY_MILLIS));
12679
+ const sequenceLine = sequence[outputSelf.sequenceIndex];
12680
+ if (sequenceLine && !empty(sequenceLine)) {
12681
+ foreach(sequenceLine, (phaseState, i) => {
12682
+ const gpioNumber = sortedPhasesSelf[i];
12683
+ gpioUtils.write(gpioNumber, phaseState, doOnEndCommand);
12684
+ });
12685
+ }
12686
+
12687
+ if (outputSelf.sequenceIndex < sequence.length - 1) outputSelf.sequenceIndex++;
12688
+ else outputSelf.sequenceIndex = 0;
12689
+ };
12690
+
12691
+ stepperMethodCallback.output = output;
12692
+ stepperMethodCallback.sortedPhases = sortedPhases;
12693
+ const stepperMethod = setInterval(stepperMethodCallback, stepDelayMillis);
12694
+ oritaClient.stepperIntervalRoutines[gpioId] = stepperMethod;
12695
+
12696
+
12697
+
12698
+ }
12699
+
12700
+ output.previousState = output.state;
12701
+ output.state = true;
12702
+ },
12703
+ off: (doOnEndCommand = null/*UNUSED*/) => {
12704
+
12705
+ if (isNumber(output.gpioInfos)) {
12706
+ // Case one single 0/1 output :
12707
+ const gpioNumber = output.gpioInfos;
12708
+ gpioUtils.write(gpioNumber, 0, doOnEndCommand);
12709
+
12710
+ } else {
12711
+ // Case stepper motor output:
12712
+ foreach(output.gpioInfos.phases, (phase) => {
12713
+ const gpioNumber = phase;
12714
+ gpioUtils.write(gpioNumber, 0, doOnEndCommand);
12715
+ });
12716
+ clearInterval(oritaClient.stepperIntervalRoutines[gpioId]);
12717
+ oritaClient.stepperIntervalRoutines[gpioId] = null;
12718
+ }
12719
+
12720
+ output.previousState = output.state;
12721
+ output.state = false;
12722
+ },
12723
+ };
12724
+ output.init();
12725
+
12726
+
12727
+ // We detect the possible outputs collisions among all the already registered outputs :
12728
+ foreach(oritaClient.outputsGPIO, (otherOutput, otherOutputName) => {
12729
+
12730
+ const collisionningOutputsIdsAndPhases = {};
12731
+ if (isNumber(otherOutput.gpioInfos)) {
12732
+ const phase = otherOutput.gpioInfos;
12733
+ if (!collisionningOutputsIdsAndPhases[otherOutputName]) {
12734
+ collisionningOutputsIdsAndPhases[otherOutputName] = { outputId: otherOutput.gpioId, phases: [phase] };
12735
+ } else {
12736
+ collisionningOutputsIdsAndPhases[otherOutputName].phases.push(phase);
12737
+ }
12738
+ } else {
12739
+ foreach(gpioInfos.phases, (phase) => {
12740
+ if (contains(otherOutput.gpioInfos.phases, phase)) {
12741
+ if (!collisionningOutputsIdsAndPhases[otherOutputName]) {
12742
+ collisionningOutputsIdsAndPhases[otherOutputName] = { outputId: otherOutput.gpioId, phases: [phase] };
12743
+ } else {
12744
+ collisionningOutputsIdsAndPhases[otherOutputName].phases.push(phase);
12745
+ }
12746
+ }
12747
+ });
12748
+ }
12749
+ if (!empty(collisionningOutputsIdsAndPhases)) {
12750
+ // // DEBUG
12751
+ // lognow("WARN : Found another outputsGPIO using this phase : ",collisionningOutputsIdsAndPhases);
12752
+ output.collisionningOutputsIds = [];
12753
+ foreach(collisionningOutputsIdsAndPhases, (collisionningOutputIdAndPhases) => {
12754
+ const collisionningOutput = oritaClient.outputsGPIO[collisionningOutputIdAndPhases.outputId];
12755
+ if (!collisionningOutput) return "continue";
12756
+ output.collisionningOutputsIds.push(collisionningOutputIdAndPhases.outputId);
12757
+ // Backlink :
12758
+ if (!collisionningOutput.collisionningOutputsIds) collisionningOutput.collisionningOutputsIds = [];
12759
+ collisionningOutput.collisionningOutputsIds.push(output.gpioId);
12760
+ });
12761
+ }
12762
+ });
12763
+
12764
+
12765
+ // We add this output to the micro client outputs :
12766
+ oritaClient.outputsGPIO[gpioId] = output;
12767
+ });
12768
+
12769
+ // 1-
12770
+ oritaClient.onRegistrationEventListeners.push({
12771
+ execute: (microClientId, message) => {
12772
+ oritaClient.client.socketToServer.send("communication", {
12773
+ type: "request.microClient.appendOutputs",
12774
+ outputsGPIO: oritaClient.outputsGPIO,
12775
+ microClientId: oritaClient.microClientId,
12776
+ });
12777
+ },
12778
+ });
12779
+
12780
+ // 3-
12781
+ oritaClient.onCommunicationEventListeners.push({
12782
+ condition: (message) => message.type === "request.mainClient.outputChanged",
12783
+ execute: (message) => {
12784
+
12785
+ // foreach(message.outputsChanged, (outputChanged)=>{
12786
+
12787
+ const outputChanged = message.outputChanged;
12788
+
12789
+ // DBG
12790
+ console.log("!!! CHANGE STATE :", outputChanged);
12791
+
12792
+ const changeToState = (gpioIdParam, stateToPut, doOnEndCommand = null/*UNUSED*/) => {
12793
+ let output = oritaClient.outputsGPIO[gpioIdParam];
12794
+ if (!output) {
12795
+ // TRACE
12796
+ lognow("ERROR : Output for gpio id «" + gpioIdParam + "» does not exist for this micro client.");
12797
+ return;
12798
+ }
12799
+ if (stateToPut) output.on(doOnEndCommand);
12800
+ else output.off(doOnEndCommand);
12801
+
12802
+ // DBG
12803
+ console.log("!!! CHANGE STATE :stateToPut", stateToPut);
12804
+ };
12805
+
12806
+ let gpioId = outputChanged.gpioId;
12807
+
12808
+ let changeStateVanilla = true;
12809
+ if (message.actionnersConfigs) {
12810
+
12811
+ let actionnerConfig = foreach(message.actionnersConfigs, (ac) => {
12812
+ if (ac.gpioId === gpioId) return ac;
12813
+ });
12814
+
12815
+ if (actionnerConfig) {
12816
+
12817
+ if (actionnerConfig.gpioId && actionnerConfig.gpioId !== gpioId) {
12818
+ return; // DO NOTHING
12819
+ }
12820
+
12821
+ if (actionnerConfig.type === "pushOnce") {
12822
+
12823
+ let output = oritaClient.outputsGPIO[gpioId];
12824
+ if (!output) {
12825
+ // TRACE
12826
+ lognow("ERROR : Output for gpio id «" + gpioId + "» does not exist for this micro client.");
12827
+ return;
12828
+ }
12829
+
12830
+ // ACTUAL STATE :
12831
+ if (output.state) return; // DO NOTHING
12832
+ // WISHED STATE :
12833
+ if (!outputChanged.state) return; // DO NOTHING
12834
+
12835
+ let latencyMillis = nonull(actionnerConfig.latencyMillis, 1000);
12836
+ // We set the output to the 1 state :
12837
+ changeToState(gpioId, true, (err, stdout, stderr) => {
12838
+ if (err) {
12839
+ console.log(err);
12840
+ return;
12841
+ }
12842
+ if (stderr) {
12843
+ console.log(stderr);
12844
+ return;
12845
+ }
12846
+
12847
+ // We return the output to the 0 state, after a while :
12848
+ setInterval(() => {
12849
+ changeToState(gpioId, false);
12850
+ }, latencyMillis);
12851
+
12852
+ });
12853
+
12854
+ changeStateVanilla = false;
12855
+ }
12856
+ }
12857
+ }
12858
+ if (changeStateVanilla) {
12859
+ changeToState(gpioId, outputChanged.state);
12860
+ }
12861
+
12862
+
12863
+ // });
12864
+
12865
+ // 4-
12866
+ oritaClient.client.socketToServer.send("communication", {
12867
+ type: "response.microClient.outputChanged",
12868
+ outputsGPIO: oritaClient.outputsGPIO,
12869
+ });
12870
+
12871
+ },
12872
+ });
12873
+
12874
+
12875
+ return oritaClient;
12876
+ };
12877
+
12878
+
12879
+
12880
+ // TODO : DEVELOP...
12881
+
12882
+ // // Mobile platforms:
12883
+ // oritaClient.registerInputsTouch=()=>{
12884
+ // return oritaClient;
12885
+ // };
12886
+ // oritaClient.registerInputsOrientation=()=>{
12887
+ // return oritaClient;
12888
+ // };
12889
+ // // Desktop / potentially mobile platforms:
12890
+ // oritaClient.registerInputsMouse=()=>{
12891
+ // return oritaClient;
12892
+ // };
12893
+ // oritaClient.registerInputsKeyboard=()=>{
12894
+ // return oritaClient;
12895
+ // };
12896
+
12897
+
12898
+ // INPUTS SENDING :
12899
+ oritaClientoritaClient.sendCommand = (commandName, commandParameters = null) => {
12900
+ const microClientId = oritaClient.microClientId;
12901
+ const command = { microClientId: microClientId, type: "microClient.send.command", name: commandName, parameters: commandParameters };
12902
+ oritaClient.client.socketToServer.send("communication", command);
12903
+ return oritaClient;
12904
+ };
12905
+
12906
+
12907
+
12908
+ oritaMicroClient.oritaClient = oritaClient;
12909
+ return oritaClient;
12910
+ };
12911
+
12912
+
12913
+ /*utils GEOMETRY library associated with aotra version : «1_29072022-2359 (25/09/2022-16:59:58)»*/
11680
12914
  /*-----------------------------------------------------------------------------*/
11681
12915
 
11682
12916
 
@@ -12904,7 +14138,7 @@ function rayVsUnitSphereClosestPoint(p, r) {
12904
14138
  // MUST REMAIN AT THE END OF THIS LIBRARY FILE !
12905
14139
 
12906
14140
  AOTRAUTILS_GEOMETRY_LIB_IS_LOADED=true;
12907
- /*utils SERVER library associated with aotra version : «1_29072022-2359 (19/08/2022-00:31:09)»*/
14141
+ /*utils SERVER library associated with aotra version : «1_29072022-2359 (25/09/2022-16:59:58)»*/
12908
14142
  /*-----------------------------------------------------------------------------*/
12909
14143
 
12910
14144