WebSDK doesn't receive published stream from iOS SDK
Currenty, I've completed WebSDK based videocall. User1 joins to the chatX and publishes his stream. User2 receives this stream via "stream-added" event in the chatX and successfully subscribes for it.
But "stream-added" event doesn't fire when user1 joins to videochat from iOS App.
client.on('stream-added', function (evt) {
var stream = evt.stream;
console.log("New stream added: " + stream.getId());
console.log("Subscribe ", stream);
client.subscribe(stream, function (err) {
console.log("Subscribe stream failed", err);
});
});
client.on('stream-subscribed', function (evt) {
var stream = evt.stream;
console.log("Subscribe remote stream successfully: " + stream.getId());
if ($('#videochat-remoteVideo #agora_remote'+stream.getId()).length === 0) {
$('#videochat-remoteVideo').append('<div id="agora_remote'+stream.getId()+'"></div>');
}
remoteBigLocalSmall();
stream.play('agora_remote' + stream.getId());
});
iOS app reveives the stream published from Web, whereas Web client doesn't receives the stream from iOS client.
What can be wrong with my implementation? How to receive stream from iOS client?
UPD:
Join chat code:
user_id = '111';
client.join(channel_key, videochat_id, user_id, function(uid) {
...
I've changed user_id type from string to int and now it works. I can't understand why, because documentation allows string uid:
join(tokenOrKey: string | null, channel: string, uid: number | string
| null, onSuccess?: function, onFailure?: function): void
The issue you are facing is related to your use of the wrong API Method. You are using joinChannelByToken which only works with Integer values when you should be using joinChannel(byUserAccount: ...) because that takes a String uid as a parameter.
let myStringId = "someStringId"
agoraKit.joinChannel(byUserAccount: myStringId, token: nil, channelId: "demoChannel1") { (sid, uid, elapsed) in
// Did join channel "demoChannel1"
}
Changing client.join method parameter uid from string to integer resolved the issue
Related
onUserJoined provides UID which is then used to set up remote video.
in live stream feature when there are two hosts streaming in one channel and if another audience joins later then how can that audience tell which uid is for which host.
Note that onUserJoined does call in random order.
https://docs.agora.io/en/All/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_channel_event_handler.html#a65fd197a39824219aedc2cba81296e82
Use case:
2 hosts already streaming in one channel. 1 of the host is original host and another is a co-host(got invited into the channel)
an audience joins the channel. onUserJoined callback is triggered twice and given the remote UID. That audience now needs to know who is the original host and related his UID and who is the co-host and his related UID.
You basically Answered your self
LIVE_BROADCASTING profile: This callback notifies the app when the host joins the channel. If other hosts are already in the channel, the SDK also reports to the app on the existing hosts. We recommend having at most 17 hosts in a channel.
I finally found a solution for that issue by informing all users that will enter the channel after the Orignal Host by the uid of the orignal host
and you can do this by using sendStreamMessage() function
First joinChannelSuccess triggers after original host login
which will return uid of the original host - and we will save it in a variable.
Then, use sendStreamMessage() to send this uid for all new users
and that by using this function which will be called when userJoined triggers
check this code
int _orignalHost = 'the uid';
_addListener() {
_engine.setEventHandler(RtcEngineEventHandler(
**joinChannelSuccess:** (channel, uid, elapsed) {
setState(() {
isJoined = true;
});
},
**userJoined:** (uid, elapsed) {
remoteUids.add(uid);
setState(() {});
},
// this trriger when you recive the mesage
**streamMessage:** (int uid, int streamId, Uint8List data) {
// save it in _orignalHost variable for the audince
},
streamMessageError:
(int uid, int streamId, ErrorCode error, int missed, int cached) {
},
));
}
Future<void> _onNewUserJoin() async {
try {
var streamId = await _engine
.createDataStreamWithConfig(DataStreamConfig(false, false));
if (streamId != null) {
await _engine.sendStreamMessage(
streamId, Uint8List.fromList(utf8.encode(_orignalHost)));
}
_controller.clear();
} catch (e) {
}
}
you can check full code for StreamMessage:
https://github.com/AgoraIO/Agora-Flutter-SDK/blob/master/example/lib/examples/advanced/stream_message/stream_message.dart
Also, You can check this for more info (anoter solution)
https://docs.agora.io/en/Real-time-Messaging/faq/audience_event?platform=Android
im trying to make it possible for a room host to kick a user, im using the rest api to kick a user, when i send a request with the following body:
public CompletableFuture<Boolean> actionOnUser(String action, Long channelId, String userId) {
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
Map body = new HashMap<>();
body.put("appid", agoraConfig.getAppId());
body.put("uid", userId);
body.put("time", 0);
body.put("cname", channelId.toString());
body.put("ip", "");
String[] privileges = { action };
body.put("privileges", privileges);
Mono<String> agoraResponse = webClient().post().uri("/dev/v1/kicking-rule").bodyValue(body).retrieve()
.bodyToMono(String.class).doOnSuccess(response -> {
logger.info("kicking-rule response status:" + response);
completableFuture.complete(true);
}).doOnError(onError -> {
logger.info("kicking rule failed" + onError);
completableFuture.complete(false);
});
agoraResponse.subscribe();
return completableFuture;
}
i get a 200 OK response with an id of the kicking rule, but the user isn't being kicked, how can i fix this?
Edit: apparently agora doesnt accept strings as uid, had to switch to int which is unfortunate because i preferred to use UUID, but this fixes the issue
agora doesnt accept strings as uid, had to switch to int which is unfortunate because i preferred to use UUID, but this fixes the issue
For implementing kick user from call functionality you can use Agora RTM SDK.
For ref:- https://www.agora.io/en/blog/muting-and-unmuting-a-remote-user-in-a-video-call-web/
Also, you can use your custom WebSocket.
Hello I followed this tutorial to create a simple webrtc example.
https://www.webrtc-experiment.com/docs/WebRTC-PeerConnection.html .
So look my JFFiddle:
https://jsfiddle.net/xzspquew/9/
and tell me please why I can't enter to the function onaddstream ? The console.log("this function is called") is neved called. Why ?
navigator.getUserMedia({audio:false, video:true}, success, error)
var pc = new RTCPeerConnection()
var pc2 = new RTCPeerConnection()
pc.onaddstream = function(event) {
console.log("this function is called")
var video2 = document.getElementById("video2")
video2.src = window.URL.createObjectURL(event.stream)
video2.play()
}
document.querySelector("#repondre").addEventListener('click', function repondre() {
var answer = prompt("Please enter your sdp remote offer");
console.log(answer)
pc2.setRemoteDescription(JSON.parse(answer))
pc2.createAnswer(successanswerrtc, errorrtc)
})
function successanswerrtc(answersdp) {
pc2.setLocalDescription(answersdp)
console.log(JSON.stringify(answersdp))
pc.setRemoteDescription(answersdp)
}
function sucessrtc(offersdp) {
pc.setLocalDescription(offersdp)
alert(JSON.stringify(offersdp))
console.log(JSON.stringify(offersdp))
}
function errorrtc(err) {
console.log("error" + err)
}
function success(stream) {
var video1 = document.getElementById("video1")
video1.src = window.URL.createObjectURL(stream)
video1.play()
pc.createOffer(sucessrtc, errorrtc)
}
function error() {
console.log("error")
}
That tutorial appears to be outdated. Perhaps https://webrtc.org/start/#demos-and-samples
According to MDN documentation, it has been deprecated:
https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onaddstream
This property has been removed from the specification; you should now use RTCPeerConnection.ontrack to watch for track events instead. It is included here in order to help you adapt existing code and understand existing samples, which may not be up-to-date yet.
It looks you are trying with an outdated demo,
Try this demo from WebRTC official samples
In your fiddle you didn't handled the candidates & streams properly .
If you are making a call from pc to pc2, you need to add stream to pc by calling pc.addstream(stream) then pc2.onaddstream or pc2.onaddtrack method will triggered.
I updated your fiddle https://jsfiddle.net/8mchrc3v/1/
I am a newbie to WebRTC. I am building an application that enables users to view each other's video stream, as well as exchange files. The audio/video part is implemented and working. The problem is I need to add the ability to exchange files now. I am using the below code to initialize the PeerConnection object
var connection = _getConnection(partnerId);
console.log("Initiate offer")
// Add our audio/video stream
connection.addStream(stream);
// Send an offer for a connection
connection.createOffer(function (desc) { _createOfferSuccess(connection, partnerId, desc) }, function (error) { console.log('Error creating session description: ' + error); });
_getConnection creates a new RTCPeerConnection object using
var connection = new RTCPeerConnection(iceconfig);
i.e., with no explicit constraints. It also initializes the different event handlers on it. Right after this, I attach the audio/video stream to this connection. I also cache these connections using the partner id, so I can use it later.
The question is, can I later recall the connection object from the cache, add a data channel to it using something like
connection.createDataChannel("DataChannel", dataChannelOptions);
And use it to share files, or do I have to create a new RTCPeerConnection object and attach the data channel to it?
You certainly do not have to create a another PeerConnection for file transfer alone. Existing PeerConnection can utilize RTCDatachannel with behaves like traditional websocket mechanism ( ie 2 way communication without a central server )
`var PC = new RTCPeerConnection();
//specifying options for my datachannel
var dataChannelOptions = {
ordered: false, // unguaranted sequence
maxRetransmitTime: 2000, // 2000 miliseconds is the maximum time to try and retrsanmit failed messages
maxRetransmits : 5 // 5 is the number of times to try to retransmit failed messages , other options are negotiated , id , protocol
};
// createing data channel using RTC datachannel API name DC1
var dataChannel = PC.createDataChannel("DC1", dataChannelOptions);
dataChannel.onerror = function (error) {
console.log("DC Error:", error);
};
dataChannel.onmessage = function (event) {
console.log("DC Message:", event.data);
};
dataChannel.onopen = function () {
dataChannel.send(" Sending 123 "); // you can add file here in either strings/blob/array bufers almost anyways
};
dataChannel.onclose = function () {
console.log("DC is Closed");
};
`
PS : while sending files over datachannel API , it is advisable to break down the files into small chunks beforehand . I suggest chunk size of almost 10 - 15 KB .
I am trying to create 1 to 1 chat from a web client.
I downloaded the SDK and the group chat example.
There seem to be really good examples for all platforms except the web.
(for example: http://quickblox.com/developers/Android_XMPP_Chat_Sample)
Can anyone provide code/example/directions?
Am i missing something or is the documentation for the web is really lacking?
Thanks
The WebSDK is enough new. And we work on its documentation.
But,here, I will show you some code snippets how you can create one to one chat.
As you know QuickBlox uses XMPP-server as a Chat service.
WebSDK doesn't have a wrapper around XMPP API, so you should include additional XMPP JS library.
For our examples, we recommended to use Strophe.js (http://strophe.im/strophejs/)
Let's begin:
1) Include your xmpp js library and WebSDK
<script src="quickblox.js"></script>
<script src="strophe.js"></script>
2) Describe your QB credentials
var QBAPP = {
app_id: '<your QuickBlox id>',
auth_key: '<your QuickBlox key>',
auth_secret: '<your QuickBlox secret>'
};
// our parameters to connect to QuickBlox Chat service
var CHAT = {
server: 'chat.quickblox.com',
bosh_server: 'http://chat.quickblox.com:5280'
};
3) Create QB session with user authentication
var params, connection;
params = {
login: '<your QB login>',
password: '<your QB password>'
};
QB.init(QBAPP.app_id, QBAPP.auth_key, QBAPP.auth_secret);
QB.createSession(params, function(err, res) {
if (err) {
console.log(err.detail);
} else {
connectChat(res.user_id, params.password);
}
});
4) Connect to QuickBlox Chat server with your user JID and password (http://quickblox.com/developers/Chat#Connecting_to_server)
function connectChat(user_id, password) {
var userJID = user_id + "-" + QBAPP.app_id + "#" + CHAT.server;
var userPass = password;
connection = new Strophe.Connection(CHAT.bosh_server);
connection.rawInput = rawInput;
connection.rawOutput = rawOutput;
connection.connect(userJID, userPass, function (status) {
switch (status) {
case Strophe.Status.ERROR:
console.log('[Connection] Error');
break;
case Strophe.Status.CONNECTING:
console.log('[Connection] Connecting');
break;
case Strophe.Status.CONNFAIL:
console.log('[Connection] Failed to connect');
break;
case Strophe.Status.AUTHENTICATING:
console.log('[Connection] Authenticating');
break;
case Strophe.Status.AUTHFAIL:
console.log('[Connection] Unauthorized');
break;
case Strophe.Status.CONNECTED:
console.log('[Connection] Connected');
// Create an event handler for getting messages
connection.addHandler(onMessage, null, 'message', null, null, null);
// send a presence message
connection.send($pres().tree());
break;
case Strophe.Status.DISCONNECTING:
console.log('[Connection] Disconnecting');
break;
case Strophe.Status.DISCONNECTED:
console.log('[Connection] Disconnected');
break;
case Strophe.Status.ATTACHED:
console.log('[Connection] Attached');
break;
}
});
}
// logs
function rawInput(data) {console.log('RECV: ' + data);}
function rawOutput(data) {console.log('SENT: ' + data);}
5) Function for receive messages
function onMessage(msg) {
console.log(msg);
var to = msg.getAttribute('to');
var from = msg.getAttribute('from');
var type = msg.getAttribute('type');
var elems = msg.getElementsByTagName('body');
// we must return true to keep the handler alive.
// returning false would remove it after it finishes.
return true;
}
6) Function for send messages
function sendMessage() {
params = {
to: '<some JID>', // JID of recipient QB User
from: connection.jid, // JID of sender QB user
type: 'chat' // type of the message
}
var msg = $msg(params).c('body').t('Hello world!');
connection.send(msg.tree());
}
I'm sure, that it helps you to create one to one chat with QuickBlox using Javascript.
If you want to use the group chat, you can look at 'Chat module code' from develop branch of Web XMPP chat sample:
https://github.com/QuickBlox/sample-chat-xmpp-web/blob/develop/qbchatroom.js
Today we finished new sample's design http://i.imgur.com/r8CSdNV.png and very soon will deploy that to production.
I suggest that you might see the 405 error because you have put the call of sendMessage function immediately after the call of connectChat function.
To connect to the chat needs some time, so you can not send the message until your client (browser) hasn't finished the connecting to the chat server at first. You need to put the call of sendMessage function in callback from function connectChat where a status is "Connected". Or you can perform sendMessage function on an onclick event to the tag <button> or something else. For your example, insert sendMessage like here:
case Strophe.Status.CONNECTED:
console.log('[Connection] Connected');
connection.addHandler(onMessage, null, 'message', null, null, null);
connection.send($pres().tree());
sendMessage();
break;
Starting from today QuickBlox has a own Web XMPP Chat plugin for WebSDK.
You can look here the new example for 1:1 Chat which uses this library:
http://quickblox.com/developers/Web_XMPP_Chat_Sample