{"version":3,"sources":["webpack:///../WCC.UI/App/components/videoRecorder/videoRecorder.html?78e2","webpack:///../WCC.UI/App/components/videoRecorder/videoRecorder.scss?35a8","webpack:///../WCC.UI/App/components/videoRecorder/videoRecorder.ts","webpack:///../WCC.UI/App/webpack/runtime/htmlExposer.js","webpack:///../WCC.UI/App/components/videoRecorder/videoRecorder.scss","webpack:///../WCC.UI/App/components/videoRecorder/videoRecorder.html"],"names":["content","expose","__esModule","default","api","module","i","options","exports","locals","availableViewportSizeToOverlay","settings","videoSettings","width","min","ideal","height","WCCVideoRecorder","constructor","config","info","effects","_config$onRecorded","startedRecordingOn","ko","observable","previewNode","isSupported","isDataReady","isRecordingRequested","toggleRecording","this","toggle","maxRecordingTime","flattenComputed","shouldFitViewport","fitViewport","onRecorded","blob","console","log","availableTime","pureComputed","totalTime","startedOn","result","undefined","timeUsed","now","getTime","availableTimeLabel","mapSingle","seconds","moment","startOf","add","format","isRecordingAllowed","stream","register","async","requestedStream","requestStream","getTracks","forEach","track","stop","node","DOMHelpers","onNodeEvent","src","URL","createObjectURL","srcObject","withEffect","recorder","setupRecorder","start","Date","maxWidth","device","maxHeight","applyBindingsToNode","element","toPx","MediaRecorder","chunks","addEventListener","e","data","size","push","state","length","Blob","type","name","toLocaleDateString","navigator","mediaDevices","getUserMedia","video","audio","__decorate","injectable","__param","inject","wccModules","componentConfig","componentInfo","system","SystemHelpers","html","getTemplatesAndResources","document","head","appendChild","___CSS_LOADER_API_IMPORT___"],"mappings":"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","file":"327.4aad32ca0b6a0239e2ac.js","sourcesContent":["define([\n \"!!../../../node_modules/html-loader/dist/cjs.js??ref--26-1!./videoRecorder.html\", \n \"!../../webpack/runtime/htmlExposer.js\"], function (content, expose) {\n content = content.__esModule ? content.default : content;\n expose(content);\n return content;\n });","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js!./videoRecorder.scss\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {};\n\noptions.insert = \"head\";\noptions.singleton = false;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","import { wccModules } from 'enums/wccModules';\r\nimport { BlobWrapper } from 'interfaces/blobWrapper';\r\nimport { inject, injectable } from 'inversify';\r\nimport { Observable, PureComputed, SubscribableOrNullableValue } from 'knockout';\r\nimport { withEffect } from 'mixins/withEffect';\r\nimport { EffectsContainer } from 'mixins/withEffects';\r\nimport './videoRecorder.html';\r\nimport './videoRecorder.scss';\r\nimport device from 'managers/device';\r\nimport { DOMHelpers } from 'helpers/dom';\r\n\r\nconst { availableViewportSizeToOverlay } = settings;\r\n\r\nconst videoSettings: MediaTrackConstraints = {\r\n width: { min: 1280, ideal: 1280 },\r\n height: { min: 720, ideal: 720 }\r\n}\r\n\r\nexport interface WCCVideoRecorderConfig {\r\n maxRecordingTime: SubscribableOrNullableValue\r\n fitViewport: SubscribableOrNullableValue\r\n onRecorded?: Action<[BlobWrapper]>\r\n}\r\n\r\n/**\r\n * Records video using media streams\r\n * */\r\n@injectable()\r\nexport default class WCCVideoRecorder {\r\n private startedRecordingOn: Observable = ko.observable()\r\n private isRecordingAllowed: PureComputed\r\n\r\n previewNode: Observable = ko.observable()\r\n\r\n availableTimeLabel: PureComputed\r\n\r\n isSupported = ko.observable(true)\r\n isDataReady = ko.observable(false) \r\n isRecordingRequested = ko.observable(false)\r\n\r\n constructor(\r\n @inject(wccModules.componentConfig) config: WCCVideoRecorderConfig,\r\n @inject(wccModules.componentInfo) info: ko.components.ComponentInfo,\r\n @inject(wccModules.effects) effects: EffectsContainer\r\n ) {\r\n const maxRecordingTime = ko.flattenComputed(config.maxRecordingTime).default(300);\r\n const shouldFitViewport = ko.flattenComputed(config.fitViewport, false);\r\n\r\n const onRecorded = config.onRecorded ?? (blob => console.log(blob));\r\n\r\n const availableTime = ko.pureComputed(() => {\r\n const totalTime = maxRecordingTime();\r\n const startedOn = this.startedRecordingOn();\r\n\r\n let result = totalTime;\r\n \r\n if (startedOn != undefined) {\r\n const timeUsed = (settings.now().getTime() - startedOn.getTime()) / 1000;\r\n\r\n if (timeUsed > 0)\r\n result -= timeUsed;\r\n\r\n if (result < 0)\r\n result = 0;\r\n }\r\n\r\n return result;\r\n });\r\n\r\n this.availableTimeLabel = availableTime.mapSingle(seconds => moment().startOf('day').add(seconds, 'seconds').format('mm:ss'));\r\n\r\n this.isRecordingAllowed = ko.pureComputed(() => this.isRecordingRequested() && availableTime() > 0); \r\n\r\n const stream: Observable = ko.observable();\r\n\r\n /**\r\n * get stream and saved it into ko container\r\n **/\r\n effects.register(async () => {\r\n try {\r\n const requestedStream = await this.requestStream();\r\n stream(requestedStream);\r\n\r\n return () => {\r\n requestedStream.getTracks().forEach(track => track.stop()); //release requested media stream\r\n stream(undefined);\r\n }\r\n } catch {\r\n this.isSupported(false);\r\n }\r\n });\r\n\r\n /**\r\n * once we have preview node and stream wire them together\r\n * so we can see video from camera\r\n **/ \r\n effects.register((node, stream) => {\r\n if (node != undefined && stream != undefined) {\r\n const effects = [\r\n DOMHelpers.onNodeEvent(node, 'canplay', () => this.isDataReady(true)),\r\n () => this.isDataReady(false)\r\n ];\r\n\r\n try {\r\n node.src = URL.createObjectURL(stream);\r\n } catch {\r\n node.srcObject = stream;\r\n } \r\n\r\n return effects;\r\n }\r\n }, [this.previewNode, stream]);\r\n\r\n /**\r\n * record video once stream is awailable and recording is allowed\r\n **/ \r\n effects.register(stream => {\r\n if (stream != undefined) {\r\n return withEffect(isRecordingAllowed => {\r\n if (isRecordingAllowed) {\r\n const recorder = this.setupRecorder(stream, onRecorded);\r\n\r\n recorder.start();\r\n this.startedRecordingOn(new Date());\r\n\r\n return () => {\r\n recorder.stop();\r\n this.startedRecordingOn(undefined);\r\n this.isRecordingRequested(false);\r\n }\r\n }\r\n }, [this.isRecordingAllowed]); \r\n }\r\n }, [stream]);\r\n\r\n const maxWidth = ko.pureComputed(() => shouldFitViewport() ? device.width() * availableViewportSizeToOverlay : undefined);\r\n const maxHeight = ko.pureComputed(() => shouldFitViewport() ? device.height() * availableViewportSizeToOverlay : undefined);\r\n\r\n ko.applyBindingsToNode(info.element, {\r\n 'css': {\r\n 'wcc-video-recorder': true,\r\n 'wcc-video-recorder--fit-viewport': true\r\n },\r\n\r\n 'style': {\r\n 'max-width': maxWidth.toPx(),\r\n 'max-height': maxHeight.toPx()\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * toggles flag which allows recording\r\n * */\r\n toggleRecording = () => {\r\n this.isRecordingRequested.toggle();\r\n }\r\n\r\n /**\r\n * create new recorder and prepare it for collecting data\r\n * actual recording will start on .start() call on recorder\r\n * once .stop is called on recorder new blob will be generated and push into onRecorded callback\r\n * @param stream\r\n * @param onRecorded\r\n */\r\n private setupRecorder(stream: MediaStream, onRecorded: Action<[BlobWrapper]>) {\r\n const recorder = new MediaRecorder(stream);\r\n const chunks: Array = [];\r\n\r\n recorder.addEventListener('dataavailable', e => {\r\n if (e.data.size > 0)\r\n chunks.push(e.data);\r\n\r\n if (recorder.state === 'inactive' && chunks.length > 0) {\r\n const blob = new Blob(chunks, { type: 'video/mp4' });\r\n const name = `Video recording - ${new Date().toLocaleDateString()}.mp4`;\r\n\r\n onRecorded({ blob, name });\r\n }\r\n });\r\n\r\n return recorder;\r\n }\r\n\r\n /**\r\n * Request video with audio (e.g. webcam) stream from browser \r\n * with fallback to video only (e.g. some screen recording codecs).\r\n * */\r\n private async requestStream() {\r\n try {\r\n return await navigator.mediaDevices.getUserMedia({ video: videoSettings, audio: true });\r\n } catch {\r\n return await navigator.mediaDevices.getUserMedia({ video: videoSettings }); \r\n }\r\n }\r\n}","define(function () {\r\n const system = require('helpers/system').SystemHelpers;\r\n\r\n return function (html) {\r\n system.getTemplatesAndResources(html)\r\n .forEach(function (node) { document.head.appendChild(node) });\r\n }\r\n});","// Imports\nvar ___CSS_LOADER_API_IMPORT___ = require(\"../../../node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.id, \".wcc-video-recorder{display:block}.wcc-video-recorder--fit-viewport{display:flex;flex-direction:column}.wcc-video-recorder--fit-viewport .wcc-video-recorder__wrapper{display:flex;flex-direction:column}.wcc-video-recorder--fit-viewport .wcc-video-recorder__body{min-width:0;min-height:0}.wcc-video-recorder--fit-viewport .wcc-video-recorder__footer{flex-shrink:0}.wcc-video-recorder__wrapper{border:1px solid #f8f8f7;border-radius:4px;overflow:hidden}.wcc-video-recorder__body{display:flex}.wcc-video-recorder__footer{display:flex;justify-content:space-between;align-items:center;background-color:#f8f8f7;border-top:1px solid #c6c6c6;padding:5px;line-height:100%}.wcc-video-recorder__record-button{display:inline-flex;width:20px;height:20px;background-color:#f5332e;border-radius:100%;box-shadow:0 0 2px 1px #262626;cursor:pointer;transition:border-radius 350ms ease-in-out}.wcc-video-recorder__record-button--active{border-radius:4px}.wcc-video-recorder__not-supported-message{color:#fff}\", \"\"]);\n// Exports\nmodule.exports = exports;\n","// Module\nvar code = \"\";\n// Exports\nmodule.exports = code;"],"sourceRoot":""}