130 lines
3.7 KiB
JavaScript
130 lines
3.7 KiB
JavaScript
import * as NotifyActions from '../actions/NotifyActions.js'
|
|
import * as StreamActions from '../actions/StreamActions.js'
|
|
import * as constants from '../constants.js'
|
|
import Peer from 'simple-peer'
|
|
import _ from 'underscore'
|
|
import _debug from 'debug'
|
|
import iceServers from '../iceServers.js'
|
|
import { play } from '../window/video.js'
|
|
|
|
const debug = _debug('peercalls')
|
|
|
|
class PeerHandler {
|
|
constructor ({ socket, user, stream, dispatch, getState }) {
|
|
this.socket = socket
|
|
this.user = user
|
|
this.stream = stream
|
|
this.dispatch = dispatch
|
|
this.getState = getState
|
|
}
|
|
handleError = err => {
|
|
const { dispatch, getState, user } = this
|
|
debug('peer: %s, error %s', user.id, err.stack)
|
|
dispatch(NotifyActions.error('A peer connection error occurred'))
|
|
const peer = getState().peers[user.id]
|
|
peer && peer.destroy()
|
|
dispatch(removePeer(user.id))
|
|
}
|
|
handleSignal = signal => {
|
|
const { socket, user } = this
|
|
debug('peer: %s, signal: %o', user.id, signal)
|
|
|
|
const payload = { userId: user.id, signal }
|
|
socket.emit('signal', payload)
|
|
}
|
|
handleConnect = () => {
|
|
const { dispatch, user } = this
|
|
debug('peer: %s, connect', user.id)
|
|
dispatch(NotifyActions.warning('Peer connection established'))
|
|
play()
|
|
}
|
|
handleStream = stream => {
|
|
const { user, dispatch } = this
|
|
debug('peer: %s, stream', user.id)
|
|
dispatch(StreamActions.addStream({
|
|
userId: user.id,
|
|
stream
|
|
}))
|
|
}
|
|
handleData = object => {
|
|
const { dispatch, user } = this
|
|
object = JSON.parse(new window.TextDecoder('utf-8').decode(object))
|
|
debug('peer: %s, message: %o', user.id, object)
|
|
const message = user.id + ': ' + object.message
|
|
dispatch(NotifyActions.info(message))
|
|
}
|
|
handleClose = () => {
|
|
const { dispatch, user } = this
|
|
debug('peer: %s, close', user.id)
|
|
dispatch(NotifyActions.error('Peer connection closed'))
|
|
dispatch(StreamActions.removeStream(user.id))
|
|
dispatch(removePeer(user.id))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Object} options
|
|
* @param {Socket} options.socket
|
|
* @param {User} options.user
|
|
* @param {String} options.user.id
|
|
* @param {Boolean} [options.initiator=false]
|
|
* @param {MediaStream} [options.stream]
|
|
*/
|
|
export function createPeer ({ socket, user, initiator, stream }) {
|
|
return (dispatch, getState) => {
|
|
const userId = user.id
|
|
debug('create peer: %s, stream:', userId, stream)
|
|
dispatch(NotifyActions.warning('Connecting to peer...'))
|
|
|
|
const oldPeer = getState().peers[userId]
|
|
if (oldPeer) {
|
|
dispatch(NotifyActions.info('Cleaning up old connection...'))
|
|
oldPeer.destroy()
|
|
dispatch(removePeer(userId))
|
|
}
|
|
|
|
const peer = new Peer({
|
|
initiator: socket.id === initiator,
|
|
stream,
|
|
config: { iceServers }
|
|
})
|
|
|
|
const handler = new PeerHandler({
|
|
socket,
|
|
user,
|
|
stream,
|
|
dispatch,
|
|
getState
|
|
})
|
|
|
|
peer.once(constants.PEER_EVENT_ERROR, handler.handleError)
|
|
peer.once(constants.PEER_EVENT_CONNECT, handler.handleConnect)
|
|
peer.once(constants.PEER_EVENT_CLOSE, handler.handleClose)
|
|
peer.on(constants.PEER_EVENT_SIGNAL, handler.handleSignal)
|
|
peer.on(constants.PEER_EVENT_STREAM, handler.handleStream)
|
|
peer.on(constants.PEER_EVENT_DATA, handler.handleData)
|
|
|
|
dispatch(addPeer({ peer, userId }))
|
|
}
|
|
}
|
|
|
|
export const addPeer = ({ peer, userId }) => ({
|
|
type: constants.PEER_ADD,
|
|
payload: { peer, userId }
|
|
})
|
|
|
|
export const removePeer = userId => ({
|
|
type: constants.PEER_REMOVE,
|
|
payload: { userId }
|
|
})
|
|
|
|
export const destroyPeers = () => ({
|
|
type: constants.PEERS_DESTROY
|
|
})
|
|
|
|
export const sendMessage = message => (dispatch, getState) => {
|
|
message = JSON.stringify({ message })
|
|
const { peers } = getState()
|
|
_.each(peers, peer => peer.send(message))
|
|
}
|