From 12ffff9dded66e25094634a834de9f23328e607d Mon Sep 17 00:00:00 2001 From: Corey Johnson & Matt Colyer Date: Tue, 23 Jul 2013 15:36:05 -0700 Subject: [PATCH] Refactor guest session --- .../collaboration/lib/bootstrap.coffee | 14 ++- .../collaboration/lib/guest-session.coffee | 94 ++++++------------- .../collaboration/lib/guest-view.coffee | 10 +- .../collaboration/lib/media-connection.coffee | 57 +++++++++++ 4 files changed, 97 insertions(+), 78 deletions(-) create mode 100644 src/packages/collaboration/lib/media-connection.coffee diff --git a/src/packages/collaboration/lib/bootstrap.coffee b/src/packages/collaboration/lib/bootstrap.coffee index 02d9f7cf8..cc4ca9126 100644 --- a/src/packages/collaboration/lib/bootstrap.coffee +++ b/src/packages/collaboration/lib/bootstrap.coffee @@ -23,9 +23,17 @@ updateProgressBar = (message, percentDone) -> loadingView.find('.progress-bar').css('width', "#{percentDone}%") guestSession = new GuestSession(sessionId) -guestSession.on 'started', -> loadingView.remove() -guestSession.on 'connection-opened', -> updateProgressBar('Downloading session data', 25) -guestSession.on 'connection-document-received', -> updateProgressBar('Synchronizing repository', 50) + +guestSession.on 'started', -> + loadingView.remove() + window.startEditorWindow() + +guestSession.on 'connection-opened', -> + updateProgressBar('Downloading session data', 25) + +guestSession.on 'connection-document-received', -> + updateProgressBar('Synchronizing repository', 50) + operationsDone = -1 guestSession.on 'mirror-progress', (message, command, operationCount) -> operationsDone++ diff --git a/src/packages/collaboration/lib/guest-session.coffee b/src/packages/collaboration/lib/guest-session.coffee index 3fe7c70fd..1d70b3d7c 100644 --- a/src/packages/collaboration/lib/guest-session.coffee +++ b/src/packages/collaboration/lib/guest-session.coffee @@ -1,12 +1,9 @@ -path = require 'path' -remote = require 'remote' -url = require 'url' - _ = require 'underscore' patrick = require 'patrick' telepath = require 'telepath' Project = require 'project' +MediaConnection = require './media-connection' sessionUtils = require './session-utils' module.exports = @@ -14,94 +11,57 @@ class GuestSession _.extend @prototype, require('event-emitter') participants: null - repository: null peer: null - stream: null + mediaConnection: null constructor: (sessionId) -> @peer = sessionUtils.createPeer() connection = @peer.connect(sessionId, reliable: true) + window.site = new telepath.Site(@getId()) connection.on 'open', => - console.log 'connection opened' @trigger 'connection-opened' connection.once 'data', (data) => - console.log 'received document', data @trigger 'connection-document-received' - @createTelepathDocument(data, connection) + + doc = @createTelepathDocument(data, connection) + repoUrl = doc.get('collaborationState.repositoryState.url') + + @mirrorRepository(repoUrl, data.repoSnapshot) + + guest = doc.get('collaborationState.guest') + host = doc.get('collaborationState.host') + @mediaConnection = new MediaConnection(guest, host) + + waitForStream: (callback) -> + @mediaConnection.waitForStream callback + + getId: -> @peer.id createTelepathDocument: (data, connection) -> - window.site = new telepath.Site(@getId()) doc = window.site.deserializeDocument(data.doc) - - mediaConnection = null - - constraints = {video: true, audio: true} - success = (stream) => - mediaConnection = new webkitRTCPeerConnection(sessionUtils.getIceServers()) - mediaConnection.onicecandidate = (event) => - return unless event.candidate? - console.log "Set Guest Candidate", event.candidate - doc.set 'collaborationState.guest.candidate', event.candidate - - mediaConnection.onaddstream = ({@stream}) => - @trigger 'stream-ready', @stream - console.log('Added Host\'s Stream', @stream) - - mediaConnection.addStream(stream) - guest = doc.get 'collaborationState.guest' - guest.set 'ready', true - - navigator.webkitGetUserMedia constraints, success, console.error + sessionUtils.connectDocument(doc, connection) atom.windowState = doc.get('windowState') - @repository = doc.get('collaborationState.repositoryState') @participants = doc.get('collaborationState.participants') @participants.on 'changed', => @trigger 'participants-changed', @participants.toObject() - guest = doc.get 'collaborationState.guest' - host = doc.get('collaborationState.host') - host.on 'changed', ({key, newValue}) => - switch key - when 'description' - hostDescription = newValue.toObject() - console.log "Received host description", hostDescription - sessionDescription = new RTCSessionDescription(hostDescription) - mediaConnection.setRemoteDescription(sessionDescription) - success = (guestDescription) => - console.log "Set guest description", guestDescription - mediaConnection.setLocalDescription(guestDescription) - guest.set('description', guestDescription) + doc - console.log "COOL?", mediaConnection? - mediaConnection.createAnswer success, console.error - when 'candidate' - hostCandidate = new RTCIceCandidate newValue.toObject() - console.log('Guest received candidate', hostCandidate) - mediaConnection.addIceCandidate(hostCandidate) - else - throw new Error("Unknown host key '#{key}'") - - sessionUtils.connectDocument(doc, connection) - @mirrorRepository(data.repoSnapshot) - - mirrorRepository: (repoSnapshot) -> - repoPath = Project.pathForRepositoryUrl(@repository.get('url')) + mirrorRepository: (repoUrl, repoSnapshot) -> + repoPath = Project.pathForRepositoryUrl(repoUrl) progressCallback = (args...) => @trigger 'mirror-progress', args... patrick.mirror repoPath, repoSnapshot, {progressCallback}, (error) => - if error? - console.error(error) - else - @trigger 'started' + throw new Error(error) if error - window.startEditorWindow() - @participants.push - id: @getId() - email: git.getConfigValue('user.email') + # 'started' will trigger window.startEditorWindow() which creates the git global + @trigger 'started' - getId: -> @peer.id + id = @getId() + email = git.getConfigValue('user.email') + @participants.push {id, email} diff --git a/src/packages/collaboration/lib/guest-view.coffee b/src/packages/collaboration/lib/guest-view.coffee index a569e15e0..c618a9c44 100644 --- a/src/packages/collaboration/lib/guest-view.coffee +++ b/src/packages/collaboration/lib/guest-view.coffee @@ -17,17 +17,11 @@ class GuestView extends View @updateParticipants(@guestSession.participants.toObject()) - @addStream(@guestSession.stream) - @guestSession.on 'stream-ready', (stream) => - console.log "Stream is ready", stream - @addStream(stream) + @guestSession.waitForStream (stream) => + @video[0].src = URL.createObjectURL(stream) @attach() - addStream: (stream) -> - return unless stream - @video[0].src = URL.createObjectURL(stream) - updateParticipants: (participants) -> @participants.empty() guestId = @guestSession.getId() diff --git a/src/packages/collaboration/lib/media-connection.coffee b/src/packages/collaboration/lib/media-connection.coffee new file mode 100644 index 000000000..d05537b57 --- /dev/null +++ b/src/packages/collaboration/lib/media-connection.coffee @@ -0,0 +1,57 @@ +_ = require 'underscore' + +sessionUtils = require './session-utils' + +module.exports = +class MediaConnection + _.extend @prototype, require('event-emitter') + + guest: null + host: null + connection: null + stream: null + + constructor: (@guest, @host) -> + constraints = {video: true, audio: true} + navigator.webkitGetUserMedia constraints, @onUserMediaAvailable, @onUserMediaUnavailable + + waitForStream: (callback) -> + if @stream + callback(@stream) + else + @on 'stream-ready', callback + + onUserMediaUnavailable: (args...) => + console.error "User's webcam is unavailable.", args... + + onUserMediaAvailable: (stream) => + @connection = new webkitRTCPeerConnection(sessionUtils.getIceServers()) + @connection.addStream(stream) + @host.on 'changed', @onHostSignal + + @connection.onicecandidate = (event) => + return unless event.candidate? + @guest.set 'candidate', event.candidate + + @connection.onaddstream = (event) => + @stream = event.stream + @trigger 'stream-ready', @stream + + @guest.set 'ready', true + + onHostSignal: ({key, newValue}) => + switch key + when 'description' + hostDescription = newValue.toObject() + sessionDescription = new RTCSessionDescription(hostDescription) + @connection.setRemoteDescription(sessionDescription) + success = (guestDescription) => + @connection.setLocalDescription(guestDescription) + @guest.set('description', guestDescription) + + @connection.createAnswer success, console.error + when 'candidate' + hostCandidate = new RTCIceCandidate newValue.toObject() + @connection.addIceCandidate(hostCandidate) + else + throw new Error("Unknown host key '#{key}'")