Firefox - mediaDevices.getUserMedia throws AbortError - firefox

I get the following error in firefox (no problems in Chrome / Edge / Safari):
MediaStreamError { name: "AbortError", message: "Starting video failed", constraint: "", stack: "" }
Browser console only shows < unavailable > when this error is thrown.
I am using adapter-latest.js from webrtc.github.io and the code works perfectly well on other pages within my application but not in one particular page. Is there a possibility to find out, what interferes with getUserMedia? I allready tried commenting out all other libraries and includes.
My code is:
var video = document.getElementById('recorder');
video.onloadedmetadata = function(e) {
$("#takePicture").show();
if($("#customerImage").attr("src") == ""){
$("#recorder").show();
}
};
navigator.mediaDevices.getUserMedia({ video: true})
.then(stream => {
video.srcObject = stream;
})
.catch(e => console.log(e));

I was facing this issue because I had Chrome also running the same app and using the webcam. So basically the webcam was already in use and I was trying to access it via Firefox too.

Are you really sure that you need adapter? In my experience it makes more problems than it solves.
Can you try to use constraints?
Example (I removed some things, but it works like a charm here):
constraints = {
width: 1280,
height: 720,
frameRate: 10, //mobile
facingMode: {
exact: "environment"
} //mobile
}
navigator.mediaDevices.getUserMedia({
audio: false,
video: constraints
}).
then(handleSuccess).catch(handleError);
function handleSuccess(stream) {
video.src = URL.createObjectURL(stream);
video.play();
}
function handleError(error) {
console.log('navigator.getUserMedia error: ', error);
}

Related

Parse iOS Universal Links with Nativescript Angular?

Following the apple documentation and Branch's documentation here, I have set up a working universal link in my Nativescript Angular (iOS) app. But, how do I parse the link when the app opens?
For example, when someone opens the app from the link, I want to have my app read the link so it can go to the correct page of the app.
There is some helpful code in this answer, but I keep getting errors with it. This could be bc the code is written in vanilla JS and I am not translating it into Angular correctly. The use of "_extends" and "routeUrL" both cause errors for me.
And the Nativescript url-handler plugin does not seem to work without further code.
So, after setting up the universal link, and installing the nativescript url-handler plugin, I have entered the following in app.module.ts:
const Application = require("tns-core-modules/application");
import { handleOpenURL, AppURL } from 'nativescript-urlhandler';
declare var NSUserActivityTypeBrowsingWeb
if (Application.ios) {
const MyDelegate = (function (_super) {
_extends(MyDelegate, _super);
function MyDelegate() {
_super.apply(this, arguments);
}
MyDelegate.prototype.applicationContinueUserActivityRestorationHandler = function (application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
this.routeUrl(userActivity.webpageURL);
}
return true;
};
MyDelegate.ObjCProtocols = [UIApplicationDelegate];
return MyDelegate;
})(UIResponder);
Application.ios.delegate = MyDelegate;
}
...
export class AppModule {
ngOnInit(){
handleOpenURL((appURL: AppURL) => {
console.log('Got the following appURL = ' + appURL);
});
}
}
The trouble seems to be mostly with "_extends" and "_super.apply". For example, I get this error:
'NativeScript encountered a fatal error: TypeError: undefined is not an object (evaluating '_extends')
EDIT: Note that the nativescript-urlhandler plugin is no longer being updated. Does anyone know how to parse universal links with Nativescript?
I have figured out a method to get this working:
The general idea is to use the iOS App Delegate method: applicationContinueUserActivityRestorationHandler.
The syntax in the Nativescript documentation on app delegates did not work for me. You can view that documentation here.
This appears to work:
--once you have a universal link set up, following documentation like here, and now you want your app to read ("handle") the details of the link that was tapped to open the app:
EDIT: This code sample puts everything in one spot in app.module.ts. However, most of the time its better to move things out of app.module and into separate services. There is sample code for doing that in the discussion here. So the below has working code, but keep in mind it is better to put this code in a separate service.
app.module.ts
declare var UIResponder, UIApplicationDelegate
if (app.ios) {
app.ios.delegate = UIResponder.extend({
applicationContinueUserActivityRestorationHandler: function(application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
let tappedUniversalLink = userActivity.webpageURL
console.log('the universal link url was = ' + tappedUniversalLink)
}
return true;
}
},
{
name: "CustomAppDelegate",
protocols: [UIApplicationDelegate]
});
}
NOTE: to get the NSUserActivity/Application Delegate stuff to work with typescript, I also needed to download the tns-platforms-declarations plugin, and configure the app. So:
$ npm i tns-platforms-declarations
and
references.d.ts
/// <reference path="./node_modules/tns-platform-declarations/ios.d.ts" />
The above code works for me to be able to read the details of the tapped universal link when the link opens the app.
From there, you can determine what you want to do with that information. For example, if you want to navigate to a specific page of your app depending on the details of the universal link, then I have found this to work:
app.module.ts
import { ios, resumeEvent, on as applicationOn, run as applicationRun, ApplicationEventData } from "tns-core-modules/application";
import { Router } from "#angular/router";
let univeralLinkUrl = ''
let hasLinkBeenTapped = false
if (app.ios) {
//code from above, to get value of the universal link
applicationContinueUserActivityRestorationHandler: function(application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
hasLinkBeenTapped = true
universalLinkUrl = userActivity.webpageURL
}
return true;
},
{
name: "CustomAppDelegate",
protocols: [UIApplicationDelegate]
});
}
#ngModule({...})
export class AppModule {
constructor(private router: Router) {
applicationOn(resumeEvent, (args) => {
if (hasLinkBeenTapped === true){
hasLinkBeenTapped = false //set back to false bc if you don't app will save setting of true, and always assume from here out that the universal link has been tapped whenever the app opens
let pageToOpen = //parse universalLinkUrl to get the details of the page you want to go to
this.router.navigate(["pageToOpen"])
} else {
universalLinkUrl = '' //set back to blank
console.log('app is resuming, but universal Link has not been tapped')
}
})
}
}
You can use the nativescript-plugin-universal-links plugin to do just that.
It has support for dealing with an existing app delegate so if you do have another plugin that implements an app delegate, both of them will work.
Here's the usage example from the docs:
import { Component, OnInit } from "#angular/core";
import { registerUniversalLinkCallback } from "nativescript-plugin-universal-links";
#Component({
selector: "my-app",
template: "<page-router-outlet></page-router-outlet>"
})
export class AppComponent {
constructor() {}
ngOnInit() {
registerUniversalLinkCallback(ul => {
// use the router to navigate to the screen
});
}
}
And the callback will receive a ul (universal link) param that looks like this
{
"href": "https://www.example.com/blog?title=welcome",
"origin": "https://www.example.com",
"pathname": "/blog",
"query": {
"title": "welcome"
}
}
Disclaimer: I'm the author of the plugin.

Not getting location in Android 8.0.0 Oreo

I am building an app in React-Native and need to have location access as per the requirement.
I have tried using react-native-fused-location for the same, as below.
FusedLocation.setLocationInterval(20000);
FusedLocation.setFastestLocationInterval(15000);
FusedLocation.setSmallestDisplacement(10);
FusedLocation.setLocationPriority(
FusedLocation.Constants.HIGH_ACCURACY
);
FusedLocation.startLocationUpdates();
FusedLocation.getFusedLocation().then(location => {
if (location != null) {
let initialPosition = JSON.stringify(location);
this.state.latitude = location.latitude;
this.state.longitude = location.longitude;
this.state.timestamp = location.timestamp;
this.state.initialPosition = initialPosition;
} else {
alert("Location unavailable, please try later");
}
}).catch(error => { // fused location catch
console.log("location retrieval failed");
});
The only output, I am receiving with the above code, in case of Oreo 8.0.0 is E/request: 100.
also tried the other way as below
navigator.geolocation.watchPosition(
location => {
console.log("inside watchPosition location");
if (location != null) {
console.log("location is not null");
let initialPosition = JSON.stringify(location.coords);
this.state.latitude = location.coords.latitude;
this.state.longitude = location.coords.longitude;
this.state.timestamp = location.coords.timestamp;
this.state.initialPosition = initialPosition;
} else {
alert("Location unavailable, please try later");
}
},
error => {
console.log("calling ShowHideActivityIndicator, getLocationWithNavigate (ios)");
this.ShowHideActivityIndicator(false);
alert("location retrieval failed");
console.log(error);
},
{ timeout: 20000, enableHighAccuracy: true, distanceFilter: 10 }
);
But getting same output in both of the above codes, that is unable to get the location specifically in Android Oreo 8.0.0. Even the location retrieving callback is not even called. Though in other versions, including Oreo 8.1.0, and lower version devices, including Marshmallow and Nougat, it seems working fine.
Though, if I turn on the fake GPS in Oreo 8.0.0, then it seems to be able to get the location. I am unable to figure out, what I am missing.
mention to google document:
In an effort to reduce power consumption, Android 8.0 (API level 26) limits how frequently background apps can retrieve the user's current location. Apps can receive location updates only a few times each hour.Background Location Limits

PerformanceObserver throwing error in Firefox, working in Chrome

I am implementing PerformanceObserver to track 'first-paint' & 'first-contentful-paint'.
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (typeof(Storage) !== 'undefined') {
if (entry.name === 'first-paint') {
localStorage.setItem(rumMetrics.RUM_METRICS_FIRST_PAINT, entry.startTime);
}
else if (entry.name === 'first-contentful-paint') {
localStorage.setItem(rumMetrics.RUM_METRICS_FIRST_CONTENTFUL_PAINT, entry.startTime);
}
}
else {
console.log('local storage is not supported here. RUM metrics won\'t be recorded.');
}
}
});
observer.observe({ entryTypes: ['paint'] });
This works perfectly in Chrome but throws an error in Firefox.
TypeError: The expression cannot be converted to return the specified type. (line: observer.observe({ entryTypes: ['paint'] });)
Update-1: 20th Apr 2018
Mozilla has confirmed the bug and it is affecting FF61 Nightly as well
Original Answer
Confirmed that this is a bug even in the developer version.
Below is the bug for the same
https://bugzilla.mozilla.org/show_bug.cgi?id=1454581

Firefox v41 issue with getUserMedia not see in Chrome or Firefox v36

I use the following code from (https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia):
navigator.mediaDevices = navigator.mediaDevices || ((navigator.mozGetUserMedia || navigator.webkitGetUserMedia) ? {
getUserMedia: function(c) {
return new Promise(function(y, n) {
(navigator.mozGetUserMedia || navigator.webkitGetUserMedia).call(navigator, c, y, n);
});
}
} : null);
to setup the microphone for use. This works great in Chrome (v45) and Firefox (v36), but in Firefox (v41) I get the following error in the console:
Error: setting a property that has only a getter
RecorderSvc.initAudio#http://fakewebsite.com/js/services/recorder.js:61:1
I can solve the problem by doing:
if (navigator.mozGetUserMedia || navigator.webkitGetUserMedia) {
navigator.mediaDevices.getUserMedia = function(c) {
return new Promise(function(y, n) {
(navigator.mozGetUserMedia || navigator.webkitGetUserMedia).call(navigator, c, y, n);
});
}
}
but this doesn't work in Chrome or Firefox (v36).
In Chrome, only navigator.webkitGetUserMedia is defined.
In Firefox (v36), only navigator.mozGetUserMedia is defined.
In Firefox (v41), both navigator.mozGetUserMedia AND
navigator.mediaDevices are defined.
I can't figure out how to fix this without breaking one of the browsers. Any ideas?
The code you've copied (which I wrote incidentally) does a lousy job trying to polyfill navigator.mediaDevices.getUserMedia into browsers that don't have it natively yet. It has since been removed from where you found it. Thanks for spotting that it's broken.
Polyfilling is tricky business, so I highly recommend using adapter.js, the official WebRTC polyfill, instead of attempting to shim it manually. You can use a recent version of adapter.js, or link to the always latest one directly, like this:
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
See https://jsfiddle.net/srn9db4h/ for an example of this that works in the browsers you mention.
I wont try to correct the code you mention, because polyfilling navigator.mediaDevices correctly got quite complicated.
It's also insufficient, because the location of getUserMedia isn't the only thing that has changed in the specification. The format of the constraints argument has changed as well, which is why navigator.mediaDevices.getUsermedia is still behind an experimental flag in Chrome 45.
adapter.js takes care of all this until the browsers catch up.
If you surround your statement in a Try Catch block, it'll work.
if (navigator.mediaDevices || (navigator.mozGetUserMedia || navigator.webkitGetUserMedia)) {
try {
navigator.mediaDevices = {
getUserMedia: function(c) {
return new Promise(function(y, n) {
(navigator.mozGetUserMedia || navigator.webkitGetUserMedia).call(navigator, c, y, n);
});
}
};
}
catch(err) {
navigator.mediaDevices.getUserMedia = function(c) {
return new Promise(function(y, n) {
(navigator.mozGetUserMedia || navigator.webkitGetUserMedia).call(navigator, c, y, n);
});
}
}
} else {
navigator.mediaDevices = null;
}

Getting a list of markers with jQuery/gmap3 when using the Directions service

I started using the gmap3 jQuery plugin today and I'm having issues with getting a list of markers.
As long as I add all the markers manually (with addMarker or addMarkers) all works well and the:
.gmap3({action:'get', name:'marker', all:true});
gives proper list of markers.
However, if i use the action:getRoute and the addDirectionsRenderer - the markers are not 'gettable' by code pasted above.
My code for showing the directions is below - it works and shows them properly on the map. Only issue is that I cannot get any markers out of it, so I can process them after creation.
var optionDirections = {
origin: startcoord,
destination: stopcoord,
waypoints: coordsAllGoogleStyle,
optimizeWaypoints: true,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
....
.gmap3({
action:'getRoute',
options: optionDirections,
callback: function(results) {
if (!results) { alert('nodata'); return; }
$(this).gmap3(
{
action:'addDirectionsRenderer',
options:{
preserveViewport: false,
draggable: false,
directions:results
}
}
);
var res = $(this).gmap3({action:'get', name:'marker', all:true});
alert('Found: '+res.length+' markers');
}
});
to make things simple, I contacted the author of this api and it kind of not support it anymore because "now people use angular"
nice is'nt it...

Resources