How to do screen sharing in agora without getting an authentication problem - vue.js

I've implemented the agora sdk 3.0 for video calls.
now I'm trying to get screen sharing to work, but I keep getting the error provided in
the picture below (Join failed: NO_AUTHORIZED).
Picture of console while sharing a screen
screen sharing code sample:
async shareScreen() {
this.shareClient = AgoraRTC.createClient({
mode: 'rtc',
codec: 'vp8'
})
this.shareClient.init('xxxxxxxxxxxxxx', () => {
this.shareClient.join('same token video call started with', 'same room name of current outgoing video call', null, (uid) => {
const streamSpec = {
streamID: uid,
audio: false,
video: false,
screen: true
}
if (isFirefox()) {
streamSpec.mediaSource = 'window';
} else if (!isCompatibleChrome()) {
streamSpec.extensionId = 'minllpmhdgpndnkomcoccfekfegnlikg';
}
this.shareScreenStream = AgoraRTC.createStream(streamSpec);
// Initialize the stream.
this.shareScreenStream.init(() => {
// Play the stream.
this.shareScreenStream.play('renderer');
// Publish the stream.
this.shareClient.publish(this.shareScreenStream);
}, function(err) {
console.log(err);
});
}, function(err) {
console.log(err);
})
});
},

The screensharing client should use an unique token based on the UID and channel name. Not the one the main user is using.

Related

Stream Web Audio with WebRTC without asking for microphone

I want to stream audio from a web page to a local server, using WebRTC. That server will process that audio and will output it immediately to the user. I need real time.
My code is actually working. However I am asking the user for the microphone with getUserMedia, and I don't need that microphone. This is quite annoying. What can I do in order to stream the audio without having to ask the user for the microphone?
Thank you.
Here is a minimal working example (it is highly inspired by https://github.com/aiortc/aiortc/blob/main/examples/server/client.js). Only the last part with comments is interesting :
let webSocket = new WebSocket('wss://0.0.0.0:8080/ws');
const config = { sdpSemantics: 'unified-plan' }
const pc = new RTCPeerConnection(config);
webSocket.onmessage = (message) => {
const data = JSON.parse(message.data);
switch(data.type) {
case "answer":
pc.setRemoteDescription(data.answer)
break;
default:
break;
}
};
function negotiate() {
return pc.createOffer()
.then(function(offer) {
return pc.setLocalDescription(offer);
})
.then(function() {
return new Promise(function(resolve) {
if (pc.iceGatheringState === 'complete') {
resolve();
} else {
function checkState() {
if (pc.iceGatheringState === 'complete') {
pc.removeEventListener('icegatheringstatechange', checkState);
resolve();
}
}
pc.addEventListener('icegatheringstatechange', checkState);
}
});
})
.then(function() {
const offer = pc.localDescription;
webSocket.send(
JSON.stringify({
type: "offer",
offer: {
sdp: offer.sdp,
type: offer.type
}
})
);
})
}
// Preparing the oscillator
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioCtx.createOscillator();
const serverDestination = audioCtx.createMediaStreamDestination();
oscillator.connect(serverDestination);
// Asking for useless microphone
navigator.mediaDevices.getUserMedia({audio: true})
.then(() => {
return negotiate();
});
// Actual streaming
const stream = new MediaStream();
serverDestination.stream.getTracks().forEach((track) => {
pc.addTrack(track, stream);
})
// User pushes button to start the oscillator
function play() {
oscillator.start();
};
Just get rid of this:
// Asking for useless microphone
navigator.mediaDevices.getUserMedia({audio: true})
.then(() => {
return negotiate();
});
As you say, it's useless and not necessary. If you don't call getUserMedia(), the user won't be prompted to share their microphone. You can make WebRTC connections without this.
I suspect the problem you're running into is that your audio context is paused. If you call audioCtx.resume() when a user clicks a button, you'll be up and running. This is due to autoplay policy.
If you don't need user media, don't ask for it with getUserMedia in your code.

ValidationError: Subscription is unusable or cannot be found. License failed

I'm trying to create a service that will be a middle man between my frontend framework and shutterstock. I'm running into an issue when trying to license an image where it says my subscription is unusable or cannot be found. I have done exactly what the documentation said and I don't know what I am missing.
let sstk = require("shutterstock-api");
sstk.setSandbox(true);
sstk.setAccessToken(process.env.SHUTTERSTOCK_TOKEN);
// Instantiate the shutterstock images api
const imagesApi = new sstk.ImagesApi();
// Instantiate the shutterstock users api
const usersApi = new sstk.UsersApi();
// Creates the body to send to shutterstock
const body = {
images: imageIds.map((imageId) => {
return {
image_id: imageId,
price: 0,
metadata: {
customer_id: "0",
},
};
}),
};
// Get subscription so we can grab the subscription id
usersApi
.getUserSubsciptionList()
.then(({ data }) => {
const subscription_id = data[0].id;
const queryParams = {
format: "jpg",
size: "huge",
subscription_id,
};
// If we successfully get the subscription id then license the images
imagesApi
.licenseImages(body, queryParams)
.then(({ data }) => {
console.log("licensedImages", data);
// Check if there was an error on any of the images
let numOfErrors = 0;
data.forEach((image) => {
if (image.error) {
numOfErrors += 1;
}
});
// If some of the images were successful
if (numOfErrors > 0 && numOfErrors < data.length) {
return errorHandler
// If all the images failed
} else if (numOfErrors > 0) {
return errorHandler
}
// If there are no errors send back the data to the frontend to manipulate it how it needs
return res.status(200).send(data);
})
.catch((err) => {
// If license error wasn't handled by Shutterstock
console.error(err);
return errorHandler
});
})
.catch((error) => {
// If subscription error wasn't handled by Shutterstock
console.error(error);
return errorHandler
});
Logged Response with status code 200
licensedImages [ exports {
image_id: id,
error:
'ValidationError: Subscription is unusable or cannot be found. License failed' } ]
I'm not sure why its not working. I've logged my subscription id and image id and they are correct.
The format and size do match the formats available on the subscription.
The subscription is a Developer Platform license.
What am I missing?
This is on an expressjs api
It looks like your Shutterstock account has both a 'Developer Platform' subscription and standard user subscription, which causes issues in the api. Your code is correct - the problem is with the validation of your subscription within the licensing flow. We'll reach out to you via email once we correctly attribute your different subscriptions.

How to insert data in firebase using expo..?

I've an issue, actually I want to insert data into firebase using expo from different screen(I'm using google auth in another screen and after completing it I'm going to main screen), it's working also but it is not saving data in which table I want it to store(after google auth, I'm saving data into firebase in 'users')..
// I'm using this code to insert data in first place (while login)
// and I'm also using isUserNew() method and it's working really fine..
onSignIn = googleUser => {
console.log('Google Auth Response', googleUser);
// We need to register an Observer on Firebase Auth to make sure auth is initialized.
var unsubscribe = firebase.auth().onAuthStateChanged(function(firebaseUser) {
unsubscribe();
// Check if we are already signed-in Firebase with the correct user.
if (!this.isUserEqual(googleUser, firebaseUser)) {
// Build Firebase credential with the Google ID token.
var credential = firebase.auth.GoogleAuthProvider.credential(
googleUser.idToken,
googleUser.accessToken
);
// Sign in with credential from the Google user.
firebase.auth().signInAndRetrieveDataWithCredential(credential).then(function(result) {
console.log('user signed in');
if(result.additionalUserInfo.isNewUser){
firebase.database().ref('/users/' + result.user.uid).set({
gmail: result.user.email,
profile_picture: result.additionalUserInfo.profile.picture,
locale: result.additionalUserInfo.profile.locale,
first_name: result.additionalUserInfo.profile.given_name,
last_name: result.additionalUserInfo.profile.family_name,
created_at: Date.now()
}).then(function (snapshot){
// console.log('Snapshot', snapshot);
});
}else{
firebase.database().ref('/users/' + result.user.uid).update({
last_logged_in: Date.now()
});
}
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
} else {
console.log('User already signed-in Firebase.');
}
}.bind(this));
};
// This code is also showing an error that I can't call setState from an //unmounted component.
// :- this function as well update() in firebase is in another screen or page.
async componentDidMount() {
try {
let {status} = await Permissions.getAsync(Permissions.LOCATION);
if(status !== 'granted'){
const {status} = await Permissions.askAsync(Permissions.LOCATION);
}else{
const watchId = navigator.geolocation.watchPosition(
({ coords : {latitude, longitude} }) => this.setState({latitude, longitude}, () => console.log('State:', this.state)),
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 0, maximumAge: 1000, distanceFilter: 1},
);
await AsyncStorage.setItem('LiveFeedId', JSON.stringify(watchId));
}
}
catch(err) {
console.error(error);
}
};
/* when I'm using this code it's saving the data but not in 'users' table in firebase */
firebase.database().ref('users/').update({
latitude: latitude,
longitude: longitude,
});
Can anyone please help me out here, I'm really new to react native..
And I want to update my latitude and longitude from another screen to firebase where I've saved my users details, ex:- 'firebase.database().ref('/users/' + result.user.uid)'..
Thanks

One to one user can not see each other during agora video call

I have implemented the agora code in my angular 5 application using agora CDN. Camera is opening but one to one user can not see each other's video frame.
Why?
var self = this;
var client = AgoraRTC.createClient({ mode: 'rtc', codec: "h264" });
client.init('my key', function () {
console.log("AgoraRTC client initialized");
client.join(null, 'TestChanel', null, function (uid) {
console.log("User " + uid + " join channel successfully");
self.uId = uid;
var localStream = AgoraRTC.createStream({
// streamID: uid,
// audio: true,
// video: true,
// screen: false,
streamID: uid,
audio: true,
cameraId: self.deviceId,
// microphoneId: self.microphone,
video: true,
screen: false,
extensionId: 'minllpmhdgpndnkomcoccfekfegnlikg',
}
);
localStream.init(function () {
console.log("getUserMedia successfully");
localStream.play('agora_local');
// localStream.play('video-caller');
client.publish(localStream, function (err) {
console.log("Publish local stream error: " + err);
});
client.on('stream-published', function (evt) {
console.log("Publish local stream successfully");
});
client.on('stream-added', function (evt) {
var stream = evt.stream;
console.log("New stream added: " + stream.getId());
client.subscribe(stream, function (err) {
console.log("Subscribe stream failed", err);
});
});
client.on('stream-subscribed', function (evt) {
var remoteStream = evt.stream;
console.log("Subscribe remote stream successfully: " + remoteStream.getId());
remoteStream.play('agora_remote' + remoteStream.getId());
})
}, function (err) {
console.log("getUserMedia failed", err);
});
}, function (err) {
console.log("Join channel failed", err);
});
}, function (err) {
console.log("AgoraRTC client init failed", err);
});
There are a few things that might help you resolve this issue:
Take advantage of Typescript typings to help with debugging. You can install a basic typing library for the SDK with the command npm install --save-dev #types/agora-rtc-sdk, to give you more debugging power.
Set a timeout or use rxjs's timer before you try to play the remote stream, that sometimes helps ensure the stream is played.
Test not assigning a cameraId in the createStream() method, or using this instead of self - you could be having issues with Angular because of it.
Also make sure in future tests that the uid used in join() is of the same type for both users. I've experienced this issue before when one client was passing in a number and the other was passing in a string.
If you're using Chrome to test this between two users, then it's probably not a browser issue, but, depending on the SDK version, there are some known bugs you should look into.

WebRTC using promises - Remote Video not seen at either end

I had earlier posted some questions on this problem. At that time I had two separate programs for caller and receiver. I was also using old-fashioned callback API. Thanks to help from #jib on that post, I was able to understand the need for some fundamental changes. I rewrote the program to make it an integrated one for both caller and receiver and have used the WebRTC promises API. My problem is that I am not getting remote video from either end. One part I understand but do not know the solution: The receiver does not create SDPs for Video in the first place, only for audio. The caller part does create SDPS for Video and audio but on the receiver end there is no event generated for remote stream.
I have checked, through console logs, that the core functions work. Offer SDP is created, sent out, received, answer SDP created, sent out, received, etc. Candidates get exchanged and added too. But the .onaddstream event handler is never triggered. Local video is shown but that is trivial.
I have spent a LOT of time on this. I simply need to get that exciting feeling of seeing remote video on both ends which has kept me going. ANY HELP WILL BE SINCERELY APPRECIATED.
<script>
$(document).ready(function () {
var iceCandidates = [], countIceCandidates=0;
var socket = io.connect();
socket.on('connect',function() { console.log("Socket connected"); });
var pc = new RTCPeerConnection({"iceServers":[{"url":"stun:stun.l.google.com:19302"}]});
//If remote video stream comes in, display it in DIV vid2
pc.onaddStream = function (event) {
stream = event.stream;
var video = $('#vid2');
video.attr('src', URL.createObjectURL(stream));
video.onloadedmetadata = function(e) { video.play(); }
}
//Display media in both Caller and Receiver
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function(stream) {
var video = $('#vid1');
video.attr('src', URL.createObjectURL(stream));
video.onloadedmetadata = function(e) { video.play(); };
pc.addStream(stream);
})
.catch(function(err) { console.log(err);});
//INITIATE CALL
$('#call').click(function() {
pc.createOffer({ offerToReceiveVideo: true, offerToReceiveAudio: true })
.then(function(offer) {
localSessionDescription = new RTCSessionDescription(offer);
pc.setLocalDescription(localSessionDescription)
.then (function() { socket.emit('sdpOffer',localSessionDescription); })
.catch(function(err) { console.log("Error in setLocalDescription"); console.log(err); })
.catch(function(err) { console.log("Error in createOffer"); console.log(err); })
});
})
pc.onicecandidate = function (event) {
socket.emit('candidate',event.candidate);
};
socket.on('candidate',function (data) {
if (data != null) {
pc.addIceCandidate(new RTCIceCandidate(data))
.then(function() { console.log("peer candidate added");})
.catch(function(err) {console.log(err); console.log("Error during peer candidate addition");});
}
});
socket.on('disconnect',function() { alert("Disconnected"); });
function error(err) {
console.log("The following error occurred: " + err.name);
}
socket.on('sdpAnswer',function(data) {
sdpAnswer = new RTCSessionDescription(data.sdpAnswer);
pc.setRemoteDescription(sdpAnswer)
.then(function() { console.log("Answer SDP Set:"); console.log(sdpAnswer); })
.catch(function(err) { console.log("Error enountered when setting remote SDP Answer"); console.log(err)});
});
socket.on('sdpOffer', function(data) {
sdpOffer = new RTCSessionDescription(data.sdpOffer);
pc.setRemoteDescription(sdpOffer)
.then(function() { console.log("Remote SDP set in receiver");
pc.createAnswer()
.then(function(sdpAnswer) {
localSessionDescription = new RTCSessionDescription(sdpAnswer);
socket.emit('sdpAnswer',localSessionDescription);
pc.setLocalDescription(localSessionDescription)
.then(function(){
console.log("Local SDP Description set in receiver:");
})
.catch(function(err) { console.log("Error enountered when setting local SDP in receiver"); console.log(err)});
})
.catch(function(err) { console.log("Error enountered when creating answer SDP in receiver"); console.log(err)});
});
});
}); //End of document.ready function
</script>
ON THE SERVER SIDE (RELEVANT CODE ONLY). I have included here just in case there are any datatype related issues - object types, etc. getting changed when sent thru the server.
io.sockets.on('connection', function(socket) {
socket.on('sdpOffer', function(data) {
sdpOffer = data.sdp;
socket.broadcast.emit('sdpOffer',{"sdpOffer":data});
});
socket.on('sdpAnswer', function(data) {
sdpAnswer = data.sdp;
socket.broadcast.emit('sdpAnswer',{"sdpAnswer":data});
});
socket.on('candidate', function(data) {
socket.broadcast.emit('candidate',data);
});
});
Rename pc.onaddStream to pc.onaddstream.