diff --git a/plugin/live/amd/build/videotime.min.js b/plugin/live/amd/build/videotime.min.js index 94eece3d..96ea4b89 100644 --- a/plugin/live/amd/build/videotime.min.js +++ b/plugin/live/amd/build/videotime.min.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})).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=>(videoInput&&videoInput.then((videoStream=>(videoStream&&videoStream.getTracks().forEach((track=>{_log.default.debug(track)})),videoStream))).catch(_notification.default.exception),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((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}addListeners(){document.querySelector("body").removeEventListener("click",handleClick),document.querySelector("body").addEventListener("click",handleClick)}subscribeTo(source){_log.default.debug(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")})),_log.default.debug(source),!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")}))))}}}_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),_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})); //# 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 d3538ee3..698d5bd4 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 }).catch(Notification.exception);\n }\n\n /**\n * Publish current video feed\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 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 if (videoInput) {\n videoInput.then(videoStream => {\n if (videoStream) {\n videoStream.getTracks().forEach(track => {\n Log.debug(track); //track.stop();\n });\n }\n return videoStream;\n }).catch(Notification.exception);\n }\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\n return videoStream;\n }).catch((e) => {\n Log.debug(e);\n\n return currentDisplay;\n });\n }\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 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 * Register player events to respond to user interaction and play progress.\n */\n addListeners() {\n document.querySelector('body').removeEventListener('click', handleClick);\n document.querySelector('body').addEventListener('click', handleClick);\n return;\n }\n\n /**\n * Subscribe to feed\n *\n * @param {int} source Feed to subscribe\n */\n subscribeTo(source) {\n Log.debug(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 Log.debug(source);\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\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 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 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","removeEventListener","source","remoteFeed","creatingSubscription","current","setTimeout","Subscribe","remoteVideo","remoteAudio","muteAudio","startConnection","img","update","unsubscribe","audioTrack","SubscribeBase","attachAudio","audioStream","attachVideo"],"mappings":";;;;;;;;qbAkBIA,MAAQ,SAENC,gBAAgBC,iBAOlBC,SAASC,qBAEEC,cAAKC,KAAK,CAAC,CACdC,KAAM,CACFC,OAAQJ,aAAaK,QACrBC,GAAIC,OAAOC,KAAKC,WAChBC,OAAQV,aAAaU,OACrBC,KAAMH,KAAKI,OACXC,MAAqB,WAAdL,KAAKK,MACZC,QAASd,aAAac,QAAQC,gBAElCN,UAAWD,KAAKC,UAChBO,KAAMC,sBAAaC,UACnBC,WAAY,oCACZ,GAAGC,MAAKC,gBACHC,KAAOD,SAASf,MACtBiB,MAAMN,sBAAaC,WAM1BM,qBACWvB,cAAKC,KAAK,CAAC,CACdC,KAAM,CACFG,GAAIC,OAAOC,KAAKc,MAChBX,KAAMH,KAAKI,QAEfH,UAAWD,KAAKC,UAChBO,KAAMC,sBAAaC,UACnBC,WAAY,uCACZ,GAORM,mBACIC,SAASC,iBAAiB,mDAAmDC,SAAQC,QACjFA,MAAMC,UAAY,KAClBD,MAAME,WAAWC,UAAUC,IAAI,aAE5BhC,cAAKC,KAAK,CAAC,CACdC,KAAM,CACFG,GAAIC,OAAOC,KAAKc,MAChBY,SAAS,EACTvB,KAAMH,KAAKI,QAEfH,UAAWD,KAAKC,UAChBO,KAAMC,sBAAaC,UACnBC,WAAY,uCACZ,GAGRgB,cACIT,SAASC,iBACL,oBAAsBnB,KAAKC,UAAY,6BACzCmB,SAAQQ,SACNA,OAAOJ,UAAUK,OAAO,kBAGvBC,MAAMC,WAGP/B,KAAKgC,eAAiBC,QAAQC,QAAQ,MACtClC,KAAKmC,gBAAkBF,QAAQC,QAAQ,OACzCd,SAAQgB,aACNA,WAAWxB,MAAKyB,cACRA,aACAA,YAAYC,YAAYlB,SAAQmB,QAC5BA,MAAMC,SAAU,EAChBD,MAAME,UAIP,QACR1B,MAAMN,sBAAaC,cAI9BgC,aAAaH,MAAOI,UACVC,aAAe,IAAIC,YAAY,CAACN,QACjCI,IAAqB,SAAdJ,MAAMO,OAGlBF,aAAaG,IAAMR,MAAMQ,iBACrBC,MAAML,iBACNK,MAAMJ,oCACJK,kBACF/B,SAASgC,eAAe,kBAAoBlD,KAAKmD,OAAOZ,MAAMzC,KAC9D8C,eAIRQ,YAAYC,SACFzB,OAASyB,EAAEC,OAAOC,QACpB,oBAAsBvD,KAAKC,UAAY,+CACrCD,KAAKC,UAAY,6CACjBD,KAAKC,UAAY,4CACjBD,KAAKC,UAAY,8CACjBD,KAAKC,UAAY,8CACjBD,KAAKC,UAAY,kCAEnB2B,OAAQ,OACF4B,OAAS5B,OAAO6B,aAAa,eAC/BC,KAAO9B,OAAO6B,aAAa,cAAgB,gBAC/CJ,EAAEM,kBACFN,EAAEO,iBACF1C,SAASC,iBACL,4GACFC,SAAQQ,SACDA,OAAO6B,aAAa,gBAAkBD,QAAY5B,OAAO6B,aAAa,cAAgBC,MACvF9B,OAAOJ,UAAUK,OAAO,aAGxB2B,YACC,QACDtC,SAASgC,eAAe,kBAAoBQ,MAAMpC,UAAY,KAC9DJ,SAASgC,eAAe,kBAAoBQ,MAAMnC,WAAWC,UAAUC,IAAI,UACvEzB,KAAKmD,OAAOnD,KAAK6D,cAAc/D,KAAO4D,WACjCzC,sBAGR,WACA,UACS,WAARyC,KAAqB1D,KAAKmC,eAAiBnC,KAAKgC,eACjDpB,MAAKyB,cACEA,aACAA,YAAYyB,iBAAiB1C,SAAQmB,QACjCA,MAAMC,QAAqB,UAAVgB,UAGlBnB,eACRtB,MAAMN,sBAAaC,qBAErB,uBACGsC,MAAMU,MACE,WAARA,UACKK,oBAEAC,cAET9C,SAASC,iBAAiB,mDAAmDC,SAAQC,QACjFA,MAAME,WAAWC,UAAUK,OAAO,eAEtCX,SACKgC,eAAe,kBAAoBQ,MACnCnC,WACAC,UACAK,OAAO,UACZX,SACKgC,eAAe,kBAAoBQ,MACnCnC,WACAC,UACAC,IAAI,iBAEJwC,cAAc,cAElB,SACD/C,SAASC,iBAAiB,mDAAmDC,SAAQC,QACjFA,MAAME,WAAWC,UAAUK,OAAO,oBAG7BO,WADG,WAARsB,KACkB1D,KAAKmC,eAELnC,KAAKgC,cAE3Bd,SACKgC,eAAe,kBAAoBQ,MACnCnC,WACAC,UACAK,OAAO,UACZX,SACKgC,eAAe,kBAAoBQ,MACnCnC,WACAC,UACAC,IAAI,iBACJwC,cAAc,cAElB,iBACIhD,oBAIV,EAMX+C,oBACU5B,WAAapC,KAAKoC,WACpBJ,cAAgBhC,KAAKgC,eAAiBC,QAAQC,QAAQ,WAErDE,WAAaJ,cAAcpB,MAAKyB,iBAC7BA,mBACOA,YACJ,OACG6B,YAAcC,UAAUC,aAAaC,aAAa,CACpDhD,OAAO,EACPiD,OAAO,gBAGNtC,cAAgBkC,YAAYnD,OAAM,IAC5BiB,gBAGJkC,YAAYtD,MAAKyB,mBACfc,OAASnD,KAAKmD,QAAU,GAC7Bd,YAAYC,YAAYlB,SAAQmB,aACvBY,OAAOZ,MAAMzC,IAAM,YAGrBuC,eACRtB,OAAOsC,iBACFL,MAAMK,GAEHjB,kBASvB2B,qBACU3B,WAAapC,KAAKoC,WACpBD,eAAiBnC,KAAKmC,gBAAkBF,QAAQC,QAAQ,MACxDqC,aAAeJ,UAAUC,aAAaI,gBAAgB,CACtDnD,OAAO,EACPiD,OAAO,SAGNlC,WAAamC,aAAa3D,MAAKyB,cAC5BD,YACAA,WAAWxB,MAAKyB,cACRA,aACAA,YAAYC,YAAYlB,SAAQmB,qBACxBS,MAAMT,UAGXF,eACRtB,MAAMN,sBAAaC,gBAErByC,OAASnD,KAAKmD,QAAU,GAC7Bd,YAAYC,YAAYlB,SAAQmB,aACvBY,OAAOZ,MAAMzC,IAAM,aAGrBuC,eACRtB,OAAOsC,iBACFL,MAAMK,GAEHjB,mBAGND,eAAiBoC,aAAa3D,MAAKyB,cACpCF,eAAevB,MAAKyB,cACZA,aACAA,YAAYC,YAAYlB,SAAQmB,qBACxBS,MAAM,2BACNA,MAAMT,OACVA,MAAME,aAKXJ,eACRtB,OAAOsC,iBACFL,MAAMK,GAEHlB,kBAIf8B,cAAcd,aACLf,WAAWxB,MAAKyB,sBACZc,OAASnD,KAAKmD,QAAU,GACzBd,YAAa,OACPoC,iBAAmBzE,KAAK0E,eAAe,SACzCC,iBAAmB3E,KAAK0E,eAAe,YAC3CrC,YAAYuC,iBAAiBxD,SAAQmB,QACjCA,MAAMsC,iBAAiB,SAAS,KACxB7E,KAAK6D,cAAc/D,IAAMyC,MAAMzC,QAC1BmB,YAELC,SACKgC,eAAe,kBAAoBlD,KAAKmD,OAAOZ,MAAMzC,KACrDyB,WACAC,UACAC,IAAI,kBAGZoC,cAAgBtB,MACjBoC,sBACKG,UAAUC,cAAc,CACzB5B,OAAQ,CAAC,CACLO,KAAM,QACNX,IAAK4B,iBAAiB5B,IACtBiC,QAASzC,QAEb0C,MAAOxE,sBAAaC,YAK5ByC,OAAO+B,KAAK,CACRxB,KAAM,QACNsB,QAASzC,MACT4C,MAAM,OAGd9C,YAAYyB,iBAAiB1C,SAAQmB,QAE7BrB,SAASkE,cAAc,+CAAiDpF,KAAKC,UAAY,iBACvFD,KAAKmD,OAAOnD,KAAK6D,cAAc/D,IAAM,QAEvCyC,MAAMC,SAAU,GAGhBiC,sBACKK,UAAUC,cAAc,CACzB5B,OAAQ,CAAC,CACLO,KAAM,QACNX,IAAK0B,iBAAiB1B,IACtBiC,QAASzC,QAEb0C,MAAOxE,sBAAaC,YAK5ByC,OAAO+B,KAAK,CACRxB,KAAM,QACNsB,QAASzC,MACT4C,MAAM,QAGThC,OAAOkC,cACDhD,iBAENyC,UAAUQ,YAAY,CACvBnC,OAAQA,OACRoC,QAAUC,YAMDV,UAAUW,KAAK,CAChBC,QANY,CACZC,QAAS,YACTtE,OAAO,EACPiD,OAAO,GAIPkB,KAAMA,QAGdP,MAAO,SAASA,6BACCW,MAAM,mBAAoBX,MAAMS,mBAKlDrD,eACRtB,MAAMN,sBAAaC,kBAITmF,kBAAkBC,mBACnCC,WAAW9F,UAAW+F,MAAOC,4BACrBjD,MAAM,2BAA6BhD,KAAKkG,gBAEvCjG,UAAYA,eACZgG,OAASA,qBAETvG,KAAK,CAAC,CACPiB,WAAY,gCACZhB,KAAM,CAACM,UAAWA,WAClBkG,KAAOtF,iBACGuF,OAAS,IAAIC,gBAAOpG,UAAW+F,YAEhCM,WAAaC,KAAKC,MAAM3F,SAASyF,iBACjClG,OAASS,SAAST,YAClBqG,OAAS5F,SAAS4F,OAEvBrH,MAAMsH,OAAOzG,YAAc,CACvBA,UAAWA,UACXgG,OAAQA,OACR7F,OAAQS,SAAST,OACjBqG,OAAQ5F,SAAS4F,OACjBE,WAAYJ,KAAKC,MAAM3F,SAASyF,kBAE/BlG,OAASS,SAAST,OAEvBc,SAASkE,cAAc,oBAAsBpF,KAAKC,UAAY,yBAAyBuB,UAAUK,OAAO,UAExGuE,OAAOQ,WAAU,mBACRlH,KAAK,CAAC,CACPiB,WAAY,gCACZhB,KAAM,CAACM,UAAWA,WAClBkG,KAAOtF,iBACGV,KAAOf,MAAMsH,OAAOzG,YACtBE,KAAKuB,SAAWvB,KAAKuB,QAAQmF,UACzBhG,SAASC,MAAQmF,aACZhF,YAETd,KAAKuB,QAAU,WAEdoF,YAAY/G,OAAOc,SAASC,QAErCN,KAAMC,sBAAaC,iBAI/BF,KAAMC,sBAAaC,kBAGlBqG,gBAEE,EAMXA,eACI7F,SAASkE,cAAc,QAAQ4B,oBAAoB,QAAS5D,aAC5DlC,SAASkE,cAAc,QAAQP,iBAAiB,QAASzB,aAS7D0D,YAAYG,qBACJjE,MAAMiE,cACJ9G,KAAOf,MAAMsH,OAAO1G,KAAKC,eAC/BiB,SAASC,iBAAiB,oBAAsBnB,KAAKC,UAAY,6BAA6BmB,SAAQQ,SACpF7B,OAAOC,KAAKiG,QACtBrE,OAAOJ,UAAUK,OAAO,aAKhCX,SAASC,iBAAiB,oBAAsBnB,KAAKC,UAAY,+BAA+BmB,SAAQQ,SACtF7B,OAAOC,KAAKiG,QACtBrE,OAAOJ,UAAUK,OAAO,0BAK5BmB,MAAMiE,SAENjH,KAAKkH,YAAelH,KAAKkH,WAAWC,sBAAyBnH,KAAKkH,WAAWL,QA2DtE7G,KAAKkH,YAAclH,KAAKkH,WAAWL,QACtC7G,KAAKkH,WAAWE,SAAWH,cACtBC,WAAa,UACbJ,YAAYG,SAEdjH,KAAKkH,WACZG,YAAW,UACFP,YAAYG,UAClB,KACIA,cACFC,WAAa,IAAII,UAAUtH,KAAKC,UAAWD,KAAKsG,WAAYtG,KAAKI,OAAQJ,KAAKyG,OAAQzG,KAAKiG,aAC3FiB,WAAWK,YAAcrG,SAASgC,eAAelD,KAAKkG,gBACtDgB,WAAWM,YAActG,SAASgC,eAAelD,KAAKkG,WAAW3E,WAAW6D,cAAc,cAC1F8B,WAAWO,UAAYtH,KAAKuB,SAAYvB,KAAKuB,QAAQZ,OAASmG,YAC9DC,WAAWQ,gBAAgBT,QAChC/F,SAASC,iBAAiB,oBAAsBnB,KAAKC,UAAY,qBAAqBmB,SAAQuG,MAC1FA,IAAInG,UAAUC,IAAI,aAEtBP,SAASC,iBAAiB,oBAAsBnB,KAAKC,UAAY,YAAYmB,SAAQuG,MACjFA,IAAInG,UAAUK,OAAO,kBA9E6D,OAChF+F,OAAS,CACXjC,QAAS,SACTiB,UAAW,CAAC,CACR9F,KAAMf,OAAOkH,UAEjBY,YAAa,CAAC,CACV/G,KAAMf,OAAOC,KAAKkH,WAAWE,aAIhCH,QAAUjH,KAAKkH,WAAWE,eACpBQ,OAAOhB,UACPK,SAAWjH,KAAKkH,WAAWE,gBAC3BQ,OAAOC,YAGd7H,KAAKkH,WAAWE,SAAWH,cACtBC,WAAWO,UAAYtH,KAAKuB,SAAYvB,KAAKuB,QAAQZ,OAASmG,YAC9DC,WAAWpC,UAAUW,KAAK,CAACC,QAASkC,SACrC5H,KAAKkH,WAAWY,kBACXZ,WAAWY,WAAWtF,SAAWxC,KAAKkH,WAAWO,WAGtDtH,KAAKuB,SAAY1B,KAAKkH,WAAWE,SAAWjH,KAAKuB,QAAQZ,OACzDX,KAAKuB,QAAQC,cACbxB,KAAKuB,QAAU,WAEdwF,WAAWE,QAAUH,QACrBA,QAAUjH,KAAKkH,kBACXA,WAAWvF,mBACXuF,WAAa,mBAElBlE,MAAM,oBAAsBhD,KAAKC,UAAY,qBAC7CF,OAAOkH,SACP/F,SAASC,iBACL,oBAAsBnB,KAAKC,UAAY,sCACzCmB,SAAQuG,MACNA,IAAInG,UAAUC,IAAI,aAEtBP,SAASC,iBACL,oBAAsBnB,KAAKC,UAAY,6BACzCmB,SAAQC,QACNA,MAAMG,UAAUK,OAAO,eAG3BX,SAASC,iBACL,oBAAsBnB,KAAKC,UAAY,sCACzCmB,SAAQuG,MACNA,IAAInG,UAAUK,OAAO,aAEzBX,SAASC,iBACL,oBAAsBnB,KAAKC,UAAY,6BACzCmB,SAAQC,QACNA,MAAMC,UAAY,KAClBD,MAAMG,UAAUC,IAAI,kDA6BtC2B,YAAc,SAASC,SACnBzB,OAASyB,EAAEC,OAAOC,QACpB,yOAKA3B,OAAQ,OACF4B,OAAS5B,OAAO6B,aAAa,eAC/BxD,UAAYoD,EAAEC,OAAOC,QAAQ,oBAAoBE,aAAa,kBAC9DtD,KAAOf,MAAMsH,OAAOzG,YACpB0G,WAAaxG,KAAKwG,WAClBV,OAAS9F,KAAK8F,OACd7F,OAASD,KAAKC,OACdqG,OAAStG,KAAKsG,OACd/C,KAAO9B,OAAO6B,aAAa,aAC/BJ,EAAEM,kBACFN,EAAEO,iBACa,WAAVJ,QAA2BrD,KAAKuB,UAAWvB,KAAKuB,QAAQmF,SAmB1C,QAAVrD,QAAgC,UAAVA,SACvB5B,OAAOJ,UAAUC,IAAI,UACrBG,OAAOL,WAAWJ,iBAAiB,gDAAgDC,SAAQQ,SACnFA,OAAO6B,aAAa,gBAAkBD,QACtC5B,OAAOJ,UAAUK,OAAO,cAIhC1B,KAAKuB,SACLvB,KAAKuB,QAAQ0B,YAAYC,KA3B7BlD,KAAKuB,QAAU,IAAIrC,QAAQY,UAAW0G,WAAYvG,OAAQqG,OAAQR,QACtD,WAARvC,KACAvD,KAAKuB,QAAQqC,eAEb5D,KAAKuB,QAAQsC,cAEjB7D,KAAKuB,QAAQgG,kBACbxG,SACKgC,eAAe,mBAAqBQ,MAAQ,WAC5CnC,WACAC,UACAK,OAAO,UACZX,SACKgC,eAAe,mBAAqBQ,MAAQ,WAC5CnC,WACAC,UACAC,IAAI,qBAiBf6F,kBAAkBS,mBAOpBxI,SAASC,qBAEEC,cAAKC,KAAK,CAAC,CACdC,KAAM,CACFC,OAAQJ,aAAaK,QACrBC,GAAIC,OAAOC,KAAKC,WAChBC,OAAQV,aAAaU,OACrBC,KAAMH,KAAKI,OACXC,OAAO,EACPS,KAAMd,KAAKc,KACXR,QAASd,aAAac,QAAQC,gBAElCN,UAAWD,KAAKC,UAChBO,KAAMC,sBAAaC,UACnBC,WAAY,oCACZ,GAGRqH,YAAYC,mCACFhF,kBACFjD,KAAKuH,YAAYhG,WAAW6D,cAAc,SAC1C6C,aAEJA,YAAY3F,YAAYlB,SAAQmB,aACvBuF,WAAavF,MAClBA,MAAMC,SAAWxC,KAAKyH,aAI9BS,YAAY7F,mCACFY,kBACFjD,KAAKuH,YACLlF"} \ 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 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 diff --git a/plugin/live/amd/src/videotime.js b/plugin/live/amd/src/videotime.js index 9a3f996c..d1dac2ea 100644 --- a/plugin/live/amd/src/videotime.js +++ b/plugin/live/amd/src/videotime.js @@ -41,11 +41,15 @@ class Publish extends PublishBase { methodname: 'videotimeplugin_live_join_room' }])[0].then(response => { this.feed = response.id; + + return response; }).catch(Notification.exception); } /** * Publish current video feed + * + * @returns {Promise} */ publishFeed() { return Ajax.call([{ @@ -62,6 +66,8 @@ class Publish extends PublishBase { /** * Stop video feed + * + * @returns {Promise} */ unpublish() { document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => { @@ -261,16 +267,6 @@ class Publish extends PublishBase { }); this.videoInput = displayInput.then(videoStream => { - if (videoInput) { - videoInput.then(videoStream => { - if (videoStream) { - videoStream.getTracks().forEach(track => { - Log.debug(track); //track.stop(); - }); - } - return videoStream; - }).catch(Notification.exception); - } this.tracks = this.tracks || {}; videoStream.getTracks().forEach(track => { this.tracks[track.id] = 'display'; @@ -292,7 +288,9 @@ class Publish extends PublishBase { track.stop(); }); } - }); + + return videoStream; + }).catch(Notification.exception); return videoStream; }).catch((e) => { @@ -302,6 +300,11 @@ class Publish extends PublishBase { }); } + /** + * Process tracks from current video stream and adjust publicatioin + * + * @param {array} tracks Additional tracks to add + */ processStream(tracks) { this.videoInput.then(videoStream => { this.tracks = this.tracks || {}; @@ -393,6 +396,15 @@ class Publish extends PublishBase { } export default class VideoTime extends VideoTimeBase { + /** + * Initialize player plugin + * + * @param {int} contextid + * @param {string} token Deft token + * @param {int} peerid Peer id for audio room participant + * + * @returns {bool} + */ initialize(contextid, token, peerid) { Log.debug("Initializing Video Time " + this.elementId); @@ -446,13 +458,90 @@ export default class VideoTime extends VideoTimeBase { return true; } + /** + * Get video element + * + * @returns {HTMLMediaElement} + */ + getPlayer() { + return document.getElementById(this.elementId); + } + /** * Register player events to respond to user interaction and play progress. */ addListeners() { + const player = this.getPlayer(); + document.querySelector('body').removeEventListener('click', handleClick); document.querySelector('body').addEventListener('click', handleClick); - return; + + if (!player) { + Log.debug('Player was not properly initialized for course module ' + this.cmId); + return; + } + + // Fire view event in Moodle on first play only. + player.addEventListener('play', () => { + if (this.hasPro) { + this.startWatchInterval(); + } + this.view(); + return true; + }); + + // Features beyond this point are for pro only. + if (!this.hasPro) { + return; + } + + // Note: Vimeo player does not support multiple events in a single on() call. Each requires it's own function. + + // Catch all events where video plays. + player.addEventListener('play', function() { + this.playing = true; + Log.debug('VIDEO_TIME play'); + }.bind(this)); + player.addEventListener('playing', function() { + this.playing = true; + Log.debug('VIDEO_TIME playing'); + }.bind(this)); + + // Catch all events where video stops. + player.addEventListener('pause', function() { + this.playing = false; + Log.debug('VIDEO_TIME pause'); + }.bind(this)); + player.addEventListener('stalled', function() { + this.playing = false; + Log.debug('VIDEO_TIME stalled'); + }.bind(this)); + player.addEventListener('suspend', function() { + this.playing = false; + Log.debug('VIDEO_TIME suspend'); + }.bind(this)); + player.addEventListener('abort', function() { + this.playing = false; + Log.debug('VIDEO_TIME abort'); + }.bind(this)); + + // Always update internal values for percent and current time watched. + player.addEventListener('timeupdate', function(event) { + this.percent = 1; + this.currentTime = player.currentTime; + this.plugins.forEach(plugin => { + if (typeof plugin.setCurrentTime == 'function') { + plugin.getSessions().then(session => { + plugin.setCurrentTime(session.id, event.seconds); + return session; + }).catch(Notification.exception); + } + }); + }.bind(this)); + + // Initiate video finish procedure. + player.addEventListener('ended', this.handleEnd.bind(this)); + player.addEventListener('pause', this.handlePause.bind(this)); } /** @@ -461,7 +550,6 @@ export default class VideoTime extends VideoTimeBase { * @param {int} source Feed to subscribe */ subscribeTo(source) { - Log.debug(source); const room = rooms[String(this.contextid)]; document.querySelectorAll('[data-contextid="' + this.contextid + '"][data-action="publish"]').forEach(button => { if (source == Number(this.peerid)) { @@ -477,7 +565,6 @@ export default class VideoTime extends VideoTimeBase { button.classList.remove('hidden'); } }); - Log.debug(source); if (this.remoteFeed && !this.remoteFeed.creatingSubscription && !this.remoteFeed.restart) { const update = { @@ -503,7 +590,7 @@ export default class VideoTime extends VideoTimeBase { this.remoteFeed.audioTrack.enabled = !this.remoteFeed.muteAudio; } - if (room.publish && this.remoteFeed.current == room.publish.feed) { + if (room.publish && this.remoteFeed.current == room.publish.feed) { room.publish.handleClose(); room.publish = null; } @@ -561,6 +648,15 @@ export default class VideoTime extends VideoTimeBase { }); } } + + /** + * Get duration of video + * + * @returns {Promise} + */ + getDuration() { + return Promise.resolve(this.currentTime); + } } const handleClick = function(e) { @@ -581,7 +677,7 @@ const handleClick = function(e) { type = button.getAttribute('data-type'); e.stopPropagation(); e.preventDefault(); - if ((action == 'publish') && (!room.publish || room.publish.restart)) { + if ((action == 'publish') && (!room.publish || room.publish.restart)) { room.publish = new Publish(contextid, iceServers, roomid, server, peerid); if (type == 'display') { room.publish.shareDisplay(); @@ -640,6 +736,11 @@ class Subscribe extends SubscribeBase { }])[0]; } + /** + * Attach audio stream to media element + * + * @param {HTMLMediaElement} audioStream Stream to attach + */ attachAudio(audioStream) { Janus.attachMediaStream( this.remoteVideo.parentNode.querySelector('audio'), @@ -651,6 +752,11 @@ class Subscribe extends SubscribeBase { }); } + /** + * Attach video stream to media element + * + * @param {HTMLMediaElement} videoStream Stream to attach + */ attachVideo(videoStream) { Janus.attachMediaStream( this.remoteVideo,