From 58a5bdebc7956c690f37724a7ca16edc66501fd4 Mon Sep 17 00:00:00 2001 From: Daniel Thies Date: Mon, 25 Sep 2023 15:54:46 -0500 Subject: [PATCH] VID-765: Enable live player services in app --- plugin/live/amd/build/videotime.min.js | 4 +- plugin/live/amd/build/videotime.min.js.map | 2 +- plugin/live/amd/src/videotime.js | 167 +++++++++++++++------ 3 files changed, 125 insertions(+), 48 deletions(-) diff --git a/plugin/live/amd/build/videotime.min.js b/plugin/live/amd/build/videotime.min.js index 96ea4b89..e7b5c392 100644 --- a/plugin/live/amd/build/videotime.min.js +++ b/plugin/live/amd/build/videotime.min.js @@ -1,4 +1,4 @@ -define("videotimeplugin_live/videotime",["exports","core/ajax","mod_videotime/videotime","block_deft/janus-gateway","core/log","core/notification","block_deft/publish","block_deft/subscribe","videotimeplugin_live/socket"],(function(_exports,_ajax,_videotime,_janusGateway,_log,_notification,_publish,_subscribe,_socket){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +define("videotimeplugin_live/videotime",["exports","core/ajax","core/config","mod_videotime/videotime","block_deft/janus-gateway","core/log","core/notification","block_deft/publish","block_deft/subscribe","videotimeplugin_live/socket"],(function(_exports,_ajax,_config,_videotime,_janusGateway,_log,_notification,_publish,_subscribe,_socket){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /* * Video time player specific js * @@ -6,6 +6,6 @@ define("videotimeplugin_live/videotime",["exports","core/ajax","mod_videotime/vi * @module videotimeplugin_live/videotime * @copyright 2022 bdecent gmbh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_ajax=_interopRequireDefault(_ajax),_videotime=_interopRequireDefault(_videotime),_janusGateway=_interopRequireDefault(_janusGateway),_log=_interopRequireDefault(_log),_notification=_interopRequireDefault(_notification),_publish=_interopRequireDefault(_publish),_subscribe=_interopRequireDefault(_subscribe),_socket=_interopRequireDefault(_socket);var rooms={};class Publish extends _publish.default{register(pluginHandle){return _ajax.default.call([{args:{handle:pluginHandle.getId(),id:Number(this.contextid),plugin:pluginHandle.plugin,room:this.roomid,ptype:"publish"==this.ptype,session:pluginHandle.session.getSessionId()},contextid:this.contextid,fail:_notification.default.exception,methodname:"videotimeplugin_live_join_room"}])[0].then((response=>(this.feed=response.id,response))).catch(_notification.default.exception)}publishFeed(){return _ajax.default.call([{args:{id:Number(this.feed),room:this.roomid},contextid:this.contextid,fail:_notification.default.exception,methodname:"videotimeplugin_live_publish_feed"}])[0]}unpublish(){return document.querySelectorAll("#video-controls-camera, #video-controls-display").forEach((video=>{video.srcObject=null,video.parentNode.classList.add("hidden")})),_ajax.default.call([{args:{id:Number(this.feed),publish:!1,room:this.roomid},contextid:this.contextid,fail:_notification.default.exception,methodname:"videotimeplugin_live_publish_feed"}])[0]}handleClose(){document.querySelectorAll('[data-contextid="'+this.contextid+'"][data-action="publish"]').forEach((button=>{button.classList.remove("hidden")})),this.janus.destroy(),[this.currentCamera||Promise.resolve(null),this.currentDisplay||Promise.resolve(null)].forEach((videoInput=>{videoInput.then((videoStream=>(videoStream&&videoStream.getTracks().forEach((track=>{track.enabled=!1,track.stop()})),null))).catch(_notification.default.exception)}))}onLocalTrack(track,on){const remoteStream=new MediaStream([track]);on&&"audio"!=track.kind&&(remoteStream.mid=track.mid,_log.default.debug(on),_log.default.debug(remoteStream),_janusGateway.default.attachMediaStream(document.getElementById("video-controls-"+this.tracks[track.id]),remoteStream))}handleClick(e){const button=e.target.closest('[data-contextid="'+this.contextid+'"][data-action="publish"], [data-contextid="'+this.contextid+'"][data-action="close"], [data-contextid="'+this.contextid+'"][data-action="mute"], [data-contextid="'+this.contextid+'"][data-action="unmute"], [data-contextid="'+this.contextid+'"][data-action="switch"], [data-contextid="'+this.contextid+'"][data-action="unpublish"]');if(button){const action=button.getAttribute("data-action"),type=button.getAttribute("data-type")||"camera";switch(e.stopPropagation(),e.preventDefault(),document.querySelectorAll('[data-region="deft-venue"] [data-action="publish"], [data-region="deft-venue"] [data-action="unpublish"]').forEach((button=>{button.getAttribute("data-action")==action&&button.getAttribute("data-type")==type||button.classList.remove("hidden")})),action){case"close":document.getElementById("video-controls-"+type).srcObject=null,document.getElementById("video-controls-"+type).parentNode.classList.add("hidden"),this.tracks[this.selectedTrack.id]==type&&this.unpublish();break;case"mute":case"unmute":("display"==type?this.currentDisplay:this.currentCamera).then((videoStream=>(videoStream&&videoStream.getAudioTracks().forEach((track=>{track.enabled="unmute"==action})),videoStream))).catch(_notification.default.exception);break;case"publish":_log.default.debug(type),"display"==type?this.shareDisplay():this.shareCamera(),document.querySelectorAll("#video-controls-camera, #video-controls-display").forEach((video=>{video.parentNode.classList.remove("selected")})),document.getElementById("video-controls-"+type).parentNode.classList.remove("hidden"),document.getElementById("video-controls-"+type).parentNode.classList.add("selected"),this.processStream([]);break;case"switch":document.querySelectorAll("#video-controls-camera, #video-controls-display").forEach((video=>{video.parentNode.classList.remove("selected")})),this.videoInput="display"==type?this.currentDisplay:this.currentCamera,document.getElementById("video-controls-"+type).parentNode.classList.remove("hidden"),document.getElementById("video-controls-"+type).parentNode.classList.add("selected"),this.processStream([]);break;case"unpublish":this.unpublish()}}return!0}shareCamera(){const videoInput=this.videoInput,currentCamera=this.currentCamera||Promise.resolve(null);this.videoInput=currentCamera.then((videoStream=>{if(videoStream)return videoStream;{const cameraInput=navigator.mediaDevices.getUserMedia({video:!0,audio:!0});return this.currentCamera=cameraInput.catch((()=>currentCamera)),cameraInput.then((videoStream=>(this.tracks=this.tracks||{},videoStream.getTracks().forEach((track=>{this.tracks[track.id]="camera"})),videoStream))).catch((e=>(_log.default.debug(e),videoInput)))}}))}shareDisplay(){const videoInput=this.videoInput,currentDisplay=this.currentDisplay||Promise.resolve(null),displayInput=navigator.mediaDevices.getDisplayMedia({video:!0,audio:!0});this.videoInput=displayInput.then((videoStream=>(this.tracks=this.tracks||{},videoStream.getTracks().forEach((track=>{this.tracks[track.id]="display"})),videoStream))).catch((e=>(_log.default.debug(e),videoInput))),this.currentDisplay=displayInput.then((videoStream=>(currentDisplay.then((videoStream=>(videoStream&&videoStream.getTracks().forEach((track=>{_log.default.debug("stop track"),_log.default.debug(track),track.stop()})),videoStream))).catch(_notification.default.exception),videoStream))).catch((e=>(_log.default.debug(e),currentDisplay)))}processStream(tracks){this.videoInput.then((videoStream=>{if(this.tracks=this.tracks||{},videoStream){const audiotransceiver=this.getTransceiver("audio"),videotransceiver=this.getTransceiver("video");if(videoStream.getVideoTracks().forEach((track=>{track.addEventListener("ended",(()=>{this.selectedTrack.id==track.id?this.unpublish():document.getElementById("video-controls-"+this.tracks[track.id]).parentNode.classList.add("hidden")})),this.selectedTrack=track,videotransceiver?this.videoroom.replaceTracks({tracks:[{type:"video",mid:videotransceiver.mid,capture:track}],error:_notification.default.exception}):tracks.push({type:"video",capture:track,recv:!1})})),videoStream.getAudioTracks().forEach((track=>{document.querySelector('.hidden[data-action="mute"][data-contextid="'+this.contextid+'"][data-type="'+this.tracks[this.selectedTrack.id]+'"]')&&(track.enabled=!1),audiotransceiver?this.videoroom.replaceTracks({tracks:[{type:"audio",mid:audiotransceiver.mid,capture:track}],error:_notification.default.exception}):tracks.push({type:"audio",capture:track,recv:!1})})),!tracks.length)return videoStream;this.videoroom.createOffer({tracks:tracks,success:jsep=>{this.videoroom.send({message:{request:"configure",video:!0,audio:!0},jsep:jsep})},error:function(error){_notification.default.alert("WebRTC error... ",error.message)}})}return videoStream})).catch(_notification.default.exception)}}class VideoTime extends _videotime.default{initialize(contextid,token,peerid){return _log.default.debug("Initializing Video Time "+this.elementId),this.contextid=contextid,this.peerid=peerid,_ajax.default.call([{methodname:"videotimeplugin_live_get_room",args:{contextid:contextid},done:response=>{const socket=new _socket.default(contextid,token);this.iceservers=JSON.parse(response.iceservers),this.roomid=response.roomid,this.server=response.server,rooms[String(contextid)]={contextid:contextid,peerid:peerid,roomid:response.roomid,server:response.server,iceServers:JSON.parse(response.iceservers)},this.roomid=response.roomid,document.querySelector('[data-contextid="'+this.contextid+'"] .videotime-control').classList.remove("hidden"),socket.subscribe((()=>{_ajax.default.call([{methodname:"videotimeplugin_live_get_feed",args:{contextid:contextid},done:response=>{const room=rooms[String(contextid)];room.publish&&room.publish.restart&&(response.feed==peerid&&this.unpublish(),room.publish=null),this.subscribeTo(Number(response.feed))},fail:_notification.default.exception}])}))},fail:_notification.default.exception}]),this.addListeners(),!0}getPlayer(){return document.getElementById(this.elementId)}addListeners(){const player=this.getPlayer();document.querySelector("body").removeEventListener("click",handleClick),document.querySelector("body").addEventListener("click",handleClick),player?(player.addEventListener("play",(()=>(this.hasPro&&this.startWatchInterval(),this.view(),!0))),this.hasPro&&(player.addEventListener("play",function(){this.playing=!0,_log.default.debug("VIDEO_TIME play")}.bind(this)),player.addEventListener("playing",function(){this.playing=!0,_log.default.debug("VIDEO_TIME playing")}.bind(this)),player.addEventListener("pause",function(){this.playing=!1,_log.default.debug("VIDEO_TIME pause")}.bind(this)),player.addEventListener("stalled",function(){this.playing=!1,_log.default.debug("VIDEO_TIME stalled")}.bind(this)),player.addEventListener("suspend",function(){this.playing=!1,_log.default.debug("VIDEO_TIME suspend")}.bind(this)),player.addEventListener("abort",function(){this.playing=!1,_log.default.debug("VIDEO_TIME abort")}.bind(this)),player.addEventListener("timeupdate",function(event){this.percent=1,this.currentTime=player.currentTime,this.plugins.forEach((plugin=>{"function"==typeof plugin.setCurrentTime&&plugin.getSessions().then((session=>(plugin.setCurrentTime(session.id,event.seconds),session))).catch(_notification.default.exception)}))}.bind(this)),this.player.addEventListener("ended",this.handleEnd.bind(this)),this.player.addEventListener("pause",this.handlePause.bind(this)))):_log.default.debug("Player was not properly initialized for course module "+this.cmId)}subscribeTo(source){const room=rooms[String(this.contextid)];if(document.querySelectorAll('[data-contextid="'+this.contextid+'"][data-action="publish"]').forEach((button=>{Number(this.peerid),button.classList.remove("hidden")})),document.querySelectorAll('[data-contextid="'+this.contextid+'"][data-action="unpublish"]').forEach((button=>{Number(this.peerid),button.classList.remove("hidden")})),!this.remoteFeed||this.remoteFeed.creatingSubscription||this.remoteFeed.restart)this.remoteFeed&&this.remoteFeed.restart?this.remoteFeed.current!=source&&(this.remoteFeed=null,this.subscribeTo(source)):this.remoteFeed?setTimeout((()=>{this.subscribeTo(source)}),500):source&&(this.remoteFeed=new Subscribe(this.contextid,this.iceservers,this.roomid,this.server,this.peerid),this.remoteFeed.remoteVideo=document.getElementById(this.elementId),this.remoteFeed.remoteAudio=document.getElementById(this.elementId).parentNode.querySelector("audio"),this.remoteFeed.muteAudio=room.publish&&room.publish.feed===source,this.remoteFeed.startConnection(source),document.querySelectorAll('[data-contextid="'+this.contextid+'"] img.poster-img').forEach((img=>{img.classList.add("hidden")})),document.querySelectorAll('[data-contextid="'+this.contextid+'"] video').forEach((img=>{img.classList.remove("hidden")})));else{const update={request:"update",subscribe:[{feed:Number(source)}],unsubscribe:[{feed:Number(this.remoteFeed.current)}]};!source&&this.remoteFeed.current?delete update.subscribe:source&&!this.remoteFeed.current&&delete update.unsubscribe,this.remoteFeed.current!=source&&(this.remoteFeed.muteAudio=room.publish&&room.publish.feed===source,this.remoteFeed.videoroom.send({message:update}),this.remoteFeed.audioTrack&&(this.remoteFeed.audioTrack.enabled=!this.remoteFeed.muteAudio),room.publish&&this.remoteFeed.current==room.publish.feed&&(room.publish.handleClose(),room.publish=null),this.remoteFeed.current=source,!source&&this.remoteFeed&&(this.remoteFeed.handleClose(),this.remoteFeed=null),_log.default.debug('[data-contextid="'+this.contextid+'"] img.poster-img'),Number(source)?(document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-embed img.poster-img').forEach((img=>{img.classList.add("hidden")})),document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-embed video').forEach((video=>{video.classList.remove("hidden")}))):(document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-embed img.poster-img').forEach((img=>{img.classList.remove("hidden")})),document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-embed video').forEach((video=>{video.srcObject=null,video.classList.add("hidden")}))))}}getDuration(){return Promise.resolve(this.currentTime)}}_exports.default=VideoTime;const handleClick=function(e){const button=e.target.closest('[data-roomid] [data-action="publish"], [data-roomid] [data-action="unpublish"],[data-roomid] [data-action="close"], [data-roomid] [data-action="switch"], [data-roomid] [data-action="mute"], [data-roomid] [data-action="unmute"]');if(button){const action=button.getAttribute("data-action"),contextid=e.target.closest("[data-contextid]").getAttribute("data-contextid"),room=rooms[String(contextid)],iceServers=room.iceServers,peerid=room.peerid,roomid=room.roomid,server=room.server,type=button.getAttribute("data-type");e.stopPropagation(),e.preventDefault(),"publish"!=action||room.publish&&!room.publish.restart?("mute"!=action&&"unmute"!=action||(button.classList.add("hidden"),button.parentNode.querySelectorAll('[data-action="mute"], [data-action="unmute"]').forEach((button=>{button.getAttribute("data-action")!=action&&button.classList.remove("hidden")}))),room.publish&&room.publish.handleClick(e)):(room.publish=new Publish(contextid,iceServers,roomid,server,peerid),"display"==type?room.publish.shareDisplay():room.publish.shareCamera(),room.publish.startConnection(),document.getElementById("video-controls-"+(type||"camera")).parentNode.classList.remove("hidden"),document.getElementById("video-controls-"+(type||"camera")).parentNode.classList.add("selected"))}};class Subscribe extends _subscribe.default{register(pluginHandle){return _ajax.default.call([{args:{handle:pluginHandle.getId(),id:Number(this.contextid),plugin:pluginHandle.plugin,room:this.roomid,ptype:!1,feed:this.feed,session:pluginHandle.session.getSessionId()},contextid:this.contextid,fail:_notification.default.exception,methodname:"videotimeplugin_live_join_room"}])[0]}attachAudio(audioStream){_janusGateway.default.attachMediaStream(this.remoteVideo.parentNode.querySelector("audio"),audioStream),audioStream.getTracks().forEach((track=>{this.audioTrack=track,track.enabled=!this.muteAudio}))}attachVideo(videoStream){_janusGateway.default.attachMediaStream(this.remoteVideo,videoStream)}}return _exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_ajax=_interopRequireDefault(_ajax),_config=_interopRequireDefault(_config),_videotime=_interopRequireDefault(_videotime),_janusGateway=_interopRequireDefault(_janusGateway),_log=_interopRequireDefault(_log),_notification=_interopRequireDefault(_notification),_publish=_interopRequireDefault(_publish),_subscribe=_interopRequireDefault(_subscribe),_socket=_interopRequireDefault(_socket);var wstoken,rooms={};class Publish extends _publish.default{register(pluginHandle){return _ajax.default.call([{args:{handle:pluginHandle.getId(),id:Number(this.contextid),plugin:pluginHandle.plugin,room:this.roomid,ptype:"publish"==this.ptype,session:pluginHandle.session.getSessionId()},contextid:this.contextid,fail:_notification.default.exception,methodname:"videotimeplugin_live_join_room"}])[0].then((response=>(this.feed=response.id,response))).catch(_notification.default.exception)}publishFeed(){return _ajax.default.call([{args:{id:Number(this.feed),room:this.roomid},contextid:this.contextid,fail:_notification.default.exception,methodname:"videotimeplugin_live_publish_feed"}])[0]}unpublish(){return document.querySelectorAll("#video-controls-camera, #video-controls-display").forEach((video=>{video.srcObject=null,video.parentNode.classList.add("hidden")})),_ajax.default.call([{args:{id:Number(this.feed),publish:!1,room:this.roomid},contextid:this.contextid,fail:_notification.default.exception,methodname:"videotimeplugin_live_publish_feed"}])[0]}handleClose(){document.querySelectorAll('[data-contextid="'+this.contextid+'"][data-action="publish"]').forEach((button=>{button.classList.remove("hidden")})),this.janus.destroy(),[this.currentCamera||Promise.resolve(null),this.currentDisplay||Promise.resolve(null)].forEach((videoInput=>{videoInput.then((videoStream=>(videoStream&&videoStream.getTracks().forEach((track=>{track.enabled=!1,track.stop()})),null))).catch(_notification.default.exception)}))}onLocalTrack(track,on){const remoteStream=new MediaStream([track]);on&&"audio"!=track.kind&&(remoteStream.mid=track.mid,_log.default.debug(on),_log.default.debug(remoteStream),_janusGateway.default.attachMediaStream(document.getElementById("video-controls-"+this.tracks[track.id]),remoteStream))}handleClick(e){const button=e.target.closest('[data-contextid="'+this.contextid+'"][data-action="publish"], [data-contextid="'+this.contextid+'"][data-action="close"], [data-contextid="'+this.contextid+'"][data-action="mute"], [data-contextid="'+this.contextid+'"][data-action="unmute"], [data-contextid="'+this.contextid+'"][data-action="switch"], [data-contextid="'+this.contextid+'"][data-action="unpublish"]');if(button){const action=button.getAttribute("data-action"),type=button.getAttribute("data-type")||"camera";switch(e.stopPropagation(),e.preventDefault(),document.querySelectorAll('[data-region="deft-venue"] [data-action="publish"], [data-region="deft-venue"] [data-action="unpublish"]').forEach((button=>{button.getAttribute("data-action")==action&&button.getAttribute("data-type")==type||button.classList.remove("hidden")})),action){case"close":document.getElementById("video-controls-"+type).srcObject=null,document.getElementById("video-controls-"+type).parentNode.classList.add("hidden"),this.tracks[this.selectedTrack.id]==type&&this.unpublish();break;case"mute":case"unmute":("display"==type?this.currentDisplay:this.currentCamera).then((videoStream=>(videoStream&&videoStream.getAudioTracks().forEach((track=>{track.enabled="unmute"==action})),videoStream))).catch(_notification.default.exception);break;case"publish":_log.default.debug(type),"display"==type?this.shareDisplay():this.shareCamera(),document.querySelectorAll("#video-controls-camera, #video-controls-display").forEach((video=>{video.parentNode.classList.remove("selected")})),document.getElementById("video-controls-"+type).parentNode.classList.remove("hidden"),document.getElementById("video-controls-"+type).parentNode.classList.add("selected"),this.processStream([]);break;case"switch":document.querySelectorAll("#video-controls-camera, #video-controls-display").forEach((video=>{video.parentNode.classList.remove("selected")})),this.videoInput="display"==type?this.currentDisplay:this.currentCamera,document.getElementById("video-controls-"+type).parentNode.classList.remove("hidden"),document.getElementById("video-controls-"+type).parentNode.classList.add("selected"),this.processStream([]);break;case"unpublish":this.unpublish()}}return!0}shareCamera(){const videoInput=this.videoInput,currentCamera=this.currentCamera||Promise.resolve(null);this.videoInput=currentCamera.then((videoStream=>{if(videoStream)return videoStream;{const cameraInput=navigator.mediaDevices.getUserMedia({video:!0,audio:!0});return this.currentCamera=cameraInput.catch((()=>currentCamera)),cameraInput.then((videoStream=>(this.tracks=this.tracks||{},videoStream.getTracks().forEach((track=>{this.tracks[track.id]="camera"})),videoStream))).catch((e=>(_log.default.debug(e),videoInput)))}}))}shareDisplay(){const videoInput=this.videoInput,currentDisplay=this.currentDisplay||Promise.resolve(null),displayInput=navigator.mediaDevices.getDisplayMedia({video:!0,audio:!0});this.videoInput=displayInput.then((videoStream=>(this.tracks=this.tracks||{},videoStream.getTracks().forEach((track=>{this.tracks[track.id]="display"})),videoStream))).catch((e=>(_log.default.debug(e),videoInput))),this.currentDisplay=displayInput.then((videoStream=>(currentDisplay.then((videoStream=>(videoStream&&videoStream.getTracks().forEach((track=>{track.stop()})),videoStream))).catch(_notification.default.exception),videoStream))).catch((e=>(_log.default.debug(e),currentDisplay)))}processStream(tracks){this.videoInput.then((videoStream=>{if(this.tracks=this.tracks||{},videoStream){const audiotransceiver=this.getTransceiver("audio"),videotransceiver=this.getTransceiver("video");if(videoStream.getVideoTracks().forEach((track=>{track.addEventListener("ended",(()=>{this.selectedTrack.id==track.id?this.unpublish():document.getElementById("video-controls-"+this.tracks[track.id]).parentNode.classList.add("hidden")})),this.selectedTrack=track,videotransceiver?this.videoroom.replaceTracks({tracks:[{type:"video",mid:videotransceiver.mid,capture:track}],error:_notification.default.exception}):tracks.push({type:"video",capture:track,recv:!1})})),videoStream.getAudioTracks().forEach((track=>{document.querySelector('.hidden[data-action="mute"][data-contextid="'+this.contextid+'"][data-type="'+this.tracks[this.selectedTrack.id]+'"]')&&(track.enabled=!1),audiotransceiver?this.videoroom.replaceTracks({tracks:[{type:"audio",mid:audiotransceiver.mid,capture:track}],error:_notification.default.exception}):tracks.push({type:"audio",capture:track,recv:!1})})),!tracks.length)return videoStream;this.videoroom.createOffer({tracks:tracks,success:jsep=>{this.videoroom.send({message:{request:"configure",video:!0,audio:!0},jsep:jsep})},error:function(error){_notification.default.alert("WebRTC error... ",error.message)}})}return videoStream})).catch(_notification.default.exception)}}class VideoTime extends _videotime.default{initialize(contextid,token,peerid){return _log.default.debug("Initializing Video Time "+this.elementId),this.contextid=contextid,this.peerid=peerid,this.instance.token&&(wstoken=this.instance.token),this.getRoom().then((response=>{const socket=new _socket.default(contextid,token);return this.iceservers=JSON.parse(response.iceservers),this.roomid=response.roomid,this.server=response.server,rooms[String(contextid)]={contextid:contextid,peerid:peerid,roomid:response.roomid,server:response.server,iceServers:JSON.parse(response.iceservers)},this.roomid=response.roomid,document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-control').forEach((control=>{control.classList.remove("hidden")})),socket.subscribe((()=>{this.getFeed().then((response=>{const room=rooms[String(contextid)];return room.publish&&room.publish.restart&&(response.feed==peerid&&this.unpublish(),room.publish=null),this.subscribeTo(Number(response.feed)),response})).catch(_notification.default.exception)})),response})).catch(_notification.default.exception),this.addListeners(),!0}getRoom(){if(wstoken){const url=new URL(_config.default.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",wstoken),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_live_get_room"),data.set("contextid",this.contextid),fetch(url).then((response=>(response.ok||_notification.default.exeption("Web service error"),response.json())))}return _ajax.default.call([{methodname:"videotimeplugin_live_get_room",args:{contextid:this.contextid},fail:_notification.default.exception}])[0]}getFeed(){if(wstoken){const url=new URL(_config.default.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",wstoken),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_live_get_feed"),data.set("contextid",this.contextid),fetch(url).then((response=>(response.ok||_notification.default.exeption("Web service error"),response.json())))}return _ajax.default.call([{methodname:"videotimeplugin_live_get_feed",args:{contextid:this.contextid},fail:_notification.default.exception}])[0]}getPlayer(){return document.getElementById(this.elementId)}addListeners(){const player=this.getPlayer();document.querySelector("body").removeEventListener("click",handleClick),document.querySelector("body").addEventListener("click",handleClick),player?(player.addEventListener("play",(()=>(this.hasPro&&this.startWatchInterval(),this.view(),!0))),this.hasPro&&(player.addEventListener("play",function(){this.playing=!0,_log.default.debug("VIDEO_TIME play")}.bind(this)),player.addEventListener("playing",function(){this.playing=!0,_log.default.debug("VIDEO_TIME playing")}.bind(this)),player.addEventListener("pause",function(){this.playing=!1,_log.default.debug("VIDEO_TIME pause")}.bind(this)),player.addEventListener("stalled",function(){this.playing=!1,_log.default.debug("VIDEO_TIME stalled")}.bind(this)),player.addEventListener("suspend",function(){this.playing=!1,_log.default.debug("VIDEO_TIME suspend")}.bind(this)),player.addEventListener("abort",function(){this.playing=!1,_log.default.debug("VIDEO_TIME abort")}.bind(this)),player.addEventListener("timeupdate",function(event){this.percent=1,this.currentTime=player.currentTime,this.plugins.forEach((plugin=>{"function"==typeof plugin.setCurrentTime&&plugin.getSessions().then((session=>(plugin.setCurrentTime(session.id,event.seconds),session))).catch(_notification.default.exception)}))}.bind(this)),player.addEventListener("ended",this.handleEnd.bind(this)),player.addEventListener("pause",this.handlePause.bind(this)))):_log.default.debug("Player was not properly initialized for course module "+this.cmId)}subscribeTo(source){const room=rooms[String(this.contextid)];if(document.querySelectorAll('[data-contextid="'+this.contextid+'"][data-action="publish"]').forEach((button=>{Number(this.peerid),button.classList.remove("hidden")})),document.querySelectorAll('[data-contextid="'+this.contextid+'"][data-action="unpublish"]').forEach((button=>{Number(this.peerid),button.classList.remove("hidden")})),!this.remoteFeed||this.remoteFeed.creatingSubscription||this.remoteFeed.restart)this.remoteFeed&&this.remoteFeed.restart?this.remoteFeed.current!=source&&(this.remoteFeed=null,this.subscribeTo(source)):this.remoteFeed?setTimeout((()=>{this.subscribeTo(source)}),500):source&&(this.remoteFeed=new Subscribe(this.contextid,this.iceservers,this.roomid,this.server,this.peerid),this.remoteFeed.remoteVideo=document.getElementById(this.elementId),this.remoteFeed.remoteAudio=document.getElementById(this.elementId).parentNode.querySelector("audio"),this.remoteFeed.muteAudio=room.publish&&room.publish.feed===source,this.remoteFeed.startConnection(source),document.querySelectorAll('[data-contextid="'+this.contextid+'"] img.poster-img').forEach((img=>{img.classList.add("hidden")})),document.querySelectorAll('[data-contextid="'+this.contextid+'"] video').forEach((img=>{img.classList.remove("hidden")})));else{const update={request:"update",subscribe:[{feed:Number(source)}],unsubscribe:[{feed:Number(this.remoteFeed.current)}]};!source&&this.remoteFeed.current?delete update.subscribe:source&&!this.remoteFeed.current&&delete update.unsubscribe,this.remoteFeed.current!=source&&(this.remoteFeed.muteAudio=room.publish&&room.publish.feed===source,this.remoteFeed.videoroom.send({message:update}),this.remoteFeed.audioTrack&&(this.remoteFeed.audioTrack.enabled=!this.remoteFeed.muteAudio),room.publish&&this.remoteFeed.current==room.publish.feed&&(room.publish.handleClose(),room.publish=null),this.remoteFeed.current=source,!source&&this.remoteFeed&&(this.remoteFeed.handleClose(),this.remoteFeed=null),Number(source)?(document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-embed img.poster-img').forEach((img=>{img.classList.add("hidden")})),document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-embed video').forEach((video=>{video.classList.remove("hidden")}))):(document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-embed img.poster-img').forEach((img=>{img.classList.remove("hidden")})),document.querySelectorAll('[data-contextid="'+this.contextid+'"] .videotime-embed video').forEach((video=>{video.srcObject=null,video.classList.add("hidden")}))))}}getDuration(){return Promise.resolve(this.currentTime)}}_exports.default=VideoTime;const handleClick=function(e){const button=e.target.closest('[data-roomid] [data-action="publish"], [data-roomid] [data-action="unpublish"],[data-roomid] [data-action="close"], [data-roomid] [data-action="switch"], [data-roomid] [data-action="mute"], [data-roomid] [data-action="unmute"]');if(button){const action=button.getAttribute("data-action"),contextid=e.target.closest("[data-contextid]").getAttribute("data-contextid"),room=rooms[String(contextid)],iceServers=room.iceServers,peerid=room.peerid,roomid=room.roomid,server=room.server,type=button.getAttribute("data-type");e.stopPropagation(),e.preventDefault(),"publish"!=action||room.publish&&!room.publish.restart?("mute"!=action&&"unmute"!=action||(button.classList.add("hidden"),button.parentNode.querySelectorAll('[data-action="mute"], [data-action="unmute"]').forEach((button=>{button.getAttribute("data-action")!=action&&button.classList.remove("hidden")}))),room.publish&&room.publish.handleClick(e)):(room.publish=new Publish(contextid,iceServers,roomid,server,peerid),"display"==type?room.publish.shareDisplay():room.publish.shareCamera(),room.publish.startConnection(),document.getElementById("video-controls-"+(type||"camera")).parentNode.classList.remove("hidden"),document.getElementById("video-controls-"+(type||"camera")).parentNode.classList.add("selected"))}};class Subscribe extends _subscribe.default{register(pluginHandle){if(wstoken){const url=new URL(_config.default.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",wstoken),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_live_join_room"),data.set("handle",pluginHandle.getId()),data.set("id",Number(this.contextid)),data.set("plugin",pluginHandle.plugin),data.set("room",this.roomid),data.set("feed",this.feed),data.set("session",pluginHandle.session.getSessionId()),fetch(url).then((response=>(response.ok||_notification.default.exeption("Web service error"),response.json()))).catch(_notification.default.exception)}return _ajax.default.call([{args:{handle:pluginHandle.getId(),id:Number(this.contextid),plugin:pluginHandle.plugin,room:this.roomid,ptype:!1,feed:this.feed,session:pluginHandle.session.getSessionId()},contextid:this.contextid,fail:_notification.default.exception,methodname:"videotimeplugin_live_join_room"}])[0]}attachAudio(audioStream){_janusGateway.default.attachMediaStream(this.remoteVideo.parentNode.querySelector("audio"),audioStream),audioStream.getTracks().forEach((track=>{this.audioTrack=track,track.enabled=!this.muteAudio}))}attachVideo(videoStream){_janusGateway.default.attachMediaStream(this.remoteVideo,videoStream)}}return _exports.default})); //# sourceMappingURL=videotime.min.js.map \ No newline at end of file diff --git a/plugin/live/amd/build/videotime.min.js.map b/plugin/live/amd/build/videotime.min.js.map index 698d5bd4..74ad68ea 100644 --- a/plugin/live/amd/build/videotime.min.js.map +++ b/plugin/live/amd/build/videotime.min.js.map @@ -1 +1 @@ -{"version":3,"file":"videotime.min.js","sources":["../src/videotime.js"],"sourcesContent":["/*\n * Video time player specific js\n *\n * @package videotimeplugin_live\n * @module videotimeplugin_live/videotime\n * @copyright 2022 bdecent gmbh \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from \"core/ajax\";\nimport VideoTimeBase from \"mod_videotime/videotime\";\nimport Janus from 'block_deft/janus-gateway';\nimport Log from \"core/log\";\nimport Notification from \"core/notification\";\nimport PublishBase from \"block_deft/publish\";\nimport SubscribeBase from \"block_deft/subscribe\";\nimport Socket from \"videotimeplugin_live/socket\";\n\nvar rooms = {};\n\nclass Publish extends PublishBase {\n /**\n * Register the room\n *\n * @param {object} pluginHandle\n * @return {Promise}\n */\n register(pluginHandle) {\n // Try a registration\n return Ajax.call([{\n args: {\n handle: pluginHandle.getId(),\n id: Number(this.contextid),\n plugin: pluginHandle.plugin,\n room: this.roomid,\n ptype: this.ptype == 'publish',\n session: pluginHandle.session.getSessionId()\n },\n contextid: this.contextid,\n fail: Notification.exception,\n methodname: 'videotimeplugin_live_join_room'\n }])[0].then(response => {\n this.feed = response.id;\n\n return response;\n }).catch(Notification.exception);\n }\n\n /**\n * Publish current video feed\n *\n * @returns {Promise}\n */\n publishFeed() {\n return Ajax.call([{\n args: {\n id: Number(this.feed),\n room: this.roomid,\n },\n contextid: this.contextid,\n fail: Notification.exception,\n methodname: 'videotimeplugin_live_publish_feed'\n }])[0];\n }\n\n\n /**\n * Stop video feed\n *\n * @returns {Promise}\n */\n unpublish() {\n document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {\n video.srcObject = null;\n video.parentNode.classList.add('hidden');\n });\n return Ajax.call([{\n args: {\n id: Number(this.feed),\n publish: false,\n room: this.roomid\n },\n contextid: this.contextid,\n fail: Notification.exception,\n methodname: 'videotimeplugin_live_publish_feed'\n }])[0];\n }\n\n handleClose() {\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"][data-action=\"publish\"]'\n ).forEach(button => {\n button.classList.remove('hidden');\n });\n\n this.janus.destroy();\n\n [\n this.currentCamera || Promise.resolve(null),\n this.currentDisplay || Promise.resolve(null),\n ].forEach(videoInput => {\n videoInput.then(videoStream => {\n if (videoStream) {\n videoStream.getTracks().forEach(track => {\n track.enabled = false;\n track.stop();\n });\n }\n\n return null;\n }).catch(Notification.exception);\n });\n }\n\n onLocalTrack(track, on) {\n const remoteStream = new MediaStream([track]);\n if (!on || (track.kind == 'audio')) {\n return;\n }\n remoteStream.mid = track.mid;\n Log.debug(on);\n Log.debug(remoteStream);\n Janus.attachMediaStream(\n document.getElementById('video-controls-' + this.tracks[track.id]),\n remoteStream\n );\n }\n\n handleClick(e) {\n const button = e.target.closest(\n '[data-contextid=\"' + this.contextid + '\"][data-action=\"publish\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"close\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"mute\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"unmute\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"switch\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"unpublish\"]'\n );\n if (button) {\n const action = button.getAttribute('data-action'),\n type = button.getAttribute('data-type') || 'camera';\n e.stopPropagation();\n e.preventDefault();\n document.querySelectorAll(\n '[data-region=\"deft-venue\"] [data-action=\"publish\"], [data-region=\"deft-venue\"] [data-action=\"unpublish\"]'\n ).forEach(button => {\n if ((button.getAttribute('data-action') != action) || (button.getAttribute('data-type') != type)) {\n button.classList.remove('hidden');\n }\n });\n switch (action) {\n case 'close':\n document.getElementById('video-controls-' + type).srcObject = null;\n document.getElementById('video-controls-' + type).parentNode.classList.add('hidden');\n if (this.tracks[this.selectedTrack.id] == type) {\n this.unpublish();\n }\n break;\n case 'mute':\n case 'unmute':\n ((type == 'display') ? this.currentDisplay : this.currentCamera)\n .then(videoStream => {\n if (videoStream) {\n videoStream.getAudioTracks().forEach(track => {\n track.enabled = (action == 'unmute');\n });\n }\n return videoStream;\n }).catch(Notification.exception);\n break;\n case 'publish':\n Log.debug(type);\n if (type == 'display') {\n this.shareDisplay();\n } else {\n this.shareCamera();\n }\n document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {\n video.parentNode.classList.remove('selected');\n });\n document\n .getElementById('video-controls-' + type)\n .parentNode\n .classList\n .remove('hidden');\n document\n .getElementById('video-controls-' + type)\n .parentNode\n .classList\n .add('selected');\n\n this.processStream([]);\n break;\n case 'switch':\n document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {\n video.parentNode.classList.remove('selected');\n });\n if (type == 'display') {\n this.videoInput = this.currentDisplay;\n } else {\n this.videoInput = this.currentCamera;\n }\n document\n .getElementById('video-controls-' + type)\n .parentNode\n .classList\n .remove('hidden');\n document\n .getElementById('video-controls-' + type)\n .parentNode\n .classList\n .add('selected');\n this.processStream([]);\n break;\n case 'unpublish':\n this.unpublish();\n }\n }\n\n return true;\n }\n\n /**\n * Set video source to user camera\n */\n shareCamera() {\n const videoInput = this.videoInput,\n currentCamera = this.currentCamera || Promise.resolve(null);\n\n this.videoInput = currentCamera.then(videoStream => {\n if (videoStream) {\n return videoStream;\n } else {\n const cameraInput = navigator.mediaDevices.getUserMedia({\n video: true,\n audio: true\n });\n\n this.currentCamera = cameraInput.catch(() => {\n return currentCamera;\n });\n\n return cameraInput.then(videoStream => {\n this.tracks = this.tracks || {};\n videoStream.getTracks().forEach(track => {\n this.tracks[track.id] = 'camera';\n });\n\n return videoStream;\n }).catch((e) => {\n Log.debug(e);\n\n return videoInput;\n });\n }\n });\n }\n\n /**\n * Set video source to display surface\n */\n shareDisplay() {\n const videoInput = this.videoInput,\n currentDisplay = this.currentDisplay || Promise.resolve(null),\n displayInput = navigator.mediaDevices.getDisplayMedia({\n video: true,\n audio: true\n });\n\n this.videoInput = displayInput.then(videoStream => {\n this.tracks = this.tracks || {};\n videoStream.getTracks().forEach(track => {\n this.tracks[track.id] = 'display';\n });\n\n return videoStream;\n }).catch((e) => {\n Log.debug(e);\n\n return videoInput;\n });\n\n this.currentDisplay = displayInput.then(videoStream => {\n currentDisplay.then(videoStream => {\n if (videoStream) {\n videoStream.getTracks().forEach(track => {\n Log.debug('stop track');\n Log.debug(track);\n track.stop();\n });\n }\n\n return videoStream;\n }).catch(Notification.exception);\n\n return videoStream;\n }).catch((e) => {\n Log.debug(e);\n\n return currentDisplay;\n });\n }\n\n /**\n * Process tracks from current video stream and adjust publicatioin\n *\n * @param {array} tracks Additional tracks to add\n */\n processStream(tracks) {\n this.videoInput.then(videoStream => {\n this.tracks = this.tracks || {};\n if (videoStream) {\n const audiotransceiver = this.getTransceiver('audio'),\n videotransceiver = this.getTransceiver('video');\n videoStream.getVideoTracks().forEach(track => {\n track.addEventListener('ended', () => {\n if (this.selectedTrack.id == track.id) {\n this.unpublish();\n } else {\n document\n .getElementById('video-controls-' + this.tracks[track.id])\n .parentNode\n .classList\n .add('hidden');\n }\n });\n this.selectedTrack = track;\n if (videotransceiver) {\n this.videoroom.replaceTracks({\n tracks: [{\n type: 'video',\n mid: videotransceiver.mid,\n capture: track\n }],\n error: Notification.exception\n });\n\n return;\n }\n tracks.push({\n type: 'video',\n capture: track,\n recv: false\n });\n });\n videoStream.getAudioTracks().forEach(track => {\n if (\n document.querySelector('.hidden[data-action=\"mute\"][data-contextid=\"' + this.contextid + '\"][data-type=\"'\n + this.tracks[this.selectedTrack.id] + '\"]'\n )) {\n track.enabled = false;\n }\n\n if (audiotransceiver) {\n this.videoroom.replaceTracks({\n tracks: [{\n type: 'audio',\n mid: audiotransceiver.mid,\n capture: track\n }],\n error: Notification.exception\n });\n\n return;\n }\n tracks.push({\n type: 'audio',\n capture: track,\n recv: false\n });\n });\n if (!tracks.length) {\n return videoStream;\n }\n this.videoroom.createOffer({\n tracks: tracks,\n success: (jsep) => {\n const publish = {\n request: \"configure\",\n video: true,\n audio: true\n };\n this.videoroom.send({\n message: publish,\n jsep: jsep\n });\n },\n error: function(error) {\n Notification.alert(\"WebRTC error... \", error.message);\n }\n });\n }\n\n return videoStream;\n }).catch(Notification.exception);\n }\n}\n\nexport default class VideoTime extends VideoTimeBase {\n /**\n * Initialize player plugin\n *\n * @param {int} contextid\n * @param {string} token Deft token\n * @param {int} peerid Peer id for audio room participant\n *\n * @returns {bool}\n */\n initialize(contextid, token, peerid) {\n Log.debug(\"Initializing Video Time \" + this.elementId);\n\n this.contextid = contextid;\n this.peerid = peerid;\n\n Ajax.call([{\n methodname: 'videotimeplugin_live_get_room',\n args: {contextid: contextid},\n done: (response) => {\n const socket = new Socket(contextid, token);\n\n this.iceservers = JSON.parse(response.iceservers);\n this.roomid = response.roomid;\n this.server = response.server;\n\n rooms[String(contextid)] = {\n contextid: contextid,\n peerid: peerid,\n roomid: response.roomid,\n server: response.server,\n iceServers: JSON.parse(response.iceservers)\n };\n this.roomid = response.roomid;\n\n document.querySelector('[data-contextid=\"' + this.contextid + '\"] .videotime-control').classList.remove('hidden');\n\n socket.subscribe(() => {\n Ajax.call([{\n methodname: 'videotimeplugin_live_get_feed',\n args: {contextid: contextid},\n done: (response) => {\n const room = rooms[String(contextid)];\n if (room.publish && room.publish.restart) {\n if (response.feed == peerid) {\n this.unpublish();\n }\n room.publish = null;\n }\n this.subscribeTo(Number(response.feed));\n },\n fail: Notification.exception\n }]);\n });\n },\n fail: Notification.exception\n }]);\n\n this.addListeners();\n\n return true;\n }\n\n /**\n * Get video element\n *\n * @returns {HTMLMediaElement}\n */\n getPlayer() {\n return document.getElementById(this.elementId);\n }\n\n /**\n * Register player events to respond to user interaction and play progress.\n */\n addListeners() {\n const player = this.getPlayer();\n\n document.querySelector('body').removeEventListener('click', handleClick);\n document.querySelector('body').addEventListener('click', handleClick);\n\n if (!player) {\n Log.debug('Player was not properly initialized for course module ' + this.cmId);\n return;\n }\n\n // Fire view event in Moodle on first play only.\n player.addEventListener('play', () => {\n if (this.hasPro) {\n this.startWatchInterval();\n }\n this.view();\n return true;\n });\n\n // Features beyond this point are for pro only.\n if (!this.hasPro) {\n return;\n }\n\n // Note: Vimeo player does not support multiple events in a single on() call. Each requires it's own function.\n\n // Catch all events where video plays.\n player.addEventListener('play', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME play');\n }.bind(this));\n player.addEventListener('playing', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME playing');\n }.bind(this));\n\n // Catch all events where video stops.\n player.addEventListener('pause', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME pause');\n }.bind(this));\n player.addEventListener('stalled', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME stalled');\n }.bind(this));\n player.addEventListener('suspend', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME suspend');\n }.bind(this));\n player.addEventListener('abort', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME abort');\n }.bind(this));\n\n // Always update internal values for percent and current time watched.\n player.addEventListener('timeupdate', function(event) {\n this.percent = 1;\n this.currentTime = player.currentTime;\n this.plugins.forEach(plugin => {\n if (typeof plugin.setCurrentTime == 'function') {\n plugin.getSessions().then(session => {\n plugin.setCurrentTime(session.id, event.seconds);\n return session;\n }).catch(Notification.exception);\n }\n });\n }.bind(this));\n\n // Initiate video finish procedure.\n this.player.addEventListener('ended', this.handleEnd.bind(this));\n this.player.addEventListener('pause', this.handlePause.bind(this));\n }\n\n /**\n * Subscribe to feed\n *\n * @param {int} source Feed to subscribe\n */\n subscribeTo(source) {\n const room = rooms[String(this.contextid)];\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"][data-action=\"publish\"]').forEach(button => {\n if (source == Number(this.peerid)) {\n button.classList.remove('hidden');\n } else {\n button.classList.remove('hidden');\n }\n });\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"][data-action=\"unpublish\"]').forEach(button => {\n if (source == Number(this.peerid)) {\n button.classList.remove('hidden');\n } else {\n button.classList.remove('hidden');\n }\n });\n\n if (this.remoteFeed && !this.remoteFeed.creatingSubscription && !this.remoteFeed.restart) {\n const update = {\n request: 'update',\n subscribe: [{\n feed: Number(source)\n }],\n unsubscribe: [{\n feed: Number(this.remoteFeed.current)\n }]\n };\n\n if (!source && this.remoteFeed.current) {\n delete update.subscribe;\n } else if (source && !this.remoteFeed.current) {\n delete update.unsubscribe;\n }\n\n if (this.remoteFeed.current != source) {\n this.remoteFeed.muteAudio = room.publish && (room.publish.feed === source);\n this.remoteFeed.videoroom.send({message: update});\n if (this.remoteFeed.audioTrack) {\n this.remoteFeed.audioTrack.enabled = !this.remoteFeed.muteAudio;\n }\n\n if (room.publish && this.remoteFeed.current == room.publish.feed) {\n room.publish.handleClose();\n room.publish = null;\n }\n this.remoteFeed.current = source;\n if (!source && this.remoteFeed) {\n this.remoteFeed.handleClose();\n this.remoteFeed = null;\n }\n Log.debug('[data-contextid=\"' + this.contextid + '\"] img.poster-img');\n if (Number(source)) {\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"] .videotime-embed img.poster-img'\n ).forEach(img => {\n img.classList.add('hidden');\n });\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"] .videotime-embed video'\n ).forEach(video => {\n video.classList.remove('hidden');\n });\n } else {\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"] .videotime-embed img.poster-img'\n ).forEach(img => {\n img.classList.remove('hidden');\n });\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"] .videotime-embed video'\n ).forEach(video => {\n video.srcObject = null;\n video.classList.add('hidden');\n });\n }\n }\n } else if (this.remoteFeed && this.remoteFeed.restart) {\n if (this.remoteFeed.current != source) {\n this.remoteFeed = null;\n this.subscribeTo(source);\n }\n } else if (this.remoteFeed) {\n setTimeout(() => {\n this.subscribeTo(source);\n }, 500);\n } else if (source) {\n this.remoteFeed = new Subscribe(this.contextid, this.iceservers, this.roomid, this.server, this.peerid);\n this.remoteFeed.remoteVideo = document.getElementById(this.elementId);\n this.remoteFeed.remoteAudio = document.getElementById(this.elementId).parentNode.querySelector('audio');\n this.remoteFeed.muteAudio = room.publish && (room.publish.feed === source);\n this.remoteFeed.startConnection(source);\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"] img.poster-img').forEach(img => {\n img.classList.add('hidden');\n });\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"] video').forEach(img => {\n img.classList.remove('hidden');\n });\n }\n }\n\n /**\n * Get duration of video\n *\n * @returns {Promise}\n */\n getDuration() {\n return Promise.resolve(this.currentTime);\n }\n}\n\nconst handleClick = function(e) {\n const button = e.target.closest(\n '[data-roomid] [data-action=\"publish\"], [data-roomid] [data-action=\"unpublish\"],'\n + '[data-roomid] [data-action=\"close\"], '\n + '[data-roomid] [data-action=\"switch\"], '\n + '[data-roomid] [data-action=\"mute\"], [data-roomid] [data-action=\"unmute\"]'\n );\n if (button) {\n const action = button.getAttribute('data-action'),\n contextid = e.target.closest('[data-contextid]').getAttribute('data-contextid'),\n room = rooms[String(contextid)],\n iceServers = room.iceServers,\n peerid = room.peerid,\n roomid = room.roomid,\n server = room.server,\n type = button.getAttribute('data-type');\n e.stopPropagation();\n e.preventDefault();\n if ((action == 'publish') && (!room.publish || room.publish.restart)) {\n room.publish = new Publish(contextid, iceServers, roomid, server, peerid);\n if (type == 'display') {\n room.publish.shareDisplay();\n } else {\n room.publish.shareCamera();\n }\n room.publish.startConnection();\n document\n .getElementById('video-controls-' + (type || 'camera'))\n .parentNode\n .classList\n .remove('hidden');\n document\n .getElementById('video-controls-' + (type || 'camera'))\n .parentNode\n .classList\n .add('selected');\n } else {\n if ((action == 'mute') || (action == 'unmute')) {\n button.classList.add('hidden');\n button.parentNode.querySelectorAll('[data-action=\"mute\"], [data-action=\"unmute\"]').forEach(button => {\n if (button.getAttribute('data-action') != action) {\n button.classList.remove('hidden');\n }\n });\n }\n if (room.publish) {\n room.publish.handleClick(e);\n }\n }\n }\n};\n\nclass Subscribe extends SubscribeBase {\n /**\n * Register the room\n *\n * @param {object} pluginHandle\n * @return {Promise}\n */\n register(pluginHandle) {\n // Try a registration\n return Ajax.call([{\n args: {\n handle: pluginHandle.getId(),\n id: Number(this.contextid),\n plugin: pluginHandle.plugin,\n room: this.roomid,\n ptype: false,\n feed: this.feed,\n session: pluginHandle.session.getSessionId()\n },\n contextid: this.contextid,\n fail: Notification.exception,\n methodname: 'videotimeplugin_live_join_room'\n }])[0];\n }\n\n /**\n * Attach audio stream to media element\n *\n * @param {HTMLMediaElement} audioStream Stream to attach\n */\n attachAudio(audioStream) {\n Janus.attachMediaStream(\n this.remoteVideo.parentNode.querySelector('audio'),\n audioStream\n );\n audioStream.getTracks().forEach(track => {\n this.audioTrack = track;\n track.enabled = !this.muteAudio;\n });\n }\n\n /**\n * Attach video stream to media element\n *\n * @param {HTMLMediaElement} videoStream Stream to attach\n */\n attachVideo(videoStream) {\n Janus.attachMediaStream(\n this.remoteVideo,\n videoStream\n );\n }\n}\n"],"names":["rooms","Publish","PublishBase","register","pluginHandle","Ajax","call","args","handle","getId","id","Number","this","contextid","plugin","room","roomid","ptype","session","getSessionId","fail","Notification","exception","methodname","then","response","feed","catch","publishFeed","unpublish","document","querySelectorAll","forEach","video","srcObject","parentNode","classList","add","publish","handleClose","button","remove","janus","destroy","currentCamera","Promise","resolve","currentDisplay","videoInput","videoStream","getTracks","track","enabled","stop","onLocalTrack","on","remoteStream","MediaStream","kind","mid","debug","attachMediaStream","getElementById","tracks","handleClick","e","target","closest","action","getAttribute","type","stopPropagation","preventDefault","selectedTrack","getAudioTracks","shareDisplay","shareCamera","processStream","cameraInput","navigator","mediaDevices","getUserMedia","audio","displayInput","getDisplayMedia","audiotransceiver","getTransceiver","videotransceiver","getVideoTracks","addEventListener","videoroom","replaceTracks","capture","error","push","recv","querySelector","length","createOffer","success","jsep","send","message","request","alert","VideoTime","VideoTimeBase","initialize","token","peerid","elementId","done","socket","Socket","iceservers","JSON","parse","server","String","iceServers","subscribe","restart","subscribeTo","addListeners","getPlayer","player","removeEventListener","hasPro","startWatchInterval","view","playing","bind","event","percent","currentTime","plugins","setCurrentTime","getSessions","seconds","handleEnd","handlePause","cmId","source","remoteFeed","creatingSubscription","current","setTimeout","Subscribe","remoteVideo","remoteAudio","muteAudio","startConnection","img","update","unsubscribe","audioTrack","getDuration","SubscribeBase","attachAudio","audioStream","attachVideo"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"videotime.min.js","sources":["../src/videotime.js"],"sourcesContent":["/*\n * Video time player specific js\n *\n * @package videotimeplugin_live\n * @module videotimeplugin_live/videotime\n * @copyright 2022 bdecent gmbh \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from \"core/ajax\";\nimport Config from \"core/config\";\nimport VideoTimeBase from \"mod_videotime/videotime\";\nimport Janus from 'block_deft/janus-gateway';\nimport Log from \"core/log\";\nimport Notification from \"core/notification\";\nimport PublishBase from \"block_deft/publish\";\nimport SubscribeBase from \"block_deft/subscribe\";\nimport Socket from \"videotimeplugin_live/socket\";\n\nvar rooms = {},\n wstoken;\n\nclass Publish extends PublishBase {\n /**\n * Register the room\n *\n * @param {object} pluginHandle\n * @return {Promise}\n */\n register(pluginHandle) {\n // Try a registration\n return Ajax.call([{\n args: {\n handle: pluginHandle.getId(),\n id: Number(this.contextid),\n plugin: pluginHandle.plugin,\n room: this.roomid,\n ptype: this.ptype == 'publish',\n session: pluginHandle.session.getSessionId()\n },\n contextid: this.contextid,\n fail: Notification.exception,\n methodname: 'videotimeplugin_live_join_room'\n }])[0].then(response => {\n this.feed = response.id;\n\n return response;\n }).catch(Notification.exception);\n }\n\n /**\n * Publish current video feed\n *\n * @returns {Promise}\n */\n publishFeed() {\n return Ajax.call([{\n args: {\n id: Number(this.feed),\n room: this.roomid,\n },\n contextid: this.contextid,\n fail: Notification.exception,\n methodname: 'videotimeplugin_live_publish_feed'\n }])[0];\n }\n\n\n /**\n * Stop video feed\n *\n * @returns {Promise}\n */\n unpublish() {\n document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {\n video.srcObject = null;\n video.parentNode.classList.add('hidden');\n });\n return Ajax.call([{\n args: {\n id: Number(this.feed),\n publish: false,\n room: this.roomid\n },\n contextid: this.contextid,\n fail: Notification.exception,\n methodname: 'videotimeplugin_live_publish_feed'\n }])[0];\n }\n\n handleClose() {\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"][data-action=\"publish\"]'\n ).forEach(button => {\n button.classList.remove('hidden');\n });\n\n this.janus.destroy();\n\n [\n this.currentCamera || Promise.resolve(null),\n this.currentDisplay || Promise.resolve(null),\n ].forEach(videoInput => {\n videoInput.then(videoStream => {\n if (videoStream) {\n videoStream.getTracks().forEach(track => {\n track.enabled = false;\n track.stop();\n });\n }\n\n return null;\n }).catch(Notification.exception);\n });\n }\n\n onLocalTrack(track, on) {\n const remoteStream = new MediaStream([track]);\n if (!on || (track.kind == 'audio')) {\n return;\n }\n remoteStream.mid = track.mid;\n Log.debug(on);\n Log.debug(remoteStream);\n Janus.attachMediaStream(\n document.getElementById('video-controls-' + this.tracks[track.id]),\n remoteStream\n );\n }\n\n handleClick(e) {\n const button = e.target.closest(\n '[data-contextid=\"' + this.contextid + '\"][data-action=\"publish\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"close\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"mute\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"unmute\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"switch\"], [data-contextid=\"'\n + this.contextid + '\"][data-action=\"unpublish\"]'\n );\n if (button) {\n const action = button.getAttribute('data-action'),\n type = button.getAttribute('data-type') || 'camera';\n e.stopPropagation();\n e.preventDefault();\n document.querySelectorAll(\n '[data-region=\"deft-venue\"] [data-action=\"publish\"], [data-region=\"deft-venue\"] [data-action=\"unpublish\"]'\n ).forEach(button => {\n if ((button.getAttribute('data-action') != action) || (button.getAttribute('data-type') != type)) {\n button.classList.remove('hidden');\n }\n });\n switch (action) {\n case 'close':\n document.getElementById('video-controls-' + type).srcObject = null;\n document.getElementById('video-controls-' + type).parentNode.classList.add('hidden');\n if (this.tracks[this.selectedTrack.id] == type) {\n this.unpublish();\n }\n break;\n case 'mute':\n case 'unmute':\n ((type == 'display') ? this.currentDisplay : this.currentCamera)\n .then(videoStream => {\n if (videoStream) {\n videoStream.getAudioTracks().forEach(track => {\n track.enabled = (action == 'unmute');\n });\n }\n return videoStream;\n }).catch(Notification.exception);\n break;\n case 'publish':\n Log.debug(type);\n if (type == 'display') {\n this.shareDisplay();\n } else {\n this.shareCamera();\n }\n document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {\n video.parentNode.classList.remove('selected');\n });\n document\n .getElementById('video-controls-' + type)\n .parentNode\n .classList\n .remove('hidden');\n document\n .getElementById('video-controls-' + type)\n .parentNode\n .classList\n .add('selected');\n\n this.processStream([]);\n break;\n case 'switch':\n document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {\n video.parentNode.classList.remove('selected');\n });\n if (type == 'display') {\n this.videoInput = this.currentDisplay;\n } else {\n this.videoInput = this.currentCamera;\n }\n document\n .getElementById('video-controls-' + type)\n .parentNode\n .classList\n .remove('hidden');\n document\n .getElementById('video-controls-' + type)\n .parentNode\n .classList\n .add('selected');\n this.processStream([]);\n break;\n case 'unpublish':\n this.unpublish();\n }\n }\n\n return true;\n }\n\n /**\n * Set video source to user camera\n */\n shareCamera() {\n const videoInput = this.videoInput,\n currentCamera = this.currentCamera || Promise.resolve(null);\n\n this.videoInput = currentCamera.then(videoStream => {\n if (videoStream) {\n return videoStream;\n } else {\n const cameraInput = navigator.mediaDevices.getUserMedia({\n video: true,\n audio: true\n });\n\n this.currentCamera = cameraInput.catch(() => {\n return currentCamera;\n });\n\n return cameraInput.then(videoStream => {\n this.tracks = this.tracks || {};\n videoStream.getTracks().forEach(track => {\n this.tracks[track.id] = 'camera';\n });\n\n return videoStream;\n }).catch((e) => {\n Log.debug(e);\n\n return videoInput;\n });\n }\n });\n }\n\n /**\n * Set video source to display surface\n */\n shareDisplay() {\n const videoInput = this.videoInput,\n currentDisplay = this.currentDisplay || Promise.resolve(null),\n displayInput = navigator.mediaDevices.getDisplayMedia({\n video: true,\n audio: true\n });\n\n this.videoInput = displayInput.then(videoStream => {\n this.tracks = this.tracks || {};\n videoStream.getTracks().forEach(track => {\n this.tracks[track.id] = 'display';\n });\n\n return videoStream;\n }).catch((e) => {\n Log.debug(e);\n\n return videoInput;\n });\n\n this.currentDisplay = displayInput.then(videoStream => {\n currentDisplay.then(videoStream => {\n if (videoStream) {\n videoStream.getTracks().forEach(track => {\n track.stop();\n });\n }\n\n return videoStream;\n }).catch(Notification.exception);\n\n return videoStream;\n }).catch((e) => {\n Log.debug(e);\n\n return currentDisplay;\n });\n }\n\n /**\n * Process tracks from current video stream and adjust publicatioin\n *\n * @param {array} tracks Additional tracks to add\n */\n processStream(tracks) {\n this.videoInput.then(videoStream => {\n this.tracks = this.tracks || {};\n if (videoStream) {\n const audiotransceiver = this.getTransceiver('audio'),\n videotransceiver = this.getTransceiver('video');\n videoStream.getVideoTracks().forEach(track => {\n track.addEventListener('ended', () => {\n if (this.selectedTrack.id == track.id) {\n this.unpublish();\n } else {\n document\n .getElementById('video-controls-' + this.tracks[track.id])\n .parentNode\n .classList\n .add('hidden');\n }\n });\n this.selectedTrack = track;\n if (videotransceiver) {\n this.videoroom.replaceTracks({\n tracks: [{\n type: 'video',\n mid: videotransceiver.mid,\n capture: track\n }],\n error: Notification.exception\n });\n\n return;\n }\n tracks.push({\n type: 'video',\n capture: track,\n recv: false\n });\n });\n videoStream.getAudioTracks().forEach(track => {\n if (\n document.querySelector('.hidden[data-action=\"mute\"][data-contextid=\"' + this.contextid + '\"][data-type=\"'\n + this.tracks[this.selectedTrack.id] + '\"]'\n )) {\n track.enabled = false;\n }\n\n if (audiotransceiver) {\n this.videoroom.replaceTracks({\n tracks: [{\n type: 'audio',\n mid: audiotransceiver.mid,\n capture: track\n }],\n error: Notification.exception\n });\n\n return;\n }\n tracks.push({\n type: 'audio',\n capture: track,\n recv: false\n });\n });\n if (!tracks.length) {\n return videoStream;\n }\n this.videoroom.createOffer({\n tracks: tracks,\n success: (jsep) => {\n const publish = {\n request: \"configure\",\n video: true,\n audio: true\n };\n this.videoroom.send({\n message: publish,\n jsep: jsep\n });\n },\n error: function(error) {\n Notification.alert(\"WebRTC error... \", error.message);\n }\n });\n }\n\n return videoStream;\n }).catch(Notification.exception);\n }\n}\n\nexport default class VideoTime extends VideoTimeBase {\n /**\n * Initialize player plugin\n *\n * @param {int} contextid\n * @param {string} token Deft token\n * @param {int} peerid Peer id for audio room participant\n *\n * @returns {bool}\n */\n initialize(contextid, token, peerid) {\n Log.debug(\"Initializing Video Time \" + this.elementId);\n\n this.contextid = contextid;\n this.peerid = peerid;\n\n if (this.instance.token) {\n wstoken = this.instance.token;\n }\n\n this.getRoom().then(response => {\n const socket = new Socket(contextid, token);\n\n this.iceservers = JSON.parse(response.iceservers);\n this.roomid = response.roomid;\n this.server = response.server;\n\n rooms[String(contextid)] = {\n contextid: contextid,\n peerid: peerid,\n roomid: response.roomid,\n server: response.server,\n iceServers: JSON.parse(response.iceservers)\n };\n this.roomid = response.roomid;\n\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"] .videotime-control').forEach(control => {\n control.classList.remove('hidden');\n });\n\n socket.subscribe(() => {\n this.getFeed().then(response => {\n const room = rooms[String(contextid)];\n if (room.publish && room.publish.restart) {\n if (response.feed == peerid) {\n this.unpublish();\n }\n room.publish = null;\n }\n this.subscribeTo(Number(response.feed));\n\n return response;\n }).catch(Notification.exception);\n });\n\n return response;\n }).catch(Notification.exception);\n\n this.addListeners();\n\n return true;\n }\n\n /**\n * Fetch room info\n *\n * @returns {Promise}\n */\n getRoom() {\n if (wstoken) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', wstoken);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_live_get_room');\n data.set('contextid', this.contextid);\n\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n\n return Ajax.call([{\n methodname: 'videotimeplugin_live_get_room',\n args: {contextid: this.contextid},\n fail: Notification.exception\n }])[0];\n }\n\n /**\n * Fetch current feed\n *\n * @returns {Promise}\n */\n getFeed() {\n if (wstoken) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', wstoken);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_live_get_feed');\n data.set('contextid', this.contextid);\n\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n\n return Ajax.call([{\n methodname: 'videotimeplugin_live_get_feed',\n args: {contextid: this.contextid},\n fail: Notification.exception\n }])[0];\n }\n\n /**\n * Get video element\n *\n * @returns {HTMLMediaElement}\n */\n getPlayer() {\n return document.getElementById(this.elementId);\n }\n\n /**\n * Register player events to respond to user interaction and play progress.\n */\n addListeners() {\n const player = this.getPlayer();\n\n document.querySelector('body').removeEventListener('click', handleClick);\n document.querySelector('body').addEventListener('click', handleClick);\n\n if (!player) {\n Log.debug('Player was not properly initialized for course module ' + this.cmId);\n return;\n }\n\n // Fire view event in Moodle on first play only.\n player.addEventListener('play', () => {\n if (this.hasPro) {\n this.startWatchInterval();\n }\n this.view();\n return true;\n });\n\n // Features beyond this point are for pro only.\n if (!this.hasPro) {\n return;\n }\n\n // Note: Vimeo player does not support multiple events in a single on() call. Each requires it's own function.\n\n // Catch all events where video plays.\n player.addEventListener('play', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME play');\n }.bind(this));\n player.addEventListener('playing', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME playing');\n }.bind(this));\n\n // Catch all events where video stops.\n player.addEventListener('pause', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME pause');\n }.bind(this));\n player.addEventListener('stalled', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME stalled');\n }.bind(this));\n player.addEventListener('suspend', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME suspend');\n }.bind(this));\n player.addEventListener('abort', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME abort');\n }.bind(this));\n\n // Always update internal values for percent and current time watched.\n player.addEventListener('timeupdate', function(event) {\n this.percent = 1;\n this.currentTime = player.currentTime;\n this.plugins.forEach(plugin => {\n if (typeof plugin.setCurrentTime == 'function') {\n plugin.getSessions().then(session => {\n plugin.setCurrentTime(session.id, event.seconds);\n return session;\n }).catch(Notification.exception);\n }\n });\n }.bind(this));\n\n // Initiate video finish procedure.\n player.addEventListener('ended', this.handleEnd.bind(this));\n player.addEventListener('pause', this.handlePause.bind(this));\n }\n\n /**\n * Subscribe to feed\n *\n * @param {int} source Feed to subscribe\n */\n subscribeTo(source) {\n const room = rooms[String(this.contextid)];\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"][data-action=\"publish\"]').forEach(button => {\n if (source == Number(this.peerid)) {\n button.classList.remove('hidden');\n } else {\n button.classList.remove('hidden');\n }\n });\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"][data-action=\"unpublish\"]').forEach(button => {\n if (source == Number(this.peerid)) {\n button.classList.remove('hidden');\n } else {\n button.classList.remove('hidden');\n }\n });\n\n if (this.remoteFeed && !this.remoteFeed.creatingSubscription && !this.remoteFeed.restart) {\n const update = {\n request: 'update',\n subscribe: [{\n feed: Number(source)\n }],\n unsubscribe: [{\n feed: Number(this.remoteFeed.current)\n }]\n };\n\n if (!source && this.remoteFeed.current) {\n delete update.subscribe;\n } else if (source && !this.remoteFeed.current) {\n delete update.unsubscribe;\n }\n\n if (this.remoteFeed.current != source) {\n this.remoteFeed.muteAudio = room.publish && (room.publish.feed === source);\n this.remoteFeed.videoroom.send({message: update});\n if (this.remoteFeed.audioTrack) {\n this.remoteFeed.audioTrack.enabled = !this.remoteFeed.muteAudio;\n }\n\n if (room.publish && this.remoteFeed.current == room.publish.feed) {\n room.publish.handleClose();\n room.publish = null;\n }\n this.remoteFeed.current = source;\n if (!source && this.remoteFeed) {\n this.remoteFeed.handleClose();\n this.remoteFeed = null;\n }\n if (Number(source)) {\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"] .videotime-embed img.poster-img'\n ).forEach(img => {\n img.classList.add('hidden');\n });\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"] .videotime-embed video'\n ).forEach(video => {\n video.classList.remove('hidden');\n });\n } else {\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"] .videotime-embed img.poster-img'\n ).forEach(img => {\n img.classList.remove('hidden');\n });\n document.querySelectorAll(\n '[data-contextid=\"' + this.contextid + '\"] .videotime-embed video'\n ).forEach(video => {\n video.srcObject = null;\n video.classList.add('hidden');\n });\n }\n }\n } else if (this.remoteFeed && this.remoteFeed.restart) {\n if (this.remoteFeed.current != source) {\n this.remoteFeed = null;\n this.subscribeTo(source);\n }\n } else if (this.remoteFeed) {\n setTimeout(() => {\n this.subscribeTo(source);\n }, 500);\n } else if (source) {\n this.remoteFeed = new Subscribe(this.contextid, this.iceservers, this.roomid, this.server, this.peerid);\n this.remoteFeed.remoteVideo = document.getElementById(this.elementId);\n this.remoteFeed.remoteAudio = document.getElementById(this.elementId).parentNode.querySelector('audio');\n this.remoteFeed.muteAudio = room.publish && (room.publish.feed === source);\n this.remoteFeed.startConnection(source);\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"] img.poster-img').forEach(img => {\n img.classList.add('hidden');\n });\n document.querySelectorAll('[data-contextid=\"' + this.contextid + '\"] video').forEach(img => {\n img.classList.remove('hidden');\n });\n }\n }\n\n /**\n * Get duration of video\n *\n * @returns {Promise}\n */\n getDuration() {\n return Promise.resolve(this.currentTime);\n }\n}\n\nconst handleClick = function(e) {\n const button = e.target.closest(\n '[data-roomid] [data-action=\"publish\"], [data-roomid] [data-action=\"unpublish\"],'\n + '[data-roomid] [data-action=\"close\"], '\n + '[data-roomid] [data-action=\"switch\"], '\n + '[data-roomid] [data-action=\"mute\"], [data-roomid] [data-action=\"unmute\"]'\n );\n if (button) {\n const action = button.getAttribute('data-action'),\n contextid = e.target.closest('[data-contextid]').getAttribute('data-contextid'),\n room = rooms[String(contextid)],\n iceServers = room.iceServers,\n peerid = room.peerid,\n roomid = room.roomid,\n server = room.server,\n type = button.getAttribute('data-type');\n e.stopPropagation();\n e.preventDefault();\n if ((action == 'publish') && (!room.publish || room.publish.restart)) {\n room.publish = new Publish(contextid, iceServers, roomid, server, peerid);\n if (type == 'display') {\n room.publish.shareDisplay();\n } else {\n room.publish.shareCamera();\n }\n room.publish.startConnection();\n document\n .getElementById('video-controls-' + (type || 'camera'))\n .parentNode\n .classList\n .remove('hidden');\n document\n .getElementById('video-controls-' + (type || 'camera'))\n .parentNode\n .classList\n .add('selected');\n } else {\n if ((action == 'mute') || (action == 'unmute')) {\n button.classList.add('hidden');\n button.parentNode.querySelectorAll('[data-action=\"mute\"], [data-action=\"unmute\"]').forEach(button => {\n if (button.getAttribute('data-action') != action) {\n button.classList.remove('hidden');\n }\n });\n }\n if (room.publish) {\n room.publish.handleClick(e);\n }\n }\n }\n};\n\nclass Subscribe extends SubscribeBase {\n /**\n * Register the room\n *\n * @param {object} pluginHandle\n * @return {Promise}\n */\n register(pluginHandle) {\n // Try a registration\n if (wstoken) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', wstoken);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_live_join_room');\n data.set('handle', pluginHandle.getId());\n data.set('id', Number(this.contextid));\n data.set('plugin', pluginHandle.plugin);\n data.set('room', this.roomid);\n data.set('feed', this.feed);\n data.set('session', pluginHandle.session.getSessionId());\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n }).catch(Notification.exception);\n }\n\n return Ajax.call([{\n args: {\n handle: pluginHandle.getId(),\n id: Number(this.contextid),\n plugin: pluginHandle.plugin,\n room: this.roomid,\n ptype: false,\n feed: this.feed,\n session: pluginHandle.session.getSessionId()\n },\n contextid: this.contextid,\n fail: Notification.exception,\n methodname: 'videotimeplugin_live_join_room'\n }])[0];\n }\n\n /**\n * Attach audio stream to media element\n *\n * @param {HTMLMediaElement} audioStream Stream to attach\n */\n attachAudio(audioStream) {\n Janus.attachMediaStream(\n this.remoteVideo.parentNode.querySelector('audio'),\n audioStream\n );\n audioStream.getTracks().forEach(track => {\n this.audioTrack = track;\n track.enabled = !this.muteAudio;\n });\n }\n\n /**\n * Attach video stream to media element\n *\n * @param {HTMLMediaElement} videoStream Stream to attach\n */\n attachVideo(videoStream) {\n Janus.attachMediaStream(\n this.remoteVideo,\n videoStream\n );\n }\n}\n"],"names":["wstoken","rooms","Publish","PublishBase","register","pluginHandle","Ajax","call","args","handle","getId","id","Number","this","contextid","plugin","room","roomid","ptype","session","getSessionId","fail","Notification","exception","methodname","then","response","feed","catch","publishFeed","unpublish","document","querySelectorAll","forEach","video","srcObject","parentNode","classList","add","publish","handleClose","button","remove","janus","destroy","currentCamera","Promise","resolve","currentDisplay","videoInput","videoStream","getTracks","track","enabled","stop","onLocalTrack","on","remoteStream","MediaStream","kind","mid","debug","attachMediaStream","getElementById","tracks","handleClick","e","target","closest","action","getAttribute","type","stopPropagation","preventDefault","selectedTrack","getAudioTracks","shareDisplay","shareCamera","processStream","cameraInput","navigator","mediaDevices","getUserMedia","audio","displayInput","getDisplayMedia","audiotransceiver","getTransceiver","videotransceiver","getVideoTracks","addEventListener","videoroom","replaceTracks","capture","error","push","recv","querySelector","length","createOffer","success","jsep","send","message","request","alert","VideoTime","VideoTimeBase","initialize","token","peerid","elementId","instance","getRoom","socket","Socket","iceservers","JSON","parse","server","String","iceServers","control","subscribe","getFeed","restart","subscribeTo","addListeners","url","URL","Config","wwwroot","data","searchParams","set","fetch","ok","exeption","json","getPlayer","player","removeEventListener","hasPro","startWatchInterval","view","playing","bind","event","percent","currentTime","plugins","setCurrentTime","getSessions","seconds","handleEnd","handlePause","cmId","source","remoteFeed","creatingSubscription","current","setTimeout","Subscribe","remoteVideo","remoteAudio","muteAudio","startConnection","img","update","unsubscribe","audioTrack","getDuration","SubscribeBase","attachAudio","audioStream","attachVideo"],"mappings":"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"} \ No newline at end of file diff --git a/plugin/live/amd/src/videotime.js b/plugin/live/amd/src/videotime.js index d1dac2ea..55a7ea64 100644 --- a/plugin/live/amd/src/videotime.js +++ b/plugin/live/amd/src/videotime.js @@ -8,6 +8,7 @@ */ import Ajax from "core/ajax"; +import Config from "core/config"; import VideoTimeBase from "mod_videotime/videotime"; import Janus from 'block_deft/janus-gateway'; import Log from "core/log"; @@ -16,7 +17,8 @@ import PublishBase from "block_deft/publish"; import SubscribeBase from "block_deft/subscribe"; import Socket from "videotimeplugin_live/socket"; -var rooms = {}; +var rooms = {}, + wstoken; class Publish extends PublishBase { /** @@ -283,8 +285,6 @@ class Publish extends PublishBase { currentDisplay.then(videoStream => { if (videoStream) { videoStream.getTracks().forEach(track => { - Log.debug('stop track'); - Log.debug(track); track.stop(); }); } @@ -411,53 +411,111 @@ export default class VideoTime extends VideoTimeBase { this.contextid = contextid; this.peerid = peerid; - Ajax.call([{ - methodname: 'videotimeplugin_live_get_room', - args: {contextid: contextid}, - done: (response) => { - const socket = new Socket(contextid, token); - - this.iceservers = JSON.parse(response.iceservers); - this.roomid = response.roomid; - this.server = response.server; - - rooms[String(contextid)] = { - contextid: contextid, - peerid: peerid, - roomid: response.roomid, - server: response.server, - iceServers: JSON.parse(response.iceservers) - }; - this.roomid = response.roomid; - - document.querySelector('[data-contextid="' + this.contextid + '"] .videotime-control').classList.remove('hidden'); - - socket.subscribe(() => { - Ajax.call([{ - methodname: 'videotimeplugin_live_get_feed', - args: {contextid: contextid}, - done: (response) => { - const room = rooms[String(contextid)]; - if (room.publish && room.publish.restart) { - if (response.feed == peerid) { - this.unpublish(); - } - room.publish = null; - } - this.subscribeTo(Number(response.feed)); - }, - fail: Notification.exception - }]); - }); - }, - fail: Notification.exception - }]); + if (this.instance.token) { + wstoken = this.instance.token; + } + + this.getRoom().then(response => { + const socket = new Socket(contextid, token); + + this.iceservers = JSON.parse(response.iceservers); + this.roomid = response.roomid; + this.server = response.server; + + rooms[String(contextid)] = { + contextid: contextid, + peerid: peerid, + roomid: response.roomid, + server: response.server, + iceServers: JSON.parse(response.iceservers) + }; + this.roomid = response.roomid; + + document.querySelectorAll('[data-contextid="' + this.contextid + '"] .videotime-control').forEach(control => { + control.classList.remove('hidden'); + }); + + socket.subscribe(() => { + this.getFeed().then(response => { + const room = rooms[String(contextid)]; + if (room.publish && room.publish.restart) { + if (response.feed == peerid) { + this.unpublish(); + } + room.publish = null; + } + this.subscribeTo(Number(response.feed)); + + return response; + }).catch(Notification.exception); + }); + + return response; + }).catch(Notification.exception); this.addListeners(); return true; } + /** + * Fetch room info + * + * @returns {Promise} + */ + getRoom() { + if (wstoken) { + const url = new URL(Config.wwwroot + '/webservice/rest/server.php'), + data = url.searchParams; + data.set('wstoken', wstoken); + data.set('moodlewsrestformat', 'json'); + data.set('wsfunction', 'videotimeplugin_live_get_room'); + data.set('contextid', this.contextid); + + return fetch(url).then((response) => { + if (!response.ok) { + Notification.exeption('Web service error'); + } + return response.json(); + }); + } + + return Ajax.call([{ + methodname: 'videotimeplugin_live_get_room', + args: {contextid: this.contextid}, + fail: Notification.exception + }])[0]; + } + + /** + * Fetch current feed + * + * @returns {Promise} + */ + getFeed() { + if (wstoken) { + const url = new URL(Config.wwwroot + '/webservice/rest/server.php'), + data = url.searchParams; + data.set('wstoken', wstoken); + data.set('moodlewsrestformat', 'json'); + data.set('wsfunction', 'videotimeplugin_live_get_feed'); + data.set('contextid', this.contextid); + + return fetch(url).then((response) => { + if (!response.ok) { + Notification.exeption('Web service error'); + } + return response.json(); + }); + } + + return Ajax.call([{ + methodname: 'videotimeplugin_live_get_feed', + args: {contextid: this.contextid}, + fail: Notification.exception + }])[0]; + } + /** * Get video element * @@ -599,7 +657,6 @@ export default class VideoTime extends VideoTimeBase { this.remoteFeed.handleClose(); this.remoteFeed = null; } - Log.debug('[data-contextid="' + this.contextid + '"] img.poster-img'); if (Number(source)) { document.querySelectorAll( '[data-contextid="' + this.contextid + '"] .videotime-embed img.poster-img' @@ -720,6 +777,26 @@ class Subscribe extends SubscribeBase { */ register(pluginHandle) { // Try a registration + if (wstoken) { + const url = new URL(Config.wwwroot + '/webservice/rest/server.php'), + data = url.searchParams; + data.set('wstoken', wstoken); + data.set('moodlewsrestformat', 'json'); + data.set('wsfunction', 'videotimeplugin_live_join_room'); + data.set('handle', pluginHandle.getId()); + data.set('id', Number(this.contextid)); + data.set('plugin', pluginHandle.plugin); + data.set('room', this.roomid); + data.set('feed', this.feed); + data.set('session', pluginHandle.session.getSessionId()); + return fetch(url).then((response) => { + if (!response.ok) { + Notification.exeption('Web service error'); + } + return response.json(); + }).catch(Notification.exception); + } + return Ajax.call([{ args: { handle: pluginHandle.getId(),