How to call addIceCandidate in dart - exception

I want to connect two peers with RTCPeerConnections but I am not able to add the IceCandidate from Alice to Bob.
example:
var alice = new RtcPeerConnection(
{"iceServers": [{"url": "stun:stun.l.google.com:19302"}]}
);
var bob = new RtcPeerConnection(
{"iceServers": [{"url": "stun:stun.l.google.com:19302"}]}
);
alice.createDataChannel("somelablel", {});
alice.onNegotiationNeeded.listen((var data){
alice.createOffer({}).then((var offer){
//got offer
alice.setLocalDescription(offer);
bob.setRemoteDescription(offer);
});
});
bob.onIceCandidate.listen((evt) {
if (evt.candidate)
print(evt.cancelable);
});
alice.onIceCandidate.listen((evt) {
if(evt.candidate != null)
//TODO: add iceCandidate to Bob
});
First version (seems to be old but is heavily used in online examples):
bob.addIceCandidate(candidatefromAlice);
Output:
Class 'RtcPeerConnection' has no instance method
'addIceCandidate' with matching arguments.
Second try (new version with 3 parameters):
bob.addIceCandidate(candidatefromAlice, (){}, (var error){
print(error.toString());
});
Output:
NotSupportedError: The implementation did not support the
requested type of object or operation. (Dartium)
How can I set the ICE candidates in dart without problems?
Info:
Dart VM version: 0.1.2.0_r30864 (Wed Dec 4 11:03:45 2013) on "linux_x64"
dartium : Chromium 31.0.1650.48

I think you will have to wait until this bug is fixed
https://code.google.com/p/dart/issues/detail?id=15008
the code you are asking for seems to be
bob.addIceCandidate(evt.candidate, () => print('void: $evt'), (var x) => print('FailureCallback: $evt'));
A comment on this question Is addIceCandidate implemented in Dartium? seems to indicate that it doesn't work in Dartium but works in Chrome after converting the project to JavaScript.

I found a workaround by using the js-interop library. Just use proxies:
import 'package:js/js.dart' as js;
// ...
_rpc = new js.Proxy(js.context.webkitRTCPeerConnection, js.map(iceServers));
// ...
var iceCandidate = new js.Proxy(js.context.RTCIceCandidate,
js.context.JSON.parse(/*your icecandidate string*/)
);
_rpc.addIceCandidate(iceCandidate);

Related

Beginner problem with chrome navigator.serial

I am working on use of serial port access with chrome browser, using "navigator.serial".
My initial experiment is based on a prior posting to stackoverflow:
Is there an example site that uses navigator.serial?
I have duplicated the code example referenced above, and have made the required configuration change #enable-experimental-web-platform-features, again as described above.
I am doing this all on Ubuntu 18.04. There are two USB serial ports attached to the machine, and I have verified using gtkterm that I can send and receive data between the two ports.
From the example given (code duplicated below), I find that I can open the serial port and establish a "reader", and the step await reader.read() does wait until an incoming character appears on the serial port, but at this point the variabler/object "data" remains undefined.
Two questions/issues:
What am I doing wrong that leaves "data" undefined? I added an alert() dialog box that pops up once const {done, data} = await reader.read(); proceeds, however, the dialog box says that "data" is at that point undefined. Is data a promise that I am failing to wait to be fulfilled?
I have not been able to find a (hopefully self-contained) reference on the methods and members of the classes involved (i.e., reader.read() and reader.write() are methods available to my object "readeer"; where can I find a list of available methods, and the properties of these?
Here is a copy of the code (small web page) that was obtained from the year-ago posting above:
<html>
<script>
var port;
var buffy = new ArrayBuffer(1);
var writer;
buffy[0]=10;
const test = async function () {
const requestOptions = {
// Filter on devices with the Arduino USB vendor ID.
//filters: [{ vendorId: 0x2341 }],
};
// Request an Arduino from the user.
port = await navigator.serial.requestPort(requestOptions);
// Open and begin reading.
await port.open({ baudrate: 115200 });
//const reader = port.in.getReader();
const reader = port.readable.getReader();
writer = port.writable.getWriter();
//const writer = port.writable.getWriter();
//writer.write(buffy);
while (true) {
const {done, data} = await reader.read();
if (done) break;
console.log(data);
}
} // end of function
</script>
<button onclick="test()">Click It</button>
</html>
Thank you for any assistance!
I was having the exact same problem and managed to solve it.
Change
const {done, data} = await reader.read();
To
const {value, done} = await reader.read();
The example where you got this from (and a few others) were wrong, params around the wrong way.
Also, not too sure why but when I used
const {data, done} = await reader.read();
it did not work either, it did not like the var data.
Documentation on navigator.serial is not great. Here are some links to help
The API (note this is draft and does not exactly match the Chrome implementation)
https://wicg.github.io/serial/
port.readable.getReader() is a ReadableStream
https://streams.spec.whatwg.org/#readablestream
that uses ReadableStreamDefaultReader which is defined as
dictionary ReadableStreamDefaultReadResult {
any value;
boolean done;
};
https://streams.spec.whatwg.org/#readablestreamdefaultreader
An explainer
https://github.com/WICG/serial/blob/gh-pages/EXPLAINER.md
A tutorial
https://codelabs.developers.google.com/codelabs/web-serial
Chromium tracker
https://goo.gle/fugu-api-tracker
The Web Serial API work item
https://bugs.chromium.org/p/chromium/issues/detail?id=884928

Geolocation.currentLocation() not working, giving null value using meteor(1.5.1) & mdg:geolocation(1.3.0)

I am working in a meteor project(1.5.1) and using mdg:geolocation#1.3.0, and i am trying to get the value of Geolocation.currentLocation() but it is giving me null value and the behaviour is not the same for all the time, sometime it is giving me null value and sometime giving me proper value.
I have research for the long time, but not got the solution yet, if possible please provide solution with meteor#1.5.1 and with use of mdg:geolocation package.
Thanks in advance...
MDG has implemented mdg:geolocation for continuous geolocation and functions in this Meteor package return a reactive var. You can use the package this way (for example):
// Continous geolocation with mdg:geolocation
// This code will run every time user location changes.
Tracker.autorun(() => {
const position = Geolocation.currentLocation();
Tracker.nonreactive(() => {
if (position) {
Meteor.call('user.update.position', position);
}
});
});
If you don't need continous geolocation, You can use javascript method instead of meteor package. See this answer for other options with windows.navigator.geolocation. In this case you may need to add cordova-plugin-geolocation in case you are building Android or iOS apps
// Navigation geolocation to get geolocation only once
let errorCallback;
let successCallback;
successCallback = position => Meteor.call('user.update.position', position);
errorCallback = err => console.log(err);
navigator.geolocation.getCurrentPosition(successCallback, errorCallback, {
maximumAge: 60000,
timeout: 20000
});

Accessing indexedDB in ServiceWorker. Race condition

There aren't many examples demonstrating indexedDB in a ServiceWorker yet, but the ones I saw were all structured like this:
const request = indexedDB.open( 'myDB', 1 );
var db;
request.onupgradeneeded = ...
request.onsuccess = function() {
db = this.result; // Average 8ms
};
self.onfetch = function(e)
{
const requestURL = new URL( e.request.url ),
path = requestURL.pathname;
if( path === '/test' )
{
const response = new Promise( function( resolve )
{
console.log( performance.now(), typeof db ); // Average 15ms
db.transaction( 'cache' ).objectStore( 'cache' ).get( 'test' ).onsuccess = function()
{
resolve( new Response( this.result, { headers: { 'content-type':'text/plain' } } ) );
}
});
e.respondWith( response );
}
}
Is this likely to fail when the ServiceWorker starts up, and if so what is a robust way of accessing indexedDB in a ServiceWorker?
Opening the IDB every time the ServiceWorker starts up is unlikely to be optimal, you'll end up opening it even when it isn't used. Instead, open the db when you need it. A singleton is really useful here (see https://github.com/jakearchibald/svgomg/blob/master/src/js/utils/storage.js#L5), so you don't need to open IDB twice if it's used twice in its lifetime.
The "activate" event is a great place to open IDB and let any "onupdateneeded" events run, as the old version of ServiceWorker is out of the way.
You can wrap a transaction in a promise like so:
var tx = db.transaction(scope, mode);
var p = new Promise(function(resolve, reject) {
tx.onabort = function() { reject(tx.error); };
tx.oncomplete = function() { resolve(); };
});
Now p will resolve/reject when the transaction completes/aborts. So you can do arbitrary logic in the tx transaction, and p.then(...) and/or pass a dependent promise into e.respondWith() or e.waitUntil() etc.
As noted by other commenters, we really do need to promisify IndexedDB. But the composition of its post-task autocommit model and the microtask queues that Promises use make it... nontrivial to do so without basically completely replacing the API. But (as an implementer and one of the spec editors) I'm actively prototyping some ideas.
I don't know of anything special about accessing IndexedDB from the context of a service worker via accessing IndexedDB via a controlled page.
Promises obviously makes your life much easier within a service worker, so I've found using something like, e.g., https://gist.github.com/inexorabletash/c8069c042b734519680c to be useful instead of the raw IndexedDB API. But it's not mandatory as long as you create and manage your own promises to reflect the state of the asynchronous IndexedDB operations.
The main thing to keep in mind when writing a fetch event handler (and this isn't specific to using IndexedDB), is that if you call event.respondWith(), you need to pass in either a Response object or a promise that resolves with a Response object. As long as you're doing that, it shouldn't matter whether your Response is constructed from IndexedDB entries or the Cache API or elsewhere.
Are you running into any actual problems with the code you posted, or was this more of a theoretical question?

webrtc: failed to send arraybuffer over data channel in chrome

I want to send streaming data (as sequences of ArrayBuffer) from a Chrome extension to a Chrome App, since Chrome message API (includes chrome.runtime.sendMessage, postMessage...) does not support ArrayBuffer and JS arrays have poor performance, I have to try other methods. Eventually, I found WebRTC over RTCDataChannel might a good solution in my case.
I have succeeded to send string over a RTCDataChannel, but when I tried to send ArrayBuffer I got:
code: 19
message: "Failed to execute 'send' on 'RTCDataChannel': Could not send data"
name: "NetworkError"
It seems that it's not a bandwidths limits problem since it failed even though I sent one byte of data. Here is my code:
pc = new RTCPeerConnection(configuration, { optional: [ { RtpDataChannels: true } ]});
//...
var dataChannel = m.pc.createDataChannel("mydata", {reliable: true});
//...
var ab = new ArrayBuffer(8);
dataChannel.send(ab);
Tested on OSX 10.10.1, Chrome M40 (Stnble), M42(Canary); and on Chromebook M40.
I have filed a bug for WebRTC here.
I modified my code, now everything worked amazing:
removed RtpDataChannels option when creating RTCPeerConnection.(YES, remove RtpDataChannels option if you want data channel, what a magic world!)
on receiver side: no need createDataChannel, instead, handle onmessage, onxxx by using event.channle from pc.ondatachannel callback:
pc.ondatachannel function(event)
var receiveChannel = event.channel;
receiveChannel.onmessage = function(event){
console.log("Got Data Channel Message:", event.data);
};
};

new APIs for windows phone 8.1

I am trying to use these two methods (of WP 8) in windows phone 8.1, but it gives error and doesn't compile, most probably becasue they are removed. I tried searching the new APIs but couldn't get any. What are other alternatives for these.
Dispatcher.BeginInvoke( () => {}); msdn link
System.Threading.Thread.Sleep(); msdn link
They still exists for Windows Phone 8.1 SIlverlight Apps, but not for Windows Phone Store Apps. The replacements for Windows Store Apps is:
Sleep (see Thread.Sleep replacement in .NET for Windows Store):
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(30));
Dispatcher (see How the Deployment.Current.Dispatcher.BeginInvoke work in windows store app?):
CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { });
Dispatcher.BeginInvoke( () => {}); is replaced by
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => {});
and System.Threading.Thread.Sleep(); is replaced by
await Task.Delay(TimeSpan.FromSeconds(doubleValue));
Be aware that not only has the API changed (adopting the API from WindowsStore apps), but the way that the Dispatcher was obtained in windowsPhone 8.0 has changed as well.
#Johan Faulk's suggestion, although will work, may return null under a multitude of conditions.
Old code to grab the dispatcher:
var dispatcher = Deployment.Current.Dispatcher;
or
Deployment.Current.Dispatcher.BeginInvoke(()=>{
// any code to modify UI or UI bound elements goes here
});
New in Windows 8.1 Deployment is not an available object or namespace.
In order to make sure the Main UI Thread dispatcher is obtained, use the following:
var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
or
CoreApplication.MainWindow.CoreWindow.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
()=>{
// UI code goes here
});
Additionally, although the method SAYS it will be executed Async the keyword await can not be used in the method invoked by RunAsync. (in the above example the method is anonymous).
In order to execute an awaitable method inside anonymous method above, decorate the anonymous method inside RunAsync() with the async keyword.
CoreApplication.MainWindow.CoreWindow.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
**async**()=>{
// UI code goes here
var response = **await** LongRunningMethodAsync();
});
For Dispatcher, try this. MSDN
private async Task MyMethod()
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { });
}
For Thread.Sleep() try await Task.Delay(1000). MSDN