vxgwsplayer-1.0.9.js 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629
  1. const { pipelines, components, utils, Buffer } = window.mediaStreamLibrary;
  2. Number.prototype.toUnsigned = function() {
  3. return ((this >>> 1) * 2 + (this & 1));
  4. };
  5. const ulawencodeTable = [
  6. 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  7. 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
  8. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  9. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  10. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  11. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  12. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  13. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  14. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  15. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  16. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  17. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  18. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  19. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  20. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  21. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7];
  22. window.vxgwsplayer = function(id, options_){
  23. window.vxgwsplayer.version="1.1.2"; //version is updated by 'npm run build'
  24. window.vxgwsplayer.players = window.vxgwsplayer.players || {};
  25. if(!document.getElementById(id)){
  26. console.error(" Player with " + id + " did not found");
  27. return undefined;
  28. }
  29. if(!window.vxgwsplayer.players[id]){
  30. /*
  31. if(typeof chrome == "undefined"){
  32. vxgwsplayer.showAvailableInChrome(id);
  33. return undefined;
  34. }
  35. if(navigator.userAgent.match(/Android/i)
  36. || navigator.userAgent.match(/webOS/i)
  37. || navigator.userAgent.match(/iPhone/i)
  38. || navigator.userAgent.match(/iPad/i)
  39. || navigator.userAgent.match(/iPod/i)
  40. || navigator.userAgent.match(/BlackBerry/i)
  41. || navigator.userAgent.match(/Windows Phone/i)
  42. ){
  43. vxgwsplayer.showAvailableInChrome(id);
  44. return undefined;
  45. };
  46. */
  47. /*
  48. if(!vxgwsplayer.browserSupportsPluginPnacl()){
  49. console.log("Not installed vxg_media_player");
  50. vxgwsplayer.showNotInstalled(id);
  51. var fs = window.RequestFileSystem || window.webkitRequestFileSystem;
  52. if (fs) {
  53. fs(window.TEMPORARY,100,function(){},function(){ vxgwsplayer.showNotInstalledInIncognitoMode(id); });
  54. }
  55. return undefined;
  56. }
  57. */
  58. // magic run app
  59. /*
  60. var fs = window.RequestFileSystem || window.webkitRequestFileSystem;
  61. if (!fs) {
  62. //console.log("RequestFileSystem failed");
  63. window.location.href = "https://www.videoexpertsgroup.com/player_start/";
  64. } else {
  65. fs(window.TEMPORARY, 1, function(){
  66. //console.log("not in incognito mode");
  67. if(!vxgwsplayer.isFrame()){
  68. //console.log("Start Chrome App");
  69. window.location.href = "https://www.videoexpertsgroup.com/player_start/";
  70. }
  71. },
  72. function(){
  73. console.log("Not installed vxg_media_player");
  74. });
  75. }
  76. */
  77. // check web socket server
  78. /*
  79. if(window.location.protocol != "https:" && !vxgwsplayer.isFrame()){
  80. vxgwsplayer.checkWebSocket().done(function(result){
  81. //console.log('websocket: success');
  82. }).fail(function(err){
  83. // check incognito mode
  84. fs(window.TEMPORARY,1,function(){ vxgwsplayer.showWebSocketFailed(id); },function(){ vxgwsplayer.showNotStartedInIncognitoMode(id); });
  85. });
  86. }
  87. */
  88. if(window.location.protocol != "https:" && vxgwsplayer.isFrame()){
  89. vxgwsplayer.checkWebSocket().done(function(result){
  90. //console.log('websocket: success');
  91. }).fail(function(err){
  92. vxgwsplayer.showNotStartedInIFrame(id);
  93. });
  94. }
  95. //window.location.href = "https://videoexpertsgroup.com/player_start/";
  96. window.vxgwsplayer.players[id] = new function(id, opts){
  97. const self = this;
  98. self.id = id;
  99. self.player = document.getElementById(id);
  100. /* init options */
  101. window.vxgwsplayer.initOptions(self, opts);
  102. self.playerWidth=self.options.width || 640;
  103. self.playerHeight=self.options.height || 480;
  104. self.playerWidth = parseInt(self.player.getAttribute('width'),10) || self.playerWidth;
  105. self.playerHeight = parseInt(self.player.getAttribute('height'),10) || self.playerHeight;
  106. self.player.style.width = self.playerWidth + 'px';
  107. self.player.style.height = self.playerHeight + 'px';
  108. self.wd = null;
  109. self.wdtries = 0;
  110. self.wdwork = null;
  111. var html = ''
  112. + '<div class="vxgwsplayer-loader" style="display: inline-block"></div>'
  113. + '<div class="vxgwsplayer-screenshot-loading" style="display: none">'
  114. + ' <div class="vxgwsplayer-screenshot-loading">'
  115. + ' </div>'
  116. + '</div>'
  117. + '<div class="vxgwsplayer-error" style="display: none">'
  118. + ' <div class="vxgwsplayer-error-text" style="display: none"></div>'
  119. + '</div>'
  120. + '<div class="vxgwsplayer-controls-zoom-position">'
  121. + ' <div class="vxgwsplayer-zoom-position-cursor"></div>'
  122. + '</div>'
  123. + '<div class="vxgwsplayer-controls-zoom">'
  124. + ' <div class="vxgwsplayer-zoom-up"></div>'
  125. + ' <div class="vxgwsplayer-zoom-progress zoom10x"></div>'
  126. + ' <div class="vxgwsplayer-zoom-down"></div>'
  127. + '</div>'
  128. + '<div class="vxgwsplayer-controls">'
  129. + ' <div class="vxgwsplayer-volume-mute"></div>'
  130. + ' <div class="vxgwsplayer-volume-down"></div>'
  131. + ' <div class="vxgwsplayer-volume-progress vol7"></div>'
  132. + ' <div class="vxgwsplayer-volume-up"></div>'
  133. + ' <div class="vxgwsplayer-play"></div>'
  134. + ' <div class="vxgwsplayer-pause" style="display: none"></div>'
  135. + ' <div class="vxgwsplayer-stop" style="display: none"></div>'
  136. +' <div class="vxgwsplayer-fullscreen"></div>'
  137. +' <div class="vxgwsplayer-takescreenshot"></div>'
  138. +' <div class="vxgwsplayer-scale"></div>'
  139. + '</div>'
  140. + '<canvas class="vxgwsplayer-stub-snapshot" style="width:100%; height:100%; display:none;"></canvas>'
  141. // + '<video class="vxgwsplayer-native-video contain" autoplay="yes" muted="yes" style="width:100%; height: 100%; position: absolute;"></video>'
  142. + '<video class="vxgwsplayer-native-video contain" muted="yes" volume="1.0" style="width:100%; height: 100%; position: absolute; transform: scale(1); left: 0%; top: 0%;"></video>'
  143. + '<video class="vxgwsplayer-stub-record" style="display: none;"></video>'
  144. /*
  145. + window.vxgwsplayer.generateEmbededElement(self);
  146. */
  147. self.player.innerHTML = html;
  148. var el_controls = self.player.getElementsByClassName('vxgwsplayer-controls')[0];
  149. var el_controls_zoom = self.player.getElementsByClassName('vxgwsplayer-controls-zoom')[0];
  150. var el_controls_zoom_position = self.player.getElementsByClassName('vxgwsplayer-controls-zoom-position')[0];
  151. var el_play = self.player.getElementsByClassName('vxgwsplayer-play')[0];
  152. var el_pause = self.player.getElementsByClassName('vxgwsplayer-pause')[0];
  153. var el_stop = self.player.getElementsByClassName('vxgwsplayer-stop')[0];
  154. var el_fullscreen = self.player.getElementsByClassName('vxgwsplayer-fullscreen')[0];
  155. var el_takescreenshot = self.player.getElementsByClassName('vxgwsplayer-takescreenshot')[0];
  156. var el_screenshot_loading = self.player.getElementsByClassName('vxgwsplayer-screenshot-loading')[0];
  157. var el_scale = self.player.getElementsByClassName('vxgwsplayer-scale')[0];
  158. var el_zoomUp = self.player.getElementsByClassName('vxgwsplayer-zoom-up')[0];
  159. var el_zoomDown = self.player.getElementsByClassName('vxgwsplayer-zoom-down')[0];
  160. var el_zoomProgress = self.player.getElementsByClassName('vxgwsplayer-zoom-progress')[0];
  161. var el_zoomPositionCursor = self.player.getElementsByClassName('vxgwsplayer-zoom-position-cursor')[0];
  162. var el_loader = self.player.getElementsByClassName('vxgwsplayer-loader')[0];
  163. var el_error = self.player.getElementsByClassName('vxgwsplayer-error')[0];
  164. var el_error_text = self.player.getElementsByClassName('vxgwsplayer-error-text')[0];
  165. var el_video = self.player.getElementsByClassName('vxgwsplayer-native-video')[0];
  166. var el_snap_stub = self.player.getElementsByClassName('vxgwsplayer-stub-snapshot')[0];
  167. var el_record = self.player.getElementsByClassName('vxgwsplayer-stub-record')[0];
  168. var el_btnstart = document.getElementById(id + '_btnstart');
  169. self.video = el_video;
  170. self.video.onplay = function() {
  171. var b = self.video.buffered;
  172. if (b.length > 0)
  173. self.video.currentTime = b.end(b.length - 1) - self.m.latency/1000;
  174. console.log('onplay: start=' + self.video.currentTime + ', buffer=(' + b.start(b.length - 1) + ', ' + b.end(b.length - 1) + ')');
  175. /*
  176. var b = self.video.buffered;
  177. if (b.length == 0) {
  178. console.log('no buffer');
  179. } else {
  180. if ((b.end(0)*1000 - self.m.latency > 0) && (self.video.paused )) {
  181. self.video.paused = false;
  182. self.video.currentTime = b.end(0) - self.m.latency/1000;
  183. self.pipeline.play();
  184. }
  185. console.log('buffer:' + b.start(0) + '~' + b.end(0));
  186. }
  187. */
  188. }
  189. self.video.onpause = function() {
  190. console.log('onpause');
  191. }
  192. /*
  193. self.module = document.getElementById(id + '_nacl_module');
  194. self.module.command = function(){
  195. var cmd = [];
  196. for(var i = 0; i < arguments.length; i++){
  197. cmd.push(arguments[i]);
  198. }
  199. if(id != self.id || self.id + '_nacl_module' != self.module.id){
  200. console.error("Mixed player id");
  201. }
  202. if(self.m.debug){
  203. console.log('Player: ' + self.id + ' cmd=[' + cmd.join('] '));
  204. }
  205. self.module.postMessage(cmd);
  206. // self.module.postMessage(arguments);
  207. }
  208. // Request the offsetTop property to force a relayout. As of Apr 10, 2014
  209. // this is needed if the module is being loaded on a Chrome App's
  210. // background page (see crbug.com/350445).
  211. self.module.offsetTop;
  212. */
  213. self.m.versionapp = "unknown";
  214. self.m.debug = self.options.debug || self.player.hasAttribute('debug') || false;
  215. var watchdog_tr = self.player.getAttribute('watchdog');
  216. // self.m.watchdog = ( (watchdog_tr !== undefined) && (watchdog_tr !==null) && (watchdog_tr !== "") ) ? parseInt(watchdog_tr,10) : 3;
  217. // if fps=1, 3sec is not enough to fill buffer to satisfy latency.
  218. self.m.watchdog = ( (watchdog_tr !== undefined) && (watchdog_tr !==null) && (watchdog_tr !== "") ) ? parseInt(watchdog_tr,10) : 5;
  219. self.m.autostart = self.player.hasAttribute('autostart');
  220. self.m.is_opened = false;
  221. self.m.latency = 0;
  222. self.m.controls = true;
  223. self.m.avsync = self.options.avsync || false;
  224. self.m.vxgReadyState = 0;
  225. self.m.autohide = self.options.autohide || 2000;
  226. self.m.lastErrorCode = -1;
  227. self.m.lastErrorDecoder = 0;
  228. self.m.autoreconnect = self.options.autoreconnect || 0;
  229. self.m.connection_timeout = self.options.connection_timeout || 0;
  230. self.m.connection_udp = self.options.connection_udp || 0;
  231. self.m.isCustomDigitalZoom = self.options.custom_digital_zoom || false;
  232. self.currentZoom = 10;
  233. self.m.snapshotFile = "";
  234. self.m.snapshotPTS = "-1";
  235. self.m.PTSVideo = "-1";
  236. self.m.PTSAudio = "-1";
  237. self.m.playAfterBufferFill = false;
  238. self.m.lastRecvTime = Date.now();
  239. vxgwsplayer.initVolumeControls(self, false);
  240. if(self.m.debug){
  241. console.log("Player " + self.id + " - init new player");
  242. }
  243. self.set_controls_opacity = function(val){
  244. el_controls.style.opacity = val;
  245. el_controls_zoom.style.opacity = val;
  246. el_controls_zoom_position.style.opacity = val;
  247. }
  248. self.set_controls_display = function(val){
  249. el_controls.style.display = val;
  250. if(self.m.isCustomDigitalZoom == true){
  251. el_controls_zoom.style.display = "none";
  252. el_controls_zoom_position.style.display = "none";
  253. }else{
  254. el_controls_zoom.style.display = val;
  255. el_controls_zoom_position.style.display = self.currentZoom == 10 ? "none" : "";
  256. }
  257. }
  258. if(self.m.isCustomDigitalZoom == false){
  259. el_controls_zoom_position.style.display = self.currentZoom == 10 ? "none" : "";
  260. }
  261. if(self.player.hasAttribute('custom-digital-zoom')){
  262. self.m.isCustomDigitalZoom = true;
  263. el_controls_zoom.style.display = "none";
  264. el_controls_zoom_position.style.display = "none";
  265. }
  266. if(!self.player.hasAttribute('controls')){
  267. self.m.controls = false;
  268. self.set_controls_display("none");
  269. }
  270. if(self.options.controls && self.options.controls == true){
  271. self.m.controls = true;
  272. self.set_controls_display("");
  273. }
  274. self.m.avsync = self.player.hasAttribute('avsync');
  275. self.m.aspectRatio = (self.player.hasAttribute('aspect-ratio-mode'))?(parseInt(self.player.getAttribute('aspect-ratio-mode'),10)):0;
  276. if(self.player.hasAttribute('autohide')){
  277. self.m.autohide = parseInt(self.player.getAttribute('autohide'),10)*1000;
  278. }else if(self.options.autohide){
  279. self.m.autohide = self.options.autohide*1000;
  280. }
  281. self.timeout = undefined;
  282. self.loadSettings = function(){
  283. if(self.m.debug){
  284. console.log('Player ' + self.id + ' - loadSettings');
  285. }
  286. /*
  287. if(self.player.hasAttribute('useragent-prefix')){
  288. self.module.command('setuseragent', self.player.getAttribute('useragent-prefix') + ' ' + navigator.userAgent)
  289. }else if(self.options.useragent_prefix){
  290. self.module.command('setuseragent', self.options.useragent_prefix + ' ' + navigator.userAgent)
  291. }
  292. */
  293. /*
  294. self.module = document.getElementById(self.id + '_nacl_module');
  295. self.module.command = function(){
  296. var cmd = [];
  297. for(var i = 0; i < arguments.length; i++){
  298. cmd.push(arguments[i]);
  299. }
  300. if(id != self.id || self.id + '_nacl_module' != self.module.id){
  301. console.error("Mixed player id");
  302. }
  303. if(self.m.debug){
  304. console.log('Player: ' + self.id + ' cmd=[' + cmd.join('] '));
  305. }
  306. self.module.postMessage(cmd);
  307. // self.module.postMessage(arguments);
  308. }
  309. self.module.offsetTop;
  310. self.module.command('setversion', window.vxgwsplayer.version);
  311. */
  312. //self.m.autoreconnect = 0;
  313. if(self.player.hasAttribute('auto-reconnect') || self.options.autoreconnect){
  314. self.m.autoreconnect = 1;
  315. /*
  316. self.module.command('setautoreconnect', '1');
  317. */
  318. }
  319. if(self.player.hasAttribute('connection-timeout')){
  320. self.m.connection_timeout = parseInt(self.player.getAttribute('connection-timeout'), 10);
  321. }
  322. if(self.options.connection_timeout != 0){
  323. /*
  324. self.module.command('setconnection_timeout', self.m.connection_timeout.toString());
  325. */
  326. }
  327. if(self.player.hasAttribute('connection-udp') || self.m.connection_udp){
  328. self.m.connection_udp = 1;
  329. /*
  330. self.module.command('setconnection_udp', '1');
  331. */
  332. }
  333. self.m.avsync = self.player.hasAttribute('avsync');
  334. self.m.aspectRatio = 0;
  335. if(self.player.hasAttribute('aspect-ratio-mode')){
  336. self.m.aspectRatio = parseInt(self.player.getAttribute('aspect-ratio-mode'), 10);
  337. }else if(self.options.aspect_ratio_mode){
  338. self.m.aspectRatio = self.options.aspect_ratio_mode;
  339. }
  340. self.aspectRatioMode(self.m.aspectRatio);
  341. /*
  342. self.module.command('setavsync', self.m.avsync ? '1' : '0');
  343. */
  344. if(self.player.hasAttribute('latency')){
  345. self.m.latency = parseInt(self.player.getAttribute('latency'), 10);
  346. /*
  347. self.module.command('setlatency', self.m.latency.toString());
  348. */
  349. }else if(self.options.latency){
  350. self.m.latency = self.options.latency;
  351. /*
  352. self.module.command('setlatency', self.m.latency.toString());
  353. */
  354. }
  355. if (self.m.latency < 0) {
  356. self.m.latency = 0;
  357. }
  358. window.vxgwsplayer.initVolumeControls(self, true);
  359. if(self.player.hasAttribute('autohide')){
  360. self.m.autohide = parseInt(self.player.getAttribute('autohide'),10)*1000;
  361. }else if(self.options.autohide){
  362. self.m.autohide = self.options.autohide*1000;
  363. }
  364. }
  365. self.moduleDidLoad = function(){
  366. if(self.m.debug){
  367. console.log('Player ' + self.id + ' - moduleDidLoad');
  368. }
  369. self.loadSettings();
  370. if(window.location.protocol == "https:"){
  371. //use Native protocol
  372. self.connectToApp();
  373. }else{
  374. //use Websocket protocol
  375. /*
  376. self.module.command('startwebsclient', vxgwsplayer.webserverport)
  377. */
  378. }
  379. }
  380. self.playerDidLoad = function(){
  381. self.loadSettings();
  382. if(self.m.debug){
  383. console.log('Player ' + self.id + " - playerDidLoad");
  384. }
  385. if(self.onReadyStateCallback){
  386. self.m.is_opened = false;
  387. self.onReadyStateCallback();
  388. }else{
  389. self.setSource(); //binary, wsurl and rtspurl should be inited
  390. }
  391. }
  392. self.connectToApp = function(){
  393. if(self.m.debug){
  394. console.log('Player ' + self.id + ' connectToApp');
  395. }
  396. //self.m.port = chrome.runtime.connect("hncknjnnbahamgpjoafdebabmoamcnni");
  397. //self.m.port = chrome.runtime.connect("invalid");
  398. if(self.m.debug){
  399. console.log('Player ' + self.id + ' connected port='+self.m.port);
  400. }
  401. self.m.portName = ""+ new Date().getTime().toString();
  402. /*
  403. self.m.port.onDisconnect.addListener(function(){
  404. if(self.m.debug)
  405. console.log('disconnected portName='+self.m.portName);
  406. self.module.command( 'stopnativeclient', '@'+self.m.portName);
  407. self.m.port = undefined;
  408. });
  409. */
  410. if(self.m.debug)
  411. console.log('connected portName='+self.m.portName);
  412. /*
  413. self.m.port.onMessage.addListener(function(msg) {
  414. if( msg != undefined && msg.id == undefined && msg[0] != undefined && msg[0].charAt(0) == '@'){
  415. if(self.module.postMessage == undefined){
  416. self.m.port.disconnect();
  417. }else{
  418. self.module.postMessage(msg);
  419. }
  420. }else
  421. if( msg != undefined && msg.cmd == 'getversionapp'){
  422. if(0 == msg.data.indexOf("VERSION_APP")){
  423. self.m.versionapp = msg.data.split(' ')[1];
  424. if(self.m.debug){
  425. console.log('Player ' + self.id + ' =VERSION_APP '+self.m.versionapp);
  426. }
  427. self.module.command( 'setappversion', self.m.versionapp);
  428. self.module.command( 'startnativeclient', '@'+self.m.portName);
  429. self.playerDidLoad();
  430. }else{
  431. console.log('Player ' + self.id + ' Invalid VERSION_APP msg.data='+msg.data);
  432. }
  433. }else{
  434. console.log('Player ' + self.id + 'getversionapp unknown msg=', msg);
  435. }
  436. });
  437. self.m.port.postMessage({id: ""+self.m.portName, cmd: "getversionapp", data: ""} );
  438. */
  439. }
  440. self.showerror = function(text){
  441. el_loader.style.display = "none";
  442. el_error.style.display = "inline-block";
  443. el_error_text.style.display = "inline-block";
  444. el_error_text.innerHTML = text;
  445. }
  446. self.hideerror = function(text){
  447. el_error.style.display = "none";
  448. el_error_text.style.display = "none";
  449. }
  450. self.readyState = function(){
  451. return self.m.vxgReadyState;
  452. }
  453. self.onReadyStateChange = function(cb){
  454. self.onReadyStateCallback = cb;
  455. }
  456. self.ready = self.onReadyStateChange;
  457. self.onStateChange = function(cb){
  458. self.onStateChangeCallback = cb;
  459. }
  460. self.onBandwidthError = function(cb){
  461. self.m.handlerBandwidthError = cb;
  462. }
  463. self.onError = function(cb){
  464. self.m.handlerError = cb;
  465. }
  466. /*
  467. self.handleMessage = function(msgEvent){
  468. if(self.m.debug){
  469. console.log('Player ' + self.id + ' handleMessage: ' + msgEvent.data);
  470. }
  471. if(msgEvent == undefined || msgEvent.data == undefined){
  472. return;
  473. }
  474. if(msgEvent.data[0] != undefined && msgEvent.data[0].charAt(0) == '@'){
  475. //proto native send to app
  476. if(self.m.port != undefined){
  477. self.m.port.postMessage(msgEvent.data);
  478. }
  479. }else if(0 == msgEvent.data.indexOf("PLAYER_INITED")){
  480. self.moduleDidLoad();
  481. }else if(0 == msgEvent.data.indexOf("PLAYER_INIT_ERR")){
  482. str = "PLAYER_INIT_ERR ";
  483. err = parseInt(msgEvent.data.split(' ')[1], 10);
  484. err_type = (err >> 16)&0xffff;
  485. console.log('err_type='+err_type);
  486. switch(err_type){
  487. case 4:
  488. str += "Init audio output error ";
  489. break;
  490. case 2:
  491. str += "Init video decoder error ";
  492. break;
  493. default:
  494. str += "Init D3D error ";
  495. break;
  496. }
  497. str += ""+err.toString();
  498. vxgwsplayer.showInitFailed(id, str);
  499. }else
  500. // Player source error=60935 WSS status=6
  501. // Player listener2: Skip picture: 170, frame_duration: 41, latencyms: 0<=frames_buf:0, b: 0, p: 0
  502. if(0 == msgEvent.data.indexOf("VERSION_APP")){
  503. self.m.versionapp = msgEvent.data.split(' ')[1];
  504. if(self.m.debug)
  505. console.log('=VERSION_APP '+self.m.versionapp);
  506. self.playerDidLoad();
  507. }else if(0 == msgEvent.data.indexOf("PTS_VIDEO")){
  508. self.m.PTSVideo = msgEvent.data.split(' ')[1];
  509. //console.log('=PTS_VIDEO '+self.m.PTSVideo);
  510. }else if(0 == msgEvent.data.indexOf("PTS_AUDIO")){
  511. self.m.PTSAudio = msgEvent.data.split(' ')[1];
  512. //console.log('=PTS_AUDIO '+self.m.PTSAudio);
  513. }else if(0 == msgEvent.data.indexOf("TAKE_SNAPSHOT")){
  514. snap_status = msgEvent.data.split(' ')[1];
  515. snap_pts = msgEvent.data.split(' ')[2];
  516. console.log('TAKE_SNAPSHOT snap_status='+snap_status+' snap_pts='+snap_pts);
  517. if(0 != snap_status.indexOf("ERROR")){
  518. self.m.snapshotFile = snap_status;
  519. if(snap_pts != undefined)
  520. self.m.snapshotPTS = snap_pts;
  521. window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
  522. window.requestFileSystem(window.TEMPORARY, 1, function(fs) {
  523. fs.root.getFile(self.m.snapshotFile, {create: false}, function(fileEntry) { // /test is filename
  524. var pom = document.createElement('a');
  525. pom.setAttribute('href', fileEntry.toURL());
  526. if(self.m.snapshotPTS == -1){
  527. pom.setAttribute('download', "snapshot.jpg");
  528. }else{
  529. pom.setAttribute('download', "snapshot_"+self.m.snapshotPTS+".jpg");
  530. }
  531. pom.style.display = 'none';
  532. document.body.appendChild(pom);
  533. pom.click();
  534. document.body.removeChild(pom);
  535. }, function(e) {
  536. console.error("[vxgwsplayer] TAKE_SNAPSHOT fs.root.getFile FAILED")
  537. });
  538. }, function(e) {
  539. console.error("[vxgwsplayer] TAKE_SNAPSHOT requestFileSystem window.TEMPORARY FAILED")
  540. });
  541. }
  542. }else if(msgEvent.data == "MEDIA_ERR_URL"){
  543. self.showerror('Problem with URL');
  544. self.m.lastErrorCode = 0;
  545. if(self.m.handlerError)
  546. self.m.handlerError(self);
  547. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_NETWORK")){
  548. self.showerror('Problem with network');
  549. self.m.lastErrorCode = 1;
  550. if(self.m.handlerError)
  551. self.m.handlerError(self);
  552. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_SOURCE")){
  553. self.showerror('Problem with source');
  554. self.m.lastErrorCode = 2;
  555. if(self.m.handlerError)
  556. self.m.handlerError(self);
  557. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_CARRIER")){
  558. self.showerror('Problem with carrier');
  559. self.m.lastErrorCode = 3;
  560. if(self.m.handlerError)
  561. self.m.handlerError(self);
  562. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_AUDIO")){
  563. self.showerror('Problem with audio');
  564. self.m.lastErrorCode = 4;
  565. if(self.m.handlerError)
  566. self.m.handlerError(self);
  567. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_VIDEO")){
  568. self.showerror('Problem with video');
  569. self.m.lastErrorCode = 5;
  570. if(self.m.handlerError)
  571. self.m.handlerError(self);
  572. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_AUTHENTICATION")){
  573. self.showerror('Problem with authentification');
  574. self.m.lastErrorCode = 6;
  575. if(self.m.handlerError)
  576. self.m.handlerError(self);
  577. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_BANDWIDTH")){
  578. //self.stop();
  579. self.m.lastErrorCode = 7;
  580. if(self.m.handlerError)
  581. self.m.handlerError(self);
  582. if(self.m.handlerBandwidthError){
  583. self.m.handlerBandwidthError(self);
  584. }else{
  585. //self.showerror('Problem with bandwidth');
  586. }
  587. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_EOF")){
  588. self.showerror('End of File');
  589. self.m.lastErrorCode = 8;
  590. if(self.m.handlerError)
  591. self.m.handlerError(self);
  592. }else if(0 == msgEvent.data.indexOf("MEDIA_ERR_DECODER")){
  593. var arr = msgEvent.data.split(' ');
  594. self.m.lastErrorDecoder = (arr.length > 1) ? parseInt(arr[1],10) : 0;
  595. if(self.m.debug)
  596. console.log('=MEDIA_ERR_DECODER '+self.m.lastErrorDecoder + ' ' + (self.m.lastErrorDecoder == 0)?'Decoder resumed':'');
  597. if(self.m.lastErrorDecoder == 0){
  598. self.m.lastErrorCode = -1;
  599. //self.hideerror();
  600. }else{
  601. self.m.lastErrorCode = 9;
  602. //self.showerror('Decoder error '+self.m.lastErrorDecoder);
  603. }
  604. if(self.m.handlerError)
  605. self.m.handlerError(self);
  606. }else if(0 == msgEvent.data.indexOf("PLAYER_CONNECTING")){
  607. self.m.vxgReadyState = 1;
  608. //el_play.style.display = "none";
  609. // el_stop.style.display = "none";
  610. // self.hideerror();
  611. el_loader.style.display = "inline-block";
  612. el_takescreenshot.style.display = "none";
  613. if(self.onStateChangeCallback)
  614. self.onStateChangeCallback(self.m.vxgReadyState);
  615. }else if(0 == msgEvent.data.indexOf("PLAYER_PLAYING")){
  616. //console.log('PLAYER_PLAYING');
  617. self.m.vxgReadyState = 2;
  618. el_play.style.display = "none";
  619. el_stop.style.display = "inline-block";
  620. el_pause.style.display = "inline-block";
  621. el_takescreenshot.style.display = "inline-block";
  622. self.hideerror();
  623. el_loader.style.display = "none";
  624. if(self.onStateChangeCallback)
  625. self.onStateChangeCallback(self.m.vxgReadyState);
  626. }else if(0 == msgEvent.data.indexOf("PLAYER_STOPPING")){
  627. self.m.vxgReadyState = 3;
  628. // el_error.style.display = "none";
  629. // el_loader.style.display = "inline-block";
  630. el_play.style.display = "none";
  631. el_stop.style.display = "none";
  632. el_pause.style.display = "none";
  633. el_takescreenshot.style.display = "none";
  634. }else if(0 == msgEvent.data.indexOf("PLAYER_STOPPED")){
  635. self.m.vxgReadyState = 0;
  636. el_play.style.display = "inline-block";
  637. el_stop.style.display = "none";
  638. el_pause.style.display = "none";
  639. el_takescreenshot.style.display = "none";
  640. if(self.onStateChangeCallback)
  641. self.onStateChangeCallback(self.m.vxgReadyState);
  642. }else if(0 == msgEvent.data.indexOf("PLAYER_PAUSED")){
  643. //console.log('PLAYER_PAUSED');
  644. self.m.vxgReadyState = 4;
  645. el_play.style.display = "inline-block";
  646. el_stop.style.display = "inline-block";
  647. el_pause.style.display = "none";
  648. // el_takescreenshot.style.display = "none";
  649. if(self.onStateChangeCallback)
  650. self.onStateChangeCallback(self.m.vxgReadyState);
  651. }
  652. }
  653. */
  654. self.handleError = function(){
  655. el_loader.style.display = "none";
  656. el_error.style.display = "block";
  657. console.error("ERROR");
  658. self.showerror('Unknown error');
  659. }
  660. self.handleCrash = function(){
  661. el_loader.style.display = "none";
  662. el_error.style.display = "block";
  663. self.showerror('Crashed');
  664. }
  665. self.restartTimeout = function(){
  666. if(self.m.autohide <= 0){
  667. self.set_controls_opacity("0");
  668. return;
  669. }
  670. self.set_controls_opacity("0.7");
  671. clearTimeout(self.timeout);
  672. self.timeout = setTimeout(function(){
  673. self.set_controls_opacity("0");
  674. },self.m.autohide);
  675. };
  676. self.player.addEventListener('mousemove', function(){
  677. self.restartTimeout();
  678. }, true);
  679. self.restartTimeout();
  680. /*
  681. //self.module.addEventListener('load', self.moduleDidLoad, true);
  682. self.module.addEventListener('message', self.handleMessage, true);
  683. self.module.addEventListener('error', self.handleError, true);
  684. self.module.addEventListener('crash', self.handleCrash, true);
  685. */
  686. if (typeof window.attachListeners !== 'undefined') {
  687. window.attachListeners();
  688. }
  689. self.error = function(){
  690. return self.m.lastErrorCode;
  691. }
  692. self.errorDecoder = function(){
  693. return self.m.lastErrorDecoder;
  694. }
  695. self.controls = function(val){
  696. if(val == undefined){
  697. return self.m.controls;
  698. }else{
  699. if(val == true){
  700. self.set_controls_display("");
  701. self.m.controls = true;
  702. }else if(val == false){
  703. self.set_controls_display("none");
  704. self.m.controls = false;
  705. }
  706. }
  707. }
  708. self.debug = function(val){
  709. if(val == undefined){
  710. return self.m.debug;
  711. }else{
  712. self.m.debug = val;
  713. }
  714. }
  715. // Truen
  716. var stinit = 0;
  717. var svt = 0;
  718. var sdt = 0;
  719. self.play = function(){
  720. self.hideerror();
  721. self.m.vxgReadyState = 1;
  722. if (self.pipeline === undefined || self.pipeline == null) {
  723. var isCreated = self.createPipeline();
  724. if (isCreated != true) {
  725. el_loader.style.display = "none";
  726. return;
  727. }
  728. }
  729. self.pipeline.ready.then(function(){
  730. firstPackage = null;
  731. self.pipeline.rtsp.play();
  732. //self.pipeline.play();
  733. //record-on-start 300s
  734. //self.startRecord(300*1000);
  735. el_stop.style.display = "inline-block";
  736. el_pause.style.display = "inline-block";
  737. el_takescreenshot.style.display = "inline-block";
  738. el_loader.style.display = "none";
  739. if(self.onStateChangeCallback){
  740. self.onStateChangeCallback(self.m.vxgReadyState);
  741. }
  742. });
  743. if(self.m.debug)
  744. console.log( 'self.play self.m.url='+self.m.url + ' self.m.is_opened='+self.m.is_opened);
  745. if(!self.m.is_opened){
  746. self.m.is_opened = true;
  747. /*
  748. self.module.command('open', self.m.url);
  749. */
  750. }
  751. el_play.style.display = "none";
  752. if(self.m.vxgReadyState != 4) {//not paused=>play, show progress
  753. el_loader.style.display = "inline-block";
  754. }
  755. /*
  756. self.module.command('play', '0');
  757. */
  758. self.applyVolume();
  759. stinit = 0;
  760. svt = 0;
  761. sdt = 0;
  762. self.wdwork = setTimeout(function(){
  763. self.updateStreamInfo();
  764. }, 1000);
  765. };
  766. self.restart = function (reason) {
  767. console.log(reason);
  768. self.wdtries = 0;
  769. self.wd = null;
  770. clearTimeout(self.wdwork);
  771. self.wdwork = null;
  772. self.stop();
  773. self.play();
  774. }
  775. self.updateStreamInfo = function() {
  776. if (self.pipeline) {
  777. var curtime = self.pipeline.currentTime;
  778. if(self.m.debug){
  779. console.log("curtime:" + curtime + "; wd:" + self.wd);
  780. }
  781. if (stinit == 0) {
  782. svt = curtime;
  783. sdt = Date.now();
  784. stinit = 1;
  785. }
  786. var stdiff = ((Date.now() - sdt) / 1000) - (curtime - svt);
  787. if (stdiff >= 0.5) {
  788. //console.warn('update currenttime! id : ' + self.id + ', dif : ' + stdiff);
  789. //el_video.currentTime = Date.now();
  790. }
  791. if (self.m.watchdog <= 0 ) {
  792. console.log('Watchdog disabled by user');
  793. return;
  794. }
  795. if (self.video.paused && !self.m.playAfterBufferFill) {
  796. console.log('Video paused. Skip watchdog');
  797. var now = Date.now();
  798. //console.log("Now: " + now + ", lastRecvTime: " + self.m.lastRecvTime);
  799. if ((now - self.m.lastRecvTime) > 5 * 1000) {
  800. self.m.lastRecvTime = now;
  801. self.restart('restart by recvTime');
  802. return;
  803. }
  804. self.wdtries = 0;
  805. self.wd = curtime;
  806. self.wdwork = setTimeout(function(){
  807. self.updateStreamInfo();
  808. }, 1000);
  809. return;
  810. }
  811. if ((self.wd == null) || /*(self.video.paused) || */((curtime - self.wd >= 0.0) && (self.wdtries < self.m.watchdog) ) ){
  812. if ((curtime - self.wd > 0.2)/* || (self.video.paused)*/ ){
  813. self.wdtries = 0;
  814. } else {
  815. self.wdtries += 1;
  816. }
  817. self.wd = curtime;
  818. self.wdwork = setTimeout(function(){
  819. self.updateStreamInfo();
  820. }, 1000);
  821. } else {
  822. self.restart('restart by wd');
  823. }
  824. }
  825. }
  826. self.stop = function(){
  827. /*
  828. self.module.command('stop', '0');
  829. */
  830. pps = '';
  831. sps = '';
  832. if (self.wdwork) {
  833. clearTimeout(self.wdwork);
  834. self.wdwork = null;
  835. }
  836. self.wdtries = 0;
  837. self.wd = null;
  838. if (dataCatcherWdId) {
  839. clearTimeout(dataCatcherWdId);
  840. dataCatcherWdId = null;
  841. }
  842. dataCatcherWdCnt = 0;
  843. if (self.pipeline !== undefined && self.pipeline != null) {
  844. self.pipeline.pause();
  845. self.pipeline.close();
  846. self.pipeline = null;
  847. }
  848. if (self.audBuffer) {
  849. self.audBuffer.clear();
  850. //self.audBuffer = null;
  851. }
  852. self.m.vxgReadyState = 0;
  853. el_play.style.display = "inline-block";
  854. el_stop.style.display = "none";
  855. el_pause.style.display = "none";
  856. el_takescreenshot.style.display = "none";
  857. if(self.onStateChangeCallback){
  858. self.onStateChangeCallback(self.m.vxgReadyState);
  859. }
  860. el_loader.style.display = "none";
  861. };
  862. self.pause = function(){
  863. //console.log("pause");
  864. /*
  865. self.module.command('pause', '0');
  866. */
  867. self.pipeline.pause();
  868. if (self.audBuffer) {
  869. self.audBuffer.clear();
  870. }
  871. self.m.vxgReadyState = 4;
  872. el_play.style.display = "inline-block";
  873. el_stop.style.display = "inline-block";
  874. el_pause.style.display = "none";
  875. // el_takescreenshot.style.display = "none";
  876. if(self.onStateChangeCallback) {
  877. self.onStateChangeCallback(self.m.vxgReadyState);
  878. }
  879. el_loader.style.display = "none";
  880. };
  881. self.autohide = function(val){
  882. if(val){
  883. self.m.autohide = val*1000;
  884. }else{
  885. return self.m.autohide/1000;
  886. }
  887. }
  888. self.autoreconnect = function(val){
  889. if(val == undefined){
  890. return self.m.autoreconnect;
  891. }else{
  892. self.m.autoreconnect = parseInt(val,10);
  893. /*
  894. self.module.command('setautoreconnect', self.m.autoreconnect.toString());
  895. */
  896. }
  897. };
  898. self.latency = function(val){
  899. if(val && val >= 0){
  900. self.m.latency = parseInt(val,10);
  901. /*
  902. self.module.command('setlatency', val.toString());
  903. */
  904. }else{
  905. return self.m.latency;
  906. }
  907. };
  908. self.connection_timeout = function(val){
  909. if(val){
  910. self.m.connection_timeout = parseInt(val,10);
  911. /*
  912. self.module.command('setconnection_timeout', val.toString());
  913. */
  914. }else{
  915. return self.m.connection_timeout;
  916. }
  917. };
  918. self.connection_udp = function(val){
  919. if(val){
  920. self.m.connection_udp = parseInt(val,10);
  921. /*
  922. self.module.command('setconnection_udp', val.toString());
  923. */
  924. }else{
  925. return self.m.connection_udp;
  926. }
  927. };
  928. /*
  929. self.aspectRatio = function(val){
  930. if(val == undefined){
  931. return self.m.aspectRatio?true:false;
  932. }else{
  933. self.m.aspectRatio = (val)?self.m.aspectRatioMode:0;
  934. self.module.command('setaspectratio', self.m.aspectRatio.toString());
  935. }
  936. }
  937. */
  938. self.aspectRatioMode = function(val){
  939. if(val == undefined){
  940. return self.m.aspectRatioMode;
  941. }else{
  942. self.m.aspectRatioMode = (val > 0)?val:self.m.aspectRatioMode;
  943. self.m.aspectRatio = val;
  944. if (val == 0) {
  945. self.video.classList.remove('fill');
  946. self.video.classList.remove('cover');
  947. self.video.classList.add('contain');
  948. } else if (val == 1) {
  949. self.video.classList.remove('fill');
  950. self.video.classList.add('cover');
  951. self.video.classList.remove('contain');
  952. } else if (val == 2) {
  953. self.video.classList.add('fill');
  954. self.video.classList.remove('cover');
  955. self.video.classList.remove('contain');
  956. }
  957. }
  958. }
  959. self.aspectRatioMode(self.m.aspectRatio);
  960. self.avsync = function(val){
  961. if(val == undefined){
  962. return self.m.avsync;
  963. }else{
  964. self.m.avsync = val;
  965. /*
  966. self.module.command('setavsync', self.m.avsync ? '1':'0');
  967. */
  968. }
  969. }
  970. self.isPlaying = function(){
  971. return (self.m.vxgReadyState == 2);
  972. }
  973. self.versionPLG = function(){
  974. return window.vxgwsplayer.version;
  975. }
  976. self.versionAPP = function(){
  977. return self.m.versionapp;
  978. }
  979. self.size = function(width, height){
  980. if(width && height){
  981. if(Number.isInteger(width) && Number.isInteger(height)){
  982. var w = parseInt(width,10);
  983. var h = parseInt(height,10);
  984. self.playerWidth = self.playerWidth != w ? w : self.playerWidth;
  985. self.playerHeight = self.playerHeight != h ? h : self.playerHeight;
  986. self.player.style.width = width + 'px';
  987. self.player.style.height = height + 'px';
  988. }else{
  989. self.player.style.width = width;
  990. self.player.style.height = height;
  991. }
  992. }else{
  993. return { width: self.playerWidth, height: self.playerHeight };
  994. }
  995. };
  996. self.changedFullscreen = function(){
  997. console.log('changedFullscreen');
  998. if (document.webkitIsFullScreen){
  999. self.size('100%', '100%');
  1000. console.log('changedFullscreen -> fullscreen');
  1001. }else{
  1002. self.size(self.playerWidth + 'px', self.playerHeight + 'px');
  1003. console.log('changedFullscreen -> NOT fullscreen');
  1004. }
  1005. };
  1006. if (document.addEventListener){
  1007. document.addEventListener('webkitfullscreenchange', self.changedFullscreen, false);
  1008. document.addEventListener('mozfullscreenchange', self.changedFullscreen, false);
  1009. document.addEventListener('fullscreenchange', self.changedFullscreen, false);
  1010. document.addEventListener('MSFullscreenChange', self.changedFullscreen, false);
  1011. }
  1012. self.fullscreen = function(){
  1013. console.log("fullscreen: clicked");
  1014. if(document.webkitIsFullScreen == true){
  1015. document.webkitCancelFullScreen();
  1016. }else{
  1017. if(self.player.requestFullscreen) {
  1018. self.player.requestFullscreen();
  1019. } else if(self.player.webkitRequestFullscreen) {
  1020. self.player.webkitRequestFullscreen();
  1021. } else if(self.player.mozRequestFullscreen) {
  1022. self.player.mozRequestFullScreen();
  1023. }
  1024. }
  1025. };
  1026. self.takescreenshot = function(){
  1027. var stub = el_snap_stub;
  1028. var videotag = el_video;
  1029. if (videotag != null ) {
  1030. var width = videotag.videoWidth ;
  1031. var height = videotag.videoHeight;
  1032. if ((width > 0) && (height > 0)) {
  1033. stub.setAttribute('width', width);
  1034. stub.setAttribute('height', height);
  1035. context = stub.getContext('2d');
  1036. if (context != null) {
  1037. context.fillRect(0, 0, width, height);
  1038. context.drawImage(videotag, 0, 0, width, height);
  1039. var downloadLink = document.createElement('a');
  1040. // jpg
  1041. downloadLink.setAttribute('download', 'snapshot.jpg');
  1042. stub.toBlob(function(blob) {
  1043. var url = URL.createObjectURL(blob);
  1044. downloadLink.setAttribute('href', url);
  1045. downloadLink.click();
  1046. }, 'image/jpeg', 1.0);
  1047. /* png
  1048. downloadLink.setAttribute('download', 'snapshot.png');
  1049. stub.toBlob(function(blob) {
  1050. var url = URL.createObjectURL(blob);
  1051. downloadLink.setAttribute('href', url);
  1052. downloadLink.click();
  1053. });
  1054. */
  1055. }
  1056. }
  1057. }
  1058. el_screenshot_loading.style.display = "block";
  1059. setTimeout(function(){
  1060. el_screenshot_loading.style.display = "";
  1061. },3000);
  1062. };
  1063. self.getScreenshotPTS = function(){
  1064. return self.m.snapshotPTS;
  1065. };
  1066. self.getPTSVideo = function(){
  1067. return self.m.PTSVideo;
  1068. };
  1069. self.getPTSAudio = function(){
  1070. return self.m.PTSAudio;
  1071. };
  1072. var audioCtx = null;
  1073. var audioGain = null;
  1074. var audioFlt = null;
  1075. var audIsRun = false;
  1076. var audBuffer = null;
  1077. self.initAudioCtx = function() {
  1078. if (self.audioCtx != null || self.audioCtx !== undefined) {
  1079. return;
  1080. }
  1081. try {
  1082. window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext;
  1083. self.audioCtx = new AudioContext();
  1084. self.audioCtx.onstatechange = function() {
  1085. if (self.audioCtx !== null && self.audioCtx !== undefined) {
  1086. if (self.audioCtx.state === "running") {
  1087. console.log("<binary> audio context running");
  1088. self.audIsRun = true;
  1089. } else if (audioContext.state === "closed") {
  1090. console.log("<binary> audio context close");
  1091. self.audioCtx = null;
  1092. self.audIsRun = false;
  1093. }
  1094. }
  1095. }
  1096. if (self.audioCtx !== undefined && self.audioCtx !== null) {
  1097. self.audioGain = self.audioCtx.createGain();
  1098. self.audBuffer = new audioBufferPCM(self.audioCtx, self.audioGain, 8000, 8/*48*/);
  1099. self.audioGain.connect(self.audioCtx.destination)
  1100. }
  1101. return true;
  1102. } catch (err) {
  1103. console.warn("Web Audio API is not supported in this web browser! : ", err);
  1104. }
  1105. }
  1106. self.audioPlayBuffer = function( data ) {
  1107. if (!self.audIsRun) {
  1108. return;
  1109. }
  1110. //test sinus for noise camera
  1111. //for (var i = 0; i < data.length; ++i) {
  1112. // data[i] = (Math.sin( i ) + 1.0) * 256;
  1113. //}
  1114. var data_js = new Float32Array(data.length);
  1115. for (var i = 0; i < data.length; i++) {
  1116. data_js[i] = data[i] / Math.pow(2, 15)
  1117. }
  1118. if(self.isMute()) {
  1119. self.audioGain.gain.value = 0;
  1120. } else {
  1121. self.audioGain.gain.value = self.m.volume;
  1122. }
  1123. if (self.audBuffer != null && self.audBuffer !== undefined) {
  1124. self.audBuffer.addBuffer( data_js);
  1125. }
  1126. delete data_js;
  1127. data_js = null;
  1128. }
  1129. self.recordedData264 = null;
  1130. self.recordedData711 = null;
  1131. var recData264Len = 0;
  1132. var recData711Len = 0;
  1133. var isRecording = false;
  1134. var isRecStarted = false;
  1135. var isRecStopping = false;
  1136. var firstPackage = null;
  1137. var record_wd = null;
  1138. var record_try = 0;
  1139. var prevRecLen = 0;
  1140. self.rech264maxsize = self.options.clipH264maxsize || Number(self.player.getAttribute('clipH264maxsize')) || 768*1024*1024; //~10min for 10Mbit
  1141. self.recg711maxsize = self.options.clipG711maxsize || Number(self.player.getAttribute('clipG711maxsize')) || 64*1024*1024;
  1142. self.defaultClipName = self.options.clipname || self.player.getAttribute('clipname') || 'clip';
  1143. var pps = '';
  1144. var sps = '';
  1145. // Truen
  1146. var dataCatcherWdId = undefined;
  1147. var dataCatcherWdCnt = 0;
  1148. self.m.debug = self.options.debug || self.player.hasAttribute('debug') || false;
  1149. function arraysAreEqual(a, b) {
  1150. var ret_val =
  1151. Array.isArray(a) &&
  1152. Array.isArray(b) &&
  1153. a.length === b.length &&
  1154. a.every((val, index) => val === b[index]);
  1155. return ret_val;
  1156. }
  1157. self.debug = function(){
  1158. //pps = '1'; //test possible pps-changing
  1159. }
  1160. self.createPipeline = function(){
  1161. el_loader.style.display = "inline-block";
  1162. firstPackage = null;
  1163. if ((self.m.wsurl !== undefined && self.m.wsurl.length > 0)
  1164. && (self.m.rtspurl !== undefined && self.m.rtspurl.length > 0)){
  1165. self.m.is_opened = true;
  1166. let Pipeline = pipelines.Html5VideoPipeline;
  1167. let mediaElement = el_video;
  1168. pps = '';
  1169. sps = '';
  1170. var authopts = {}
  1171. if (self.m.user && self.m.password) {
  1172. authopts = {
  1173. username: self.m.user,
  1174. password: self.m.password
  1175. }
  1176. }
  1177. self.pipeline = new Pipeline({
  1178. ws: {
  1179. uri: self.m.wsurl,
  1180. },
  1181. rtsp: {
  1182. uri: self.m.rtspurl,
  1183. },
  1184. auth: authopts,
  1185. mediaElement,
  1186. });
  1187. self.pipeline.onSourceOpen = function(mse, tracks) {
  1188. //mse.duration = 10.0;
  1189. //mse.sourceBuffers[0].timestampOffset = -3.0;
  1190. }
  1191. var dataCatcherRTP = new components.dataCatcherDepay(0);//ULAW
  1192. dataCatcherRTP.onDataCallback = function( msg) {
  1193. if(self.m.debug){
  1194. console.log('Playback' + ((isRecording)?('+Recording'):('')) +': data(ulaw) catcher: len ' + msg.data.length + ' type:' + msg.type + ' rawdata len ' + msg.rawdata.length );
  1195. }
  1196. if (isRecStarted == true) {
  1197. if (recData711Len + msg.data.length < self.recg711maxsize) {
  1198. var data = msg.data;
  1199. self.recordedData711.set( data, recData711Len);
  1200. recData711Len += data.length;
  1201. delete msg.data;
  1202. delete data; data = null;
  1203. }
  1204. }
  1205. msg = null;
  1206. }
  1207. self.pipeline.insertAfter(self.pipeline.firstComponent.next, dataCatcherRTP);
  1208. var lastupdatetime = Date.now();
  1209. var forceupdatecheckcount = 0;
  1210. var forceupdatecountthreshold = 10;
  1211. var forceupdatetimethreshold = 100; //ms
  1212. self.pipeline.onDataCallback = function(sourceBuffer, msg) { // mp4 with H264 or H264+AAC
  1213. self.m.lastRecvTime = Date.now();
  1214. var b = sourceBuffer.buffered;
  1215. if (b.length == 0) {
  1216. //console.log('no buffer');
  1217. } else if (false) {
  1218. if ((b.end(0)*1000 - self.m.latency > 0) && (self.video.paused ) && (self.m.vxgReadyState != 4)) {
  1219. self.video.paused = false;
  1220. self.pipeline.play();
  1221. }
  1222. else {
  1223. if ((Date.now() - lastupdatetime >= 100) || forceupdatecheckcount > 0) {
  1224. if ((self.video.currentTime + (self.m.latency + forceupdatetimethreshold)/1000) < b.end(0)) {
  1225. forceupdatecheckcount++;
  1226. if (forceupdatecheckcount > forceupdatecountthreshold) {
  1227. console.log('update time');
  1228. self.video.currentTime = b.end(0) - self.m.latency/1000;
  1229. forceupdatecheckcount = 0;
  1230. }
  1231. }
  1232. else {
  1233. if (forceupdatecheckcount > 0) {
  1234. forceupdatecheckcount = 0;
  1235. }
  1236. }
  1237. lastupdatetime = Date.now();
  1238. }
  1239. }
  1240. //console.log('buffer:' + b.start(0) + '~' + b.end(0));
  1241. }
  1242. else {
  1243. if (self.m.playAfterBufferFill) {
  1244. /*
  1245. for (var i = 0; i < b.length; i++) {
  1246. console.log('buffer[' + i + ']: ' + b.start(i) + ', ' + b.end(i));
  1247. }
  1248. */
  1249. if (b.end(b.length - 1) * 1000 - self.m.latency >= 0) {
  1250. self.m.playAfterBufferFill = false;
  1251. console.log("Buffer filled. Start pipeline.");
  1252. self.pipeline.play();
  1253. }
  1254. }
  1255. }
  1256. if(self.m.debug){
  1257. console.log( 'Playback' + ((isRecording)?('+Recording'):('')) +': w.data length:' + msg.data.length );
  1258. }
  1259. if (firstPackage == null) {
  1260. firstPackage = msg.data;
  1261. }
  1262. if (isRecording == true) {
  1263. if (msg.idrPicture == true) {
  1264. isRecStarted = true;
  1265. }
  1266. if (isRecStarted) {
  1267. if( recData264Len + msg.data.length < self.rech264maxsize) {
  1268. var data = msg.data;
  1269. self.recordedData264.set( data, recData264Len);
  1270. recData264Len += data.length;
  1271. delete msg.data;
  1272. delete data; data = null;
  1273. }
  1274. else { // Truen
  1275. console.warn('len(' + recData264Len + ') + new(' + msg.data.length + ') >= max(' + self.rech264maxsize + ')');
  1276. clearTimeout(record_wd);
  1277. self.stopRecord();
  1278. record_try = 0;
  1279. }
  1280. }
  1281. }
  1282. msg = null;
  1283. }
  1284. // Truen
  1285. function dataCatcherWd() {
  1286. dataCatcherWdCnt++;
  1287. if (dataCatcherWdCnt > 4) {
  1288. setTimeout(function() {
  1289. self.restart('restart by dataCatcherWd');
  1290. },10);
  1291. }
  1292. else {
  1293. dataCatcherWdId = setTimeout(function() {
  1294. dataCatcherWd();
  1295. }, 1000);
  1296. }
  1297. }
  1298. /* raw pcm (after g711 decode) data callback*/
  1299. var dataCatcherPCM = new components.g711toPCM(); //96-h264, 97-aac, 98-metadata, 0-g711?
  1300. dataCatcherPCM.onDataCallback = function( msg) {
  1301. self.initAudioCtx();
  1302. self.audioPlayBuffer(msg.data);
  1303. delete msg.data;
  1304. msg = null;
  1305. // Truen
  1306. if (dataCatcherWdId != undefined) {
  1307. clearTimeout(dataCatcherWdId);
  1308. }
  1309. dataCatcherWdCnt = 0;
  1310. dataCatcherWdId = setTimeout(function() {
  1311. dataCatcherWd();
  1312. },1000);
  1313. }
  1314. self.pipeline.insertAfter(self.pipeline.firstComponent.next.next, dataCatcherPCM);
  1315. /* catch h264 sps/pps data callback*/
  1316. var dataCatcherH264 = new components.dataCatcherDepay(96);
  1317. dataCatcherH264.onDataCallback = function( msg) {
  1318. /* Truen
  1319. if (msg.data[0] == 0x67) {
  1320. //console.log('data[H264] : SPS');
  1321. if (sps == '') {
  1322. sps = Array.from(msg.data);
  1323. } else if ( !arraysAreEqual (sps, Array.from(msg.data)) ) {
  1324. setTimeout(function(){
  1325. self.restart('restart by sps-changed');
  1326. },10);
  1327. }
  1328. } else */if (msg.data[0] == 0x68) {
  1329. //console.log('data[H264] : PPS');
  1330. if (pps == '') {
  1331. pps = Array.from(msg.data);
  1332. } else if ( !arraysAreEqual ( pps, Array.from(msg.data)) ) {
  1333. setTimeout(function(){
  1334. self.restart('restart by pps-changed');
  1335. },10);
  1336. }
  1337. }
  1338. // Truen
  1339. if (dataCatcherWdId != undefined) {
  1340. clearTimeout(dataCatcherWdId);
  1341. }
  1342. dataCatcherWdCnt = 0;
  1343. dataCatcherWdId = setTimeout(function() {
  1344. dataCatcherWd();
  1345. },1000);
  1346. }
  1347. self.pipeline.insertAfter(self.pipeline.firstComponent.next, dataCatcherH264);
  1348. /*
  1349. // aac - data callback
  1350. var dataCatcherAAC = new components.dataCatcherDepay(97); //96-h264, 97-aac, 98-metadata, 0-g711?
  1351. dataCatcherAAC.onDataCallback = function( msg) {
  1352. console.log('data(aac) catcher: ' + msg.data.length + ' type:' + msg.type );
  1353. }
  1354. self.pipeline.insertAfter(self.pipeline.firstComponent.next, dataCatcherAAC);
  1355. */
  1356. self.pipeline.onSdp = function(sdp) {
  1357. console.log('onSdp');
  1358. var str = sdp.rawdata.toString();
  1359. console.log(str);
  1360. console.log(sdp);
  1361. }
  1362. self.pipeline.onPlay = function(range) {
  1363. console.log('onPlay: latency: ' + self.m.latency);
  1364. self.m.playAfterBufferFill = true;
  1365. //self.pipeline.play();
  1366. }
  1367. return true;
  1368. }
  1369. return false;
  1370. }
  1371. self.setSource = function (cameraIP, user, pwd, wsport=80, rtspport=554 ) {
  1372. if (cameraIP !== undefined) {
  1373. self.m.wsurl = 'ws://'+cameraIP+':'+wsport+'/rtsp_over_websocket';
  1374. self.m.rtspurl = 'rtsp://'+cameraIP+':'+rtspport+'/video1_audio1';
  1375. self.m.user = user;
  1376. self.m.password = pwd;
  1377. }
  1378. var isCreated = self.createPipeline();
  1379. if (isCreated) {
  1380. self.wdtries = 0;
  1381. self.play();
  1382. } else {
  1383. self.m.is_opened = false;
  1384. self.stop();
  1385. return undefined;
  1386. }
  1387. /*
  1388. if(url != undefined){
  1389. self.m.url = url;
  1390. console.log('Player ' + self.id+' src='+self.m.url+' autostart='+self.m.autostart+' is_opened='+self.m.is_opened);
  1391. if(self.m.url.length > 0 && self.m.autostart){
  1392. self.m.is_opened = true;
  1393. self.module.command('open', url);
  1394. }else{
  1395. self.m.is_opened = false;
  1396. //el_play.style.display = "inline-block";
  1397. //el_stop.style.display = "none";
  1398. //el_loader.style.display = 'none';
  1399. self.stop();
  1400. }
  1401. } else {
  1402. return self.m.url;
  1403. }
  1404. */
  1405. }
  1406. self.dispose = function(){
  1407. self.player.innerHTML = "";
  1408. delete window.vxgwsplayer.players[self.id];
  1409. }
  1410. self.custom_digital_zoom = function(newval){
  1411. if(newval != undefined){
  1412. if(self.m.isCustomDigitalZoom == false && newval == true){
  1413. self.m.isCustomDigitalZoom = true;
  1414. self.setCustomDigitalZoom(100,0,0); // reset
  1415. self.set_controls_display("");
  1416. }else if(self.m.isCustomDigitalZoom == true && newval == false){
  1417. self.m.isCustomDigitalZoom = false;
  1418. self.set_controls_display("");
  1419. self.setNewZoom(10);
  1420. }
  1421. }else{
  1422. return self.m.isCustomDigitalZoom;
  1423. }
  1424. }
  1425. self.setCustomDigitalZoom = function(ratio, x, y){
  1426. if (ratio !== parseInt(ratio, 10) || x !== parseInt(x, 10) || y !== parseInt(y, 10)){
  1427. throw "[vxgwsplayer] setDigitalZoom / Some values is not integer";
  1428. }
  1429. if(ratio < 100 || ratio > 1000/*500*/){ // Truen
  1430. throw "[vxgwsplayer] setDigitalZoom / Parameter Ratio must be 100..500";
  1431. }
  1432. if(self.m.isCustomDigitalZoom != true){
  1433. throw "[vxgwsplayer] setDigitalZoom / Please enable custom digital zoom";
  1434. }
  1435. self.video.style.transform = "scale(" + (ratio/100) + ")";
  1436. el_controls_zoom_position.style.display = "none";
  1437. var s = self.size();
  1438. var newx = x - s.width/2;
  1439. var newy = y - s.height/2;
  1440. var neww = s.width*(100/ratio);
  1441. var newh = s.height*(100/ratio);
  1442. var left = Math.floor(-100*(newx + neww/2)/neww);
  1443. var top = Math.floor(-100*(newy + newh/2)/newh);
  1444. self.video.style.left = left + '%';
  1445. self.video.style.top = top + '%';
  1446. }
  1447. self.setNewZoom = function(v){
  1448. if(v >= 30){ v = 30; }
  1449. if(v <= 10){ v = 10; }
  1450. if(self.currentZoom != v){
  1451. self.currentZoom = v;
  1452. self.video.style.transform = "scale(" + (ratio/100) + ")";
  1453. el_zoomPositionCursor.style.transform = "scale(" + (10/self.currentZoom) + ")";
  1454. el_zoomProgress.className = el_zoomProgress.className.replace(/zoom\d+x/g,'zoom' + Math.ceil(self.currentZoom) + 'x');
  1455. el_controls_zoom_position.style.display = self.currentZoom == 10 ? "none" : "";
  1456. self.video.style.left = left + '%';
  1457. self.video.style.top = top + '%';
  1458. el_zoomPositionCursor.style.left = '';
  1459. el_zoomPositionCursor.style.top = '';
  1460. }
  1461. }
  1462. self.zoomUp = function(){
  1463. self.setNewZoom(self.currentZoom + 5)
  1464. }
  1465. self.zoomDown = function(){
  1466. self.setNewZoom(self.currentZoom - 5);
  1467. }
  1468. self.zoomProgressDownBool = false;
  1469. self.zoomProgressDown = function(e){
  1470. self.zoomProgressDownBool = true;
  1471. }
  1472. self.zoomProgressMove = function(e){
  1473. if(self.zoomProgressDownBool == true){
  1474. var y = e.pageY - vxgwsplayer.getAbsolutePosition(e.currentTarget).y;
  1475. var height = el_zoomProgress.offsetHeight;
  1476. var steps = height/5;
  1477. y = 10*(Math.floor((height-y)/steps)/2 + 1);
  1478. self.setNewZoom(y);
  1479. }
  1480. }
  1481. self.zoomProgressLeave = function(e){
  1482. self.zoomProgressDownBool = false;
  1483. }
  1484. self.zoomProgressUp = function(e){
  1485. if(self.zoomProgressDownBool == true){
  1486. var y = e.pageY - vxgwsplayer.getAbsolutePosition(e.currentTarget).y;
  1487. var height = el_zoomProgress.offsetHeight;
  1488. var steps = height/5;
  1489. y = 10*(Math.floor((height-y)/steps)/2 + 1);
  1490. self.setNewZoom(y);
  1491. }
  1492. self.zoomProgressDownBool = false;
  1493. }
  1494. self.zoomCursorDownBool = false;
  1495. self.zoomCursorX = 0;
  1496. self.zoomCursorY = 0;
  1497. self.zoomCursorWidth = 160;
  1498. self.zoomCursorHeight = 120;
  1499. self.zoomControlsWidth = 0;
  1500. self.zoomControlsHeight = 0;
  1501. self.zoomCursorDown = function(e){
  1502. self.zoomCursorX = e.pageX;
  1503. self.zoomCursorY = e.pageY;
  1504. self.zoomCursorWidth = el_zoomPositionCursor.offsetWidth;
  1505. self.zoomCursorHeight = el_zoomPositionCursor.offsetHeight;
  1506. self.zoomControlsWidth = el_controls_zoom_position.offsetWidth;
  1507. self.zoomControlsHeight = el_controls_zoom_position.offsetHeight;
  1508. self.zoomCursorDownBool = true;
  1509. }
  1510. self.zoomCursorUp = function(e){
  1511. console.log("zoomCursorUp");
  1512. self.zoomCursorDownBool = false;
  1513. }
  1514. self.zoomCursorMove = function(e){
  1515. if(self.zoomCursorDownBool == true){
  1516. var diffX = self.zoomCursorX - e.pageX;
  1517. var diffY = self.zoomCursorY - e.pageY;
  1518. self.zoomCursorX = e.pageX;
  1519. self.zoomCursorY = e.pageY;
  1520. var newx = el_zoomPositionCursor.offsetLeft - diffX;
  1521. var newy = el_zoomPositionCursor.offsetTop - diffY;
  1522. var d2x = (self.zoomControlsWidth - self.zoomCursorWidth*(10/self.currentZoom));
  1523. var d2y = (self.zoomControlsHeight - self.zoomCursorHeight*(10/self.currentZoom));
  1524. var minX = -1*d2x/2;
  1525. var maxX = d2x/2;
  1526. var minY = -1*d2y/2;
  1527. var maxY = d2y/2;
  1528. if(newx < minX) newx = minX;
  1529. if(newy < minY) newy = minY;
  1530. if(newx >= maxX) newx = maxX;
  1531. if(newy >= maxY) newy = maxY;
  1532. el_zoomPositionCursor.style.left = newx + "px";
  1533. el_zoomPositionCursor.style.top = newy + "px";
  1534. var zoom = self.currentZoom/10 - 1;
  1535. var left = Math.floor(-100*((newx/d2x)*zoom));
  1536. var top = Math.floor(-100*((newy/d2y)*zoom));
  1537. self.video.style.left = left + '%';
  1538. self.video.style.top = top + '%';
  1539. }
  1540. }
  1541. self.setNewZoom = function(v){
  1542. if(v >= 30){ v = 30; }
  1543. if(v <= 10){ v = 10; }
  1544. if(self.currentZoom != v){
  1545. self.currentZoom = v;
  1546. self.video.style.transform = "scale(" + (self.currentZoom/10) + ")";
  1547. el_zoomPositionCursor.style.transform = "scale(" + (10/self.currentZoom) + ")";
  1548. el_zoomProgress.className = el_zoomProgress.className.replace(/zoom\d+x/g,'zoom' + Math.ceil(self.currentZoom) + 'x');
  1549. el_controls_zoom_position.style.display = self.currentZoom == 10 ? "none" : "";
  1550. self.video.style.left = '';
  1551. self.video.style.top = '';
  1552. el_zoomPositionCursor.style.left = '';
  1553. el_zoomPositionCursor.style.top = '';
  1554. }
  1555. }
  1556. self.zoomUp = function(){
  1557. self.setNewZoom(self.currentZoom + 5)
  1558. }
  1559. self.zoomDown = function(){
  1560. self.setNewZoom(self.currentZoom - 5);
  1561. }
  1562. self.zoomProgressDownBool = false;
  1563. self.zoomProgressDown = function(e){
  1564. self.zoomProgressDownBool = true;
  1565. }
  1566. self.zoomProgressMove = function(e){
  1567. if(self.zoomProgressDownBool == true){
  1568. var y = e.pageY - vxgwsplayer.getAbsolutePosition(e.currentTarget).y;
  1569. var height = el_zoomProgress.offsetHeight;
  1570. var steps = height/5;
  1571. y = 10*(Math.floor((height-y)/steps)/2 + 1);
  1572. self.setNewZoom(y);
  1573. }
  1574. }
  1575. self.zoomProgressLeave = function(e){
  1576. self.zoomProgressDownBool = false;
  1577. }
  1578. self.zoomProgressUp = function(e){
  1579. if(self.zoomProgressDownBool == true){
  1580. var y = e.pageY - vxgwsplayer.getAbsolutePosition(e.currentTarget).y;
  1581. var height = el_zoomProgress.offsetHeight;
  1582. var steps = height/5;
  1583. y = 10*(Math.floor((height-y)/steps)/2 + 1);
  1584. self.setNewZoom(y);
  1585. }
  1586. self.zoomProgressDownBool = false;
  1587. }
  1588. self.zoomCursorDownBool = false;
  1589. self.zoomCursorX = 0;
  1590. self.zoomCursorY = 0;
  1591. self.zoomCursorWidth = 160;
  1592. self.zoomCursorHeight = 120;
  1593. self.zoomControlsWidth = 0;
  1594. self.zoomControlsHeight = 0;
  1595. self.zoomCursorDown = function(e){
  1596. self.zoomCursorX = e.pageX;
  1597. self.zoomCursorY = e.pageY;
  1598. self.zoomCursorWidth = el_zoomPositionCursor.offsetWidth;
  1599. self.zoomCursorHeight = el_zoomPositionCursor.offsetHeight;
  1600. self.zoomControlsWidth = el_controls_zoom_position.offsetWidth;
  1601. self.zoomControlsHeight = el_controls_zoom_position.offsetHeight;
  1602. self.zoomCursorDownBool = true;
  1603. }
  1604. self.zoomCursorUp = function(e){
  1605. console.log("zoomCursorUp");
  1606. self.zoomCursorDownBool = false;
  1607. }
  1608. self.zoomCursorMove = function(e){
  1609. if(self.zoomCursorDownBool == true){
  1610. var diffX = self.zoomCursorX - e.pageX;
  1611. var diffY = self.zoomCursorY - e.pageY;
  1612. self.zoomCursorX = e.pageX;
  1613. self.zoomCursorY = e.pageY;
  1614. var newx = el_zoomPositionCursor.offsetLeft - diffX;
  1615. var newy = el_zoomPositionCursor.offsetTop - diffY;
  1616. var d2x = (self.zoomControlsWidth - self.zoomCursorWidth*(10/self.currentZoom));
  1617. var d2y = (self.zoomControlsHeight - self.zoomCursorHeight*(10/self.currentZoom));
  1618. var minX = -1*d2x/2;
  1619. var maxX = d2x/2;
  1620. var minY = -1*d2y/2;
  1621. var maxY = d2y/2;
  1622. if(newx < minX) newx = minX;
  1623. if(newy < minY) newy = minY;
  1624. if(newx >= maxX) newx = maxX;
  1625. if(newy >= maxY) newy = maxY;
  1626. el_zoomPositionCursor.style.left = newx + "px";
  1627. el_zoomPositionCursor.style.top = newy + "px";
  1628. var zoom = self.currentZoom/10 - 1;
  1629. var left = Math.floor(-100*((newx/d2x)*zoom));
  1630. var top = Math.floor(-100*((newy/d2y)*zoom));
  1631. self.video.style.left = left + '%';
  1632. self.video.style.top = top + '%';
  1633. }
  1634. }
  1635. var isAudioCapture = false;
  1636. var audioCapture = null;
  1637. self.startBackwardAudio = function () {
  1638. if (self.isAudioCapture) {
  1639. return;
  1640. }
  1641. if (!self.pipeline.rtsp.audioback_chnl) {
  1642. console.warn('backward channel not found in SDP');
  1643. return;
  1644. }
  1645. if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  1646. console.log('getUserMedia supported.');
  1647. navigator.mediaDevices.getUserMedia ({ audio: true })
  1648. .then(function(stream) {
  1649. var buflen = 2048;
  1650. var numchannels = 1;
  1651. var rtp_pkt;
  1652. var rtsp_hdr;
  1653. self.audioCapture = new AudioContext({ sampleRate: 8000 });
  1654. var input = self.audioCapture.createMediaStreamSource(stream);
  1655. var node = (input.context.createScriptProcessor ||
  1656. input.context.createJavaScriptNode).call(input.context,
  1657. buflen, numchannels, numchannels
  1658. );
  1659. self.isAudioCapture = true;
  1660. input.connect(node);
  1661. node.connect(input.context.destination);
  1662. node.onaudioprocess = function(e) {
  1663. if (self.isAudioCapture) {
  1664. var data = e.inputBuffer.getChannelData(0);
  1665. /*
  1666. console.log("got audio buffer: " + e.inputBuffer.length
  1667. + " for " + e.inputBuffer.duration
  1668. + " samplerate " + e.inputBuffer.sampleRate
  1669. + " data: [" + data[0] + "][" + data[1] + "][" + data[2] + "][" + data[3] + "]"
  1670. );
  1671. */
  1672. if (!rtsp_hdr) {
  1673. //console.log(self.pipeline);
  1674. //console.log(self.pipeline.rtsp);
  1675. //console.log(self.pipeline.rtsp.audioback_chnl);
  1676. // Stream data (such as RTP packets) is encapsulated by an ASCII dollar sign
  1677. // (0x24 hexadecimal), followed by one byte of channel identifier, followed by two bytes of the length of
  1678. // the encapsulated binary data.The stream data follows immediately afterwards.Each $ block contains
  1679. // only one upper layer protocol data unit, such as an RTP packet.
  1680. var len = e.inputBuffer.length + 12;
  1681. rtsp_hdr = new Uint8Array(4);
  1682. rtsp_hdr[0] = 0x24;
  1683. rtsp_hdr[1] = self.pipeline.rtsp.audioback_chnl;
  1684. rtsp_hdr[2] = (len >>> 8);
  1685. rtsp_hdr[3] = (len & 0xFF);
  1686. rtsp_hdr._isBuffer = true;
  1687. rtsp_hdr.data = rtsp_hdr;
  1688. /* RFC3550 http://www.ietf.org/rfc/rfc3550.txt
  1689. V = 2, // version. always 2 (2 bits)
  1690. P = 0, // padding. (1 bit)
  1691. X = 0, // header extension (1 bit)
  1692. CC = 0, // CSRC count (4 bits)
  1693. M = 0, // marker (1 bit)
  1694. PT = 0, // payload type. (7 bits)
  1695. SN = // sequence number. SHOULD be random (16 bits)
  1696. TS = 1, // timestamp (32 bits)
  1697. SSRC = 1; // synchronization source (32 bits)
  1698. //CSRC = 0, // contributing sources (32 bits)
  1699. //DP = 0, // header extension, 'Defined By Profile' (16 bits)
  1700. //EL = 0; // header extension length (16 bits)
  1701. */
  1702. rtp_pkt = new Uint8Array(len);
  1703. rtp_pkt[0] = 0x80;
  1704. rtp_pkt[1] = 0;//ulaw
  1705. var SN = Math.floor(1000 * Math.random());
  1706. rtp_pkt[2] = (SN >>> 8)
  1707. rtp_pkt[3] = (SN & 0xFF);
  1708. rtp_pkt[4] = 0;
  1709. rtp_pkt[5] = 0;
  1710. rtp_pkt[6] = 0;
  1711. rtp_pkt[7] = 1;
  1712. rtp_pkt[8] = 0;
  1713. rtp_pkt[9] = 0;
  1714. rtp_pkt[10] = 0;
  1715. rtp_pkt[11] = 1;
  1716. rtp_pkt._isBuffer = true;
  1717. rtp_pkt.data = rtp_pkt;
  1718. }
  1719. var seq = (rtp_pkt[2] << 8 | rtp_pkt[3]) + 1;
  1720. seq = seq.toUnsigned();
  1721. if (seq <= 65535) {
  1722. rtp_pkt[2] = (seq >>> 8);
  1723. rtp_pkt[3] = (seq & 0xFF);
  1724. }
  1725. var time = (rtp_pkt[4] << 24 | rtp_pkt[5] << 16 | rtp_pkt[6] << 8 | rtp_pkt[7]) + rtp_pkt.length;
  1726. time = time.toUnsigned();
  1727. if (time <= 4294967295) {
  1728. rtp_pkt[4] = (time >>> 24);
  1729. rtp_pkt[5] = (time >>> 16 & 0xFF);
  1730. rtp_pkt[6] = (time >>> 8 & 0xFF);
  1731. rtp_pkt[7] = (time & 0xFF);
  1732. }
  1733. self.pipeline._src.outgoing.write(rtsp_hdr);
  1734. self.pipeline._src.outgoing.write(rtp_pkt);
  1735. const BIAS = 0x84;
  1736. const CLIP = 32635;
  1737. for (var i = 0; i < e.inputBuffer.length; ++i) {
  1738. var pcm_16_sample = Math.min(1, data[i]) * 0x7FFF;
  1739. var sign = (pcm_16_sample >> 8) & 0x80;
  1740. if (sign != 0) pcm_16_sample = -pcm_16_sample;
  1741. pcm_16_sample = pcm_16_sample + BIAS;
  1742. if (pcm_16_sample > CLIP) pcm_16_sample = CLIP;
  1743. var exponent = ulawencodeTable[(pcm_16_sample >> 7) & 0xFF];
  1744. var mantissa = (pcm_16_sample >> (exponent + 3)) & 0x0F;
  1745. rtp_pkt[i+12] = ~(sign | (exponent << 4) | mantissa);
  1746. }
  1747. self.pipeline._src.outgoing.write(rtsp_hdr);
  1748. self.pipeline._src.outgoing.write(rtp_pkt);
  1749. }
  1750. }
  1751. }).catch(function(err) {
  1752. console.log('The following getUserMedia error occured: ' + err);
  1753. });
  1754. } else {
  1755. console.log('getUserMedia not supported on your browser!');
  1756. }
  1757. }
  1758. self.stopBackwardAudio = function() {
  1759. self.isAudioCapture = false;
  1760. self.audioCapture = null;
  1761. }
  1762. function wait(delayInMS) {
  1763. return new Promise(resolve => setTimeout(resolve, delayInMS));
  1764. }
  1765. function mergeTypedArrays(a, b) {
  1766. if(!a && !b) throw 'Please specify valid arguments for parameters a and b.';
  1767. if(!b || b.length === 0) return a;
  1768. if(!a || a.length === 0) return b;
  1769. if(Object.prototype.toString.call(a) !== Object.prototype.toString.call(b))
  1770. throw 'The types of the two arguments passed for parameters a and b do not match.';
  1771. var c = new a.constructor(a.length + b.length);
  1772. c.set(a);
  1773. c.set(b, a.length);
  1774. return c;
  1775. }
  1776. self.onRecord = null;
  1777. self.ffmpeg_worker = null;
  1778. self.startRecord = function( ms_length = 5000){
  1779. isRecStarted = false;
  1780. if (isRecording || isRecStopping) return;
  1781. self.ffmpeg_worker = new Worker('/vxgwsplayer/ffmpeg/ffmpeg-worker-mp4.js');
  1782. clearTimeout(record_wd);
  1783. prevRecLen = 0;
  1784. self.recordedData264 = new Uint8Array(self.rech264maxsize);
  1785. self.recordedData711 = new Uint8Array(self.recg711maxsize);
  1786. recData264Len = 0;
  1787. recData711Len = 0;
  1788. if (firstPackage != null) {
  1789. self.recordedData264.set(firstPackage, recData264Len);
  1790. recData264Len += firstPackage.length;
  1791. }
  1792. isRecording = true;
  1793. isRecStopping = false;
  1794. if (self.onRecord !== null) {
  1795. var args = {};
  1796. args.isRecording = isRecording;
  1797. args.isRecStopping = isRecStopping;
  1798. self.onRecord(args);
  1799. }
  1800. if (ms_length > 0) {
  1801. setTimeout(function(){
  1802. self.stopRecord();
  1803. }, ms_length);
  1804. }
  1805. function recordWd () {
  1806. clearTimeout(record_wd);
  1807. if (!isRecording) return;
  1808. if (!isRecStarted || recData264Len > prevRecLen) {
  1809. prevRecLen = recData264Len;
  1810. console.log('record watchdog: OK - record in process');
  1811. record_wd = setTimeout(function(){recordWd();}, 5000);
  1812. } else {
  1813. if (record_try > 3) {
  1814. console.warn('Early record save before expected time due record stream error or allocated memmory is over');
  1815. self.stopRecord();
  1816. record_try = 0;
  1817. } else {
  1818. console.log('record watchdog: may be error (recdata:'+recData264Len+'<= prevrecorded:'+prevRecLen+'<= maxsize:'+self.rech264maxsize+'): - check in process ');
  1819. record_try += 1;
  1820. record_wd = setTimeout(function(){recordWd();}, 5000);
  1821. }
  1822. }
  1823. }
  1824. record_wd = setTimeout(function(){recordWd();}, 5000);
  1825. }
  1826. self.stopRecord = async function stopRecord() {
  1827. if (isRecording == false || isRecStopping == true) {
  1828. return;
  1829. }
  1830. isRecording = false;
  1831. isRecStarted = false;
  1832. isRecStopping = true;
  1833. if (self.onRecord !== null) {
  1834. var args = {};
  1835. args.isRecording = isRecording;
  1836. args.isRecStopping = isRecStopping;
  1837. self.onRecord(args);
  1838. }
  1839. //const OUT_FILE_NAME = self.defaultClipName + '.avi';
  1840. const OUT_FILE_NAME = self.defaultClipName + '.mkv';
  1841. //const OUT_FILE_NAME = self.defaultClipName + '.mov';
  1842. var data = self.recordedData264.subarray(0, recData264Len);
  1843. var outfile;
  1844. self.ffmpeg_worker.onmessage = function(arg) {
  1845. var msg = arg.data;
  1846. switch (msg.type) {
  1847. case "stdout":
  1848. console.log("ffmpeg: stdout: " + msg.data);
  1849. break;
  1850. case "stderr":
  1851. console.log("ffmpeg: stderr: " + msg.data);
  1852. break;
  1853. case "exit":
  1854. console.log("Process exited with code " + msg.data);
  1855. break;
  1856. case 'done': {
  1857. //const blob = new Blob([msg.data.MEMFS[0].data], {type: "video/avi"});
  1858. const blob = new Blob([msg.data.MEMFS[0].data], {type: "video/mkv"});
  1859. //const blob = new Blob([msg.data.MEMFS[0].data], {type: "video/mov"});
  1860. let a = document.createElement("a");
  1861. //document.body.appendChild(a);
  1862. a.style.display = 'none';
  1863. let url = URL.createObjectURL(blob);
  1864. a.href = url;
  1865. a.download = OUT_FILE_NAME;
  1866. a.click();
  1867. window.URL.revokeObjectURL(url);
  1868. delete self.recordedData264; self.recordedData264 = null;
  1869. delete self.recordedData711; self.recordedData711 = null;
  1870. recData264Len = 0;
  1871. recData711Len = 0;
  1872. isRecStopping = false;
  1873. if (self.onRecord !== null) {
  1874. var args = {};
  1875. args.isRecording = isRecording;
  1876. args.isRecStopping = isRecStopping;
  1877. self.onRecord(args);
  1878. }
  1879. setTimeout(function () {
  1880. if (self.ffmpeg_worker != null) {
  1881. self.ffmpeg_worker.terminate();
  1882. self.ffmpeg_worker = null;
  1883. }
  1884. }, 0);
  1885. } break;
  1886. }
  1887. };
  1888. if(self.recordedData711.length>0){
  1889. var data711 = self.recordedData711.subarray(0, recData711Len);
  1890. self.ffmpeg_worker.postMessage({
  1891. type: 'run',
  1892. TOTAL_MEMORY: 581510912, // 268435456,
  1893. // arguments: ['-formats']
  1894. //avi
  1895. //arguments: ['-r','30', '-i', 'input.mp4', '-f', 'mulaw', '-ar', '8000', '-ac', '1', '-i', 'input.ulaw', '-vcodec', 'copy', '-acodec', 'copy', OUT_FILE_NAME],
  1896. //mkv
  1897. arguments: ['-i', 'input.mp4', '-f', 'mulaw', '-ar', '8000', '-ac', '1', '-i', 'input.ulaw', '-vcodec', 'copy', '-acodec', 'copy', OUT_FILE_NAME],
  1898. //mov
  1899. //arguments: ['-i', 'input.mp4', '-f', 'mulaw', '-ar', '8000', '-ac', '1', '-i', 'input.ulaw', '-vcodec', 'copy', '-acodec', 'copy', OUT_FILE_NAME],
  1900. MEMFS: [{name: 'input.mp4', data: data}, {name: 'input.ulaw', data: data711 }],
  1901. });
  1902. }else{
  1903. self.ffmpeg_worker.postMessage({
  1904. type: 'run',
  1905. TOTAL_MEMORY: 581510912, // 268435456,
  1906. //avi
  1907. //arguments: ['-r','30', '-i', 'input.mp4', '-vcodec', 'copy', '-acodec', 'copy', OUT_FILE_NAME],
  1908. //mkv
  1909. arguments: ['-i', 'input.mp4', '-vcodec', 'copy', '-acodec', 'copy', OUT_FILE_NAME],
  1910. //mov
  1911. //arguments: ['-i', 'input.mp4', '-vcodec', 'copy', '-acodec', 'copy', OUT_FILE_NAME],
  1912. MEMFS: [{name: 'input.mp4', data: data}],
  1913. });
  1914. }
  1915. /*
  1916. if(self.recordedData711.length>0){
  1917. var data711 = self.recordedData711.subarray(0, recData711Len);
  1918. var file2 = { name:IN_FILE_NAME_ULAW, data:data711}
  1919. const args = ['-i', IN_FILE_NAME_264, '-f', 'mulaw', '-ar', '8000', '-ac', '1', '-i', IN_FILE_NAME_ULAW, '-vcodec', 'copy', '-acodec', 'copy', OUT_FILE_NAME];
  1920. var ret = await runFFmpeg(IN_FILE_NAME_264, data, args, OUT_FILE_NAME, [ file2 ] );
  1921. data = null;
  1922. data711 = null;
  1923. ret.Core.PThread.ih();
  1924. delete ret.Core;
  1925. outfile = ret.file;
  1926. }
  1927. else{
  1928. const args = ['-i', IN_FILE_NAME_264, '-vcodec', 'copy', '-acodec', 'copy', OUT_FILE_NAME];
  1929. const ret = await runFFmpeg(IN_FILE_NAME_264, data, args, OUT_FILE_NAME );
  1930. data = null;
  1931. ret.Core.PThread.ih();
  1932. delete ret.Core;
  1933. outfile = ret.file;
  1934. }
  1935. let a = document.createElement("a");
  1936. document.body.appendChild(a);
  1937. a.style.display = 'none';
  1938. a.href = URL.createObjectURL(new Blob([outfile.buffer], { type: 'video/mp4' }));
  1939. a.download = OUT_FILE_NAME;
  1940. a.click();
  1941. delete self.recordedData264; self.recordedData264 = null;
  1942. delete self.recordedData711; self.recordedData711 = null;
  1943. recData264Len = 0;
  1944. recData711Len = 0;
  1945. isRecStopping = false;
  1946. if (self.onRecord !== null) {
  1947. var args = {};
  1948. args.isRecording = isRecording;
  1949. args.isRecStopping = isRecStopping;
  1950. self.onRecord(args);
  1951. }
  1952. */
  1953. }
  1954. self.recordStatus = function() {
  1955. if (isRecording == true) {
  1956. var ret = {};
  1957. ret.recording = true;
  1958. ret.recStopping = false;
  1959. ret.recData264Len = recData264Len;
  1960. ret.recData711Len = recData711Len;
  1961. return ret;
  1962. } else if (isRecording == false && isRecStopping) {
  1963. var ret = {};
  1964. ret.recording = false;
  1965. ret.recStopping = true;
  1966. ret.recData264Len = recData264Len;
  1967. ret.recData711Len = recData711Len;
  1968. return ret;
  1969. } else {
  1970. var ret = {};
  1971. ret.recording = false;
  1972. ret.recStopping = false;
  1973. ret.recData264Len = recData264Len;
  1974. ret.recData711Len = recData711Len;
  1975. return ret;
  1976. }
  1977. }
  1978. el_play.onclick = self.play;
  1979. el_pause.onclick = self.pause;
  1980. el_stop.onclick = self.stop;
  1981. el_fullscreen.onclick = self.fullscreen;
  1982. el_takescreenshot.onclick = self.takescreenshot;
  1983. el_zoomUp.onclick = self.zoomUp;
  1984. el_zoomDown.onclick = self.zoomDown;
  1985. el_zoomPositionCursor.addEventListener('mousedown',self.zoomCursorDown,false);
  1986. el_zoomPositionCursor.addEventListener('mousemove',self.zoomCursorMove,false);
  1987. el_zoomPositionCursor.addEventListener('mouseleave',self.zoomCursorUp,false);
  1988. el_zoomPositionCursor.addEventListener('mouseup',self.zoomCursorUp,false);
  1989. el_zoomProgress.addEventListener('mousedown',self.zoomProgressDown,false);
  1990. el_zoomProgress.addEventListener('mousemove',self.zoomProgressMove,false);
  1991. el_zoomProgress.addEventListener('mouseleave',self.zoomProgressLeave,false);
  1992. el_zoomProgress.addEventListener('mouseup',self.zoomProgressUp,false);
  1993. }(id, options_);
  1994. window.vxgwsplayer.players[id].playerDidLoad();
  1995. }else{
  1996. // console.warn(id + " - already exists player");
  1997. }
  1998. return window.vxgwsplayer.players[id];
  1999. };
  2000. window.vxgwsplayer.webserverport = '8778';
  2001. window.vxgwsplayer.isFrame = function() {
  2002. try {
  2003. return window.self !== window.top;
  2004. } catch (e) {
  2005. return true;
  2006. }
  2007. }
  2008. /*
  2009. window.vxgwsplayer.browserSupportsPluginPnacl = function() {
  2010. return navigator.mimeTypes['application/x-pnacl'] !== undefined &&
  2011. navigator.mimeTypes['application/vxg_media_player'] !== undefined;
  2012. }
  2013. */
  2014. window.vxgwsplayer.showGlobalErrorMessage = function(id, html){
  2015. var player = document.getElementById(id);
  2016. var width=640;
  2017. var height=480;
  2018. width = parseInt(player.width,10) || width;
  2019. height = parseInt(player.height,10) || height;
  2020. player.style.width = width + 'px';
  2021. player.style.height = height + 'px';
  2022. player.innerHTML = html;
  2023. return undefined;
  2024. }
  2025. window.vxgwsplayer.showNotInstalled = function(id){
  2026. vxgwsplayer.showGlobalErrorMessage(id, ''
  2027. + '<div class="vxgwsplayer-unsupport">'
  2028. + ' <div class="vxgwsplayer-unsupport-content">'
  2029. + ' <a href="https://www.videoexpertsgroup.com/player_start/" ' + (vxgwsplayer.isFrame() ? 'target="_blank"' : '')+ '>Click here for install plugin</a>'
  2030. + ' <br/><br/> or visit in webstore <a href="https://chrome.google.com/webstore/detail/vxg-media-player/hncknjnnbahamgpjoafdebabmoamcnni" target="_blank">VXG Media Player</a>'
  2031. + ' </div>'
  2032. + '</div>');
  2033. }
  2034. window.vxgwsplayer.showAvailableInChrome = function(id){
  2035. vxgwsplayer.showGlobalErrorMessage(id, ''
  2036. + '<div class="vxgwsplayer-unsupport">'
  2037. + ' <div class="vxgwsplayer-unsupport-content">'
  2038. + ' Available in <a href="https://www.google.com/chrome/" target="_blank">Chrome for Desktop PC only</a>'
  2039. + ' </div>'
  2040. + '</div>');
  2041. }
  2042. window.vxgwsplayer.showWebSocketFailed = function(id){
  2043. vxgwsplayer.showGlobalErrorMessage(id, ''
  2044. + '<div class="vxgwsplayer-unsupport">'
  2045. + ' <div class="vxgwsplayer-unsupport-content">'
  2046. + ' Could not connect to plugin (WebSocket Error). Please try restart your browser.'
  2047. + ' </div> '
  2048. + '</div>');
  2049. }
  2050. window.vxgwsplayer.showNotInstalledInIncognitoMode = function(id){
  2051. vxgwsplayer.showGlobalErrorMessage(id, ''
  2052. + '<div class="vxgwsplayer-unsupport">'
  2053. + ' <div class="vxgwsplayer-unsupport-content"> You have opened this page in incognito mode. Please open it in a regular tab, install the plugin and then come back.'
  2054. + ' <br/><br/> Also you can install <a href="https://chrome.google.com/webstore/detail/vxg-media-player/hncknjnnbahamgpjoafdebabmoamcnni" target="_blank">VXG Media Player</a> from webstore in regular tab.'
  2055. + ' </div>'
  2056. + '</div>');
  2057. }
  2058. window.vxgwsplayer.showNotStartedInIncognitoMode = function(id){
  2059. vxgwsplayer.showGlobalErrorMessage(id, ''
  2060. + '<div class="vxgwsplayer-unsupport">'
  2061. + ' <div class="vxgwsplayer-unsupport-content"> You have opened this page in incognito mode. Please open it in a regular tab and then come back.'
  2062. + ' </div>'
  2063. + '</div>');
  2064. }
  2065. window.vxgwsplayer.startPlayerInNewTab = function(){
  2066. console.log('start player');
  2067. var params = "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes"
  2068. var win = window.open('https://www.videoexpertsgroup.com/player_start/', "_blank", params)
  2069. setTimeout(function(){
  2070. win.close();
  2071. location.reload();
  2072. /*for(var id in window.vxgwsplayer.players){
  2073. console.log("Restart player: " + id);
  2074. }*/
  2075. },1000);
  2076. }
  2077. window.vxgwsplayer.showNotStartedInIFrame = function(id){
  2078. vxgwsplayer.showGlobalErrorMessage(id, ''
  2079. + '<div class="vxgwsplayer-unsupport">'
  2080. + ' <div class="vxgwsplayer-unsupport-content"> You have opened this page in frame.<br>'
  2081. + ' Please click on <a href="javascript:void(0);" onclick="window.vxgwsplayer.startPlayerInNewTab();">this link</a> for start Chrome App (VXG Media Player).'
  2082. + ' </div>'
  2083. + '</div>');
  2084. }
  2085. window.vxgwsplayer.showInitFailed = function(id, str){
  2086. vxgwsplayer.showGlobalErrorMessage(id, ''
  2087. + '<div class="vxgwsplayer-unsupport">'
  2088. + ' <div class="vxgwsplayer-unsupport-content">'
  2089. + ' Chrome plugin init error. Try to update Video/Audio drivers. '
  2090. + str
  2091. + ' </div> '
  2092. + '</div>');
  2093. }
  2094. window.vxgwsplayer.Promise = function(){
  2095. var completed = false;
  2096. this.done = function(callback){
  2097. this.done_callback = callback;
  2098. if(this.completed){
  2099. this.done_callback(this.err);
  2100. }
  2101. return this;
  2102. }
  2103. this.fail = function(callback){
  2104. this.fail_callback = callback;
  2105. if(this.completed){
  2106. this.fail_callback(this.err);
  2107. }
  2108. return this;
  2109. }
  2110. this.resolve = function(result) {
  2111. if(!this.completed){
  2112. this.result = result;
  2113. this.done_callback(result);
  2114. }
  2115. this.completed = true;
  2116. }
  2117. this.reject = function(err) {
  2118. if(!this.completed){
  2119. this.err = err;
  2120. this.fail_callback(err);
  2121. }
  2122. this.completed = true;
  2123. }
  2124. };
  2125. /*
  2126. window.vxgwsplayer.checkWebSocket = function(){
  2127. var p = new vxgwsplayer.Promise();
  2128. setTimeout(function(){
  2129. var testWebSocket = new WebSocket('ws://127.0.0.1:' + vxgwsplayer.webserverport + '/');
  2130. testWebSocket.onerror=function(event){
  2131. p.reject();
  2132. }
  2133. testWebSocket.onmessage = function(evt){
  2134. console.log(evt);
  2135. }
  2136. testWebSocket.onopen=function(){
  2137. testWebSocket.close();
  2138. p.resolve();
  2139. }
  2140. },60000);
  2141. return p;
  2142. }
  2143. */
  2144. // helper funxtion
  2145. window.vxgwsplayer.getAbsolutePosition = function(element){
  2146. var r = { x: element.offsetLeft, y: element.offsetTop };
  2147. if (element.offsetParent) {
  2148. var tmp = vxgwsplayer.getAbsolutePosition(element.offsetParent);
  2149. r.x += tmp.x;
  2150. r.y += tmp.y;
  2151. }
  2152. return r;
  2153. };
  2154. // init options
  2155. window.vxgwsplayer.initOptions = function(self, options){
  2156. self.options = options || {};
  2157. self.m = {};
  2158. self.m.wsurl = self.player.getAttribute('wsurl') || self.options.wsurl || "";
  2159. self.m.rtspurl = self.player.getAttribute('rtspurl') || self.options.rtspurl || "";
  2160. self.m.user = self.player.getAttribute('user') || self.options.user || "";
  2161. self.m.password = self.player.getAttribute('password') || self.options.password || "";
  2162. /*
  2163. var nmf_path = "media_player.nmf";
  2164. var nmf_src = "pnacl/Release/media_player.nmf";
  2165. self.m.nmf_path = self.player.getAttribute('nmf-path') || self.options.nmf_path || nmf_path;
  2166. self.m.nmf_src = self.player.getAttribute('nmf-src') || self.options.nmf_src || nmf_src;
  2167. */
  2168. self.m.autostart_parameter = self.player.hasAttribute('autostart') ? '1' : '0';
  2169. self.m.audio_parameter = (self.player.hasAttribute('audio') && parseInt(self.player.getAttribute('audio', 10)) == 0) ? '0' : '1';
  2170. self.m.mute_parameter = (self.player.hasAttribute('mute') && parseInt(self.player.getAttribute('mute', 10)) == 1) ? '1' : '0';
  2171. }
  2172. // generate embeded element for nacl player
  2173. /*
  2174. window.vxgwsplayer.generateEmbededElement = function(self){
  2175. return ''
  2176. + '<embed class="vxgwsplayer-module" style="transform: scale(1); z-index: -1;" '
  2177. + ' autostart_parameter="' + self.m.autostart_parameter + '"'
  2178. + ' mute_parameter="' + self.m.mute_parameter + '" '
  2179. + ' audio_parameter="' + self.m.audio_parameter + '" '
  2180. + ' name="nacl_module" '
  2181. + ' id="' + self.id + '_nacl_module" '
  2182. + ' path="' + self.m.nmf_path + '" '
  2183. + ' src="' + self.m.nmf_src + '" '
  2184. + ' url="' + self.m.url + '" '
  2185. + ' type="application/x-pnacl" />';
  2186. }
  2187. */
  2188. class audioBufferPCM {
  2189. constructor(audioCtx, audioGain, sampleRate, bufferSize = 10) {
  2190. this.ctx = audioCtx;
  2191. this.gain = audioGain;
  2192. this.sampleRate = sampleRate;
  2193. this.bufferSize = bufferSize;
  2194. this.chunks = [];
  2195. this.isPlaying = false;
  2196. this.startTime = 0;
  2197. this.lastChunkOffset = 0;
  2198. }
  2199. clear() {
  2200. this.chunks.splice(0, this.chunks.length);
  2201. }
  2202. createChunk(chunk) {
  2203. var audioBuffer = this.ctx.createBuffer(1, chunk.length, this.sampleRate);
  2204. audioBuffer.getChannelData(0).set(chunk);
  2205. var source = this.ctx.createBufferSource();
  2206. source.buffer = audioBuffer;
  2207. source.connect(this.gain);
  2208. source.onended = (e) => {
  2209. this.chunks.splice(this.chunks.indexOf(source), 1);
  2210. if (this.chunks.length == 0) {
  2211. this.isPlaying = false;
  2212. this.startTime = 0;
  2213. this.lastChunkOffset = 0;
  2214. }
  2215. };
  2216. return source;
  2217. }
  2218. addBuffer(data) {
  2219. if (this.isPlaying && (this.chunks.length > this.bufferSize)) {
  2220. console.warn("audio chunk discarded");
  2221. return;
  2222. } else if (this.isPlaying && (this.chunks.length <= this.bufferSize)) { // schedule & add right now
  2223. var chunk = this.createChunk(data);
  2224. chunk.start(this.startTime + this.lastChunkOffset);
  2225. this.lastChunkOffset += chunk.buffer.duration;
  2226. this.chunks.push(chunk);
  2227. chunk = null;
  2228. } else if ((this.chunks.length < (this.bufferSize / 2)) && !this.isPlaying) { // add & don't schedule
  2229. var chunk = this.createChunk(data);
  2230. this.chunks.push(chunk);
  2231. chunk = null;
  2232. } else { // add & schedule entire buffer
  2233. this.isPlaying = true;
  2234. var chunk = this.createChunk(data);
  2235. this.chunks.push(chunk);
  2236. chunk = null;
  2237. this.startTime = this.ctx.currentTime;
  2238. this.lastChunkOffset = 0;
  2239. for (let i = 0; i < this.chunks.length; i++) {
  2240. var chunk = this.chunks[i];
  2241. chunk.start(this.startTime + this.lastChunkOffset);
  2242. this.lastChunkOffset += chunk.buffer.duration;
  2243. }
  2244. }
  2245. }
  2246. }
  2247. // init volumes
  2248. window.vxgwsplayer.initVolumeControls = function(self, onloadsettings){
  2249. self.m.volume = self.options.volume || 0.7;
  2250. var el_volumeMute = self.player.getElementsByClassName('vxgwsplayer-volume-mute')[0];
  2251. var el_volumeDown = self.player.getElementsByClassName('vxgwsplayer-volume-down')[0];
  2252. var el_volumeProgress = self.player.getElementsByClassName('vxgwsplayer-volume-progress')[0];
  2253. var el_volumeUp = self.player.getElementsByClassName('vxgwsplayer-volume-up')[0];
  2254. if(self.player.hasAttribute('volume')){
  2255. self.m.volume = parseFloat(self.player.getAttribute('volume'));
  2256. self.m.volume = Math.ceil(self.m.volume*10)/10;
  2257. if(onloadsettings){
  2258. /*
  2259. self.module.command('setvolume', self.m.volume.toFixed(1));
  2260. */
  2261. }
  2262. }else if(self.options.volume){
  2263. console.warn("TODO volume");
  2264. }
  2265. self.m.mute = self.video.hasAttribute('muted') || self.options.mute || self.m.volume == 0 || self.m.mute_parameter == '1';
  2266. if(self.m.mute){
  2267. el_volumeDown.style.display='none';
  2268. el_volumeProgress.style.display='none';
  2269. el_volumeUp.style.display='none';
  2270. }
  2271. el_volumeProgress.className = el_volumeProgress.className.replace(/vol\d+/g,'vol' + Math.ceil(self.m.volume*10));
  2272. self.isMute = function(){
  2273. return self.m.mute;
  2274. }
  2275. self.applyVolume = function(){
  2276. if(self.isMute()){
  2277. el_volumeDown.style.display='none';
  2278. el_volumeProgress.style.display='none';
  2279. el_volumeUp.style.display='none';
  2280. el_volumeProgress.className = el_volumeProgress.className.replace(/vol\d+/g,'vol0')
  2281. }else{
  2282. el_volumeDown.style.display='inline-block';
  2283. el_volumeProgress.style.display='inline-block';
  2284. el_volumeUp.style.display='inline-block';
  2285. el_volumeProgress.className = el_volumeProgress.className.replace(/vol\d+/g,'vol' + Math.floor(self.m.volume*10));
  2286. }
  2287. /*
  2288. self.module.command('setvolume', self.m.mute? '0': '' + self.m.volume.toFixed(1));
  2289. */
  2290. if (self.isMute()){
  2291. self.video.setAttribute('muted', true);
  2292. self.video.muted = true;
  2293. if (self.audioGain != null && self.audioGain !== undefined && self.audioCtx != null && self.audioCtx !== undefined) {
  2294. self.audioGain.gain.setValueAtTime(0, self.audioCtx.currentTime);
  2295. }
  2296. } else {
  2297. self.video.removeAttribute('muted');
  2298. self.video.muted = false;
  2299. self.video.setAttribute('volume', self.m.volume.toFixed(1));
  2300. self.video.volume = self.m.volume.toFixed(1);
  2301. if (self.audioGain != null && self.audioGain !== undefined && self.audioCtx != null && self.audioCtx !== undefined) {
  2302. self.audioGain.gain.setValueAtTime( self.m.volume, self.audioCtx.currentTime);
  2303. }
  2304. }
  2305. // self.video.volume = self.m.mute? '0': '' + self.m.volume.toFixed(1)
  2306. if (self.audioCtx !== undefined || self.audioCtx != null) {
  2307. self.audioCtx.resume();
  2308. }
  2309. }
  2310. self.mute = function(){
  2311. self.restartTimeout();
  2312. self.m.mute = !self.m.mute;
  2313. self.applyVolume();
  2314. }
  2315. self.volume = function(val){
  2316. if(val != undefined){
  2317. val = val > 1 ? 1 : val;
  2318. val = val < 0 ? 0 : val;
  2319. self.m.volume = Math.ceil(val*10)/10;
  2320. self.applyVolume();
  2321. }else{
  2322. return self.m.volume;
  2323. }
  2324. }
  2325. self.volup = function(){
  2326. self.restartTimeout();
  2327. if(Math.round(self.m.volume*10) < 10){
  2328. self.m.volume = self.m.volume + 0.1;
  2329. self.applyVolume();
  2330. }
  2331. };
  2332. self.voldown = function(){
  2333. self.restartTimeout();
  2334. if(Math.round(self.m.volume*10) > 0){
  2335. self.m.volume = self.m.volume - 0.1;
  2336. self.applyVolume();
  2337. }
  2338. };
  2339. el_volumeMute.onclick = self.mute;
  2340. el_volumeDown.onclick = self.voldown;
  2341. el_volumeUp.onclick = self.volup;
  2342. }
  2343. document.addEventListener('DOMContentLoaded', function() {
  2344. console.log("vxgwsplayer isFrame: " + window.vxgwsplayer.isFrame());
  2345. // console.log("vxgwsplayer browserSupportsPluginPnacl: " + window.vxgwsplayer.browserSupportsPluginPnacl());
  2346. // search all vxgwsplayers
  2347. var els = document.getElementsByClassName("vxgwsplayer");
  2348. for (var i = 0; i < els.length; i++) {
  2349. if(els[i].id){
  2350. vxgwsplayer(els[i].id);
  2351. }else{
  2352. console.error("Player has not id", els[i]);
  2353. }
  2354. }
  2355. // TODO check ws
  2356. // TODO start Chrome App
  2357. });