UNPKG

@eatsjobs/media-mock

Version:

Media-Mock is a JavaScript library that simulates media devices (like webcams) in web applications, allowing developers to test and debug media constraints, device configurations, and stream functionality without needing physical devices. This is particul

4 lines (3 loc) 11.9 kB
"use strict";var k=Object.defineProperty;var B=(c,e,t)=>e in c?k(c,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):c[e]=t;var o=(c,e,t)=>B(c,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function l(c,e,t){const i=c[e];return Object.defineProperty(c,e,{writable:!0,configurable:!0,value:t}),()=>{Object.defineProperty(c,e,{writable:!0,configurable:!0,value:i})}}function m({deviceId:c,groupId:e,kind:t,label:i,mockCapabilities:n={width:{min:1,max:1280},height:{min:1,max:720}}}){return{deviceId:c,groupId:e,kind:t,label:i,getCapabilities:()=>n,toJSON(){return{deviceId:`${this.deviceId}`,kind:this.kind,label:`${this.label}`,groupId:`${this.groupId}`}}}}const b={aspectRatio:!0,deviceId:!0,displaySurface:!0,echoCancellation:!0,facingMode:!0,frameRate:!0,groupId:!1,height:!0,sampleRate:!1,sampleSize:!1,torch:!0,volume:!0,whiteBalanceMode:!0,width:!0,zoom:!0},x={...b,torch:!1},p={"iPhone 12":{videoResolutions:[{width:1920,height:1080},{width:1280,height:720},{width:640,height:480},{width:320,height:240}],mediaDeviceInfo:[m({deviceId:"A7FB77364106629BF38E043E6B000EE5FD680B9B",kind:"videoinput",label:"Front Camera",groupId:"C1B048C04520A18C3611DC837450814245482489",mockCapabilities:{aspectRatio:{max:4032,min:.00033068783068783067},deviceId:"1A100C35A33042B643BE0438DBBF9FDC95AF1913",facingMode:["user"],frameRate:{max:60,min:1},groupId:"C1B048C04520A18C3611DC837450814245482489",height:{max:3024,min:1},whiteBalanceMode:["manual","continuous"],width:{max:4032,min:1},zoom:{max:4,min:1}}}),m({deviceId:"9729B396E0C2B460BC7B69C0E368EB0B605058A9",kind:"videoinput",label:"Back Dual Wide Camera",groupId:"A1F2417053FF79495E7D01AF37A6C4461CE0C060",mockCapabilities:{aspectRatio:{max:4032,min:.00033068783068783067},deviceId:"D87C414E22C375BB0697DCB83A24D97BD520624D",facingMode:["environment"],focusDistance:{min:.12},frameRate:{max:60,min:1},groupId:"A1F2417053FF79495E7D01AF37A6C4461CE0C060",height:{max:3024,min:1},torch:!0,whiteBalanceMode:["manual","continuous"],width:{max:4032,min:1},zoom:{max:2,min:.5}}}),m({deviceId:"0B74C1149038CA5235F6C2325E53AE22AA920379",kind:"videoinput",label:"Back Ultra Wide Camera",groupId:"B402A3862F28FB8D54BDF33BD7D41874FE175517",mockCapabilities:{aspectRatio:{max:4032,min:.00033068783068783067},deviceId:"BE00A990BEDE2D324EB0AD51F567EE4ADC24D9B0",facingMode:["environment"],focusDistance:{min:.12},frameRate:{max:60,min:1},groupId:"B402A3862F28FB8D54BDF33BD7D41874FE175517",height:{max:3024,min:1},torch:!0,whiteBalanceMode:["manual","continuous"],width:{max:4032,min:1},zoom:{max:4,min:1}}}),m({deviceId:"C92FE814FCB4F2F856CDCBFD1C555429774DD0E2",kind:"videoinput",label:"Back Camera",groupId:"14122C2CE97B69A84360822AB87E8206C32B5BD8",mockCapabilities:{aspectRatio:{max:4032,min:.00033068783068783067},deviceId:"D13A012C1D5C9F9899B40BDA0790184EE57FD282",facingMode:["environment"],focusDistance:{min:.12},frameRate:{max:60,min:1},groupId:"14122C2CE97B69A84360822AB87E8206C32B5BD8",height:{max:3024,min:1},torch:!0,whiteBalanceMode:["manual","continuous"],width:{max:4032,min:1},zoom:{max:4,min:1}}})],supportedConstraints:b},"Samsung Galaxy M53":{videoResolutions:[{width:1920,height:1080},{width:1280,height:720},{width:640,height:480}],mediaDeviceInfo:[m({deviceId:"87fcafb209f5ff2a6d7c8a5d14afe1c9aba9f209330e93933e545e40b102b35f",groupId:"f70f63d2f4eea57dafe6c6b60833aa69a02f06bb0a6878cb277fb4d70daa9020",kind:"videoinput",label:"camera2 1, facing front",mockCapabilities:{aspectRatio:{max:2400,min:.0009191176470588235},deviceId:"87fcafb209f5ff2a6d7c8a5d14afe1c9aba9f209330e93933e545e40b102b35f",facingMode:["user"],frameRate:{max:30,min:1},groupId:"f70f63d2f4eea57dafe6c6b60833aa69a02f06bb0a6878cb277fb4d70daa9020",height:{max:1088,min:1},resizeMode:["none","crop-and-scale"],width:{max:2400,min:1}}}),m({deviceId:"81cb5898aebd672ef65d04ed1bc7b00c704f2b6aa94200bc5556ff02c89ea14d",groupId:"7300f91d6cb037dcaa6fe16abb59f4e9f92fb471e2280ff0e313e07c49cb536c",kind:"videoinput",label:"camera2 2, facing front",mockCapabilities:{aspectRatio:{max:2400,min:.0009191176470588235},deviceId:"81cb5898aebd672ef65d04ed1bc7b00c704f2b6aa94200bc5556ff02c89ea14d",facingMode:["user"],frameRate:{max:30,min:1},groupId:"7300f91d6cb037dcaa6fe16abb59f4e9f92fb471e2280ff0e313e07c49cb536c",height:{max:1088,min:1},resizeMode:["none","crop-and-scale"],width:{max:2400,min:1}}}),m({deviceId:"99be6eecad8c050052df5dbb08b0460d2715b0a3b18fc5c7f08d6073d312ca34",groupId:"40f44b864c99ab042a21cf87df882d0ef5c7f88f7cbfcee74cefc1e393b8616b",kind:"videoinput",label:"camera2 0, facing back",mockCapabilities:{aspectRatio:{max:3840,min:.000462962962962963},deviceId:"99be6eecad8c050052df5dbb08b0460d2715b0a3b18fc5c7f08d6073d312ca34",facingMode:["environment"],frameRate:{max:30,min:1},groupId:"40f44b864c99ab042a21cf87df882d0ef5c7f88f7cbfcee74cefc1e393b8616b",height:{max:2160,min:1},resizeMode:["none","crop-and-scale"],width:{max:3840,min:1},torch:!0}})],supportedConstraints:b},"Mac Desktop":{videoResolutions:[{width:1920,height:1080},{width:1280,height:720},{width:640,height:480}],mediaDeviceInfo:[m({deviceId:"e91a0ba82ba051029709163c442d340a3919dfabd",groupId:"7ce19c839ef9ab1a4cba8d4dd4d3c1bbbf3ad",kind:"videoinput",label:"FaceTime HD Camera (2C0E:82E3)",mockCapabilities:{aspectRatio:{max:1920,min:.0005208333333333333},backgroundBlur:[!1],deviceId:"370CF6B3449B7B73599E8DAEEE75FB41788A0712",frameRate:{max:30,min:1},groupId:"F2EFF7249C97B5531FF959C8F977138341165F6B",height:{max:1920,min:1},width:{max:1920,min:1}}})],supportedConstraints:x}};async function M(c){const e=new Image;e.src=c;try{return await e.decode(),e}catch{throw new Error(`Failed to load image: ${c}`)}}function F(){return{mediaDevices:{getUserMedia:!0,getSupportedConstraints:!0,enumerateDevices:!0}}}function E(c){var i;const e=["mp4","webm","ogg","mov","avi","mkv","flv","wmv","m4v","3gp","mpg","mpeg","asf","rm","vob"],t=(i=c.split(".").pop())==null?void 0:i.toLowerCase();return e.includes(t??"")}function R(c){return new Promise(e=>{c.addEventListener("loadeddata",async()=>{try{await c.play(),e()}catch(t){console.error(t),e()}}),c.load()})}class w{constructor(){o(this,"settings",{mediaURL:"./assets/640x480-sample.png",device:p["iPhone 12"],constraints:p["iPhone 12"].supportedConstraints,canvasScaleFactor:1});o(this,"mediaMockImageId","media-mock-image");o(this,"mediaMockCanvasId","media-mock-canvas");o(this,"currentImage");o(this,"mapUnmockFunction",new Map);o(this,"currentStream");o(this,"intervalId",null);o(this,"debug",!1);o(this,"canvas");o(this,"ctx");o(this,"mockedVideoTracksHandler",e=>e);o(this,"fps",30);o(this,"resolution",{width:640,height:480})}setMediaURL(e){return this.settings.mediaURL=e,this.intervalId&&this.startIntervalDrawing(),this}async startIntervalDrawing(){var i,n;this.intervalId&&clearInterval(this.intervalId);const{width:e,height:t}=this.resolution;if(E(this.settings.mediaURL)){const d=document.createElement("video");d.addEventListener("error",()=>{console.error("Failed to load video source. Ensure the format is supported and the URL is valid.")},{once:!0}),d.src=this.settings.mediaURL,d.muted=!0,d.playsInline=!0,d.loop=!0,d.autoplay=!0,d.hidden=!0,d.crossOrigin="anonymous",await R(d),this.intervalId=setInterval(()=>{var s,a,r;(s=this.ctx)==null||s.clearRect(0,0,e,t),this.ctx.fillStyle="#ffffff",(a=this.ctx)==null||a.fillRect(0,0,e,t),(r=this.ctx)==null||r.drawImage(d,0,0,e,t)},1e3/this.fps)}else this.currentImage=await M(this.settings.mediaURL),this.currentImage.id=this.mediaMockImageId,this.debug&&console.log(` Canvas: ${e}x${t}, Image: ${(i=this.currentImage)==null?void 0:i.naturalWidth}x${(n=this.currentImage)==null?void 0:n.naturalHeight}`),this.intervalId=setInterval(()=>{var I,D,C;(I=this.ctx)==null||I.clearRect(0,0,e,t),this.ctx.fillStyle="#ffffff",(D=this.ctx)==null||D.fillRect(0,0,e,t);const{naturalWidth:d,naturalHeight:s}=this.currentImage,a=d/s,r=e/t;let h,u,g,v;const f=this.settings.canvasScaleFactor;a>r?(h=e*f,u=e*f/a,g=(e-h)/2,v=(t-u)/2):(u=t*f,h=t*f*a,g=(e-h)/2,v=(t-u)/2),(C=this.ctx)==null||C.drawImage(this.currentImage,g,v,h,u)},1e3/this.fps)}addMockDevice(e){return this.settings.device.mediaDeviceInfo.push(e),this.triggerDeviceChange(),this}removeMockDevice(e){return this.settings.device.mediaDeviceInfo=this.settings.device.mediaDeviceInfo.filter(t=>t.deviceId!==e),this.triggerDeviceChange(),this}triggerDeviceChange(){navigator.mediaDevices.dispatchEvent(new Event("devicechange"))}enableDebugMode(){return this.debug=!0,this.canvas!=null&&document.querySelector(this.mediaMockCanvasId)==null&&(this.canvas.style.border="10px solid red",document.body.append(this.canvas)),this.currentImage!=null&&document.querySelector(this.mediaMockImageId)==null&&(this.currentImage.style.border="10px solid red",document.body.append(this.currentImage)),this}disableDebugMode(){this.debug=!1;const e=document.getElementById(this.mediaMockCanvasId),t=document.getElementById(this.mediaMockImageId);return e==null||e.remove(),t==null||t.remove(),this}setMockedVideoTracksHandler(e){return this.mockedVideoTracksHandler=e,this}mock(e,t=F()){if(this.settings.device=e,typeof navigator.mediaDevices>"u"){class i extends EventTarget{}l(navigator,"mediaDevices",new i)}if(t!=null&&t.mediaDevices.getUserMedia){const i=l(navigator.mediaDevices,"getUserMedia",n=>this.getMockStream(n));this.mapUnmockFunction.set("getUserMedia",i)}if(t!=null&&t.mediaDevices.getSupportedConstraints){const i=l(navigator.mediaDevices,"getSupportedConstraints",()=>this.settings.constraints);this.mapUnmockFunction.set("getSupportedConstraints",i)}if(t!=null&&t.mediaDevices.enumerateDevices){const i=l(navigator.mediaDevices,"enumerateDevices",async()=>this.settings.device.mediaDeviceInfo);this.mapUnmockFunction.set("enumerateDevices",i)}return this}unmock(){return this.stopMockStream(),this.disableDebugMode(),this.mapUnmockFunction.forEach(e=>e()),this.mapUnmockFunction.clear(),this}stopMockStream(){var e,t,i,n;this.intervalId&&clearInterval(this.intervalId),(t=(e=this.currentStream)==null?void 0:e.getVideoTracks())==null||t.forEach(d=>d.stop()),(n=(i=this.currentStream)==null?void 0:i.stop)==null||n.call(i)}setCanvasScaleFactor(e){return this.settings.canvasScaleFactor=Math.max(.1,e),this}async getMockStream(e){this.resolution=this.getResolution(e,this.settings.device),this.fps=this.getFPSFromConstraints(e),this.canvas=document.createElement("canvas"),this.canvas.id=this.mediaMockCanvasId;const{width:t,height:i}=this.resolution;this.canvas.width=t,this.canvas.height=i,this.ctx=this.canvas.getContext("2d"),this.ctx.fillStyle="#ffffff",this.ctx.fillRect(0,0,t,i),await this.startIntervalDrawing(),this.debug&&this.enableDebugMode();const n=this.canvas.captureStream(this.fps);return this.currentStream=new MediaStream(this.mockedVideoTracksHandler((n==null?void 0:n.getVideoTracks())??[])),this.currentStream}getFPSFromConstraints(e){return typeof e.video=="object"&&e.video.frameRate?typeof e.video.frameRate=="number"?e.video.frameRate:e.video.frameRate.ideal||30:30}getResolution(e,t){const i=window.innerHeight>window.innerWidth,n=e.video.width||{ideal:640},d=e.video.height||{ideal:480};let s;if(i){if(s=t.videoResolutions.find(a=>a.height>a.width&&(typeof d=="number"?a.height===d:a.height===d.ideal)&&(typeof n=="number"?a.width===n:a.width===n.ideal)),!s){const a=t.videoResolutions.find(r=>(typeof n=="number"?r.height===n:r.height===n.ideal)&&(typeof d=="number"?r.width===d:r.width===d.ideal));a&&(s={width:a.height,height:a.width})}}else s=t.videoResolutions.find(a=>(typeof n=="number"?a.width===n:a.width===n.ideal)&&(typeof d=="number"?a.height===d:a.height===d.ideal));if(!s&&i&&(s=t.videoResolutions.find(a=>a.height>a.width),!s&&t.videoResolutions.length>0)){const a=t.videoResolutions[0];s={width:a.height,height:a.width}}return s||t.videoResolutions[0]}}const y=new w;exports.MediaMock=y;exports.MediaMockClass=w;exports.createMediaDeviceInfo=m;exports.devices=p;