{"id":5654,"date":"2021-05-03T16:16:08","date_gmt":"2021-05-03T14:16:08","guid":{"rendered":"https:\/\/studios.aalto.fi\/?post_type=userguide&#038;p=5654"},"modified":"2024-05-06T17:19:02","modified_gmt":"2024-05-06T14:19:02","slug":"test-camera-and-microphone","status":"publish","type":"userguide","link":"https:\/\/studios.aalto.fi\/fi\/userguide\/test-camera-and-microphone\/","title":{"rendered":"Test camera and microphone"},"content":{"rendered":"\n<div class=\"wp-block-columns as-default-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column as-default-columns-main-content is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:66.66%\">\n<p>This page lets you select both camera and microphone inputs to check that they&#8217;re working as expected. Unfortunately, the Safari browser doesn&#8217;t currently support the microphone input, so use Firefox or another browser for this test. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Camera_test\"><\/span>Camera test<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>If you allowed this page to access the camera just a moment ago, a live feed from the selected camera should appear below.<\/p>\n\n\n\n<video style=\"width: 100%; background: rgba(128,128,128,0.2)\" autoplay=\"true\" id=\"videoElement\"><\/video><div class=\"video-options\"><select><\/select><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Microphone_test\"><\/span>Microphone test<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Similarly to the camera, a permission prompt just asked you to allow access to the microphone. If granted, a bar below should react to sound. (Note: not supported on Safari yet).<\/p>\n\n\n\n<canvas id=\"meter\" style=\"border: 1px solid var(--lineColor); width: 100%; height: 50px;\"><\/canvas>\n\n\n\n<script>\nvar video = document.querySelector(\"#videoElement\");\n\nif (navigator.mediaDevices.getUserMedia) {\n  navigator.mediaDevices.getUserMedia({ video: true })\n    .then(function (stream) {\n      video.srcObject = stream;\n    })\n    .catch(function (err0r) {\n      console.log(\"Something went wrong!\");\n    });\n}\n\nsetTimeout(function()\n{\njQuery(function()\n{\n  function resizeOps()\n  {\n    let\n      windowWidth = jQuery( '.entry-content' ).first().width(),\n      videoHeight = ( windowWidth \/ 16 ) * 9\n    ;\n\t\t\t\n    jQuery('#videoElement').height( videoHeight );\n    \n    console.log('resize');\n  }\n\t\n  jQuery( window ).on( 'resize', function()\n  {\n    resizeOps();\n  });\n\t\n  resizeOps();\n\n});\n\n},100);\n\n<\/script>\n\n<script>\n\n\/*\nThe MIT License (MIT)\nCopyright (c) 2014 Chris Wilson\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and\/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*\/\n\nfunction createAudioMeter(audioContext,clipLevel,averaging,clipLag) {\n\tvar processor = audioContext.createScriptProcessor(512);\n\tprocessor.onaudioprocess = volumeAudioProcess;\n\tprocessor.clipping = false;\n\tprocessor.lastClip = 0;\n\tprocessor.volume = 0;\n\tprocessor.clipLevel = clipLevel || 0.98;\n\tprocessor.averaging = averaging || 0.95;\n\tprocessor.clipLag = clipLag || 750;\n\n\t\/\/ this will have no effect, since we don't copy the input to the output,\n\t\/\/ but works around a current Chrome bug.\n\tprocessor.connect(audioContext.destination);\n\n\tprocessor.checkClipping =\n\t\tfunction(){\n\t\t\tif (!this.clipping)\n\t\t\t\treturn false;\n\t\t\tif ((this.lastClip + this.clipLag) < window.performance.now())\n\t\t\t\tthis.clipping = false;\n\t\t\treturn this.clipping;\n\t\t};\n\n\tprocessor.shutdown =\n\t\tfunction(){\n\t\t\tthis.disconnect();\n\t\t\tthis.onaudioprocess = null;\n\t\t};\n\n\treturn processor;\n}\n\nfunction volumeAudioProcess( event ) {\n\tvar buf = event.inputBuffer.getChannelData(0);\n    var bufLength = buf.length;\n\tvar sum = 0;\n    var x;\n\n\t\/\/ Do a root-mean-square on the samples: sum up the squares...\n    for (var i=0; i<bufLength; i++) {\n    \tx = buf[i];\n    \tif (Math.abs(x)>=this.clipLevel) {\n    \t\tthis.clipping = true;\n    \t\tthis.lastClip = window.performance.now();\n    \t}\n    \tsum += x * x;\n    }\n\n    \/\/ ... then take the square root of the sum.\n    var rms =  Math.sqrt(sum \/ bufLength);\n\n    \/\/ Now smooth this out with the averaging factor applied\n    \/\/ to the previous sample - take the max here because we\n    \/\/ want \"fast attack, slow release.\"\n    this.volume = Math.max(rms, this.volume*this.averaging);\n}\n\n\nvar audioContext = null;\nvar meter = null;\nvar canvasContext = null;\nvar WIDTH=500;\nvar HEIGHT=50;\nvar rafID = null;\n\nwindow.onload = function() {\n\n    \/\/ grab our canvas\n\tcanvasContext = document.getElementById( \"meter\" ).getContext(\"2d\");\n\t\n    \/\/ monkeypatch Web Audio\n    window.AudioContext = window.AudioContext || window.webkitAudioContext;\n\t\n    \/\/ grab an audio context\n    audioContext = new AudioContext();\n\n    \/\/ Attempt to get audio input\n    try {\n        \/\/ monkeypatch getUserMedia\n        navigator.getUserMedia = \n        \tnavigator.getUserMedia ||\n        \tnavigator.webkitGetUserMedia ||\n        \tnavigator.mozGetUserMedia;\n\n        \/\/ ask for an audio input\n        navigator.getUserMedia(\n        {\n            \"audio\": {\n                \"mandatory\": {\n                    \"googEchoCancellation\": \"false\",\n                    \"googAutoGainControl\": \"false\",\n                    \"googNoiseSuppression\": \"false\",\n                    \"googHighpassFilter\": \"false\"\n                },\n                \"optional\": []\n            },\n        }, onMicrophoneGranted, onMicrophoneDenied);\n    } catch (e) {\n        alert('getUserMedia threw exception :' + e);\n    }\n\n}\n\nfunction onMicrophoneDenied() {\n    alert('Stream generation failed.');\n}\n\nvar mediaStreamSource = null;\n\nfunction onMicrophoneGranted(stream) {\n    \/\/ Create an AudioNode from the stream.\n    mediaStreamSource = audioContext.createMediaStreamSource(stream);\n\n    \/\/ Create a new volume meter and connect it.\n    meter = createAudioMeter(audioContext);\n    mediaStreamSource.connect(meter);\n\n    \/\/ kick off the visual updating\n    onLevelChange();\n}\n\nfunction onLevelChange( time ) {\n    \/\/ clear the background\n    canvasContext.clearRect(0,0,WIDTH,HEIGHT);\n\n    \/\/ check if we're currently clipping\n    if (meter.checkClipping())\n        canvasContext.fillStyle = \"red\";\n    else\n        canvasContext.fillStyle = \"green\";\n\n    \/\/ draw a bar based on the current volume\n    canvasContext.fillRect(0, 0, meter.volume * WIDTH * 1.4, HEIGHT);\n\n    \/\/ set up the next visual callback\n    rafID = window.requestAnimationFrame( onLevelChange );\n}\n\n<\/script>\n\n<script>\n\nconst cameraOptions = document.querySelector('.video-options>select');\n\nconst getCameraSelection = async () => {\n  const devices = await navigator.mediaDevices.enumerateDevices();\n  const videoDevices = devices.filter(device => device.kind === 'videoinput');\n  const options = videoDevices.map(videoDevice => {\n    return `<option value=\"${videoDevice.deviceId}\">${videoDevice.label}<\/option>`;\n  });\n  cameraOptions.innerHTML = options.join('');\n};\n\ngetCameraSelection();\n\n<\/script>\n<\/div>\n\n\n\n<div class=\"wp-block-column as-default-columns-sidebar is-layout-flow wp-block-column-is-layout-flow\" style=\"padding-top:0;padding-right:0;padding-bottom:0;padding-left:0;flex-basis:33.33%\"><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This page lets you select both camera and microphone inputs to check that they&#8217;re working as expected. Unfortunately, the Safari browser doesn&#8217;t currently support the microphone input, so use Firefox or another browser for this test. Camera test If you allowed this page to access the camera just a moment ago, a live feed from [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":8774,"template":"wp-custom-template-page-with-no-featured-image","meta":{"_acf_changed":false,"footnotes":""},"tags":[],"productcategories":[],"class_list":["post-5654","userguide","type-userguide","status-publish","has-post-thumbnail","hentry"],"acf":[],"mb":[],"mfb_rest_fields":["title"],"_links":{"self":[{"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/userguide\/5654","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/userguide"}],"about":[{"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/types\/userguide"}],"author":[{"embeddable":true,"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/users\/1"}],"version-history":[{"count":4,"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/userguide\/5654\/revisions"}],"predecessor-version":[{"id":12149,"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/userguide\/5654\/revisions\/12149"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/media\/8774"}],"wp:attachment":[{"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/media?parent=5654"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/tags?post=5654"},{"taxonomy":"productcategories","embeddable":true,"href":"https:\/\/studios.aalto.fi\/fi\/wp-json\/wp\/v2\/productcategories?post=5654"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}