I would liked to detect whether or not microphone permissions have been granted on my site when it loads without actually running something like the following:
navigator.webkitGetUserMedia({audio: active},
function(){alert('worked')},
function(){alert('failed')});
Is there a simple API to detect whether the user has permanently granted microphone access to my application (which runs over https)?
Update
microphone has been added to the Permission API even if it's not yet available on Safari nor Internet Explorer.
You could hope that it would be accessible from the permission api, but it isn't :(
Perhaps in the feature this could work like the rest of this:
navigator.permissions.query(
// { name: 'camera' }
{ name: 'microphone' }
// { name: 'geolocation' }
// { name: 'notifications' }
// { name: 'midi', sysex: false }
// { name: 'midi', sysex: true }
// { name: 'push', userVisibleOnly: true }
// { name: 'push' } // without userVisibleOnly isn't supported in chrome M45, yet
).then(function(permissionStatus){
console.log(permissionStatus.state); // granted, denied, prompt
permissionStatus.onchange = function(){
console.log("Permission changed to " + this.state);
}
})
Old answer
The only way i see it possible is if you keep track of this yourself with a key/value item in localStorage when you ask for permission.
Unfortunately it doesn't notify you when it has been changed
// initialization
if( localStorage.getItem('voice_access') === null ){
// just assume it is prompt
localStorage.setItem('voice_access', 'prompt');
}
// Then somewhere
navigator.getUserMedia({ audio: true }, function (e) {
// http://stackoverflow.com/q/15993581/1008999
//
// In chrome, If your app is running from SSL (https://),
// this permission will be persistent.
// That is, users won't have to grant/deny access every time.
localStorage.setItem("voice_access", "granted");
}, function (err) {
if (err.name === 'PermissionDismissedError') {
localStorage.setItem('voice_access', 'prompt')
}
if (err.name === 'PermissionDeniedError') {
localStorage.setItem('voice_access', 'denied')
}
})
You could go the extra mile and build a nice little wrapper with this code above and extend/replace the permission api to handle more enum names and create a broadcast api to tell the other tabs when it changes. but why make it so complicated...? The localStorage can't be 100% trusted. it can be changed anywhere any time both with permission and storage cleared
you already got the polling method for checking permissions.
here is some information from MDN:
https://developer.mozilla.org/en-US/docs/Web/API/Navigator.getUserMedia
and some more: https://developer.mozilla.org/en-US/docs/WebRTC
here is an example:
navigator.getMedia (
// constraints
{
video: true,
audio: true
},
// successCallback
function(localMediaStream) {
var video = document.querySelector('video');
video.src = window.URL.createObjectURL(localMediaStream);
video.onloadedmetadata = function(e) {
// Do something with the video here.
};
},
// errorCallback
function(err) {
console.log("The following error occured: " + err);
}
);
navigator.getUserMedia is now obsolete, replaced by MediaDevices.getUserMedia, which returns a promise. If the promise gets rejected you get an DOMException with indication of the problem. Insufficient permissions is one of the options there.
Details here:
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
I guess this would be helpful:
function isMicrophoneAllowed(){
navigator.permissions.query({
name: 'microphone'
}).then(function(permissionStatus){
return permissionStatus.state !== 'denied';
});
}
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I'm using Vuejs and i would i have two methods one is to make a call and another one is to hangup
i would like to access to device variable that i have in makeCall methods from hangup
error : Cannot set property 'device' of undefined at eval
this is my code :
export default {
components: {Modal},
data: () => ({
device: '',
showModal: false,
form:{
output: ''
},
collection: {
}
}),
created(){
},
methods: {
init(){
this.showModal = true
},
dialer(digit){
this.form.output += `${digit}`
this.count++
},
clearScreen(){
let screen = document.getElementById('output').value
this.form.output = screen.slice(0, -1)
},
hangUp(){
this.device.disconnectAll();
},
makeCall(){
console.log("Requesting Access Token...");
// Using a relative link to access the Voice Token function
getAPI.get("api/contacts/token/")
.then(function (response) {
console.log("Got a token.");
console.log("Token: " + response.data.token);
// Setup Twilio.Device
this.device = new Twilio.Device(response.data.token, {
// Set Opus as our preferred codec. Opus generally performs better, requiring less bandwidth and
// providing better audio quality in restrained network conditions. Opus will be default in 2.0.
codecPreferences: ["opus", "pcmu"],
// Use fake DTMF tones client-side. Real tones are still sent to the other end of the call,
// but the client-side DTMF tones are fake. This prevents the local mic capturing the DTMF tone
// a second time and sending the tone twice. This will be default in 2.0.
fakeLocalDTMF: true,
// Use `enableRingingState` to enable the device to emit the `ringing`
// state. The TwiML backend also needs to have the attribute
// `answerOnBridge` also set to true in the `Dial` verb. This option
// changes the behavior of the SDK to consider a call `ringing` starting
// from the connection to the TwiML backend to when the recipient of
// the `Dial` verb answers.
enableRingingState: true,
debug: true,
});
this.device.on("ready", function (device) {
console.log("Twilio.Device Ready!");
});
this.device.on("error", function (error) {
console.log("Twilio.Device Error: " + error.message);
});
this.device.on("connect", function (conn) {
console.log('Successfully established call ! ');
// $('#modal-call-in-progress').modal('show')
});
this.device.on("disconnect", function (conn) {
console.log("Call ended.");
// $('.modal').modal('hide')
});
var params = {
To: document.getElementById('output').value
};
console.log("Calling me " + document.getElementById('output').value + "...");
if (this.device) {
var outgoingConnection = this.device.connect(params);
outgoingConnection.on("ringing", function () {
console.log("Ringing...");
});
}
})
.catch(function (err) {
console.log(err);
console.log("Could not get a token from server!");
});
}
}
}
</script>
The error was due to how this works in JS. The function declaration in the promise was creating a different this context than the main function. The function keyword sets this based on where it is called, whereas arrow functions set this based on where it is defined in the code.
All you need to do is replace the function(response){} declaration in the getAPI promise .then with an arrow function, and it will work fine.
makeCall(){
console.log("Requesting Access Token...");
// Using a relative link to access the Voice Token function
getAPI.get("api/contacts/token/")
.then((response) => {
Try replacing these lines - to use an arrow function in the .then
I'm using SIPJS to make calls between 2 callers using web browser.
Now i want to add (Screen sharing) feature , so far i managed to open chrome screen sharing window and i get the stream and played it in video element.
But what i really need is to send this stream to the other caller so he can see my screen sharing.
What I've tried so far:
After i get the (screen sharing stream) i pass it to session.sessionDescriptionHandler.peerConnection , and then catch the stream (or track) using these events onTrackAdded , onaddTrack , onaddStream , onstream
But none of there events get anything.
Also tried to send the stream with video constraint before the call start
video: {
mandatory: {
chromeMediaSource: 'desktop',
// chromeMediaSourceId: event.data.sourceId,
maxWidth: window.screen.width > 1920 ? window.screen.width : 1920,
maxHeight: window.screen.height > 1080 ? window.screen.height : 1080
},
optional: []
}
Even tried to send the stream with video constraint
navigator.mediaDevices.getDisplayMedia(constraints)
.then(function(stream) {
//We've got media stream
console.log("----------then triggered-------------");
var options = {
sessionDescriptionHandlerOptions: {
constraints: {
audio: true,
video: stream
}
}
}
pub_session = userAgent.invite(reciver_name,options);
})
.catch(function(error) {
console.log("----------catch-------------");
console.log(error);
});
also didn't work.
Here is my Code
First get the screen sharing stream and send it to the other user
// Get screen sharing and send it.
navigator.mediaDevices.getDisplayMedia(constraints)
.then(function(stream) {
//We've got media stream
console.log("----------then triggered-------------");
var pc = session.sessionDescriptionHandler.peerConnection;
stream.getTracks().forEach(function(track) {
pc.addTrack(track, stream);
});
})
.catch(function(error) {
console.log("----------catch-------------");
console.log(error);
});
Then catch that stream at the other side
// Reciving stream or track
userAgent.on('invite', function (session) {
session.on('trackAdded', function() {
console.log('-------------trackAdded triggered--------------');
});
session.on('addTrack', function (track) {
console.log('-------------addTrack triggered--------------');
});
session.on('addStream', function (stream) {
console.log('-------------addStream triggered--------------');
});
session.on('stream', function (stream) {
console.log('-------------stream triggered--------------');
});
});
But still get nothing from that code above
So how can i pass that stream or track to the other caller after the call starts ?
thank you so much
I Found the solution from some great gentlemen in SIPJS groups
Hope the answer will help someone as it helped me
var option = {video: {mediaSource: 'screen'}, audio: true};
navigator.mediaDevices.getDisplayMedia(option)
.then(function(streams){
var pc = session.sessionDescriptionHandler.peerConnection;
var videoTrack = streams.getVideoTracks()[0];
var sender = pc.getSenders().find(function(s) {
return s.track.kind == videoTrack.kind;
});
console.log('found sender:', sender);
sender.replaceTrack(videoTrack);
}, function(error){
console.log("error ", error);
});
We use FileOpener2 plugin for cordova to open a downloaded .apk file from our servers. Recently, we found that Android 6.0 or higher devices are throwing an exception only on the file open process. We were able to trace this down to the cordova.js file, where the posted exception occurs. We have yet to find a cause or a fix, but have put a workaround in place. Any info would be amazing on this so we can maintain our in-app self updating process going on all Android devices.
Code (Working on Android <= 6.0):
// we need to access LocalFileSystem
window.requestFileSystem(LocalFileSystem.PERSISTENT, 5 * 1024 * 1024, function (fs) {
//Show user that download is occurring
$("#toast").dxToast({
message: "Downloading please wait..",
type: "warning",
visible: true,
displayTime: 20000
});
// we will save file in .. Download/OURAPPNAME.apk
var filePath = cordova.file.externalRootDirectory + '/Download/' + "OURAPPNAME.apk";
var fileTransfer = new FileTransfer();
var uri = encodeURI(appDownloadURL);
fileTransfer.download(uri, filePath, function (entry) {
//Show user that download is occurring/show user install is about to happen
$("#toast").dxToast({
message: "Download complete! Launching...",
type: "success",
visible: true,
displayTime: 2000
});
////Use pwlin's fileOpener2 plugin to let the system open the .apk
cordova.plugins.fileOpener2.open(
entry.toURL(),
'application/vnd.android.package-archive',
{
error: function (e) {
window.open(appDownloadURL, "_system");
},
success: function () { console.log('file opened successfully'); }
}
);
},
function (error) {
//Show user that download had an error
$("#toast").dxToast({
message: error.message,
type: "error",
displayTime: 5000
});
},
false);
})
Debugging Information:
THIS IS NOT OUR CODE, BUT APACHE/CORDOVA CODE
Problem File: cordova.js
function androidExec(success, fail, service, action, args) {
// argsJson - "["file:///storage/emulated/0/download/OURAPPNAME.apk","application/vnd.android.package-archive"]"
//callbackId - FileOpener21362683899
//action - open
//service FileOpener2
//bridgesecret - 1334209170
// msgs = "230 F09 FileOpener21362683899 sAttempt to invoke virtual method 'android.content.res.XmlResourceParser //android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference"
var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
// If argsJson was received by Java as null, try again with the PROMPT bridge mode.
// This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666.
if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "#Null arguments.") {
androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
androidExec(success, fail, service, action, args);
androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
} else if (msgs) {
messagesFromNative.push(msgs);
// Always process async to avoid exceptions messing up stack.
nextTick(processMessages);
}
I am working on application in Nativescript which implements push notification. Lets say server sends push notification and based on action mentioned in payload of notification i will have to redirect in application. This redirection should be performed if user taps on notification from drawer and application is in background. Other case when application should not redirect if its in foreground. I have managed a flag for that as follow
app.js
application.on(application.launchEvent, function (args) {
appSettings.setBoolean('AppForground', true);
});
application.on(application.suspendEvent, function (args) {
appSettings.setBoolean('AppForground', false);
});
application.on(application.resumeEvent, function (args) {
appSettings.setBoolean('AppForground', true);
});
application.on(application.exitEvent, function (args) {
appSettings.setBoolean('AppForground', false);
});
application.on(application.lowMemoryEvent, function (args) {
appSettings.setBoolean('AppForground', false);
});
application.on(application.uncaughtErrorEvent, function (args) {
appSettings.setBoolean('AppForground', false);
});
And on Push notification listener
var settings = {
// Android settings
senderID: '1234567890', // Android: Required setting with the sender/project number
notificationCallbackAndroid: function(data, pushNotificationObject) { // Android: Callback to invoke when a new push is received.
var payload = JSON.parse(JSON.parse(pushNotificationObject).data);
if (appSettings.getBoolean('AppForground') == false){
switch (payload.action) {
case "APPOINTMENT_DETAIL":
frame.topmost().navigate({
moduleName: views.appointmentDetails,
context: {
id: payload.id
}
});
break;
case "MESSAGE":
frame.topmost().navigate({
moduleName: views.appointmentDetails,
context: {
id: payload.id,
from: "messages"
}
});
break;
case "REFERENCES":
frame.topmost().navigate({
moduleName: views.clientDetails,
context: {
id: payload.id,
name: ""
}
});
break;
default:
}
}
},
// iOS settings
badge: true, // Enable setting badge through Push Notification
sound: true, // Enable playing a sound
alert: true, // Enable creating a alert
// Callback to invoke, when a push is received on iOS
notificationCallbackIOS: function(message) {
alert(JSON.stringify(message));
}
};
pushPlugin.register(settings,
// Success callback
function(token) {
// if we're on android device we have the onMessageReceived function to subscribe
// for push notifications
if(pushPlugin.onMessageReceived) {
pushPlugin.onMessageReceived(settings.notificationCallbackAndroid);
}
},
// Error Callback
function(error) {
alert(error);
}
);
Now the problem, is that if application is in killed state and notification arrives. Then it sets flag to true as application is launched which it should not. So due to that redirection is not performed and in other cases when application is in foreground state then also its navigating through pages (which should not be) on receiving notification.
I doubt about flag management is causing the problem but not sure. Would you please guide me if anything is wrong with what i did ?
UPDATE
I am using push-plugin.
Thanks.
I use this for notifications
https://github.com/EddyVerbruggen/nativescript-plugin-firebase
This plugin use FCM, it adds to datas received from notifications foreground parameter so from payload you can determine if app was background(foreground==false, app is not active or was started after notification arrived) or foreground(foreground==true, app is open and active), but you need to some changes to code as they are different plugins
You can use pusher-nativescript npm module.
import { Pusher } from 'pusher-nativescript';
/*Observation using the above.
- Project gets build successfully.
- on run -> ERROR TypeError: pusher_nativescript__WEBPACK_IMPORTED_MODULE_6__.Pusher is not a constructor
- Use: import * as Pusher from 'pusher-nativescript';
- Make sure to install nativescript-websocket with this package.
*/
var pusher = new Pusher('Your_app_key', { cluster: 'your_cluster_name' });
var channel = pusher.subscribe('my-channel');
channel.bind('my-event', function(data) {
alert(JSON.stringify(data));
});
My Real Time Chat App is based on Sails and SocketIO.It shows all users along with available online users .When a User logged in,a UserConnected socket is emitted and When a User is disconnected,a UserDisconnected socket is emitted ,
My Server side socketio code in config/sockets.js is
onConnect: function(session, socket) {
if (session.passport) {
if (session.passport.user && socket.id) {
sails.io.sockets.emit('UserConnected', {userID : session.passport.user}); }
}
}
//// By default: do nothing
//// This is a good place to broadcast a disconnect message, or any other custom socket.io logic
},
onDisconnect: function(session, socket) {
if (session.passport) {
if (session.passport.user && socket.id) {
sails.io.sockets.emit('UserDisconnected', {userID : session.passport.user});
}
}
//// By default: do nothing
//// This is a good place to broadcast a disconnect message, or any other custom socket.io logic
}
The Problem is that when a User refreshes the page ,it shows connected and disconnected to another User and one major problem is that if one User logged in two different browsers and if any one browser is closed is shows User disconnected to other Users but the User is actually available in another browser. How would I modify/code So that these problems will be fixed?Thanks in Advance
#InternalFX posted a good method; an alternative that you can use on Sails v0.10.x would be:
onConnect: function(session, socket) {
// If this is a logged in user, subscribe the socket to a
// custom "loggedInCount" room
if (session.user) {
var roomName = 'loggedIn'+session.user.id;
sails.sockets.join(socket, roomName);
// If this is the first subscriber, the user is just coming online,
// so notify any subscribers about the state change.
if (sails.sockets.subscribers(roomName).length == 1) {
User.message(session.user.id, {state: 'online'}, socket);
}
}
},
onDisconnect: function(session, socket) {
if (session.user) {
var roomName = 'loggedIn'+session.user.id;
sails.sockets.leave(socket, roomName);
// If this was the last subscriber, the user is going offline,
// so notify any subscribers about the state change.
if (sails.sockets.subscribers(roomName).length == 0) {
User.message(session.user.id, {state: 'offline'}, socket);
}
}
},
This uses Sails' built-in pubsub architecture to notify connected sockets whenever a particular user comes online or goes offline. It requires sockets to subscribe to the user instances they want to know about (using something like socket.get('/user') on the client), which is a good practice to get into. This way you can be notified only about the users you care about (e.g. if you had a "friends list").
Here is the method I am using for a similar purpose.
var online_users = {};
module.exports.sockets = {
onConnect: function(session, socket) {
if (_.isString(session.user_id)) {
if (_.has(online_users, session.user_id)) {
online_users[session.user_id] += 1;
} else {
online_users[session.user_id] = 1;
}
}
sails.io.sockets.emit('crm/online_users', online_users);
},
onDisconnect: function(session, socket) {
if (_.isString(session.user_id)) {
if (_.has(online_users, session.user_id)) {
online_users[session.user_id] -= 1;
} else {
online_users[session.user_id] = 0;
}
}
sails.io.sockets.emit('crm/online_users', online_users);
},
}
It keeps track of how many browsers are logged in as a specific user. So you could use the following.
if (online_users[session.user_id] > 0) { console.log('USER IS LOGGED IN'); }`