From e8375b920e80a4c219b5445a8a9971227d7d0029 Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Wed, 4 Feb 2015 13:00:19 -0600 Subject: [PATCH 01/21] VRFS-1844 : Logic and UI to insert video page on gear wizard - Incremental. --- .../javascripts/wizard/gear/gear_wizard.js | 16 ++++++++----- .../wizard/gear/step_video_gear.js | 23 ++++++++++++++++++ .../wizard/gear/_gear_wizard.html.haml | 13 +++++++--- .../clients/wizard/gear/_video_gear.html.haml | 24 +++++++++++++++++++ 4 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 web/app/assets/javascripts/wizard/gear/step_video_gear.js create mode 100644 web/app/views/clients/wizard/gear/_video_gear.html.haml diff --git a/web/app/assets/javascripts/wizard/gear/gear_wizard.js b/web/app/assets/javascripts/wizard/gear/gear_wizard.js index cb0cd4317..f889aaffd 100644 --- a/web/app/assets/javascripts/wizard/gear/gear_wizard.js +++ b/web/app/assets/javascripts/wizard/gear/gear_wizard.js @@ -23,14 +23,16 @@ var STEP_SELECT_TRACKS = 2; var STEP_SELECT_CHAT = 3; var STEP_DIRECT_MONITOR = 4; - var STEP_ROUTER_NETWORK = 5; - var STEP_SUCCESS = 6; + var STEP_VIDEO_GEAR = 5; + var STEP_ROUTER_NETWORK = 6; + var STEP_SUCCESS = 7; var stepUnderstandGear = new context.JK.StepUnderstandGear(app, this); var stepSelectGear = new context.JK.StepSelectGear(app, this); var stepConfigureTracks = new context.JK.StepConfigureTracks(app, this); var stepConfigureVoiceChat = new context.JK.StepConfigureVoiceChat(app, this); var stepDirectMonitoring = new context.JK.StepDirectMonitoring(app, this); + var stepVideoGear = new context.JK.StepVideoGear(app, this); var stepNetworkTest = new context.JK.StepNetworkTest(app, this); var stepSuccess = new context.JK.StepSuccess(app, this); @@ -40,8 +42,9 @@ 2: stepConfigureTracks, 3: stepConfigureVoiceChat, 4: stepDirectMonitoring, - 5: stepNetworkTest, - 6: stepSuccess + 5: stepVideoGear, + 6: stepNetworkTest, + 7: stepSuccess } function newSession() { @@ -210,8 +213,9 @@ stepConfigureTracks.initialize($wizardSteps.filter($('[layout-wizard-step=2]')), self); stepConfigureVoiceChat.initialize($wizardSteps.filter($('[layout-wizard-step=3]')), self); stepDirectMonitoring.initialize($wizardSteps.filter($('[layout-wizard-step=4]')), self); - stepNetworkTest.initialize($wizardSteps.filter($('[layout-wizard-step=5]')), self); - stepSuccess.initialize($wizardSteps.filter($('[layout-wizard-step=6]')), self); + stepVideoGear.initialize($wizardSteps.filter($('[layout-wizard-step=5]')), self); + stepNetworkTest.initialize($wizardSteps.filter($('[layout-wizard-step=6]')), self); + stepSuccess.initialize($wizardSteps.filter($('[layout-wizard-step=7]')), self); wizard.initialize($dialog, $wizardSteps, STEPS); diff --git a/web/app/assets/javascripts/wizard/gear/step_video_gear.js b/web/app/assets/javascripts/wizard/gear/step_video_gear.js new file mode 100644 index 000000000..ee63b3b34 --- /dev/null +++ b/web/app/assets/javascripts/wizard/gear/step_video_gear.js @@ -0,0 +1,23 @@ +(function (context, $) { + + "use strict"; + + context.JK = context.JK || {}; + context.JK.StepVideoGear = function (app, $dialog) { + + var $step = null; + + function beforeShow() { + + } + + function initialize(_$step) { + $step = _$step; + } + + this.beforeShow = beforeShow; + this.initialize = initialize; + + return this; + } +})(window, jQuery); \ No newline at end of file diff --git a/web/app/views/clients/wizard/gear/_gear_wizard.html.haml b/web/app/views/clients/wizard/gear/_gear_wizard.html.haml index 1266a83c3..1eb73c591 100644 --- a/web/app/views/clients/wizard/gear/_gear_wizard.html.haml +++ b/web/app/views/clients/wizard/gear/_gear_wizard.html.haml @@ -158,12 +158,17 @@ %span.direct-monitoring-btn Play - .wizard-step.network-test{ 'layout-wizard-step' => "5", 'dialog-title' => "Test Router & Network", 'dialog-purpose' => "TestRouterNetwork" } + .wizard-step.video-gear{ 'layout-wizard-step' => "5", 'dialog-title' => "Select Video Gear", 'dialog-purpose' => "SelectVideoGear" } + .ftuesteps + .clearall + = render :partial => '/clients/wizard/gear/video_gear' + + .wizard-step.network-test{ 'layout-wizard-step' => "6", 'dialog-title' => "Test Router & Network", 'dialog-purpose' => "TestRouterNetwork" } .ftuesteps .clearall = render :partial => '/clients/network_test' - .wizard-step{ 'layout-wizard-step' => "6", 'dialog-title' => "Success!", 'dialog-purpose' => "Success" } + .wizard-step{ 'layout-wizard-step' => "7", 'dialog-title' => "Success!", 'dialog-purpose' => "Success" } .ftuesteps .clearall .wizard-step-content @@ -208,8 +213,10 @@ %a.ftue-stepnumber{'data-step-number' => 4} 5 .ftue-step-title Turn Off Direct Monitoring %a.ftue-stepnumber{'data-step-number' => 5} 6 - .ftue-step-title Test Router & Network + .ftue-step-title Select Video Gear %a.ftue-stepnumber{'data-step-number' => 6} 7 + .ftue-step-title Test Router & Network + %a.ftue-stepnumber{'data-step-number' => 7} 8 .ftue-step-title Success! diff --git a/web/app/views/clients/wizard/gear/_video_gear.html.haml b/web/app/views/clients/wizard/gear/_video_gear.html.haml new file mode 100644 index 000000000..de8eb20b5 --- /dev/null +++ b/web/app/views/clients/wizard/gear/_video_gear.html.haml @@ -0,0 +1,24 @@ +.help-text In this step, you will select your video gear. Please watch the video for best instructions. +.wizard-step-content + .wizard-step-column + %h2 Instructions + .ftue-box.instructions + %p Select webcam to use for video in sessions. + %p Verify that you see the video for the webcam in the window to the right. + %p Configure webcam settings if desired. + .center + %a.button-orange.watch-video{href:'https://www.youtube.com/watch?v=f7niycdWm7Y', rel:'external'} WATCH VIDEO + .wizard-step-column + %h2.sub-header Webcam + %form.voice + .webcam-select + %select#webcam-select + %h3 Use Music Microphone + %p I am already using a microphone to capture my vocal or instrumental music, so I can talk with other musicians using that microphone + .configure-webcam + %button#webcam-settings{type: 'button'} + .clearall + .wizard-step-column + %h2.video-header Preview + .webcam-preview + \ No newline at end of file From 3c3681964ddf0326997c3e8ce9dde7f97412ceac Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Thu, 5 Feb 2015 09:00:58 -0600 Subject: [PATCH 02/21] Don't render unused view. --- web/app/views/clients/index.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 92d50feda..acf32e572 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -15,7 +15,7 @@ <%= render "searchResults" %> <%= render "faders" %> <%= render "vu_meters" %> -<%= render "ftue" %> + <%= render "jamServer" %> <%= render "iconInstrumentSelect" %> <%= render "muteSelect" %> From 0d9773297cba67a9be9cfa21d195224b8ee42330 Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Thu, 5 Feb 2015 13:36:34 -0600 Subject: [PATCH 03/21] VRFS-1844 : Styling and layout for video gear page. --- .../client/wizard/gearWizard.css.scss | 43 ++++++++++++++++++- .../clients/wizard/gear/_video_gear.html.haml | 23 +++++----- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss b/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss index 29d498f69..eaaea4bc4 100644 --- a/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss +++ b/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss @@ -315,7 +315,46 @@ } } - .wizard-step[layout-wizard-step="5"], .network-test { + // Video Gear: + .wizard-step[layout-wizard-step="5"] { + .wizard-step-content .wizard-step-column { + &:nth-of-type(1) { + width: 33%; + height: 350px; + } + &:nth-of-type(2) { + width: 33%; + } + + .webcam-preview { + .webcam-content { + min-width: 200px; + min-height: 200px; + } + width: auto; + height: auto; + overflow: scroll; + } + + .wizard_control { + margin-bottom: 10px; + } + + ul { + margin-bottom: 20px; + + a { + color:$ColorLink; + } + + a:hover { + color:$ColorLinkHover; + } + } + } + } + + .wizard-step[layout-wizard-step="6"], .network-test { .wizard-step-content .wizard-step-column { &:nth-of-type(1) { @@ -468,7 +507,7 @@ } } - .wizard-step[layout-wizard-step="6"] { + .wizard-step[layout-wizard-step="7"] { .wizard-step-content .wizard-step-column { &:nth-of-type(1) { width: 50%; diff --git a/web/app/views/clients/wizard/gear/_video_gear.html.haml b/web/app/views/clients/wizard/gear/_video_gear.html.haml index de8eb20b5..410fba4f5 100644 --- a/web/app/views/clients/wizard/gear/_video_gear.html.haml +++ b/web/app/views/clients/wizard/gear/_video_gear.html.haml @@ -3,22 +3,23 @@ .wizard-step-column %h2 Instructions .ftue-box.instructions - %p Select webcam to use for video in sessions. - %p Verify that you see the video for the webcam in the window to the right. - %p Configure webcam settings if desired. + %ul + %li Select webcam to use for video in sessions. + %li Verify that you see the video for the webcam in the window to the right. + %li Configure webcam settings if desired. .center %a.button-orange.watch-video{href:'https://www.youtube.com/watch?v=f7niycdWm7Y', rel:'external'} WATCH VIDEO .wizard-step-column %h2.sub-header Webcam - %form.voice - .webcam-select - %select#webcam-select - %h3 Use Music Microphone - %p I am already using a microphone to capture my vocal or instrumental music, so I can talk with other musicians using that microphone - .configure-webcam - %button#webcam-settings{type: 'button'} + %form.video + .webcam-select.wizard_control + %select#webcam-select.w100 + .configure-webcam.wizard_control + %a.button-orange.asio-settings-output-btn Webcam Settings + %em No webcam detected. If using an external webcam, please make sure it is plugged in to your computer. .clearall .wizard-step-column %h2.video-header Preview - .webcam-preview + .webcam-preview.ftue-box + .webcam-content \ No newline at end of file From 17b4b1aeca001d26cbd3bb86c5a2234aaab40184 Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Mon, 9 Feb 2015 09:43:23 -0600 Subject: [PATCH 04/21] VRFS-1844 : Fake jam client calls for video APIS to enable faster iterations --- web/app/assets/javascripts/fakeJamClient.js | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js index e9bae710f..12d0e4e4a 100644 --- a/web/app/assets/javascripts/fakeJamClient.js +++ b/web/app/assets/javascripts/fakeJamClient.js @@ -21,6 +21,7 @@ var frameSize = 2.5; var fakeJamClientRecordings = null; var p2pCallbacks = null; + var videoShared = false; function dbg(msg) { logger.debug('FakeJamClient: ' + msg); } @@ -46,6 +47,38 @@ function FTUESetMusicProfileName() { } + + function FTUESelectVideoCaptureDevice(device, settings) { + + } + function FTUESetVideoEncodeResolution(resolution) { + + } + function FTUEGetVideoCaptureDeviceNames() { + return ["Built-in Webcam HD"] + } + function FTUECurrentSelectedVideoDevice() { + return "Built-in Webcam HD" + } + function FTUEGetAvailableEncodeVideoResolutions() { + return { + 1: "1024x768", + 2: "800x600" + } + } + + function isSessVideoShared() { + return videoShared; + } + + function SessStopVideoSharing() { + videoShared=false; + } + + function SessStartVideoSharing(bitrate=0) { + videoShared=true; + } + function FTUEGetInputLatency() { dbg("FTUEGetInputLatency"); return 2; @@ -1002,6 +1035,17 @@ this.CloseRecording = CloseRecording; this.OnDownloadAvailable = OnDownloadAvailable; + // Video functionality: + this.FTUESelectVideoCaptureDevice = FTUESelectVideoCaptureDevice + this.FTUESetVideoEncodeResolution = FTUESetVideoEncodeResolution; + this.FTUEGetVideoCaptureDeviceNames = FTUEGetVideoCaptureDeviceNames; + this.FTUECurrentSelectedVideoDevice = FTUECurrentSelectedVideoDevice; + this.FTUEGetAvailableEncodeVideoResolutions = FTUEGetAvailableEncodeVideoResolutions; + + this.isSessVideoShared = isSessVideoShared; + this.SessStopVideoSharing = SessStopVideoSharing; + this.SessStartVideoSharing = SessStartVideoSharing; + // Clipboard this.SaveToClipboard = SaveToClipboard; From 1081efffdd3daa453ae4e5238360f08bc30be1f0 Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Wed, 11 Feb 2015 11:10:25 -0600 Subject: [PATCH 05/21] VRFS-1844 : A webcam component to initialize, and manage the state of, the webcam setup pane. Since this is accessed in several places, this javascript needed generifying. --- .../javascripts/webcam_viewer.js.coffee | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 web/app/assets/javascripts/webcam_viewer.js.coffee diff --git a/web/app/assets/javascripts/webcam_viewer.js.coffee b/web/app/assets/javascripts/webcam_viewer.js.coffee new file mode 100644 index 000000000..6bef93d2c --- /dev/null +++ b/web/app/assets/javascripts/webcam_viewer.js.coffee @@ -0,0 +1,104 @@ +$ = jQuery +context = window +context.JK ||= {}; + +context.JK.WebcamViewer = class WebcamViewer + constructor: (@root) -> + @client = context.jamClient + @logger = context.JK.logger + @initialScan = false + @toggleBtn = null + @webcamSelect = null + @resolutionSelect = null + @videoShared=false + @resolution=null + + init: (root) => + console.log 'root', root + @root = root + @toggleBtn = @root.find(".webcam-test-btn") + @webcamSelect = @root.find(".webcam-select-container select") + @resolutionSelect = @root.find(".webcam-resolution-select-container select") + @webcamSelect.on("change", this.selectWebcam) + console.log 'webcamSelect', @webcamSelect + + beforeShow:() => + this.loadWebCams() + this.selectWebcam() + this.loadResolutions() + this.selectResolution() + @initialScan = true + #client.SessSetInsetPosition(5) + #client.SessSetInsetSize(1) + #client.FTUESetAutoSelectVideoLayout(false) + #client.SessSelectVideoDisplayLayoutGroup(1) + + + selectWebcam:(e, data) => + console.log 'Selecting control: ', @webcamSelect + device = @webcamSelect.val() + if device != null and device != '' + console.log 'Selecting webcam: ', device + + selectResolution:() => + console.log 'Selecting res control: ', @resolutionSelect + @resolution = @resolutionSelect.val() + if @resolution != null and @resolution != '' + console.log 'Selecting res: ', @resolution + @client.FTUESetVideoEncodeResolution @resolution + + setVideoOff:() => + if this.isVideoShared() + @client.SessStopVideoSharing() + + isVideoShared:() => + @videoShared + + setToggleState:() => + available = @webcamSelect.find('option').size() > 0 + shared = this.isVideoShared() + console.log 'Setting toggle from : ', shared + @toggleBtn.prop 'disabled', true + @toggleBtn.prop 'disabled', !available + + toggleWebcam:() => + console.log 'Toggling webcam from: ', this.isVideoShared() + if this.isVideoShared() + @client.SessStopVideoSharing() + @videoShared = false + else + @client.SessStartVideoSharing 0 + @videoShared = true + + loadWebCams:() => + devices = @client.FTUEGetVideoCaptureDeviceNames() + selectedDevice = @client.FTUECurrentSelectedVideoDevice() + selectControl = @webcamSelect + context._.each devices, (device) -> + selected = device == selectedDevice + option = $('