I have been trying to get data chat working using webrtc. It was working previously in google chrome and suddenly stopped working, I have narrowed down the issue to 'ondatachannel' callback function not getting triggered. The exact same code works fine in Mozilla.
Here's the overall code:
app.pc_config =
{'iceServers': [
{'url': 'stun:stun.l.google.com:19302'}
]};
app.pc_constraints = {
'optional': [
/* {'DtlsSrtpKeyAgreement': true},*/
{'RtpDataChannels': true}
]};
var localConnection = null, remoteConnection = null;
try {
localConnection = new app.RTCPeerConnection(app.pc_config, app.pc_constraints);
localConnection.onicecandidate = app.setIceCandidate;
localConnection.onaddstream = app.handleRemoteStreamAdded;
localConnection.onremovestream = app.handleRemoteStreamRemoved;
}
catch (e) {
console.log('Failed to create PeerConnection, exception: ' + e.message);
return;
}
isStarted = true;
In Create Channel that follows this:
var localConnection = app.localConnection;
var sendChannel = null;
try {
sendChannel = localConnection.createDataChannel(app.currentchannel,
{reliable: false});
sendChannel.onopen = app.handleOpenState;
sendChannel.onclose = app.handleCloseState;
sendChannel.onerror = app.handleErrorState;
sendChannel.onmessage = app.handleMessage;
console.log('created send channel');
} catch (e) {
console.log('channel creation failed ' + e.message);
}
if (!app.isInitiator){
localConnection.ondatachannel = app.gotReceiveChannel;
}
app.sendChannel = sendChannel;
I create Offer:
app.localConnection.createOffer(app.gotLocalDescription, app.handleError);
and Answer:
app.localConnection.createAnswer(app.gotLocalDescription, app.handleError);
the offer and answer get created successfully, candidates are exchanged and onicecandidate event is triggered at both ends! Local Description and RemoteDescription are set on both respective ends.
I have a pusher server for signalling, I am able to send and receive messages through the pusher server successfully.
The same webrtc code works for audio/video = true, the only issue is when I try to create datachannel. The only step that does not get executed is the callback function not getting executed i.e "gotReceiveChannel"
I'm starting to think it's the version of chrome.. I am not able to get the GitHub example working in chrome either: (Step4 for data chat)
https://bitbucket.org/webrtc/codelab
While the same code works in Mozilla.
The sendChannel from the offerer has a "readyState" of "connecting"
Any help much appreciated.
Related
In a Chrome Extension, I have no problem adding, updating, and removing data to/from an IndexedDB database accessed by my service worker with Chrome Runtime Messaging sent from my content script. My trouble is doing a full table read from my content script. I do a console.log() to dump out the property before I send it back in my sendResponse in the Chrome Runtime Messaging, and I see the data there properly, but the content script receives an undefined. I assume this is because of the asynchronous nature of getting the data. I tried promises and async/await and the combination thereof and I just can't seem to get anything except an undefined in my content script on the message back from the service worker. I also ran sending a test array back and that worked just fine -- but receiving the IndexedDB table data does not work in the message passing. I also tried to JSONify the data and that didn't help either. What's the catch?
service-worker.js
importScripts('modules/idb.js');
var SW = {};
SW.onReady = function(){
chrome.runtime.onMessage.addListener(function(o, sender, sendResponse) {
(o.readTable) && sendResponse(SW.readTable(o,sender));
});
};
SW.readTable = function(o,sender){
var sTable = o.table;
new Promise((resolve) => {
IDB.readTable(sTable,function(asEntries){
resolve(asEntries);
});
}).then((asEntries) => {
console.log('SW asEntries',asEntries); // this shows me valid data in tests
var o = {};
// can also change this to fake data with asEntries being a string array and bug goes away in content.js
o.response = asEntries;
return o;
});
};
SW.onReady();
modules/idb.js
var IDB = {};
// Requires storage (or, even better, unlimitedStorage) permission in your manifest.json file.
// Note also that dev console of service worker will not show data -- have to use toolbar button popup panel (if you have one) and
// dev console from there, or code to access it, which sucks.
IDB.connectStore = function(sTable,sReadWriteSetting,fn){
var conn = indexedDB.open('unlimitedStorage', 1);
conn.onupgradeneeded = function(e) {
var db = e.target.result;
db.createObjectStore(sTable);
};
conn.onsuccess = function(e) {
var db = e.target.result;
var tx = db.transaction(sTable,sReadWriteSetting);
var store = tx.objectStore(sTable);
fn(db,tx,store);
};
};
IDB.addToTable = function(sTable,sKey,sVal){
IDB.connectStore(sTable,'readwrite',function(db,tx,store){
if ((sKey === undefined) || (sKey === '') || (sKey === null) || (sKey === false)) { // auto key by increment
var req = store.count();
req.onsuccess = function(e){
sKey = e.target.result + 1;
store.add(sVal,sKey);
tx.complete;
}
} else {
store.add(sVal,sKey);
tx.complete;
}
});
};
IDB.removeFromTable = function(sTable,sKey){
IDB.connectStore(sTable,'readwrite',function(db,tx,store){
store.delete(sKey);
tx.complete;
});
};
IDB.readTableByKey = function(sTable,sKey,fn){
IDB.connectStore(sTable,'readonly',function(db,tx,store){
var req = store.get(sKey);
req.onerror = function(e){
fn(e.target.result);
}
req.onsuccess = function(e){
fn(e.target.result);
}
});
};
IDB.readTable = function(sTable,fn){
IDB.connectStore(sTable,'readonly',function(db,tx,store){
var req = store.getAll();
req.onerror = function(e){
fn(e.target.result);
}
req.onsuccess = function(e){
fn(e.target.result);
}
});
};
content.js
var CONTENT = {};
CONTENT.onReady = function(){
var o = {};
o.readTable = true;
o.table = 'loadTimes';
chrome.runtime.sendMessage(o,function(response){
if (response.response) { // errors here with response property being undefined
console.log('CONTENT RCVD asEntries',response.response);
}
});
};
CONTENT.onReady();
Chrome extensions API, unlike Firefox WebExtensions, can't handle Promise returned from a callback or provided in sendResponse, https://crbug.com/1185241.
There's also a bug in your readTable: you need to add return before new Promise((resolve)
The solution is two-fold:
Use return true from the callback to allow asynchronous sendResponse
Call sendReponse inside .then of a Promise chain.
chrome.runtime.onMessage.addListener(function(o, sender, sendResponse) {
if (o.readTable) {
SW.readTable(o,sender).then(sendResponse);
return true;
} else {
sendResponse(); // Chrome 99-101 bug workaround, https://crbug.com/1304272
}
});
Do not use this answer. It is here for posterity reasons and is just a workaround. The chosen solution works.
The fix is to return data in a different message thread:
In the service worker in SW.readTable(), just return variable o with o.response = true and then ignore the response in the content script.
Before returning the variable o from SW.readTable(), do a chrome.runtime.sendMessage({readTableResult = true, data: asEntries},function(response){ /* ignore response */});
In the content script, ignore any response back from the readTable message. So, the if (response.response) {...} condition can be eliminated.
In the content script, add a message listener with chrome.runtime.onMessage.addListener(o, sender, sendResponse) and look for the condition (o.readTableResult). Once received, the o.data will now contain the asEntries data.
I am trying to build an addon working on both firefox and chrome in order to get started with extensions (it's not an extension to be published). My aim is basically to recover the mouse movements and a screenshot of the tab and send them through a REST API.
Everything was working fine as of yesterday, but as I am testing today, I am getting an error stating that the content script isn't able to communicate with my background script.
I have checked if a new version of firefox was released overnight and it doesn't seem to be the case to my knowledge. I then have extensively checked the google runtime APIs, and my code seems to be constructed accordingly to the documentation.
What's more intriguing is that everything was working fine even with multiple trials.
If I try to print the content of the sent message, it doesn't print anything.
When I load a temporary addon on firefox, I get a temporary ID, and the error I get is the following :
Error: Could not establish connection. Receiving end does not exist.
background.js:1:745 Unchecked lastError value: Error: Could not
establish connection. Receiving end does not exist. background.js:1
sendRequestToSpecificTab
moz-extension://94826cb7-3494-4f28-abda-e0dbb477ca37/js/background.js:1
I noticed that the ID specified in the error is different than the ID that is provided when I load the addon.
Here is my code :
keylog.js
//capturing the mouse movements
window.addEventListener("mousemove", logMouseMove, false);
window.addEventListener("mousedown", logMouseDown, false);
function logMouseMove(e) {
let currentdate = Date.now();
chrome.runtime.sendMessage({action: "mouselog",data : currentdate+': ('+e.pageX+','+e.pageY+')'});
}
function logMouseDown(e) {
let currentdate = Date.now();
chrome.runtime.sendMessage({action: "mouselog",data :currentdate+': ['+e.pageX+','+e.pageY+']'});
}
And background.js :
"use strict";
let concatenated = "";
let mouse_coord={};
let mouse_json = {};
var id = "";
chrome.runtime.onMessage.addListener(msg => {
var ID = function () {
return '_' + Math.random().toString(36).substr(2, 9);
};
if(msg.action == "mouselog") {
let splitted = msg.data.split(':');
mouse_coord[splitted[0]] = splitted[1];
console.log(msg.data);
if(splitted[1].charAt(0) === '[') {
id = ID();
mouse_json[id] = mouse_coord;
mouse_coord = {};
concatenated += JSON.stringify(mouse_json, null, 4);
let donnes= {};
donnes['id'] = id;
donnes['data'] = mouse_json;
chrome.tabs.query({active: true, currentWindow:true}, (tab) => {
donnes['tab'] = tab;
sendData('http://localhost:33333/mouselog', JSON.stringify(donnes));
});
mouse_json = {};
chrome.tabs.captureVisibleTab(
null,
{},
function(dataUrl)
{
let data = {};
data['id'] = id;
data["data"] = dataUrl;
sendData('http://localhost:33333/saveimg', JSON.stringify(data));
console.log('Sent screenshot');
}
);
try {
chrome.tabs.executeScript(null, {
file: 'injection_script.js'
}, function() {
if (chrome.runtime.lastError) {
message.innerText = 'There was an error injecting script : \n' + chrome.runtime.lastError.message;
}
});
} catch(err) {
console.error(err);
}
}
}
});
I am also declaring on my manifest all the necessary permissions :
"all_urls", "activeTab", "storage", "tabs", "webRequest"
Is there anything I am doing wrong ? I haven't changed a single line to the code that was working last time I tested, so I am doubting the issue may not be from my code, but from the browser ?
I am currently try to get the data from cloudmqtt by subscribe to a topic. But when I try to convert it to string so that my Alexa could read it the test service of Alexa tell me "The remote endpoint could not be called, or the response it returned was invalid."
My Subscribing code is as follow
var mqtt = require('mqtt');
function DHTSensorInSession(intent, session, callback) {
const cardTitle = intent.name;
let repromptText = '';
let sessionAttributes = {};
const shouldEndSession = true;
let speechOutput = '';
let Tempe = '';
var mqttpromise = new Promise( function(resolve,reject){
var client = mqtt.connect({port:19546,host:'m14.cloudmqtt.com',username:'jkgnbggq',password:'VbG2-RvZTEt-'})
client.on('connect', function() { // When connected
// publish a message to any mqtt topic
client.publish('main/light/esp', 'connected')
client.subscribe('main/sensor/temp')
});
client.on('message',function(topic,message){
if(topic.toString() === 'main/sensor/temp')
{
Tempe += message.toString();
}
client.end();
resolve('Done sending');
})
});
mqttpromise.then(
function(data) {
console.log('Function called succesfully:', data);
sessionAttributes = createSensorAttributes(Tempe);
speechOutput = "That wire less light has been turned " + Tempe;
repromptText = "Ok, turning the light " + Tempe;
callback(sessionAttributes,buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
},
function(err) {
console.log('An error occurred:', err);
}
);
}
Refer to the logs for your lambda to locate any error messages. These can be found in the AWS console, or using the ASK CLI command "ask lambda log ...".
These may appear a bit cryptic at first, but they can be very helpful when something goes wrong. Look for the entries with the words "error" or "fail". Often they will include a line number of your index.js (or other) file showing you exactly which line is causing the problem.
Alternatively, create unit tests to test your code locally before uploading.
There are lots of articles and posts online about doing this.
MQTT doesn't work that way.
Normally messages are only delivered to already connected clients that are subscribed to a topic at the instant they the message is published. The exception to this is if the message is flagged as retained, in this case the LAST message published will be delivered to a new client at the point where they subscribe to the topic.
I have the following callback for the onicecandidate event of RTCPeerConnection:
function iceCallback(event) {
if (event.candidate) {
var candidate = event.candidate;
socSend("candidate", candidate. event.target.id);
}
}
I am able to read the candidate from the event.candidate. But when I try to read the event.target.id, I get an exception, cannot read property target of undefined.
"id" is a property I previously created for the RTCPeerConnection. This is for a multiuser video chat.
I am trying to figure out which RTCPeerConnection fired the onicecandidate event so I know to which client I need to send the icecandidate. I am using the adapter.js library.
I assumed that some part of your code would be like below, I have just added a simple modification:
peerConnections ={};
function createNewConncection(id){
var pc = new RTCPeerConnection();
pc.onaddstream = ...
...
//pc.onicecandidate = iceCallback; // OLD CODE
pc.onicecandidate = iceCallback.bind({pc:pc, id:id}); // NEW CODE
peerConnections[id] = pc;
}
function iceCallback(event) {
if (event.candidate) {
var candidate = event.candidate;
//socSend("candidate", candidate. event.target.id); // OLD CODE
socSend("candidate", this.id); // NEW CODE
}
}
I have problems with simple push on ffos. Here is my code:
var endpoint;
$(document).ready(function() {
registerPush();
navigator.mozSetMessageHandler("push", function(message) {
if(message.pushEndpoint == endpoint) {
console.log("push notification: "+message.version);
}
});
navigator.mozSetMessageHandler("push-register", function() {
registerPush();
});
});
function registerPush() {
var req = navigator.push.register();
req.onsuccess = function(e) {
endpoint = e.target.result;
console.log(endpoint);
}
}
It is working ok when i start the app, but after few minutes if i try to send a push to the endpoint, nothing happens. But when i call the registerPush(); function, everithing works again for few minutes.
It is said that there may be a bug. Some routers may are filtering the push notifications, so that may be the problem. I think It may be bypassed using a 3G connection.