Is it possible to tell if another Chrome tab is using webkitSpeechRecognition?
If you try to use webkitSpeechRecognition while another tab is using it, it will throw an error "aborted" without any message. I want to be able to know if webkitSpeechRecognition is open in another tab, and if so, throw a better error that could notify the user.
Unless your customer is on the same website(you could check by logging the ip/browserprint in database and requesting by json) you cannot do that.
Cross domain protection is in effect, and that lets you know zilch about what happens in other tabs or frames.
I am using webkitSpeechRecognition for chrome ( does not work on FF) and I faced same issues like multiple Chrome tabs. Until the browser implement a better error message a temporary solutions that work for me:
You need to detect when a tab is focused or not in Chrome using
Javascript.
Make javascript code like this
isChromium = window.chrome;
if(isChromium)
{
if (window.addEventListener)
{
// bind focus event
window.addEventListener("focus", function (event)
{
console.log("Browser tab focus..");
recognition.stop();// to avoid error
recognition.start();
}, false);
window.addEventListener("blur", function (event)
{
console.log("Browser tab blur..");
recognition.stop();
}, false);
}
}
There's a small workaround for it. You can store the timestamp in a variable upon activating SpeechRecognition and when it exits after a few seconds of inactivity, it will be compared to a timestamp since the SpeechRecognition was activated. Since two tabs are using the API simultaneously, it will exit immediately.
For Chrome, you can use the code below and modify it base on your needs. Firefox doesn't support this yet at the moment.
var transcriptionStartTime;
var timeSinceLastStart;
function configureRecognition(){
var webkitSpeechRecognition = window.webkitSpeechRecognition || window.SpeechRecognition;
if ('webkitSpeechRecognition' in window) {
recognition = new webkitSpeechRecognition();
recognition.continuous = true;
recognition.interimResults = true;
recognition.lang = "en-US";
recognition.onend = function() {
timeSinceLastStart = new Date().getTime() - transcriptionStartTime;
if (timeSinceLastStart < 100) {
alert('Speech recognition failed to start. Please close the tab that is currently using it.');
}
}
}
}
See browser compatibility here: https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition
Related
I'm trying to build something using the processor node here. Almost anything I do in terms of debugging it crashes chrome. Specifically the tab. Whenever I bring up dev tools, and 100% of the time i put a breakpoint in the onaudioprocess node, the tab dies and I have to either find the chrome helper process for that tab or force quit chrome altogether to get started agin. Its basically crippled my development for the time being. Is this a known issue? Do I need to take certain precautions to prevent chrome from crashing? Are the real time aspects are the web audio api simply not debuggable?
Without seeing your code, it's a bit hard to diagnose the problem.
Does running this code snippet crash your browser tab?
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function onPlay() {
let scriptProcessor = audioCtx.createScriptProcessor(4096, 2, 2);
scriptProcessor.onaudioprocess = onAudioProcess;
scriptProcessor.connect(audioCtx.destination);
let oscillator = audioCtx.createOscillator();
oscillator.type = "sawtooth";
oscillator.frequency.value = 220;
oscillator.connect(scriptProcessor);
oscillator.start();
}
function onAudioProcess(event) {
let { inputBuffer, outputBuffer } = event;
for (let channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
let inputData = inputBuffer.getChannelData(channel);
let outputData = outputBuffer.getChannelData(channel);
for (let sample = 0; sample < inputBuffer.length; sample++) {
outputData[sample] = inputData[sample];
// Add white noise to oscillator.
outputData[sample] += ((Math.random() * 2) - 1) * 0.2;
// Un-comment the following line to crash the browser tab.
// console.log(sample);
}
}
}
<button type="button" onclick="onPlay()">Play</button>
If it crashes, there's something else in your local dev environment causing you problems, because it runs perfectly for me.
If not, then maybe you are doing a console.log() (or some other heavy operation) in your onaudioprocess event handler? Remember, this event handler processes thousands of audio samples every time it is called, so you need to be careful what you do with it. For example, try un-commenting the console.log() line in the code snippet above – your browser tab will crash.
I'm creating a simple program for reading text file on the Windows Phone. I decided to make it a Universal Windows Platform (UWP) App.
In the app, I have a very simple MessageDialog, with three options, Yes, No, Cancel. It works perfectly on the Desktop and in the Simulator. However, when testing with the actual device, the ShowAsync method fails with the message: "Value does not fall in the expected range".
This only happens if there are more than two commands registered in the dialog. Does the MessageDialog class really supports up to three commands - as the documentation suggests - or is this only applying for UWP Apps running on Desktop devices?
At the moment, there is a clear statement in the docs:
The dialog has a command bar that can support up to 3 commands in desktop apps, or 2 commands in mobile apps.
Sad but true: on mobiles, there are two commands only. Need more? Use ContentDialog instead.
It looks like the documentation is missing information about Mobile (and really the API should do a better job here).
For Mobile, if you hit the Back key you get a null return value, so you can do this (not recommended coding pattern, but best I can think of):
async Task Test()
{
const int YES = 1;
const int NO = 2;
const int CANCEL = 3;
var dialog = new MessageDialog("test");
dialog.Commands.Add(new UICommand { Label = "yes", Id = YES });
dialog.Commands.Add(new UICommand { Label = "no", Id = NO });
// Ugly hack; not really how it's supposed to be used.
// TODO: Revisit if MessageDialog API is updated in future release
var deviceFamily = AnalyticsInfo.VersionInfo.DeviceFamily;
if (deviceFamily.Contains("Desktop"))
{
dialog.Commands.Add(new UICommand { Label = "cancel", Id = CANCEL });
}
// Maybe Xbox 'B' button works, but I don't know so best to not do anything
else if (!deviceFamily.Contains("Mobile"))
{
throw new Exception("Don't know how to show dialog for device "
+ deviceFamily);
}
// Will return null if you press Back on Mobile
var result = await dialog.ShowAsync();
// C# 6 syntactic sugar to avoid some null checks
var id = (int)(result?.Id ?? CANCEL);
Debug.WriteLine("You chose {0}", id);
}
Our chrome extension does not work correctly anymore since version 37.0.2062.103 (It used to work correctly on chrome version 36.0.1985.143).
Specifically, the debugger API has stopped working for us when we use the DOMDebugger.
See the attached code: (background.js)
chrome.tabs.onUpdated.addListener(function(tabId,changeInfo,tab){
if( changeInfo.status == "loading" && tab.active){
var debugId = {tabId:tabId};
chrome.debugger.attach(debugId, '1.0', function() {
chrome.debugger.sendCommand(debugId, 'Debugger.enable', {}, function() {
chrome.debugger.sendCommand(debugId, "DOMDebugger.setEventListenerBreakpoint", {'eventName':'click'},
function(result) {
console.log('registering click');
});
});
});
}
});
chrome.debugger.onEvent.addListener(onEvent);
function onEvent(debuggeeId, method,params) {
if(method=="Debugger.paused"){
console.log('DONE!');
}
};
The extension successfully starts the debugger. we get the yellow debugger ribbon.
We also see the 'registering click' msg in the console. the result argument is an empty object {} (line 8).
However upon clicking on a button that has a click event listener nothing happens.
It used to work without any issues.
It seems like it regressed with https://codereview.chromium.org/305753005. One needs to call "DOM.enable" for it to work now. On the Chrome side, we should implicitly enable DOM domain upon setEventListenerBreakpoint for backwards compatibility. Unfortunately it already squeezed into the stable release.
I've been tracking down a bug for days... then I realized the bug was me. :/
I had been using webRequest.onComplete, filtered for scripts. My error was that I made the incorrect association between the scripts being loaded and being executed. The get loaded in a different order than they get executed, and thus the timing of the events is not in the order I need them in. I need to inject between certain scripts so I need an event right after a file has been executed and before the next one.
The only solution I can think of at the moment is to alter the JS being loaded before it gets executed. But it makes my stomach turn. And the bfcache would wreak even more havoc, so not a great solution either.
I would use the HTML5 spec's afterscriptexecute, but that is not implemented in Chrome. Is there another API, perhaps an extension API that I can use?
Note: This method no longer works as of Chrome 36. There are no direct alternatives.
Note: The answer below only applies to external scripts, i.e. those loaded with <script src>.
In Chrome (and Safari), the "beforeload" event is triggered right before a resource is loaded. This event allows one to block the resource, so that the script is never fetched. In this event, you can determine whether the loaded resource is a script, and check whether you want to perform some action
This event can be used to emulate beforescriptexecute / afterscriptexecute:
document.addEventListener('beforeload', function(event) {
var target = event.target;
if (target.nodeName.toUpperCase() !== 'SCRIPT') return;
var dispatchEvent = function(name, bubbles, cancelable) {
var evt = new CustomEvent(name, {
bubbles: bubbles,
cancelable: cancelable
});
target.dispatchEvent(evt);
if (evt.defaultPrevented) {
event.preventDefault();
}
};
var onload = function() {
cleanup();
dispatchEvent('afterscriptexecute', true, false);
};
var cleanup = function() {
target.removeEventListener('load', onload, true);
target.removeEventListener('error', cleanup, true);
}
target.addEventListener('error', cleanup, true);
target.addEventListener('load', onload, true);
dispatchEvent('beforescriptexecute', true, true);
}, true);
The dispatch times are not 100% identical to the original ones, but it is sufficient for most cases. This is the time line for the (non-emulated) events:
beforeload Before the network request is started
beforescriptexecute Before a script executes
afterscriptexecute After a script executes
onload After the script has executed
Here's an easy way to see that the events are working as expected:
window.addEventListener('afterscriptexecute', function() {
alert(window.x);
});
document.head.appendChild(document.createElement('script')).src = 'data:,x=1';
document.head.appendChild(document.createElement('script')).src = 'data:,x=2';
The demo can be seen live at http://jsfiddle.net/sDaZt/
I'm not familiar with Chrome Extensions (only browser javascript), but I think that you will unfortunately have to edit your loaded JS so that is calls a function of your choice when it is executed, if you want to do this nicely. This it what Google does for asynchronously loading its Maps Javascript file:
function loadScript() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://maps.googleapis.com/maps/api/js?sensor=false&callback=executed";
document.body.appendChild(script);
}
function executed() {
/* Google maps has finished loading, do awesome things ! */
}
If you really don't want to edit your loaded JS files, you could have a setInterval (or a recursive function with setTimeout) checking regularly if some functions or variables are initialized.
Have you tried script loading using Modernizr.js?
I had a similar issue, where the timing of script loading was causing conflict. I used Modernizr.js, which includes the library yepnope.js by default. Below is an example of some scripts I loaded conditionally. You can include a test clause, or simply load them in the order you prefer, with the guarantee that they will load and execute in the order you wish due to the callback.
Here is an example with a conditional clause:
Modernizr.load({
test: false, //Or whatever else you'd like. Can be conditional, or not so conditional
yep: {
'script1': 'MyJavascriptLibrary1.js'
},
nope: {
'script2': 'MyJavascriptLibrary2.js',
'script3': 'MyJavascriptLibrary3.js'
},
callback: {
'script1': function (url, result, key) {
console.log('MyJavascriptLibrary1.js loaded'); //will not load in this example
},
'script2': function (url, result, key) {
console.log('MyJavascriptLibrary2.js loaded first');
},
'script3': function (url, result, key) {
console.log('MyJavascriptLibrary3.js loaded second');
}
}
});
If triggering false, MyJavascriptLibrary2.js and MyJavascriptLibrary3.js will load in the appropriate order, no matter what elements influence how they would behave normally (file size, connection speed, etc.). In these callbacks, you may fire additional javascript as well, in the order you wish to do so. Example:
'script2': function (url, result, key) {
alert('anything in here will fire before MyJavascriptLibrary3.js executes');
},
Note this can be done without Modernizr.load({...
but using simply yepnope({...
For more documentation, check out the yepnope.js API
I have the latest versions of Firefox and IE, but the example in html5rocks.com is not working in these two browsers. I tested with Chrome and it works fine.
I have noted that these browsers does not fire any event ('onsuccess' or 'onerror') on attempting to open the indexedDB as follows.
var request = indexedDB.open("todos");
Please share any ideas/solution for this issue.
to make html5rocks demo work on Firefox you need to attach onupgradeneeded event on database open instead of setversion method for creating the database.
here is the code sample that works both on Firefox and Chrome:
myStorage.indexedDB.open = function() {
var v = 1;
var request = indexedDB.open("todos", v);
//Firefox code for db init
request.onupgradeneeded = function (e) {
myStorage.indexedDB.db = e.target.result;
var db = myStorage.indexedDB.db;
// We can only create Object stores in a setVersion transaction;
if(db.objectStoreNames.contains("todo")) {
var storeReq = db.deleteObjectStore("todo");
}
var store = db.createObjectStore("todo",
{keyPath: "timeStamp"});
}
request.onsuccess = function(e) {
myStorage.indexedDB.db = e.target.result;
var db = myStorage.indexedDB.db;
//Chrome code for db init
if (v!= db.version && db.setVersion) {
var setVrequest = db.setVersion(v);
// onsuccess is the only place we can create Object Stores
setVrequest.onerror = myStorage.indexedDB.onerror;
setVrequest.onsuccess = function(e) {
if(db.objectStoreNames.contains("todo")) {
db.deleteObjectStore("todo");
}
var store = db.createObjectStore("todo",
{keyPath: "timeStamp"});
myStorage.indexedDB.getAllTodoItems();
};
}
else
myStorage.indexedDB.getAllTodoItems();
};
request.onerror = myStorage.indexedDB.onerror;
}
Edit: Here is a link to working version of the html5roks ToDo demo, which I maintain on github, expanded with two new features for viewing details data and updating values.
Chrome is behind on the IndexedDB standard.
There was a new revision introduced in December and Firefox and IE have upgraded. Chrome has not yet.
I believe it's mostly folks from the Chrome crew who run HTML5Rocks.com so it makes sense why these examples would be behind.
The big change between the pre and post-December 2010 API are the change in setVersion requests and the new onupgradeneeded callback.
Todo list example is outdated IndexedDB specification implemented on chrome. Now you got to use onupgardedneeded method, and well setVersion too for now.
IndexedDB is not supported on IE. Visit html5test.com for verification
Edit 2015: IndexedDB API is available in IE as of version 10