diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js
index ee3d67d7e..39732919b 100644
--- a/web/app/assets/javascripts/fakeJamClient.js
+++ b/web/app/assets/javascripts/fakeJamClient.js
@@ -157,6 +157,10 @@
return 'Good Device';
}
+ function FTUEIsMusicDeviceWDM() {
+ return false;
+ }
+
function RegisterVolChangeCallBack(functionName) {
dbg('RegisterVolChangeCallBack');
}
@@ -684,6 +688,7 @@
this.FTUEGetAllAudioConfigurations = FTUEGetAllAudioConfigurations;
this.FTUEGetGoodAudioConfigurations = FTUEGetGoodAudioConfigurations;
this.FTUEGetConfigurationDevice = FTUEGetConfigurationDevice;
+ this.FTUEIsMusicDeviceWDM = FTUEIsMusicDeviceWDM;
// Session
this.SessionAddTrack = SessionAddTrack;
diff --git a/web/app/assets/javascripts/gear_wizard.js b/web/app/assets/javascripts/gear_wizard.js
index 4926c6777..634710d76 100644
--- a/web/app/assets/javascripts/gear_wizard.js
+++ b/web/app/assets/javascripts/gear_wizard.js
@@ -16,6 +16,9 @@
var self = null;
var operatingSystem = null;
+ // populated by loadDevices
+ var deviceInformation = null;
+
// SELECT DEVICE STATE
var validScore = false;
@@ -32,18 +35,27 @@
var audioDeviceBehavior = {
MacOSX_builtin : {
+ display: 'MacOSX Built-In',
videoURL: undefined
},
MACOSX_interface : {
+ display: 'MacOSX external interface',
videoURL: undefined
},
Win32_wdm : {
+ display: 'Windows WDM',
videoURL: undefined
},
Win32_asio : {
+ display: 'Windows ASIO',
videoURL: undefined
},
Win32_asio4all : {
+ display: 'Windows ASIO4ALL',
+ videoURL: undefined
+ },
+ Linux : {
+ display: 'Linux',
videoURL: undefined
}
}
@@ -65,8 +77,66 @@
var $audioOutput = $currentWizardStep.find('.select-audio-output-device');
var $bufferIn = $currentWizardStep.find('.select-buffer-in');
var $bufferOut = $currentWizardStep.find('.select-buffer-out');
- var $nextButton = $ftueButtons.find('.btn-next');
var $frameSize = $currentWizardStep.find('.select-frame-size');
+ var $inputPorts = $currentWizardStep.find('.input-ports');
+ var $outputPorts = $currentWizardStep.find('.output-ports');
+ var $scoreReport = $currentWizardStep.find('.results');
+ var $nextButton = $ftueButtons.find('.btn-next');
+
+ // should return one of:
+ // * MacOSX_builtin
+ // * MACOSX_interface
+ // * Win32_wdm
+ // * Win32_asio
+ // * Win32_asio4all
+ // * Linux
+ function determineDeviceType(deviceId, displayName) {
+ if(operatingSystem == "MacOSX") {
+ if(displayName.toLowerCase().trim() == "built-in") {
+ return "MacOSX_builtin";
+ }
+ else {
+ return "MacOSX_interface";
+ }
+ }
+ else if(operatingSystem == "Win32") {
+ if(context.jamClient.FTUEIsMusicDeviceWDM(deviceId)) {
+ return "Win32_wdm";
+ }
+ else if(displayName.toLowerCase().indexOf("asio4all") > -1) {
+ return "Win32_asio4all"
+ }
+ else {
+ return "Win32_asio";
+ }
+ }
+ else {
+ return "Linux";
+ }
+ }
+
+
+ function loadDevices() {
+ var devices = context.jamClient.FTUEGetDevices(false);
+
+ var loadedDevices = {};
+
+ // augment these devices by determining their type
+ context._.each(devices, function(displayName, deviceId) {
+ var deviceInfo = {};
+
+ deviceInfo.id = deviceId;
+ deviceInfo.type = determineDeviceType(deviceId, displayName);
+ deviceInfo.displayType = audioDeviceBehavior[deviceInfo.type].display;
+ deviceInfo.displayName = deviceInfo.displayName;
+
+ loadedDevices[deviceId] = deviceInfo;
+ })
+
+ deviceInformation = context._.keys(loadedDevices).sort();
+
+ logger.debug(context.JK.dlen(deviceInformation) + " devices loaded." , deviceInformation);
+ }
// returns a deviceInfo hash for the device matching the deviceId, or null.
function findDevice(deviceId) {
@@ -81,18 +151,214 @@
return $audioOutput.val();
}
+ function selectedFramesize() {
+ return parseFloat($frameSize.val());
+ }
+
+ function selectedBufferIn() {
+ return parseFloat($frameSize.val());
+ }
+
+ function selectedBufferOut() {
+ return parseFloat($frameSize.val());
+ }
+
function initializeNextButtonState() {
+ console.log(context.jamClient.FTUEGetDevices(false));
+ console.log("chat devices", jamClient.FTUEGetChatInputs());
$nextButton.removeClass('button-orange button-grey');
if(validScore) $nextButton.addClass('button-orange');
else $nextButton.addClass('button-grey');
}
- function audioDeviceUnselected() {
+ function initializeAudioInput() {
+ var optionsHtml = '';
+ optionsHtml = '';
+ context._.each(deviceInformation, function(deviceInfo, deviceId) {
+ optionsHtml += '';
+ });
+ $audioInput.html(optionsHtml);
+ alert(optionsHtml)
+ context.JK.dropdown($audioInput);
+
+ initializeAudioInputChanged();
+ }
+
+ function initializeAudioOutput() {
+ var optionsHtml = '';
+ optionsHtml = '';
+ context._.each(deviceInformation, function(deviceInfo, deviceId) {
+ optionsHtml += '';
+ });
+ $audioOutput.html(optionsHtml);
+ context.JK.dropdown($audioOutput);
+
+ initializeAudioOutputChanged();
+ }
+
+ function initializeFramesize() {
+
+ }
+
+ function initializeFormElements() {
+ if(!deviceInformation) throw "devices are not initialized";
+
+ initializeAudioInput();
+ initializeAudioOutput();
+ initializeFramesize();
+ initializeBuffers();
+ }
+
+ function resetFrameBuffers() {
+ $frameSize.val('2.5');
+ $bufferIn.val('0');
+ $bufferOut.val('0');
+ }
+
+ function clearInputPorts() {
+ $inputPorts.empty();
+ }
+
+ function clearOutputPorts() {
+ $outputPorts.empty();
+ }
+
+ function resetScoreReport() {
+ $scoreReport.empty();
+ }
+
+ function updateScoreReport(latencyResult) {
+ var latencyClass = "neutral";
+ var latencyValue = 'N/A';
+ var validLatency = false;
+ if (latencyResult && latencyResult.latencyknown) {
+ var latency = latencyResult.latency;
+ latencyValue = Math.round(latencyValue * 100) / 100;
+ if (latency.latency <= 10) {
+ latencyClass = "good";
+ validLatency = true;
+ } else if (latency.latency <= 20) {
+ latencyClass = "acceptable";
+ validLatency = true;
+ } else {
+ latencyClass = "bad";
+ }
+ }
+
+ validScore = validLatency; // validScore may become based on IO variance too
+
+ $scoreReport.html(latencyValue);
+ }
+
+ function loadAudioDrivers() {
+ var drivers = context.jamClient.FTUEGetDevices(false);
+ var chatDrivers = jamClient.FTUEGetChatInputs();
+ var optionsHtml = '';
+ var chatOptionsHtml = '';
+
+
+ var driverOptionFunc = function (driverKey, index, list) {
+ if(!drivers[driverKey]) {
+ logger.debug("skipping unknown device:", driverKey)
+ }
+ else {
+ optionsHtml += '';
+ }
+ };
+
+ var chatOptionFunc = function (driverKey, index, list) {
+ chatOptionsHtml += '';
+ };
+
+ var selectors = [
+ '[layout-wizard-step="0"] .settings-2-device select',
+ '[layout-wizard-step="2"] .settings-driver select'
+ ];
+
+ // handle standard devices
+ var sortedDeviceKeys = context._.keys(drivers).sort();
+ context._.each(sortedDeviceKeys, driverOptionFunc);
+ $.each(selectors, function (index, selector) {
+ var $select = $(selector);
+ $select.empty();
+ $select.html(optionsHtml);
+ context.JK.dropdown($select);
+ });
+
+ selectors = ['[layout-wizard-step="0"] .settings-2-voice select'];
+ var sortedVoiceDeviceKeys = context._.keys(chatDrivers).sort();
+
+ // handle voice inputs
+ context._.each(sortedVoiceDeviceKeys, chatOptionFunc);
+ $.each(selectors, function (index, selector) {
+ var $select = $(selector);
+ $select.empty();
+ $select.html(chatOptionsHtml);
+ context.JK.dropdown($select);
+ });
+
+ }
+ function audioInputDeviceUnselected() {
validScore = false;
-
-
initializeNextButtonState();
+ resetFrameBuffers();
+ clearInputPorts();
+ }
+
+ function renderScoringStarted() {
+ validScore = false;
+ initializeNextButtonState();
+ resetScoreReport();
+ }
+
+ function renderScoringStopped() {
+ initializeNextButtonState();
+ }
+
+
+ // Given a latency structure, update the view.
+ function newFtueUpdateLatencyView(latency) {
+ var $report = $('.ftue-new .latency .report');
+ var $instructions = $('.ftue-new .latency .instructions');
+ var latencyClass = "neutral";
+ var latencyValue = "N/A";
+ var $saveButton = $('#btn-ftue-2-save');
+ if (latency && latency.latencyknown) {
+ latencyValue = latency.latency;
+ // Round latency to two decimal places.
+ latencyValue = Math.round(latencyValue * 100) / 100;
+ if (latency.latency <= 10) {
+ latencyClass = "good";
+ setSaveButtonState($saveButton, true);
+ } else if (latency.latency <= 20) {
+ latencyClass = "acceptable";
+ setSaveButtonState($saveButton, true);
+ } else {
+ latencyClass = "bad";
+ setSaveButtonState($saveButton, false);
+ }
+ } else {
+ latencyClass = "unknown";
+ setSaveButtonState($saveButton, false);
+ }
+
+ $('.ms-label', $report).html(latencyValue);
+ $('p', $report).html('milliseconds');
+
+ $report.removeClass('good acceptable bad unknown');
+ $report.addClass(latencyClass);
+
+ var instructionClasses = ['neutral', 'good', 'acceptable', 'unknown', 'bad', 'start', 'loading'];
+ $.each(instructionClasses, function (idx, val) {
+ $('p.' + val, $instructions).hide();
+ });
+ if (latency === 'loading') {
+ $('p.loading', $instructions).show();
+ } else {
+ $('p.' + latencyClass, $instructions).show();
+ renderStopNewFtueLatencyTesting();
+ }
}
function initializeWatchVideo() {
@@ -103,7 +369,7 @@
context.JK.Banner.showAlert('You must first choose an Audio Input Device so that we can determine which video to show you.');
}
else {
- var videoURL = audioDeviceBehavior[audioDevice.type];
+ var videoURL = audioDeviceBehavior[audioDevice.type].videoURL;
if(videoURL) {
$(this).attr('href', videoURL);
@@ -124,7 +390,7 @@
throw "this button should be hidden";
}
else {
- var videoURL = audioDeviceBehavior[audioDevice.type];
+ var videoURL = audioDeviceBehavior[audioDevice.type].videoURL;
if(videoURL) {
$(this).attr('href', videoURL);
@@ -143,102 +409,43 @@
$audioInput.unbind('change').change(function(evt) {
var audioDeviceId = selectedAudioInput();
-
if(!audioDeviceId) {
- audioDeviceUnselected();
+ audioInputDeviceUnselected();
return false;
}
var audioDevice = findDevice(selectedAudioInput());
-
if(!audioDevice) {
- context.JK.alertSupportedNeeded('Unable to find device information for: ' + audioDevice);
+ context.JK.alertSupportedNeeded('Unable to find device information for: ' + audioDeviceId);
+ return false;
}
- releaseDropdown(function () {
- renderStartNewFtueLatencyTesting();
- var $select = $(evt.currentTarget);
+ renderScoringStarted();
- var $audioSelect = $('.ftue-new .settings-2-device select');
- var audioDriverId = $audioSelect.val();
+ jamClient.FTUESetMusicDevice(audioDeviceId);
+ jamClient.FTUESetInputLatency(selectedAudioInput());
+ jamClient.FTUESetOutputLatency(selectedAudioOutput());
+ jamClient.FTUESetFrameSize(selectedFramesize());
- if (!audioDriverId) {
- context.JK.alertSupportNeeded();
+ logger.debug("Calling FTUESave(false)");
+ jamClient.FTUESave(false);
- renderStopNewFtueLatencyTesting();
- // reset back to 'Choose...'
- newFtueEnableControls(false);
- return;
- }
- jamClient.FTUESetMusicDevice(audioDriverId);
+ var latency = jamClient.FTUEGetExpectedLatency();
+ console.log("FTUEGetExpectedLatency: %o", latency);
- var musicInputs = jamClient.FTUEGetMusicInputs();
- var musicOutputs = jamClient.FTUEGetMusicOutputs();
-
- // set the music input to the first available input,
- // and output to the first available output
- var kin = null, kout = null, k = null;
- // TODO FIXME - this jamClient call returns a dictionary.
- // It's difficult to know what to auto-choose.
- // For example, with my built-in audio, the keys I get back are
- // digital in, line in, mic in and stereo mix. Which should we pick for them?
- for (k in musicInputs) {
- kin = k;
- break;
- }
- for (k in musicOutputs) {
- kout = k;
- break;
- }
- var result;
- if (kin && kout) {
- jamClient.FTUESetMusicInput(kin);
- jamClient.FTUESetMusicOutput(kout);
- } else {
- // TODO FIXME - how to handle a driver selection where we are unable to
- // autoset both inputs and outputs? (I'd think this could happen if either
- // the input or output side returned no values)
- renderStopNewFtueLatencyTesting();
- console.log("invalid kin/kout %o/%o", kin, kout);
- return;
- }
-
- newFtueUpdateLatencyView('loading');
-
- newFtueEnableControls(true);
- newFtueOsSpecificSettings();
- // make sure whatever the user sees in the frontend is what the backend thinks
- // this is necesasry because if you do a FTUE pass, close the client, and pick the same device
- // the backend will *silently* use values from before, because the frontend does not query the backend
- // for these values anywhere.
-
- // setting all 3 of these cause 3 FTUE's. Instead, we set batchModify to true so that they don't call FtueSave(false), and call later ourselves
- batchModify = true;
- newFtueAsioFrameSizeToBackend($('#ftue-2-asio-framesize'));
- newFtueAsioInputLatencyToBackend($('#ftue-2-asio-input-latency'));
- newFtueAsioOutputLatencyToBackend($('#ftue-2-asio-output-latency'));
- batchModify = false;
-
- //setLevels(0);
- renderVolumes();
-
- logger.debug("Calling FTUESave(" + false + ")");
- jamClient.FTUESave(false)
- pendingFtueSave = false; // this is not really used in any real fashion. just setting back to false due to batch modify above
-
- setVuCallbacks();
-
- var latency = jamClient.FTUEGetExpectedLatency();
- console.log("FTUEGetExpectedLatency: %o", latency);
- newFtueUpdateLatencyView(latency);
- });
-
- })
+ renderScoringStopped();
+ });
}
+
+ function initializeAudioOutputChanged() {
+
+ }
+
function initializeStep() {
+ loadDevices();
+ initializeFormElements();
initializeNextButtonState();
initializeWatchVideo();
- initializeAudioInputChanged();
}
initializeStep();
diff --git a/web/app/views/clients/gear/_gear_wizard.html.haml b/web/app/views/clients/gear/_gear_wizard.html.haml
index 09d99a642..0ce16062d 100644
--- a/web/app/views/clients/gear/_gear_wizard.html.haml
+++ b/web/app/views/clients/gear/_gear_wizard.html.haml
@@ -38,7 +38,7 @@
%select.w100.select-audio-input-device
%option None
%h2 Audio Input Ports
- .ftue-box.list.ports.output-ports
+ .ftue-box.list.ports.input-ports
%a.button-orange.asio-settings-btn ASIO SETTINGS...
%a.button-orange.resync-btn RESYNC
.wizard-step-column
@@ -46,7 +46,7 @@
%select.w100.select-audio-output-device
%option Same as input
%h2 Audio Output Ports
- .ftue-box.list.ports.input-ports
+ .ftue-box.list.ports.output-ports
.frame-and-buffers
.framesize
%h2 Frame