我使用webrtc datachannel创建了一个非常简单的聊天应用程序。这在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);
}
})
}
})
是否应该添加更多前缀?
答案 0 :(得分:1)
Firefox不支持(很快)协商需要(或重新协商)。对于Firefox,只需在addStream()或createDataChannel()之后调用协商代码(或者如果对你更好的话,可以制作一个negotiationneeded事件)。