import { send } from './signalPlugin' import store from './index' var lastPeer // horrible const configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] } const state = { name: null, peers: [] } const getters = { displayName: state => state.name } const actions = { setName ({ commit }, name) { commit('SET_NAME', name) }, async makeOffer ({ commit }, targetName) { commit('CREATE_PEER_CONNECTION', targetName) commit('OFFER', targetName) }, async offer ({ commit }, { offer, senderName }) { console.log('offer from ' + senderName) commit('CREATE_PEER_CONNECTION', senderName) commit('ANSWER', { target: senderName, offer: offer }) }, answer ({ commit }, { answer, senderName }) { console.log('answer from ' + senderName) commit('FINALIZE', { target: senderName, answer: answer }) }, candidate ({ commit }, { candidate, senderName }) { commit('CANDIDATE', { target: senderName, candidate: candidate }) }, leave ({ commit }) { commit('LEAVE') }, broadcast ({ commit }, { message, type }) { commit('BROADCAST', { message: message, type: type }) } } const mutations = { SET_NAME (state, name) { state.name = name }, CREATE_PEER_CONNECTION (state, target) { console.log('[RTC] create peer connection with ' + target) var peer = { name: target, connection: new RTCPeerConnection(configuration), dataChannel: null } state.peers.push(peer) peer.connection.onicecandidate = function (event) { if (event.candidate) { send({ type: 'candidate', name: state.name, target: target, data: event.candidate }) } } peer.connection.onnegotiationneeded = function () { handleNegotiationNeededEvent(target) } peer.connection.onsignalingstatechange = function () { handleSignalingStateChangeEvent(peer.connection) } peer.connection.oniceconnectionstatechange = function () { handleICEConnectionStateChangeEvent(peer.connection) } peer.connection.onicegatheringstatechange = function () { handleICEGatheringStateChangeEvent(peer.connection) } }, async OFFER (state, target) { console.log('[RTC] make offer to ' + target) var peer = state.peers.find(peer => peer.name === target) peer.dataChannel = peer.connection.createDataChannel('dataChannel') peer.dataChannel.onmessage = handleDataChannelMessage peer.dataChannel.onopen = handleDataChannelStateChangeEvent peer.dataChannel.onclose = handleDataChannelStateChangeEvent var offer = await peer.connection.createOffer() send({ type: 'offer', name: state.name, target: target, data: offer }) await peer.connection.setLocalDescription(offer) }, async ANSWER (state, { target, offer }) { console.log('[RTC] answer to ' + target) var peer = state.peers.find(peer => peer.name === target) // Permet d'associer le datachannel de la callback au bon peer lastPeer = peer peer.connection.ondatachannel = handleDataChannelCallback await peer.connection.setRemoteDescription(new RTCSessionDescription(offer)) var answer = await peer.connection.createAnswer() await peer.connection.setLocalDescription(answer) send({ type: 'answer', name: state.name, target: target, data: answer }) }, FINALIZE (state, { target, answer }) { var peer = state.peers.find(peer => peer.name === target) peer.connection.setRemoteDescription(new RTCSessionDescription(answer)) }, CANDIDATE (state, { target, candidate }) { var peer = state.peers.find(peer => peer.name === target) peer.connection.addIceCandidate(new RTCIceCandidate(candidate)) }, LEAVE (state) { state.peers.forEach((peer) => { peer.connection.close() }) state.peers = {} }, BROADCAST (state, { message, type }) { const data = JSON.stringify({ type: type, message: message }) console.log('[RTC] broadcast message ' + data) state.peers.forEach(peer => { peer.dataChannel.send(data) }) } } function handleICEConnectionStateChangeEvent (connection) { console.log('[RTC] ice connection change to ' + connection.iceConnectionState) } function handleICEGatheringStateChangeEvent (connection) { console.log('[RTC] ice gathering change to ' + connection.iceGatheringState) } async function handleNegotiationNeededEvent (target) { console.log('[RTC] negotiation needed from ' + target) } async function handleSignalingStateChangeEvent (connection) { console.log('[RTC] state changed to ' + connection.signalingState) switch (connection.signalingState) { case 'closed': await connection.close() break } } function handleDataChannelStateChangeEvent () { console.log('[RTC] data channel state change') } function handleDataChannelCallback (event) { console.log('[RTC] data channel callback ' + event + ' target ' + event.target) var peer = lastPeer peer.dataChannel = event.channel peer.dataChannel.onmessage = handleDataChannelMessage peer.dataChannel.onopen = handleDataChannelStateChangeEvent peer.dataChannel.onclose = handleDataChannelStateChangeEvent store.dispatch('rtc/broadcast', { message: store.state.room.roomStatus, type: 'status' }) } function handleDataChannelMessage (event) { console.log('[RTC] data channel message ' + event.data) var data = JSON.parse(event.data) console.log('[RTC] data channel message type ' + data.type) switch (data.type) { case 'status': store.dispatch('room/setRoomStatus', data.message) break case 'vote': store.dispatch('room/vote', { link: data.message.link, linkID: data.message.linkID, isPositive: data.message.isPositive, voterName: data.message.voterName }) break } } export default { namespaced: true, state, getters, actions, mutations }