1

我使用 webrtc 数据通道制作了一个非常简单的聊天应用程序。这在 Chrome - Chrome 中运行良好,但在 FF - Chrome、Chrome - FF、FF - FF 中根本不起作用。这是我带角度的完整代码

var PeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection;
var SessionDescription = window.RTCSessionDescription || window.webkitRTCSessionDescription || window.mozRTCSessionDescription || window.msRTCSessionDescription;
var IceCandidate = window.RTCIceCandidate || window.webkitRTCIceCandidate || window.mozRTCIceCandidate || window.msRTCIceCandidate;

angular.module('moonRTC', ['moonUtil'])

.factory('RTC', ['RTCConfiguration', 'uid', 'log', 'moonConnection', function(RTCConfiguration, uid, log, moonConnection) {
    return function RTCGenerator(idIfExist) {
        var generator = {};

        var ref;
        if (idIfExist) {
            ref = new Firebase(RTCConfiguration.firebase).child('user').child(idIfExist);
        } else {
            ref = new Firebase(RTCConfiguration.firebase).child('guest').child(new Date().getTime());
            ref.onDisconnect().remove();
        }
        ref.child('online').set(1);
        ref.child('online').onDisconnect().remove();
        ref.child('message').onDisconnect().remove();
        generator.ref = ref;
        generator.address = ref.child('message').toString();
        generator.connections = {};
        generator.handlers = [];

        function createPeerConnection(remoteRef, isPassive) {
            var pc = new PeerConnection(RTCConfiguration.config);
            pc.onicecandidate = function(e) {
                if (!e.candidate || !remoteRef) return;
                remoteRef.push({
                    sender : generator.address,
                    type : 'candidate',
                    value : e.candidate
                });
            }
            pc.onnegotiationneeded = function() {
                if (isPassive) return;
                pc.createOffer(function(desc) {
                    pc.setLocalDescription(desc, function() {
                        if (!remoteRef) return;
                        remoteRef.push({
                            sender : generator.address,
                            type : 'sdp',
                            value : pc.localDescription
                        });
                    }, log.err);
                }, log.err);
            }
            generator.connections[remoteRef.toString()] = pc;
            return pc;
        }

        generator.connect = function(remoteAddress) {
            var pc = createPeerConnection(new Firebase(remoteAddress));
            return new moonConnection(pc);
        }

        generator.listen = function(connectionHandler) {
            if (typeof connectionHandler === 'function') generator.handlers.push(connectionHandler);
        }

        ref.child('message').on('child_added', function(snapshot) {
            var message = snapshot.val();
            snapshot.ref().remove();
            if (!message.type || !message.sender || !message.value) return;
            switch (message.type) {
                case 'sdp':
                    var remoteRef = new Firebase(message.sender);
                    switch (message.value.type) {
                        case 'offer':
                            var pc = createPeerConnection(remoteRef, true);
                            pc.setRemoteDescription(new SessionDescription(message.value), function() {
                                pc.createAnswer(function(desc) {
                                    pc.setLocalDescription(desc, function() {
                                        remoteRef.push({
                                            sender : generator.address,
                                            type : 'sdp',
                                            value : pc.localDescription
                                        });
                                        generator.handlers.forEach(function(each) {
                                            each(new moonConnection(pc));
                                        });
                                    }, log.err);
                                }, log.err);
                            }, log.err);
                            break;
                        case 'answer':
                            var pc = generator.connections[message.sender];
                            if (!pc) return;
                            pc.setRemoteDescription(new SessionDescription(message.value), function() {

                            }, log.err);
                            break;
                    }
                    break;
                case 'candidate':
                    var pc = generator.connections[message.sender];
                    if (!pc) return;
                    pc.addIceCandidate(new IceCandidate(message.value));
                    break;
            }
        });

        return generator;
    }
}])

.value('RTCConfiguration', {
        config : {
            iceServers: [
                //this is super commonly used stun server. so let's ignore it for performance
                //{url : 'stun:stun.l.google.com:19302'},
                {url : 'stun:stun1.l.google.com:19302'},
                {url : 'stun:stun2.l.google.com:19302'},
                {url : 'stun:stun3.l.google.com:19302'},
                {url : 'stun:stun4.l.google.com:19302'},
                {url : 'stun:stun.ekiga.net'},
                {url : 'stun:stun.ideasip.com'},
                {url : 'stun:stun.rixtelecom.se'},
                {url : 'stun:stun.schlund.de'},
                {url : 'stun:stun.stunprotocol.org:3478'},
                {url : 'stun:stun.voiparound.com'},
                {url : 'stun:stun.voipbuster.com'},
                {url : 'stun:stun.voipstunt.com'},
                {url : 'stun:stun.voxgratia.org'}
            ]
        },
        firebase : 'https://moonshare.firebaseio.com/'
})

.factory('moonConnection', ['$rootScope', 'moonChannel', function($rootScope, moonChannel) {

    function moonConnection(peerConnection) {
        var self = this;
        self.PeerConnection = peerConnection;
        self.handlers = {
            channel : [],
            stream : [],
            close : []
        }
        peerConnection.ondatachannel = function(e) {
            self.handlers.channel.forEach(function(each) {
                $rootScope.$apply(function() {
                    each(new moonChannel(e.channel));
                });
            });
        }
        peerConnection.onaddstream = function(e) {
            self.handlers.stream.forEach(function(each) {
                $rootScope.$apply(function() {
                    each(e.stream);
                });
            });
        }

        this.channel = function() {
            return new moonChannel(peerConnection.createDataChannel('channel'));
        }
    }

    moonConnection.prototype.on = function(type, handler) {
        if (!this.handlers[type] || typeof handler !== 'function') return;
        this.handlers[type].push(handler);
    }

    moonConnection.prototype.close = function() {
        this.handlers.close.forEach(function(each) {
            $rootScope.$apply(function() {
                each();
            });
        });
        this.PeerConnection.close();
    }

    return moonConnection;
}])

.factory('moonChannel', ['$rootScope', function($rootScope) {

    function moonChannel(dataChannel) {
        var self = this;
        self.DataChannel = dataChannel;
        self.handlers = {
            open : [],
            message : [],
            error : [],
            close : []
        }
        dataChannel.onopen = function() {
            self.handlers.open.forEach(function(each) {
                $rootScope.$apply(each)
            });
        }
        dataChannel.onmessage = function(e) {
            self.handlers.message.forEach(function(each) {
                $rootScope.$apply(function() {
                    each(e.data);
                });
            });
        }
        dataChannel.onerror = function(e) {
            self.handlers.error.forEach(function(each) {
                $rootScope.$apply(function() {
                    each(e.data);
                });
            });
        }
        dataChannel.onclose = function() {
            self.handlers.close.forEach(function(each) {
                $rootScope.$apply(each);
            });
        }
        self.close = function() {
            dataChannel.close;
        }
        self.send = function(data) {
            dataChannel.send(data);
        }
    }

    moonChannel.prototype.on = function(type, handler) {
        if (!this.handlers[type] || !(typeof handler === 'function')) return;
        this.handlers[type].push(handler);
    }

    return moonChannel;
}])

和这个

angular.module('moonShare', ['moonRTC', 'moonUtil'])

.controller('app', function(RTC, $scope) {
    $scope.msgs = [];
    var rtc = RTC();
    rtc.listen(function(connection) {
        connection.on('channel', function(channel) {
            $scope.msgs.push({value:'got channel'});
            onChannel(channel);
        });
    });
    $scope.address = rtc.address;
    $scope.connect = function() {
        var connection = rtc.connect($scope.remote);
        onChannel(connection.channel());
    }

    function onChannel(channel) {
        channel.on('open', function() {
            $scope.msgs.push({value:'channel opened'});
            channel.on('message', function(message) {
                $scope.msgs.push({value:message});
            });
            $scope.send = function() {
                $scope.msgs.push({value:$scope.message});
                channel.send($scope.message);
            }
        })
    }
})

是否应该添加更多前缀?

4

1 回答 1

1

Firefox 还不支持需要协商(或重新协商)(很快)。对于 Firefox,只需在您的 addStream()s 或 createDataChannel()s 之后调用协商代码(或制造一个协商需要的事件,如果这对您更有效)。

于 2015-02-08T15:36:57.133 回答