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: [{ urls: 'stun:stun.l.google.com:19302' }] }, 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(JSON.stringify({ 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(JSON.stringify({ 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(JSON.stringify({ 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)); } // 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) { this.peers.forEach((peer) => { if (peer.enableDataChannels) { peer.sendDirectly(message, payload, channel); } }); } shout(messageLabel, payload) { this.sendDirectlyToAll(messageLabel, payload, 'liowebrtc'); } whisper(peer, messageLabel, payload) { peer.sendDirectly(messageLabel, payload); } } export default WebRTC;