How to disable browser CPU throttling on SetTimeout? - javascript

When the browser is minimized or the tab is on the background they set setTimeout to a minimum of 1 second
example code:
const wait = ms => new Promise(r => setTimeout(r, ms))
async function doStuff() {
let p0 = performance.now();
await wait(100);
let p1 = performance.now();
console.log('time',(p1-p0));
await doStuff();
}
When the tab or the browser is on focus the console.log prints 100, when it's minimized 1000.
I also tried to use a web worker:
const cross_origin_script_url = "https://filebin.net/w73l748cgfap1qau/test.js?t=29itk5mt";
const worker_url = getWorkerURL( cross_origin_script_url );
const worker = new Worker( worker_url );
const wait = ms => new Promise(r => setTimeout(r, ms))
worker.onmessage = async function() {
let p0 = performance.now();
await wait(100);
let p1 = performance.now();
console.log('time',(p1-p0));
}
//worker.onmessage = (evt) => console.log( evt.data );
//URL.revokeObjectURL( worker_url );
// Returns a blob:// URL which points
// to a javascript file which will call
// importScripts with the given URL
function getWorkerURL( url ) {
const content = `importScripts( "${ url }" );`;
return URL.createObjectURL( new Blob( [ content ], { type: "text/javascript" } ) );
}
filebin test.js:
// worker.js
setInterval(function() {
postMessage('');
}, 1);
But it's very inconsistent, time using web worker:
How I can disable/bypass it?

Related

Async function in for loop

I'm trying to lazy load maps in the page. As the map element intersects, I load the script an run the appendMap() function. If two maps are in the viewport, the loadScript function test for map-scipt id is faster than the script loading, and I have an error because appendMap function does not exists.
How can I make this functions async to wait for the script loading at least one time ?
// Intersection Observer
const lazyInit = (element,margin,fn) => {
const observer = new IntersectionObserver((entries) => {
if (entries.some(({isIntersecting}) => isIntersecting)) {
observer.disconnect();
fn();
}
},{rootMargin: margin + 'px'});
observer.observe(element);
};
// Load script
function loadScript(url,id,fn){
var s = document.getElementById(id);
if(!s){
s = document.createElement('script');
s.id = id;
s.src = url;
s.async = true;
document.head.appendChild(s);
s.onload = function(){
fn();
}
} else {
fn();
}
}
// Maps
for(const map of document.querySelectorAll('.map')){
lazyInit(map,600,() => {
loadScript('/map-script.js','map-script',() => {
appendMap(map);
});
});
}
Can you try to make the function lazyInit async ?
const lazyInit = async (element,margin,fn) => {
const observer = new IntersectionObserver((entries) => {
if (entries.some(({isIntersecting}) => isIntersecting)) {
observer.disconnect();
await fn();
}
},{rootMargin: margin + 'px'});
observer.observe(element);
};
for (const map of document.querySelectorAll('.map')) {
const lazyResp = lazyInit(map, 600, () => {
loadScript('/map-script.js','map-script',() => {
appendMap(map);
});
});
}

What to do to store recording stream into the mobile browser using Media Recorder API?

I have a project requirement to record and store the currently running video stream. I have used webRTC for video streaming, and to record the video streaming, I have used MediaRecorder API. It is completely working fine in the desktop system. But it is not working in the mobile browser.
Any idea why it is not working in the mobile browser?
Following is the code snippet:
componentDidMount = async () => {
recordingStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true,
});
const mergedAudio = await this.mergeAudioStreams();
console.log("audio track length... ", mergedAudio.length);
const tracks = [
...recordingStream.getVideoTracks(),
...mergedAudio,
];
captureStream = new MediaStream(tracks);
mediaRecorder = new MediaRecorder(captureStream, options);
mediaRecorder.ondataavailable = this.handleDataAvailable;
mediaRecorder.start();
}
handleDataAvailable = async event => {
console.log("data-available", event);
if (event.data.size > 0) {
recordedChunks.push(event.data);
this.download();
} else {
// ...
console.log("in else");
}
};
download = async () => {
console.log("in download fn");
var blob = await new Blob(recordedChunks, {
type: "video/mp4",
});
//called the API to store the recorded video
}
mergeAudioStreams = async () => {
console.log("recordScreen fn called");
const ctx = new AudioContext();
const dest = ctx.createMediaStreamDestination();
let localSource, remoteSource;
if (this.state.localStream.getAudioTracks().length > 0) {
localSource = ctx.createMediaStreamSource(this.state.localStream);
}
if (this.state.selectedVideo.stream.getAudioTracks().length > 0) {
remoteSource = ctx.createMediaStreamSource(
this.state.selectedVideo.stream
);
}
const localGain = ctx.createGain();
const remoteGain = ctx.createGain();
localGain.gain.value = 0.7;
remoteGain.gain.value = 0.7;
localSource.connect(localGain).connect(dest);
remoteSource.connect(remoteGain).connect(dest);
console.log("combine tracks..", dest.stream.getAudioTracks());
return dest.stream.getAudioTracks();
};

Audio Record Problem in JavaScript some of the recording is missing

Hello Everyone I am trying to Record Audio and then after Recording I play it and when I hit the Cut function it just get the second I am on it in the player and cut to the end and start recording again and then overwrite the chunks array till the end with the new recording to sum up all of that all I need is when I record 5 seconds and then I want to overwrite the last 3 seconds so I remove the last 3 elements in the array and push the new chunks to the original array
when I do that and send the new chunk to the audio player it plays the first time as intended and if I pressed play again it just plays the newly recorded part only without the first 2 seconds that I preserved from the old recording
let audioChunks = [];
let Recorder = null;
const recordAudio = () => {
return new Promise(resolve => {
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
const mediaRecorder = new MediaRecorder(stream);
mediaRecorder.addEventListener("dataavailable", event => {
audioChunks.push(event.data);
});
const start = () => {
mediaRecorder.start(1000);
};
const stop = () => {
return new Promise(resolve => {
mediaRecorder.addEventListener("stop", () => {
const audioBlob = new Blob(audioChunks,{type: 'audio/mpeg-3'});
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
document.getElementById("AudioRecodingPlayer").src = audio.src;
document.getElementById("AudioRecodingPlayer").currentTime = 0;
const play = () => {
audio.play();
};
resolve({ audioBlob, audioUrl, play });
});
mediaRecorder.stop();
});
};
resolve({ start, stop });
});
});
};
async function StartRecording(){
Recorder = await recordAudio();
Recorder.start();
}
async function StopRecording(){
const audio = Recorder.stop();
}
function Cut(){
var Audio = document.getElementById("AudioRecodingPlayer");
var CurrenTime = Math.round(Audio.currentTime);
audioChunks.length = CurrenTime;
StartRecording();
}
On the Cut() function, you are not actually removing the elements of the array, nor changing the index or window. You are only changing the value of length.
What you would have to do is overwrite the audio chunks, or remove the chunks from that point forward.
let audioChunks = [];
let Recorder = null;
const recordAudio = () => {
return new Promise(resolve => {
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
const mediaRecorder = new MediaRecorder(stream);
mediaRecorder.addEventListener("dataavailable", event => {
audioChunks.push(event.data);
});
const start = () => {
mediaRecorder.start(1000);
};
const stop = () => {
return new Promise(resolve => {
mediaRecorder.addEventListener("stop", () => {
const audioBlob = new Blob(audioChunks,{type: 'audio/mpeg-3'});
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
document.getElementById("AudioRecodingPlayer").src = audio.src;
document.getElementById("AudioRecodingPlayer").currentTime = 0;
const play = () => {
audio.play();
};
resolve({ audioBlob, audioUrl, play });
});
mediaRecorder.stop();
});
};
resolve({ start, stop });
});
});
};
async function StartRecording(){
Recorder = await recordAudio();
Recorder.start();
}
async function StopRecording(){
const audio = Recorder.stop();
}
function Cut(){
var Audio = document.getElementById("AudioRecodingPlayer");
var CurrenTime = Math.round(Audio.currentTime);
audioChunks.splice(CurrentTime); // this will actually remove the elements after the "CurrentTime" index
StartRecording();
}

How can I pause a specific function in NodeJS?

Okay, so I've been trying to do this for a long time but I just can't find a solution. I'm building a personal Voice Assistant that only records when a hotword is detected, and everything until here works fine. To record the audio, I'm using the npm package node-record-lcpm16. I can't seem to find a solution to pause or stop(and start again) the recording. On the npm website of the audiorecorder there is a function specified that says recording.stop()
but it doesn't work for me. My code right now is:
const recorder = require('node-record-lpcm16');
const fs = require('file-system');
const speech = require('#google-cloud/speech');
const say = require('say');
const notifier = require('node-notifier');
const Bumblebee = require('bumblebee-hotword-node');
const { setTimeout } = require('timers');
const { record } = require('node-record-lpcm16');
const bumblebee = new Bumblebee;
const voice = 'Microsoft Zira Desktop';
bumblebee.addHotword('computer');
const config = {
encoding: 'LINEAR16',
sampleRateHertz: 16000,
languageCode: 'en-US',
};
const request = {
config,
interimResults: false,
};
const client = new speech.SpeechClient();
const recognizeStream = client
.streamingRecognize(request)
.on('error', console.error)
.on('data', data => findfunction(data.results[0].alternatives[0].transcript)
);
const recording = recorder.record({
sampleRateHertz: 16000,
threshold: 0,
recorder: 'sox',
silence: '5.0',
})
.stream().on('error', console.error); //Here is the Recorder, and I can't actually stop it and that's my problem.
recording.pipe(recognizeStream);
bumblebee.on('hotword', function(hotword){
console.log('Hotword detected:', hotword); // It does these actions as soon as the hotword is detected
recording.pipe(recognizeStream);
setTimeout(function stop(){
recording.pipe(fs.createWriteStream("\\\\.\\NUL")),
console.log('Stopped Recording.')
}, 5000);
});
console.log('Computer initiated.');
bumblebee.start();
//Everything down from here is just what do to with the translated speech, it doesn't play a role in my problem.
function findfunction(Data){
let findFunction = Data;
console.log(Data);
if(findFunction.includes('time')){
whattimeisit(findFunction);
};
if(findFunction.includes('day')){
whatdateisit(findFunction);
};
if(findFunction.includes('thank you')){
thankyou();
};
if(findFunction.includes('remind')){
setatimer(findFunction);
};
};
function whattimeisit(timeString){
const date = new Date();
const time = date.toLocaleTimeString();
say.speak(`It's currently ${time}.`, voice);
console.log(`It's currently ${time}.`);
};
function whatdateisit(dateString){
const date = new Date();
const currentDate = date.toLocaleDateString();
say.speak(`It's currently ${currentDate}.`, voice);
console.log(`It's currently ${currentDate}.`);
};
function thankyou(){
say.speak("You're welcome!", voice);
console.log("You're welcome!");
};
function setatimer(timerString){
const timer = timerString.replace(/\D/g, '');
setTimeout(function stop() {notifier.notify({title: 'Computer', message: 'Your timer ran out!', icon: './computericon1.png'})} , timer * 60000);
if(timer == 1){
say.speak(`Set a timer for ${timer} minute.`, voice);
console.log(`Set a timer for ${timer} minute.`);
}else{
say.speak(`Set a timer for ${timer} minutes.`, voice);
console.log(`Set a timer for ${timer} minutes.`);
};
};
Any help would be greatly appreciated!
I've played about with your code.. it's definitely a fun project to play with!
I would suggest maybe just modifying the code to record to a buffer, then send that to the google speech recognition engine.
The reason recording.stop() was probably not working for you is that you were calling it on the stream. If we separate the recording and recordingStream variables we can control the flow better.
I've updated the code so when we get the hotword, we stop recording, recognize the speech, then start recording again.
const recorder = require('node-record-lpcm16');
const Bumblebee = require('bumblebee-hotword-node');
const say = require('say');
const voice = 'Microsoft Zira Desktop';
const speech = require('#google-cloud/speech');
let chunks = null;
let recording = null;
function startRecording() {
console.log("listening...");
chunks = [];
recording = recorder.record({
sampleRateHertz: 16000,
threshold: 0,
recorder: 'sox',
silence: '5.0',
})
const recordingStream = recording.stream();
recordingStream.on('error', () => {});
// Tune this to ensure we only send the last few seconds of audio to google..
const maxChunks = 10;
recordingStream.on('data', (chunk) => {
chunks.push(chunk);
// keep the number of chunks below a reasonable limit...
if (chunks.length > maxChunks) {
chunks = chunks.slice(-maxChunks);
}
});
recordingStream.on('end', async () => {
// Create a buffer from our recording, it should only be a few seconds long.
const audioBuffer = Buffer.concat(chunks);
console.log("Chunk count:", chunks.length);
await recognizeSpeech(audioBuffer);
startRecording();
});
}
async function recognizeSpeech(audioBuffer) {
console.log(`recognizeSpeech: Converting audio buffer to text (${audioBuffer.length} bytes)...`)
const client = new speech.SpeechClient();
const request = {
config: { encoding: 'LINEAR16', sampleRateHertz: 16000, languageCode: 'en-US'},
audio: { content: audioBuffer.toString("base64") }
};
// Convert our audio to text.
const response = await client.recognize(request)
findfunction(response[0].results[0].alternatives[0].transcript);
}
startRecording();
startBumblebee();
function startBumblebee() {
const bumblebee = new Bumblebee();
bumblebee.addHotword('computer');
bumblebee.on('hotword', function(hotword){
console.log('Hotword detected:', hotword);
setTimeout(() => {
console.log('Stopping recording...');
recording.stop()
}, 2000);
});
bumblebee.start( );
}
// Nothing changed from here...
function findfunction(Data){
let findFunction = Data;
console.log(Data);
if(findFunction.includes('time')){
whattimeisit(findFunction);
};
if(findFunction.includes('day')){
whatdateisit(findFunction);
};
if(findFunction.includes('thank you')){
thankyou();
};
if(findFunction.includes('remind')){
setatimer(findFunction);
};
};
function whattimeisit(timeString){
const date = new Date();
const time = date.toLocaleTimeString();
say.speak(`It's currently ${time}.`, voice);
console.log(`It's currently ${time}.`);
};
function whatdateisit(dateString){
const date = new Date();
const currentDate = date.toLocaleDateString();
say.speak(`It's currently ${currentDate}.`, voice);
console.log(`It's currently ${currentDate}.`);
};
function thankyou(){
say.speak("You're welcome!", voice);
console.log("You're welcome!");
};
function setatimer(timerString){
const timer = timerString.replace(/\D/g, '');
setTimeout(function stop() {notifier.notify({title: 'Computer', message: 'Your timer ran out!', icon: './computericon1.png'})} , timer * 60000);
if(timer == 1){
say.speak(`Set a timer for ${timer} minute.`, voice);
console.log(`Set a timer for ${timer} minute.`);
}else{
say.speak(`Set a timer for ${timer} minutes.`, voice);
console.log(`Set a timer for ${timer} minutes.`);
};
};

Time limit for code execution

Considering the following execution of a JS program in a JS settlement, how can I implement a time limit to prevent infinite loops in program?
try {
var x = eval(document.getElementById("program").value);
} catch(e) {
...
}
Note: the call should be able to specify a maximum execution time, just in case program enters an infinite loop.
You could use a webworker to run this in another thread:
// Worker-helper.js
self.onmessage = function(e) {
self.postMessage(eval(e.data));
};
Them use the worker as:
var worker = new Worker('Worker-helper.js');
worker.postMessage(document.getElementById("program").value);
worker.onmessage = result => {
alert(result);
};
setTimeout(() => worker.terminate(), 10 * 1000);
...which will kill the worker after 10 seconds.
Easy to use utility:
function funToWorker(fn) {
var response = "(" + fn.toString() + ")()";
var blob;
try {
blob = new Blob([response], {type: 'application/javascript'});
} catch (e) { // Backwards-compatibility
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
blob = new BlobBuilder();
blob.append(response);
blob = blob.getBlob();
}
return new Worker(URL.createObjectURL(blob));
}
function limitedEval(string, timeout) {
return new Promise((resolve, reject) => {
const worker = funToWorker(function() {
self.onmessage = e => {
self.postMessage(eval(e.data));
}
});
worker.onmessage = e => resolve(e.data);
worker.postMessage(string);
setTimeout(() => {
worker.terminate();
reject();
}, timeout);
});
}
Usable as:
limitedEval("1 + 2", 1000)
.then(console.log)
.catch(console.error);
Try it!

Categories