Quickblox Javascript SDK + Angular + webRTC - 无法读取未定义的属性'send'



我已经建立了一个功能齐全的webRTC视频会议客户端,使用Quickblox Javascript SDK + Angular + webRTC。一件奇怪的事情正在发生,每次我清除缓存并从头开始登录时,当我发起呼叫时,我都会收到以下错误:

MediaStream {id: "iAmALongalphanumericStringThatGoesHere", active: true, onaddtrack: null, onremovetrack: null, onactive: null…}
quickblox.min.js:86149 [QBWebRTC]: Call, extension: {"name":"Erik Grosskurth","id":6184}
quickblox.min.js:86149 [QBWebRTC]: _createPeer, iceServers: {"iceServers":[{"url":"stun:stun.l.google.com:19302","urls":"stun:stun.l.google.com:19302"},{"url":"stun:turn.quickblox.com","username":"quickblox","credential":"iAmALongalphanumericStringThatGoesHere","urls":"stun:turn.quickblox.com"},{"url":"turn:turn.quickblox.com:3478?transport=udp","username":"quickblox","credential":"iAmALongalphanumericStringThatGoesHere","urls":"turn:turn.quickblox.com:3478?transport=udp"},{"url":"turn:turn.quickblox.com:3478?transport=tcp","username":"quickblox","credential":"iAmALongalphanumericStringThatGoesHere","urls":"turn:turn.quickblox.com:3478?transport=tcp"}]}
quickblox.min.js:86149 [QBWebRTC]: RTCPeerConnection init. userID: 6184, sessionID: 73eabb0a-21f1-4aa4-b928-f669090041d3, type: offer
telemed.js:467 null
quickblox.min.js:86149 [QBWebRTC]: getAndSetLocalSessionDescription success
quickblox.min.js:86149 [QBWebRTC]: _startDialingTimer, dialingTimeInterval: 5000
quickblox.min.js:86149 [QBWebRTC]: _dialingCallback, answerTimeInterval: 0
quickblox.min.js:73302 Uncaught TypeError: Cannot read property 'send' of undefined
at Strophe.Websocket._onIdle (quickblox.min.js:73302)
at Strophe.Connection._onIdle (quickblox.min.js:71559)
at Strophe.Connection.flush (quickblox.min.js:70444)
at Strophe.Websocket._send (quickblox.min.js:73407)
at Strophe.Connection.send (quickblox.min.js:70429)
at WebRTCSignalingProvider.sendMessage (quickblox.min.js:87369)
at WebRTCSession.processCall (quickblox.min.js:86798)
at _dialingCallback (quickblox.min.js:85422)
at RTCPeerConnection._startDialingTimer (quickblox.min.js:85429)
at quickblox.min.js:86422

有趣的是,如果我刷新页面,它工作正常,完全没有问题。当我遇到$scope问题时,我在开发过程中看到过这种情况,但我已经退缩了,无法确定它何时开始发生。有人可以确定此错误的原因吗?

这是我的控制器代码:

app.controller('patientCtrl', function($scope, $http, $location) {
QB.init(QBApp.appId, QBApp.authKey, QBApp.authSecret, config);
$scope.peers = [];
$scope.occupants = [];
$scope.recipient = {};
$scope.recipients = {};
$scope.session = {};
$scope.dialogs = {};
$scope.modal = false;
$scope.callWaiting = false;
$scope.$watch('peers');
$scope.$watch('occupants');
$scope.$watch('session');
$scope.$watch('modal');
$scope.$watch('callOptions');
$scope.$watch('callWaiting');
$scope.$watch('toggleConnCtrl');
$scope.user = JSON.parse(sessionStorage.getItem('userParams'));
var patient = {
userId: $scope.user.id,
password: $scope.user.password,
login: $scope.user.full_name
};
$scope.localMediaParams = {
audio: true,
video: true,
options: {
muted: true,
mirror: true
},
elemId: 'localVideoEl',
optional: {
minWidth: 240,
maxWidth: 320,
minHeight: 160,
maxHeight: 240
}
};
// HANDLE VISIT DATA AND SET UP CHAT
$scope.reqVisit = {
sKey : sessionStorage.getItem('key'),
sType: 'visit',
iObjectId: 1142606//sessionStorage.getItem('sessionId')
};
$http.post('/ws/Util.asmx/returnObject',$scope.reqVisit).then(function(response) {
$scope.visit = response.data.d;
QB.createSession(function(err,result){
if (result) {
QB.login($scope.user, function(loginErr, loginUser){
if (loginErr) {
console.log('log in error');
console.log(loginErr);
}else {
$scope.user = loginUser;
console.log($scope.user);
QB.chat.connect(patient, function(err, result) {
if (result) {   
$scope.roomData = JSON.parse(sessionStorage.getItem('userParams'));
$scope.user.user_tags = $scope.roomData.tag_list;
QB.users.update($scope.user.id, {tag_list: $scope.roomData.tag_list}, function(err, user){
if (user) {
console.log('updated room');
} else  {
console.log(err); 
}
});
$scope.updatePeerList($scope);
QB.chat.dialog.list({name: $scope.user.user_tags}, function(err, resDialogs) {
if (resDialogs) {
if (resDialogs.total_entries === 0) {
var chatParams = {
type: 2,
occupants_ids: $scope.occupants,
name: $scope.user.user_tags
};
QB.chat.dialog.create(chatParams, function(err, createdDialog) {
if (createdDialog) {
console.log(createdDialog);
} else {
console.log(err);
}
});
}else {
angular.forEach(resDialogs.items, function(item, i, arr) {
console.log('item found');
$scope.chatSession = item;
// join room
if ($scope.chatSession.type !== 3) {
QB.chat.muc.join($scope.chatSession.xmpp_room_jid, function() {
});
}
$scope.occupants = [];
$scope.chatSession.occupants_ids.map(function(userId) {
if ($scope.user.id !== userId && $scope.occupants.indexOf(userId) < 1) {
$scope.occupants.push(userId);
$scope.$apply($scope.occupants);
}
});
angular.forEach($scope.occupants, function (user_id) {
if (user_id !== $scope.user.id) {
var msg = {
type: 'chat',
extension: {
notification_type: 1,
_id: $scope.chatSession.xmpp_room_jid,
name: $scope.user.full_name,
occupant: $scope.user.id
}
};
console.log(user_id);
QB.chat.send(user_id, msg);
}
});
});
}
} else {
console.log('error with chat.dialog.list');
console.log(err);
}
});                                                 
} else { 
console.log('chat.connect failed');
console.log(res); 
}
});
}
});
}else if (err) {
console.log(err);
}
});
},function(errorHandler) {
console.log(errorHandler);
$scope.logout();
});
// HANDLE VIDEO CALLING
$scope.startCall = function() {
if (angular.equals($scope.recipients, {})) {
$scope.flyOutPeers = !$scope.flyOutPeers;
alert('Please choose a person to call');
}else {
if (!angular.equals($scope.session, {}) && !angular.equals($scope.session, undefined)) {
console.log('session hasn't been started');
$scope.session.stop({});
$scope.session = {};
return false;
}else {
$scope.session = QB.webrtc.createNewSession($scope.occupants, QB.webrtc.CallType.VIDEO);
$scope.modal = true;
$scope.callWaiting = true;
$scope.session.getUserMedia($scope.localMediaParams, function(err, stream) {
if (err){
console.log(err);
}else{
console.log(stream);
$scope.session.call($scope.recipient, function(error) {
console.log(error);
});
}
});
}
}
};
$scope.answerCall = function() {
$scope.modal = false;
$scope.callOptions = false;
$scope.toggleConnCtrl = true;
$scope.session.getUserMedia($scope.localMediaParams, function(err, stream) {
if (err){
console.log(err);
$scope.session.stop({});
}else{
console.log(stream);
$scope.session.accept({});
}
});
};
$scope.declineCall = function() {
$scope.session.reject({});
//$scope.session.stop({});
$scope.modal = false;
$scope.callOptions = false;
$scope.toggleConnCtrl = false;
$scope.session = {};
};
$scope.endCall = function() {
$scope.session.stop({});
$scope.modal = false;
$scope.callWaiting = false;
$scope.toggleConnCtrl = false;
$scope.session = {};
};
// HANDLE LISTENERS
QB.webrtc.getMediaDevices('videoinput').then(function(devices) {
if(devices.length > 1) {
//console.log(devices);
console.log('you have more than one media device')
}
}).catch(function(error) {
console.warn('getMediaDevices', error);
});
// Call was placed
QB.webrtc.onCallListener = function(session, extension) {
$scope.callerData = extension;
$scope.modal = true;$scope.$apply($scope.modal);
$scope.callOptions = true;$scope.$apply($scope.callOptions);
$scope.session = {};$scope.$apply($scope.session);
};
// No answer
QB.webrtc.onUserNotAnswerListener = function(session, userId) {
console.log('User '+session.currentUserID+' is not answering');
$scope.toggleConnCtrl = true;$scope.$apply($scope.toggleConnCtrl);
$scope.modal = false;$scope.$apply($scope.modal);
$scope.callWaiting = false;$scope.$apply($scope.callWaiting);
};
// Call was answered
QB.webrtc.onAcceptCallListener = function(session, userId, extension) {
console.log('User '+session.currentUserID+' just answered');
$scope.toggleConnCtrl = true;$scope.$apply($scope.toggleConnCtrl);
$scope.modal = false;$scope.$apply($scope.modal);
$scope.callWaiting = false;$scope.$apply($scope.callWaiting);
};  
// Call was declined
QB.webrtc.onRejectCallListener = function(session, userId, extension) {
console.log('User '+session.currentUserID+' sent you to voicemail');
$scope.toggleConnCtrl = false;$scope.$apply($scope.toggleConnCtrl);
$scope.modal = false;$scope.$apply($scope.modal);
$scope.callWaiting = false;$scope.$apply($scope.callWaiting);
$scope.session = {};$scope.$apply($scope.session);
};  
// End call
QB.webrtc.onStopCallListener = function(session, userId, extension) {
console.log('User '+session.currentUserID+' hung up');
$scope.toggleConnCtrl = false;$scope.$apply($scope.toggleConnCtrl);
$scope.modal = false;$scope.$apply($scope.modal);
$scope.callOptions = false;$scope.$apply($scope.callOptions);
$scope.session = {};$scope.$apply($scope.session);
};                                  
QB.webrtc.onRemoteStreamListener = function(session, userID, remoteStream) {
$scope.session.attachMediaStream('remoteVideoEl', remoteStream);
};                              
QB.webrtc.onSessionConnectionStateChangedListener = function(session, userID, connectionState) {
};                                                                              
QB.chat.onMessageListener = function onMessage(userId, message) {
if (message.extension && message.extension.notification_type === '1') {
//console.log(message);
console.log(message.extension.name+' just logged on');
$scope.updatePeerList($scope);  
}else if (message.extension && message.extension.notification_type === '2') {
//console.log(message);
console.log(message.extension.name+' just logged out');
$scope.updatePeerList($scope);  
}
};
// HANDLE USERS
$scope.updatePeerList = function($scope) {
QB.users.get({tags: [$scope.user.user_tags]}, function(err, result){
if (result) {
var newObj = {};
$scope.peers = [];
$scope.occupants = [];
angular.forEach(result.items, function(e) {
if ($scope.user.id !== e.user.id && $scope.occupants.indexOf(e.user.id) < 1) {
$scope.occupants.push(e.user.id);
$scope.$apply($scope.occupants);
}
if (e.user.full_name !== $scope.user.full_name) {
var ONE_HOUR = 60 * 60 * 1000,
d = new Date(e.user.last_request_at);
if (((new Date) - d) < ONE_HOUR) { 
newObj.name = e.user.full_name;
newObj.userData = e.user;
newObj.status = true;
$scope.peers.push(newObj);
}else {
newObj.name = e.user.full_name;
newObj.userData = e.user;
newObj.status = false;
$scope.peers.push(newObj);
}   
}
});
$scope.$apply($scope.peers);
}else {
console.log('error getting peer list');
console.log(err);
}
});
}       
$scope.setRecipient = function(ele, name, index) {
if (angular.equals($scope.recipients, {})) { 
$scope.recipients[index] = false;
}else if (!angular.equals($scope.recipients, {}) && $scope.recipients[index]) {
$scope.recipients[index] = true;
}else {
angular.forEach($scope.recipients, function(value, key) {
if (key === index) {
$scope.recipients[index] = true;
}else {
$scope.recipients[key] = false;
}
});
}
if($scope.recipients[index]) {
$scope.recipients[index] = false;
$scope.recipient = "";
} else {
$scope.recipients[index] = true;
$scope.recipient = {
name: name,
id: ele.peer.userData.id
}
}
};
// HANDLE LOG OUT and UNLOAD
$scope.logout = function() {
QB.logout(function(err, result){
if (result) {
// success
} else {
// error
}
});
QB.users.update($scope.user.id, {tag_list: ""}, function(err, user){
if (user) {
console.log('changed rooms');
console.log(user); 
} else  {
console.log(err); 
}
});
console.log('change path');
$location.path('/');
}
$scope.$on('onBeforeUnload', function (e, confirmation) {
confirmation.message = "All data will be lost.";
e.preventDefault();
QB.users.update($scope.user.id, {tag_list: ""}, function(err, user){
if (user) {
console.log('changed rooms');
console.log(user); 
} else  {
console.log(err); 
}
});
var msg = {
type: 'chat',
extension: {
notification_type: 2,
_id: $scope.chatSession.xmpp_room_jid,
name: $scope.user.full_name,
occupant: $scope.user.id
}
};
angular.forEach($scope.occupants, function(e) {
if (e !== $scope.user.id) {
QB.chat.send(e, msg);
}
});
});
$scope.$on('onUnload', function () {
console.log('onUnload'); // Use 'Preserve Log' option in Console
//$scope.logout();
});


});

以下是发生错误的 SDK 中的代码块:

_onIdle: function () {
var data = this._conn._data;
if (data.length > 0 && !this._conn.paused) {
for (var i = 0; i < data.length; i++) {
if (data[i] !== null) {
var stanza, rawStanza;
if (data[i] === "restart") {
stanza = this._buildStream().tree();
} else {
stanza = data[i];
}
rawStanza = Strophe.serialize(stanza);
console.log(rawStanza);
this._conn.xmlOutput(stanza);
this._conn.rawOutput(rawStanza);
// HERE IS WHERE I GET THE ERROR
this.socket.send(rawStanza);
// HERE IS WHERE I GET THE ERROR
}
}
this._conn._data = [];
}
}

当呼叫发起时,会向您尝试连接的对手发送一条消息。

以下是来自呼叫不起作用的消息:

<message to="6184-5@chatcaduceustelemed.quickblox.com" type="headline" id="58d15d3311d18b4a8d000001" xmlns="jabber:client">
<extraParams xmlns="jabber:client">
<name>Erik Grosskurth</name>
<id>6184</id>
<sessionID>5ce4c0e0-02cc-4baa-86b0-91dfe28ac0d4</sessionID>
<callType>1</callType>
<callerID>NaN</callerID>
<opponentsIDs>
<opponentID>6184</opponentID>
</opponentsIDs>
<sdp> </sdp>
<moduleIdentifier>WebRTCVideoChat</moduleIdentifier>
<signalType>call</signalType>
<platform>web</platform>
</extraParams>
</message>

这是我刷新并启动呼叫后的消息:

<message to="6184-5@chatcaduceustelemed.quickblox.com" type="headline" id="58d15c8cd15a7a2513000001" xmlns="jabber:client">
<extraParams xmlns="jabber:client">
<name>Erik Grosskurth</name>
<id>6184</id>
<sessionID>1a37ad44-c408-4b1d-bda8-436f3322d7e9</sessionID>
<callType>1</callType>
<callerID>6186</callerID>
<opponentsIDs>
<opponentID>6184</opponentID>
</opponentsIDs>
<sdp></sdp>
<moduleIdentifier>WebRTCVideoChat</moduleIdentifier>
<signalType>call</signalType>
<platform>web</platform>
</extraParams>
</message>

如您所见,呼叫者ID在不起作用的呼叫中是NaN,而在起作用的呼叫上是正确的。我尝试像这样手动设置此启动器 ID:

$scope.session = QB.webrtc.createNewSession($scope.occupants, QB.webrtc.CallType.VIDEO);
$scope.session.initiatorID = $scope.user.id;
$scope.modal = true;
$scope.callWaiting = true;
$scope.session.getUserMedia($scope.localMediaParams, function(err, stream) {
if (err){
console.log(err);
}else{
console.log(stream);
console.log('placing a call to '+$scope.recipient.name);
$scope.session.call($scope.recipient, function(error) {
if(error) {
console.log(error);
} else {
console.log('successfully placed call with no errors');
}
});
}
});

但这行不通。请有人解释为什么会发生这种情况吗?

因此,如果您收到错误"无法读取未定义的属性'发送'",请确保一次初始化 SDK。

如果您使用的是 Angular,请使用此

app.run(function ($rootScope) {
QB.init(QBApp.appId, QBApp.authKey, QBApp.authSecret, config);
});

对于每个调用,您需要创建新的WebRTC会话。

我找到了这一行代码。

$scope.session.call($scope.recipient, function(error) {
console.log(error);
});

尝试进行调用并设置一个空对象,而不是像这样$scope.收件人:

$scope.session.call({}, function(error) {
console.log(error);
});

另外,你能检查一下,你的WebRTC会话是否存在于QB.chat.connect回调上吗?在这里,您可以找到一个代码示例。

https://github.com/QuickBlox/quickblox-javascript-sdk/blob/gh-pages/samples/webrtc/js/app.js#L236

您的解决方案应如下所示:

if (!angular.equals($scope.session, {}) && !angular.equals($scope.session, undefined)) {
$scope.session.stop({});
$scope.session = {};
}

calllerId 设置在这里: https://github.com/QuickBlox/quickblox-javascript-sdk/blob/gh-pages/src/modules/webrtc/qbWebRTCClient.js#L93

当您创建新会话时,您可以输入您的 ID。 你能尝试这样做吗? 如果这可以解决此问题,我认为您在聊天连接时遇到问题。

请提供反馈。

相关内容

最新更新