Quickblox Javascript SDK+;角度+;webRTC-无法读取属性';发送';未定义的

Quickblox Javascript SDK+;角度+;webRTC-无法读取属性';发送';未定义的,javascript,angularjs,webrtc,quickblox,Javascript,Angularjs,Webrtc,Quickblox,我使用Quickblox Javascript SDK+Angular+webRTC构建了一个功能齐全的webRTC视频会议客户端。一件奇怪的事情正在发生,每次我清除缓存并从头开始登录时,当我发起呼叫时,我都会收到以下错误: MediaStream {id: "iAmALongalphanumericStringThatGoesHere", active: true, onaddtrack: null, onremovetrack: null, onactive: null…} quic

我使用Quickblox Javascript SDK+Angular+webRTC构建了一个功能齐全的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();
        });





    });

但这不起作用。请有人解释为什么会发生这种情况???

对于每个呼叫,您需要创建新的WebRTC会话

我发现这行代码

$scope.session.call($scope.recipient, function(error) {
    console.log(error);
});
尝试调用并设置空对象,而不是$scope.recipient,如下所示:

$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');
            }
        });
    }
});
$scope.session.call({}, function(error) {
    console.log(error);
});
if (!angular.equals($scope.session, {}) && !angular.equals($scope.session, undefined)) {
    $scope.session.stop({});
    $scope.session = {};
}
另外,能否检查QB.chat.connect回调上是否存在WebRTC会话?在这里您可以找到一个代码示例

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

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

$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');
            }
        });
    }
});
$scope.session.call({}, function(error) {
    console.log(error);
});
if (!angular.equals($scope.session, {}) && !angular.equals($scope.session, undefined)) {
    $scope.session.stop({});
    $scope.session = {};
}

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

我发现这行代码

$scope.session.call($scope.recipient, function(error) {
    console.log(error);
});
尝试调用并设置空对象,而不是$scope.recipient,如下所示:

$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');
            }
        });
    }
});
$scope.session.call({}, function(error) {
    console.log(error);
});
if (!angular.equals($scope.session, {}) && !angular.equals($scope.session, undefined)) {
    $scope.session.stop({});
    $scope.session = {};
}
另外,能否检查QB.chat.connect回调上是否存在WebRTC会话?在这里您可以找到一个代码示例

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

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

$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');
            }
        });
    }
});
$scope.session.call({}, function(error) {
    console.log(error);
});
if (!angular.equals($scope.session, {}) && !angular.equals($scope.session, undefined)) {
    $scope.session.stop({});
    $scope.session = {};
}
calllerId在此处设置:

当你创建一个新的会话时,你可以输入你的Id。你能试着这样做吗? 如果这能解决这个问题,我想你的聊天连接有问题

请提供反馈。

calllerId设置在此处:

当你创建一个新的会话时,你可以输入你的Id。你能试着这样做吗? 如果这能解决这个问题,我想你的聊天连接有问题

请给出反馈。

因此,如果您遇到错误“无法读取未定义的属性'send'”以确保您只初始化SDK一次

如果您使用的是角度,请使用此选项

 app.run(function ($rootScope) {
  QB.init(QBApp.appId, QBApp.authKey, QBApp.authSecret, config);
 });
因此,如果出现错误“无法读取未定义的属性'send'”,请确保初始化SDK一次

如果您使用的是角度,请使用此选项

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


因此,我在会话对象my>>initiatorId=NaN上发现了一些问题。我尝试手动设置initiatorId,但它抛出了相同的错误。您能否提供如何重现此错误的分步指南。步骤1:session=QB.webrtc.createNewSession,步骤2:session.getUserMedia,步骤3:session.call步骤4:call,扩展名:{“name”:“Erik Marta”,“id”:6184}步骤5:_createPeer,步骤6:rtpeerconnection init步骤7:getAndSetLocalSessionDescription成功步骤8:_startDialingTimer,拨号时间间隔:5000步骤9:_diallingcallback我在Chrome版本57.0.2987.98(64位)和Firefox 52.0(32位)之间来回走动因此,我在会话对象my>>initiatorId=NaN上发现了一些问题。我尝试手动设置initiatorId,但它抛出了相同的错误。您能否提供如何重现此错误的分步指南。步骤1:session=QB.webrtc.createNewSession,步骤2:session.getUserMedia,步骤3:session.call步骤4:call,扩展名:{“name”:“Erik Marta”,“id”:6184}步骤5:_createPeer,步骤6:rtpeerconnection init步骤7:getAndSetLocalSessionDescription成功步骤8:_startDialingTimer,DiallingTimeInterval:5000步骤9:_DiallingCallback我在Chrome 57.0.2987.98(64位)和Firefox 52.0(32位)之间来回奔波,我已经确定了问题的原因,这是直接原因:当用户1登录(创建用户)并将其标记列表设置为房间字符串时,问题就会出现。当用户2登录(创建用户)时,它不会返回由用户1创建的聊天对话框,尽管将过滤器设置为按标签列表返回对话框,因为在DB中生成该对话框时,用户2的对手id尚未创建。因此,当用户2登录(创建其用户)时,它会检查具有匹配标记列表的对话框,但由于用户2的用户id在创建聊天对话框时未附加到聊天对话框,因此总结果返回为0。因此,我的代码随后正确地生成了一个与对手的新对话框。问题是用户1无法接收到用户2已登录的通知。调试数据包吐出一条xml消息,其中对手已被识别,但启动器id为NaN,我相信这是因为这两个用户登录到不同的房间。此外,我已经有了在startCall click事件中添加的建议代码块(您的解决方案应该是这样的)。你是说它应该去别的地方吗?请参阅上面的代码并查看$scope.startCall函数。我已经确定了问题,它是由以下原因直接导致的:当用户1登录(创建用户)并将其标记列表设置为房间字符串时,问题就会出现。当用户2登录(创建用户)时,它不会返回由用户1创建的聊天对话框,尽管将过滤器设置为按标签列表返回对话框,因为在DB中生成该对话框时,用户2的对手id尚未创建。因此,当用户2登录(创建其用户)时,它会检查具有匹配标记列表的对话框,但由于用户2的用户id在创建聊天对话框时未附加到聊天对话框,因此总结果返回为0。因此,我的代码随后正确地生成了一个与对手的新对话框。问题是用户1无法接收到用户2已登录的通知。调试数据包吐出一条xml消息,其中对手已被识别,但启动器id为NaN,我相信这是因为这两个用户登录到不同的房间。此外,我已经有了在startCall click事件中添加的建议代码块(您的解决方案应该是这样的)。你是说它应该去别的地方吗?请参阅上面的代码并查看$scope.startCall函数。