Login with Facebook Phonegap Plugin Issue - phonegap-plugins

/* global FB */
"use strict";
/*
* #author Ally Ogilvie
* #copyright Wizcorp Inc. [ Incorporated Wizards ] 2014
* #file - facebookConnectPlugin.js
* #about - JavaScript interface for PhoneGap bridge to Facebook Connect SDK
*
*
*/
if (!window.cordova) {
// This should override the existing facebookConnectPlugin object created from cordova_plugins.js
var facebookConnectPlugin = {
getLoginStatus: function (s, f) {
// Try will catch errors when SDK has not been init
try {
FB.getLoginStatus(function (response) {
s(response);
});
} catch (error) {
if (!f) {
console.error(error.message);
} else {
f(error.message);
}
}
},
showDialog: function (options, s, f) {
if (!options.name) {
options.name = "";
}
if (!options.message) {
options.message = "";
}
if (!options.caption) {
options.caption = "";
}
if (!options.description) {
options.description = "";
}
if (!options.href) {
options.href = "";
}
if (!options.picture) {
options.picture = "";
}
// Try will catch errors when SDK has not been init
try {
FB.ui({
method: options.method,
message: options.message,
name: options.name,
caption: options.caption,
description: (
options.description
),
href: options.href,
picture: options.picture
},
function (response) {
if (response && (response.request || !response.error_code)) {
s(response);
} else {
f(response);
}
});
} catch (error) {
if (!f) {
console.error(error.message);
} else {
f(error.message);
}
}
},
// Attach this to a UI element, this requires user interaction.
login: function (permissions, s, f) {
// JS SDK takes an object here but the native SDKs use array.
var permissionObj = {};
if (permissions && permissions.length > 0) {
permissionObj.scope = permissions.toString();
}
FB.login(function (response) {
if (response.authResponse) {
s(response);
} else {
f(response.status);
}
}, permissionObj);
},
getAccessToken: function (s, f) {
var response = FB.getAccessToken();
if (!response) {
if (!f) {
console.error("NO_TOKEN");
} else {
f("NO_TOKEN");
}
} else {
s(response);
}
},
logEvent: function (eventName, params, valueToSum, s, f) {
// AppEvents are not avaliable in JS.
s();
},
logPurchase: function (value, currency, s, f) {
// AppEvents are not avaliable in JS.
s();
},
logout: function (s, f) {
// Try will catch errors when SDK has not been init
try {
FB.logout( function (response) {
s(response);
});
} catch (error) {
if (!f) {
console.error(error.message);
} else {
f(error.message);
}
}
},
api: function (graphPath, permissions, s, f) {
// JS API does not take additional permissions
// Try will catch errors when SDK has not been init
try {
FB.api(graphPath, function (response) {
if (response.error) {
f(response);
} else {
s(response);
}
});
} catch (error) {
if (!f) {
console.error(error.message);
} else {
f(error.message);
}
}
},
// Browser wrapper API ONLY
browserInit: function (appId, version) {
if (!version) {
version = "v2.0";
}
FB.init({
appId : appId,
cookie : true,
xfbml : true,
version : version
})
}
};
// Bake in the JS SDK
(function () {
if (!window.FB) {
console.log("launching FB SDK");
var e = document.createElement('script');
e.src = document.location.protocol + '//connect.facebook.net/en_US/sdk.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}
}());
}
I'm having error of FB not Defined when I try login with facebook in my code and gives error in above js file that FB is not Defined.

Related

Gpay payment-gateway integration in NodeJS

I tried it in Html and Javascript it's working perfect in web (mobile's browser).I am using angular for frontend and node for backend but not getting any proper solution for redirect Playstore or Gpay for mobile browser. Basically I want to implement for mobile browser.
this is my node for backend code & for frontend I already paste static. So, request you that please check & get back to me proper resolution or tutorial. Thanks & Regards--
const canMakePaymentCache = 'canMakePaymentCache';
onBuyClicked();
function readSupportedInstruments() {
let formValue = {};
formValue['pa'] = keys.GPAY_MERCHANT_ID;//merchantId
formValue['pn'] = `Test_Gpay_Name`;//transactionId
formValue['tn'] = 'Testing Messages ';//message
formValue['mc'] = 'merchant Code';//
formValue['tr'] = 'Transaction Reference';
formValue['tid'] = 'Transaction id';
formValue['url'] = 'http://localhost.co/';
return formValue;
}
function readAmount() {
//const pay_amount = parseInt(req.body.amount) * 100;
return parseInt(req.body.amount) * 100;
}
function onBuyClicked() {
// if (!window.PaymentRequest) {
// console.log('Web payments are not supported in this browser.');
// return;
// }
let formValue = readSupportedInstruments();
const supportedInstruments = [
{
supportedMethods: ['https://pwp-server.appspot.com/pay-dev'],
data: formValue,
},
{
supportedMethods: ['https://tez.google.com/pay'],
data: formValue,
},
];
const details = {
total: {
label: 'Total',
amount: {
currency: 'INR',
value: readAmount(),
},
},
displayItems: [
{
label: 'Original amount',
amount: {
currency: 'INR',
value: readAmount(),
},
},
],
};
const options = {
requestShipping: false,
requestPayerName: false,
requestPayerPhone: false,
requestPayerEmail: false,
shippingType: 'shipping',
};
let request = null;
try {
//const PaymentRequest = {};
//request = PaymentRequest(supportedInstruments, details, options);
request ={supportedInstruments, details, options};
} catch (e) {
return;
}
if (!request) {
console.log('Web payments are not supported in this browser.');
return;
}
var canMakePaymentPromise = checkCanMakePayment(request);
canMakePaymentPromise
.then((result) => {
showPaymentUI(request, result);
})
.catch((err) => {
console.log('Error calling checkCanMakePayment: ' + err);
});
}
function checkCanMakePayment(request) {
//if (sessionStorage.hasOwnProperty(canMakePaymentCache)) {
//return Promise.resolve(JSON.parse(sessionStorage[canMakePaymentCache]));
//}
var canMakePaymentPromise = Promise.resolve(true);
if (request.canMakePayment) {
canMakePaymentPromise = request.canMakePayment();
}
return canMakePaymentPromise
.then((result) => {
canMakePaymentCache = result;
return result;
})
.catch((err) => {
console.log('Error calling canMakePayment: ' + err);
});
}
function showPaymentUI(request, canMakePayment) {
if (!canMakePayment) {
redirectToPlayStore();
return;
}
let paymentTimeout = window.setTimeout(function () {
window.clearTimeout(paymentTimeout);
request.abort()
.then(function () {
console.log('Payment timed out after 20 minutes.');
})
.catch(function () {
console.log('Unable to abort, user is in the process of paying.');
});
}, 20 * 60 * 1000); /* 20 minutes */
request.show()
.then(function (instrument) {
window.clearTimeout(paymentTimeout);
processResponse(instrument); // Handle response from browser.
})
.catch(function (err) {
console.log(err);
});
}
function processResponse(instrument) {
var instrumentString = instrumentToJsonString(instrument);
console.log(instrumentString);
fetch('/buy', {
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json' }),
body: instrumentString,
credentials: 'include',
})
.then(function (buyResult) {
if (buyResult.ok) {
return buyResult.json();
}
console.log('Error sending instrument to server.');
})
.then(function (buyResultJson) {
completePayment(
instrument, buyResultJson.status, buyResultJson.message);
})
.catch(function (err) {
console.log('Unable to process payment. ' + err);
});
}
function completePayment(instrument, result, msg) {
instrument.complete(result)
.then(function () {
console.log('Payment completes.');
console.log(msg);
document.getElementById('inputSection').style.display = 'none'
document.getElementById('outputSection').style.display = 'block'
document.getElementById('response').innerHTML =
JSON.stringify(instrument, undefined, 2);
})
.catch(function (err) {
console.log(err);
});
}
console.log(`in line 448....`);
function redirectToPlayStore() {
//if (confirm('Tez not installed, go to play store and install?')) {
//window.location.href = 'https://play.google.com/store/apps/details?id=com.google.android.apps.nbu.paisa.user.alpha'
//res.writeHead( "https://play.google.com/store/apps/details?id=com.google.android.apps.nbu.paisa.user.alpha" );
const response_data = axios
.post(
'https://play.google.com/store/apps/details?id=com.google.android.apps.nbu.paisa.user.alpha',
)
console.log(`in line no. 459... ${response_data}`);
return response_data;
//};
}
function instrumentToJsonString(instrument) {
var instrumentDictionary = {
methodName: instrument.methodName,
details: instrument.details,
shippingAddress: addressToJsonString(instrument.shippingAddress),
shippingOption: instrument.shippingOption,
payerName: instrument.payerName,
payerPhone: instrument.payerPhone,
payerEmail: instrument.payerEmail,
};
return JSON.stringify(instrumentDictionary, undefined, 2);
}

Cannot set variable from within node.js request callback

I'm using Hive to review images being sent to our server. When I get a hit off of the image I want to be able to let the frontend know so I can show a warning message. I set this variable "goodImage" to be true if the image is fine and false if the image is bad. When I return the variable, it always returns undefined. I've tried awaiting the request, but it doesn't work. Any help here would be much appreciated.
async function checkImage(imgUrl, uid){
let goodImage
const options = {
method: 'POST',
url: 'https://api.thehive.ai/api/v2/task/sync',
headers: {
'accept': 'application/json',
'authorization': `token ${functions.config().hive.key}`
},
form: {
'image_url': imgUrl,
},
json: true
};
try {
request(options, async function (error, response, body) {
if (error) {
console.error(error);
throw new HttpsError('internal', 'Pick another Image.');
}
let codeViolations = [];
if(body.status[0] !== undefined && body.status[0].response.output[0] !== undefined){
const classes = body.status[0].response.output[0].classes;
for(let i = 0; i < classes.length; i++) {
if(looking_for_sexual_tags.includes(classes[i].class)){
if(classes[i].score > .9) {
if(!codeViolations.includes('Nudity, Pornography, and Other Sexual Content')){
codeViolations.push('Nudity, Pornography, and Other Sexual Content');
}
}
} else if(looking_for_hate_tags.includes(classes[i].class)){
if(classes[i].score > .9) {
if(!codeViolations.includes('Hateful Conduct and Harassment')){
codeViolations.push('Hateful Conduct and Harassment');
}
}
} else if(looking_for_violence_tags.includes(classes[i].class)){
if(classes[i].score > .9) {
if(!codeViolations.includes('Violence and Threats')){
codeViolations.push('Violence and Threats');
}
}
}
}
if(codeViolations.length > 0) {
//await banUser(uid, 'Inappropriate Image', codeViolations);
goodImage = false;
} else {
goodImage = true;
}
}
else{
goodImage = true;
}
});
}
catch (e) {
console.error('Error acquiring image tags from hive.');
console.log(e);
return undefined;
}
return goodImage;
}
You are not awaiting the request, you are using callbacks. The statement return goodImage; will be executed before the request has finished. There's a couple of ways to fix this, so for example you can wrap the callback in a custom promise:
async function checkImage(imgUrl, uid) {
let goodImage;
const options = {
method: 'POST',
url: 'https://api.thehive.ai/api/v2/task/sync',
headers: {
'accept': 'application/json',
'authorization': `token ${functions.config().hive.key}`,
},
form: {
'image_url': imgUrl,
},
json: true,
};
try {
const responseBody = await new Promise((resolve, reject) => {
request(options, function(error, response, body) {
if (error) {
console.error(error);
return reject(new HttpsError('internal', 'Pick another Image.'));
}
resolve(body);
});
});
let codeViolations = [];
if (responseBody.status[0] !== undefined && responseBody.status[0].response.output[0] !== undefined) {
const classes = responseBody.status[0].response.output[0].classes;
for (let i = 0; i < classes.length; i++) {
if (looking_for_sexual_tags.includes(classes[i].class)) {
if (classes[i].score > .9) {
if (!codeViolations.includes('Nudity, Pornography, and Other Sexual Content')) {
codeViolations.push('Nudity, Pornography, and Other Sexual Content');
}
}
} else if (looking_for_hate_tags.includes(classes[i].class)) {
if (classes[i].score > .9) {
if (!codeViolations.includes('Hateful Conduct and Harassment')) {
codeViolations.push('Hateful Conduct and Harassment');
}
}
} else if (looking_for_violence_tags.includes(classes[i].class)) {
if (classes[i].score > .9) {
if (!codeViolations.includes('Violence and Threats')) {
codeViolations.push('Violence and Threats');
}
}
}
}
if (codeViolations.length > 0) {
//await banUser(uid, 'Inappropriate Image', codeViolations);
goodImage = false;
} else {
goodImage = true;
}
} else {
goodImage = true;
}
} catch (e) {
console.error('Error acquiring image tags from hive.');
console.log(e);
return undefined;
}
return goodImage;
}
Note: you should really consider exchanging the request-library for another http-library as it has been deprecated. We currently use superagent for our REST-api and are really happy with it (fast, simple). It also supports promises out of the box, allowing you to simply do: const response = await superagent(...); instead of having to wind up your own promise.
I switched away from using request as suggested by #eol. I used request-promise and it worked like a charm, here is the full functional code.
async function checkImage(imgUrl, uid) {
let goodImage;
const options = {
method: 'POST',
uri: 'https://api.thehive.ai/api/v2/task/sync',
headers: {
'accept': 'application/json',
'authorization': `token ${functions.config().hive.key}`,
},
form: {
'image_url': imgUrl,
},
json: true,
};
try {
const body = await rp(options);
let codeViolations = [];
if (body.status[0] !== undefined && body.status[0].response.output[0] !== undefined) {
const classes = body.status[0].response.output[0].classes;
for (let i = 0; i < classes.length; i++) {
if (looking_for_sexual_tags.includes(classes[i].class)) {
if (classes[i].score > .9) {
if (!codeViolations.includes('Nudity, Pornography, and Other Sexual Content')) {
codeViolations.push('Nudity, Pornography, and Other Sexual Content');
}
}
} else if (looking_for_hate_tags.includes(classes[i].class)) {
if (classes[i].score > .9) {
if (!codeViolations.includes('Hateful Conduct and Harassment')) {
codeViolations.push('Hateful Conduct and Harassment');
}
}
} else if (looking_for_violence_tags.includes(classes[i].class)) {
if (classes[i].score > .9) {
if (!codeViolations.includes('Violence and Threats')) {
codeViolations.push('Violence and Threats');
}
}
}
}
if (codeViolations.length > 0) {
//await banUser(uid, 'Inappropriate Image', codeViolations);
goodImage = false;
} else {
goodImage = true;
}
} else {
goodImage = true;
}
} catch (e) {
console.error('Error acquiring image tags from hive.');
console.log(e);
return undefined;
}
return goodImage;
}

How to only export specific methods from a class?

I have a class which has 10 methods, and only 8 of those 10 should be exported, the other 2 are for authenticating tokens and I don't want them to be exported since the user won't need to call them ever ( I'm writing a package for npmjs ), my question is, how to only export the class with those 8 methods while the class itself is using the other two?
Edit: added some code
class StackClass {
constructor(p1, p2) {
this.data = {
p1,
p2,
accessToken: null,
expiresIn: null,
tokenType: null
};
}
async getToken() {
return new Promise(async (resolve, reject) => {
try {
let fetchResponse = await fetch(
"url with this.data.p1 and this.data.p2"
);
let fetchData = await fetchResponse.json();
if (fetchData.status != 200) {
reject("ERROR");
} else {
// get the token and save it in this.data
this.data.accessToken = fetchData.access_token;
this.data.expiresIn = fetchData.expires_in;
this.data.tokenType = fetchData.token_type;
resolve(fetchData);
}
} catch (err) {
console.log(err);
}
});
}
async isTokenValid() {
if (new Date() >= this.data.expiresIn) {
// Generate a new Token
try {
await this.getToken();
} catch (err) {
console.log(err);
}
}
// else - Do nothing and use current token saved in this.data.accessToken
}
async getData() {
try {
await this.isTokenValid();
await fetch("url2 with this.data.accessToken");
} catch (err) {
console.log(err);
}
}
}
let user = new StackClass("username", "password");
user.isTokenValid(); // SHOULD BE PRIVATE
user.getToken(); // SHOULD BE PRIVATE
user.getData(); // SHOULD BE PUBLIC
Define the isTokenValid and getToken as standalone functions instead. You should also avoid the explicit Promise construction antipattern, and only catch in a place where you can sensibly handle the error, which is usually in the caller of the asynchronous function (perhaps getData, perhaps in the consumer of the StackClass class):
class StackClass {
constructor(p1, p2) {
this.data = {
p1,
p2,
accessToken: null,
expiresIn: null,
tokenType: null
};
}
async getData() {
try {
await isTokenValid(this);
await fetch("url2 with this.data.accessToken");
} catch (err) {
// or you can just avoid the `try`/`catch` altogether,
// and have the consumer of getData handle problems
console.log(err);
}
}
}
function isTokenValid(stack) {
if (new Date() >= stack.data.expiresIn) {
// Generate a new Token
return getToken(stack);
}
// else - Do nothing and use current token saved in this.data.accessToken
}
async function getToken(stack) {
const fetchResponse = await fetch(
"url with this.data.p1 and this.data.p2"
);
const fetchData = await fetchResponse.json();
if (fetchData.status != 200) {
throw new Error('error');
} else {
// get the token and save it in this.data
stack.data.accessToken = fetchData.access_token;
stack.data.expiresIn = fetchData.expires_in;
stack.data.tokenType = fetchData.token_type;
}
}
Why don't you export a function that takes a list of arguments, creates an object of your class with those arguments, and then return a new object literal with only public methods? Take a look:
my-class.js
class MyClass {
constructor(f1, f2) {
this.field1 = f1;
this.field2 = f2;
}
m1() {
this.m2();
}
m2() {
console.log('this.field1', this.field1);
this.m3();
}
m3() {
console.log('this.field2', this.field2);
this._m4();
}
_m4() {
console.log('private m4');
this._m5();
}
_m5() {
console.log('private m5');
}
}
module.exports = (f1, f2) => {
const my = new MyClass(f1, f2);
return {
m1: my.m1.bind(my),
m2: my.m2.bind(my),
m3: my.m3.bind(my),
}
}
index.js
const myObj = require('./my-class')('f1', 'f2');
myObj.m1();
Live demo
This way you are hiding the private methods which should not be accessible outside of the module.

WebRTC P2P with browser and Android (Flutter) not working although everything seems fine

I tried to set up a WebRTC P2P video communication with flutter, a node backend as signaling server and kurento media server.
When I run the app in combination with the Kurento Demo everything works fine but as soon as I try to implement my own backend the video stream doesn't start although the log messages indicate that everything is ok.
Please let me know if more input is required to find a solution.
Relevant code snippets
Web Frontend:
call(username) {
const wrapper = this;
const remoteVideo = this.videoOutputFactory();
if (!remoteVideo) {
console.error('videoOutput not found');
}
const options = {
'remoteVideo': document.getElementById('testVideo'),
onicecandidate(candidate) {
console.debug('onicecandidate', candidate);
wrapper.rpc.onIceCandidate(candidate);
},
mediaConstraints: wrapper.remoteMediaConstraints
};
console.debug('WebRtcWrapper.call: options', options);
return new Promise((resolve, reject) => {
console.log('Creating WebRtcPeer');
this.webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options, (error) => {
if (error) {
console.error('Error while creating WebRtcPeer', error);
reject(error);
return;
}
console.log('Generating WebRtcPeer offer');
this.webRtcPeer.generateOffer((offerError, offerSdp) => {
if (offerError) {
console.error('Error while generating WebRtcPeer offer', error);
reject(error);
return;
}
this.rpc.call(username, offerSdp).then((res) => {
console.log("Got call answer - Generated-SDPOffer: " + offerSdp);
if (res.response === 'rejected') {
console.log('Call rejected by peer');
reject(res.rejectionMessage);
return;
}
console.log('Processing peer SDP answer', res.sdpAnswer);
this.webRtcPeer.processAnswer(res.sdpAnswer);
});
});
});
});
}
App
TestController._()
: _channel = IOWebSocketChannel.connect('wss://server.marcostephan.at:443') {
_peer = jsonrpc.Peer(_channel.cast<String>());
_peer.registerMethod(
'rtc.incomingCall', (jsonrpc.Parameters message) async => await _onIncomingCall(message));
_peer.registerMethod(
'rtc.offerIceCandidate', (jsonrpc.Parameters message) => _onOfferIceCandidate(message));
_peer.registerMethod(
'rtc.startCommunication', (jsonrpc.Parameters message) => _onStartCommunication(message));
_peer.registerMethod('conn.heartbeat', (jsonrpc.Parameters message) => "");
_peer.registerFallback((jsonrpc.Parameters params) =>
print('Unknown request [${params.method}]: ${params.value}'));
_peer.listen();
_peer.sendRequest("auth.login", {'username': 'john.doe', 'role': 'actor'});
_peer.sendNotification("disp.helpMe", {'category': 'spareParts'});
}
_onIncomingCall(jsonrpc.Parameters message) async {
try{
print('Incoming call from ${message['username'].value}');
if (this.onStateChange != null) {
this.onStateChange(SignalingState.CallStateNew);
}
await _createPeerConnection();
RTCSessionDescription s = await _peerConnection
.createOffer(_constraints);
_peerConnection.setLocalDescription(s);
return {
'from': message['username'].value,
'callResponse': 'accept',
'sdpOffer': s.sdp
};
}
catch(e){
print('TestController._onIncomingCall: ERROR: $e');
}
}
_onOfferIceCandidate(jsonrpc.Parameters message) {
try{
var candidateMap = message['candidate'].value;
print('Received IceCandidate $candidateMap');
if (_peerConnection != null) {
RTCIceCandidate candidate = new RTCIceCandidate(candidateMap['candidate'],
candidateMap['sdpMid'], candidateMap['sdpMLineIndex']);
_peerConnection.addCandidate(candidate);
}
}
catch(e){
print('TestController._onOfferIceCandidate: ERROR: $e');
}
}
_onStartCommunication(jsonrpc.Parameters message) {
try{
_peerConnection.setRemoteDescription(
RTCSessionDescription(message['sdpAnswer'].value, 'answer'));
}
catch(e){
print('TestController._onStartCommunication: ERROR: $e');
}
}
_createPeerConnection() async {
_localStream = await _createStream();
RTCPeerConnection pc = await createPeerConnection(_iceServers, _config);
_peerConnection = pc;
pc.addStream(_localStream);
pc.onAddStream = (stream) {
if (this.onRemoteStream != null) this.onRemoteStream(stream);
//_remoteStreams.add(stream);
};
pc.onIceConnectionState = (state) {
print(
'TestController._createPeerConnection: onIceConnectionState: $state');
};
pc.onIceCandidate = (candidate) {
_peer.sendNotification("rtc.onIceCandidate", {
'candidate': {
'sdpMLineIndex': candidate.sdpMlineIndex,
'sdpMid': candidate.sdpMid,
'candidate': candidate.candidate
}
});
};
}
Future<MediaStream> _createStream() async {
final Map<String, dynamic> mediaConstraints = {
'audio': true,
'video': {
'mandatory': {
'minWidth': '1980',
'minHeight': '1020',
'minFrameRate': '30',
},
'facingMode': 'environment',
'optional': [],
}
};
MediaStream stream = await navigator.getUserMedia(mediaConstraints);
if (this.onLocalStream != null) {
this.onLocalStream(stream);
}
return stream;
}
final Map<String, dynamic> _iceServers = {
'iceServers': [
{'url': 'stun:stun.l.google.com:19302'},
]
};
final Map<String, dynamic> _config = {
'mandatory': {},
'optional': [
{'DtlsSrtpKeyAgreement': true},
],
};
final Map<String, dynamic> _constraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': true,
},
'optional': [],
};
Logs
Web Frontend
Pastebin
App
Pastebin

WebRTC: One to one Audio call not working in different machine

I am trying to implement a one to one audio call using webRTC (signalling using websockets) . But it works when i try it in one system using multiple tabs of chrome (localhost). When I try to hit my server from another machine it does initial handshakes , but call doesn't happen.
But when i try to change the tag to and changed the constraints to video constraints . it works even if the we try to access from other machine (i.e video call works ).
I initially thought it was because if firewall but when video call worked I was puzzled .
Here is my code:
// Constraints to get audio stream only
$scope.constraints = {
audio: {
mandatory: {
googEchoCancellation: true
},
optional: []
},
video:false
};
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// success Callback of getUserMedia(), stream variable is the audio stream.
$scope.successCallback = function (stream) {
if (window.URL) {
myVideo.src = window.URL.createObjectURL(stream); // converting media stream to Blob URL.
} else {
myVideo.src = stream;
}
//attachMediaStream(audioTag, stream);
localStream = stream;
if (initiator)
maybeStart();
else
doAnswer();
};
// failure Callback of getUserMedia()
$scope.failureCallback = function (error) {
console.log('navigator.getUserMedia Failed: ', error);
};
var initiator, started = false;
$("#call").click(function () {
socket.emit("message", undefined);
initiator = true;
navigator.getUserMedia($scope.constraints, $scope.successCallback, $scope.failureCallback);
});
var channelReady = false;
socket.on('message', function (data) {
channelReady = true;
if (data) {
if (data.type === 'offer') {
if (!initiator) {
$("#acceptCall").show();
$("#acceptCall").click(function(){
if (!initiator && !started) {
var pc_config = {
iceServers: [
{ url: "stun:stun.l.google.com:19302" },
{ url: "turn:numb.viagenie.ca", credential: "drfunk", username: "toadums#hotmail.com"}
]
};
pc = new webkitRTCPeerConnection(pc_config);
pc.onicecandidate = onIceCandidate;
pc.onaddstream = onRemoteStreamAdded;
}
pc.setRemoteDescription(new RTCSessionDescription(data));
$scope.acceptCall();
});
}
} else if (data.type === 'answer' && started) {
pc.onaddstream = onRemoteStreamAdded;
pc.setRemoteDescription(new RTCSessionDescription(data));
} else if (data.type === 'candidate' && started) {
var candidate = new RTCIceCandidate({
sdpMLineIndex: data.label,
candidate: data.candidate
});
pc.addIceCandidate(candidate);
} else if (data.type === 'bye' && started) {
console.log("Bye");
}
}
});
function onRemoteStreamAdded(event) {
othersVideo.src = URL.createObjectURL(event.stream);
};
var sdpConstraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': false
}
};
function doAnswer() {
pc.addStream(localStream);
pc.createAnswer(gotDescription,null,sdpConstraints);
}
function gotDescription(desc) {
pc.setLocalDescription(desc);
socket.send(desc);
}
function maybeStart() {
if (!started && localStream && channelReady)
createPeerConnection();
pc.addStream(localStream);
started = true;
if (initiator)
doCall();
}
$scope.acceptCall = function () {
navigator.getUserMedia($scope.constraints, $scope.successCallback, $scope.failureCallback);
}
function createPeerConnection() {
var pc_config = {
iceServers: [
{ url: "stun:stun.l.google.com:19302" },
{ url: "turn:numb.viagenie.ca", credential: "drfunk", username: "toadums#hotmail.com"}
]
};
pc = new webkitRTCPeerConnection(pc_config);
pc.onicecandidate = onIceCandidate;
console.log("Created RTCPeerConnnection with config:\n" + " \"" +
JSON.stringify(pc_config) + "\".");
};
function doCall() {
$scope.caller = true;
pc.createOffer(setLocalAndSendMessage,null,sdpConstraints);
};
function setLocalAndSendMessage(sessionDescription) {
pc.setLocalDescription(sessionDescription);
socket.send(sessionDescription);
}
function onIceCandidate(event) {
if (event.candidate) {
socket.emit('message', {
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate
});
} else {
console.log("End of candidates.");
}
}
If navigator.mediaDevices is undefined, this because work only in secure context (https)
see:
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia

Resources