import util from 'util'; import mockconsole from 'mockconsole'; import LocalMedia from './localmedia'; import Peer from './peer'; import webrtcSupport from './webrtcsupport'; class WebRTC extends LocalMedia { constructor(opts) { super(opts); const self = this; const options = opts || {}; const config = this.config = { debug: false, peerConnectionConfig: { iceServers: [], }, peerConnectionConstraints: { optional: [], }, receiveMedia: { offerToReceiveAudio: 1, offerToReceiveVideo: 1, }, enableDataChannels: true, }; let item; this.logger = ((() => { // we assume that if you're in debug mode and you didn't // pass in a logger, you actually want to log as much as // possible. if (opts.debug) { return opts.logger || console; } // or we'll use your logger which should have its own logic // for output. Or we'll return the no-op. return opts.logger || mockconsole; })()); // set options for (item in options) { if (options.hasOwnProperty(item)) { this.config[item] = options[item]; } } // check for support if (!webrtcSupport.support) { this.logger.error('Your browser doesn\'t seem to support WebRTC'); } // where we'll store our peer connections this.peers = []; // call localMedia constructor // localMedia.call(this, this.config); this.on('speaking', () => { if (!self.hardMuted) { self.peers.forEach((peer) => { if (peer.enableDataChannels) { const dc = peer.getDataChannel('liowebrtc'); if (dc.readyState !== 'open') return; dc.sendDirectlyToAll({ type: 'speaking' }); } }); } }); this.on('stoppedSpeaking', () => { if (!self.hardMuted) { self.peers.forEach((peer) => { if (peer.enableDataChannels) { const dc = peer.getDataChannel('liowebrtc'); if (dc.readyState !== 'open') return; dc.sendDirectlyToAll({ type: 'stoppedSpeaking' }); } }); } }); this.on('volumeChange', (volume, treshold) => { if (!self.hardMuted) { self.peers.forEach((peer) => { if (peer.enableDataChannels) { const dc = peer.getDataChannel('liowebrtc'); if (dc.readyState !== 'open') return; dc.sendDirectlyToAll({ type: 'payload', volume }); } }); } }); // log events in debug mode if (this.config.debug) { this.on('*', (event, val1, val2) => { let logger; // if you didn't pass in a logger and you explicitly turning on debug // we're just going to assume you're wanting log output with console if (self.config.logger === mockconsole) { logger = console; } else { logger = self.logger; } logger.log('event:', event, val1, val2); }); } } createPeer(opts) { let peer; opts.parent = this; peer = new Peer(opts); this.peers.push(peer); return peer; } // removes peers removePeers(id, type) { this.getPeers(id, type).forEach((peer) => { peer.end(); }); } // fetches all Peer objects by session id and/or type getPeers(sessionId, type) { return this.peers.filter(peer => (!sessionId || peer.id === sessionId) && (!type || peer.type === type)); } getPeerById(id) { return this.peers.filter(p => p.id === id)[0]; } getPeerByNick(nick) { return this.peers.filter(p => p.nick === nick)[0]; } // sends message to all sendToAll(message, payload) { this.peers.forEach((peer) => { peer.send(message, payload); }); } // sends message to all using a datachannel // only sends to anyone who has an open datachannel sendDirectlyToAll(message, payload, channel, shout) { const msgId = `${Date.now()}_${Math.random() * 1000000}`; this.peers.forEach((peer) => { if (peer.enableDataChannels) { peer.sendDirectly(message, payload, channel, shout, msgId); } }); } shout(messageType, payload) { this.sendDirectlyToAll(messageType, payload, 'liowebrtc', true); } whisper(peer, messageType, payload) { peer.sendDirectly(messageType, payload); } broadcast(messageType, payload) { this.sendToAll('signalData', { type: messageType, payload }); } transmit(peer, messageType, payload) { peer.send('signalData', { type: messageType, payload }); } } export default WebRTC;