jam-cloud/web/app/assets/javascripts/wizard/gear/step_select_gear.js

931 lines
32 KiB
JavaScript

(function (context, $) {
"use strict";
context.JK = context.JK || {};
context.JK.StepSelectGear = function (app, dialog) {
var ALERT_NAMES = context.JK.ALERT_NAMES;
var EVENTS = context.JK.EVENTS;
var ASSIGNMENT = context.JK.ASSIGNMENT;
var VOICE_CHAT = context.JK.VOICE_CHAT;
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
var gearUtils = context.JK.GearUtils;
var self = null;
var $step = null;
var logger = context.JK.logger;
var rest = context.JK.Rest();
var frameBuffers = new context.JK.FrameBuffers(app);
var gearTest = new context.JK.GearTest(app);
var loopbackShowing = false;
// the goal of lastFailureAnalytics and trackedPass are to send only a single AudioTest 'Pass' or 'Failed' event, per FTUE wizard open/close
var lastFailureAnalytics = {};
var trackedPass = false;
var $watchVideoInput = null;
var $watchVideoOutput = null;
var $audioInput = null;
var $audioOutput = null;
var $inputChannels = null;
var $outputChannels = null;
var $knobs = null;
var $scoreReport = null;
var $asioInputControlBtn = null;
var $asioOutputControlBtn = null;
var $resyncBtn = null;
var $templateAudioPort = null;
var $launchLoopbackBtn = null;
var $instructions = null;
var operatingSystem = null;
var iCheckIgnore = false;
var validDevice = false; // do we currently have a device selected that we can score against?
// cached values between
var deviceInformation = null;
var lastSelectedDeviceInfo = null;
var shownOutputProdOnce = false;
var shownInputProdOnce = false;
var selectedDeviceInfo = null;
var musicPorts = null;
var savedProfile = false;
// returns a deviceInfo hash for the device matching the deviceId, or undefined.
function findDevice(deviceId) {
return deviceInformation[deviceId];
}
function selectedAudioInput() {
return $audioInput.val();
}
function selectedAudioOutput() {
return $audioOutput.val();
}
function setInputAudioDevice(value) {
context.JK.dropdown($audioInput.val(value).easyDropDown('select', value.toString(), true))
}
function setOutputAudioDevice(value) {
if(value != "" && value == selectedAudioInput()) {
value = ''; // to force Same as Input
}
context.JK.dropdown($audioOutput.val(value).easyDropDown('select', value.toString(), true))
}
function initializeNextButtonState() {
dialog.setNextState(gearTest.isGoodFtue() || dialog.getLoopbackWizard().getGearTest().isGoodFtue());
}
function initializeBackButtonState() {
dialog.setBackState(!gearTest.isScoring());
}
function initializeAudioInput() {
var optionsHtml = '';
optionsHtml = '<option selected="selected" value="">Choose...</option>';
context._.each(deviceInformation, function (deviceInfo, deviceId) {
if(deviceInfo.inputCount > 0) {
optionsHtml += '<option title="' + deviceInfo.displayName + '" value="' + deviceId + '">' + deviceInfo.displayName + '</option>';
}
});
$audioInput.html(optionsHtml);
context.JK.dropdown($audioInput);
$audioInput.easyDropDown('enable')
initializeAudioInputChanged();
}
function initializeAudioOutput() {
var optionsHtml = '';
optionsHtml = '<option selected="selected" value="">Same as Input</option>';
context._.each(deviceInformation, function (deviceInfo, deviceId) {
if(deviceInfo.outputCount > 0) {
optionsHtml += '<option title="' + deviceInfo.displayName + '" value="' + deviceId + '">' + deviceInfo.displayName + '</option>';
}
});
$audioOutput.html(optionsHtml);
context.JK.dropdown($audioOutput);
$audioOutput.easyDropDown('disable'); // enable once they pick something in input
initializeAudioOutputChanged();
}
// reloads the backend's channel state for the currently selected audio devices,
// and update's the UI accordingly
function initializeChannels() {
musicPorts = jamClient.FTUEGetChannels();
initializeInputPorts(musicPorts);
initializeOutputPorts(musicPorts);
}
// select 2 (or 1) inputs and 2 outputs for the user. required to get a latency score
// also, arguably convenient
function autoSelectMinimumValidChannels() {
var audioInputDeviceId = selectedAudioInput();
var audioOutputDeviceId = selectedAudioOutput();
var $allInputs = $inputChannels.find('input[type="checkbox"]');
if ($allInputs.length == 0) {
// ERROR: not enough channels
if(!audioInputDeviceId || audioInputDeviceId == '') {
context.JK.prodBubble($audioInput.closest('.easydropdown-wrapper'), 'select-input', {}, {positions:['right', 'top']});
}
else {
// this path should be impossible because we filter output devices with 0 inputs from the input device dropdown
// but we might flip that, so it's nice to leave this in to catch us later
context.JK.Banner.showAlert('To be a valid input audio device, the device must have at least 1 input port.');
}
return false;
}
// ensure 1, or preferably 2, input channels are selected
var $assignedInputs = $inputChannels.find('input[type="checkbox"]:checked');
var $unassignedInputs = $inputChannels.find('input[type="checkbox"]:not(:checked)');
if ($assignedInputs.length == 0) {
if ($allInputs.length >= 2) {
logger.debug("selecting 2 inputs")
$unassignedInputs.eq(0).iCheck('check').attr('checked', 'checked');
// this is required because iCheck change handler re-writes the inputs. So we have to refetch unassigned outputs
$unassignedInputs = $inputChannels.find('input[type="checkbox"]:not(:checked)');
$unassignedInputs.eq(0).iCheck('check').attr('checked', 'checked');
}
else {
logger.debug("selecting 1 inputs")
$unassignedInputs.eq(0).iCheck('check').attr('checked', 'checked');
}
}
var $allOutputs = $outputChannels.find('input[type="checkbox"]');
if ($allOutputs.length < 2) {
if(!audioOutputDeviceId || audioOutputDeviceId == '') {
context.JK.prodBubble($audioOutput.closest('.easydropdown-wrapper'), 'select-output', {}, {positions:['right', 'top'], duration:7000});
}
else {
// this path indicates that the user has deliberately chosen a device, so we need to tell them that this device does not work with JamKazam
context.JK.prodBubble($audioOutput.closest('.easydropdown-wrapper'), 'select-output', {}, {positions:['right', 'top'], duration:7000});
}
return false;
}
// ensure 2 outputs are selected
var $assignedOutputs = $outputChannels.find('input[type="checkbox"]:checked');
var $unassignedOutputs = $outputChannels.find('input[type="checkbox"]:not(:checked)');
if ($assignedOutputs.length == 0) {
logger.debug("selecting both outputs")
$unassignedOutputs.eq(0).iCheck('check').attr('checked', 'checked');
// this is required because iCheck change handler re-writes the inputs. So we have to refetch unassigned outputs
$unassignedOutputs = $outputChannels.find('input[type="checkbox"]:not(:checked)');
$unassignedOutputs.eq(0).iCheck('check').attr('checked', 'checked');
}
else if ($assignedOutputs.length == 1) {
logger.debug("selecting 1 output to round out 2 total")
$unassignedOutputs.eq(0).iCheck('check').attr('checked', 'checked');
}
return true;
}
// during this phase of the FTUE, we have to assign selected input channels
// to tracks. The user, however, does not have a way to indicate which channel
// goes to which track (that's not until the next step of the wizard).
// so, we just auto-generate a valid assignment
function newInputAssignment() {
var assigned = 0;
context._.each(musicPorts.inputs, function (inputChannel) {
if (gearUtils.isChannelAssigned(inputChannel)) {
assigned += 1;
}
});
var newAssignment = Math.floor(assigned / 2) + 1;
return newAssignment;
}
function inputChannelChanged() {
if (iCheckIgnore) return;
var $checkbox = $(this);
var channelId = $checkbox.attr('data-id');
var isChecked = $checkbox.is(':checked');
if (isChecked) {
var newAssignment = newInputAssignment();
logger.debug("assigning input channel %o to track: %o", channelId, newAssignment);
context.jamClient.TrackSetAssignment(channelId, true, newAssignment);
}
else {
logger.debug("unassigning input channel %o", channelId);
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.UNASSIGNED);
// unassigning creates a hole in our auto-assigned tracks. reassign them all to keep it consistent
var $assignedInputs = $inputChannels.find('input[type="checkbox"]:checked');
var assigned = 0;
context._.each($assignedInputs, function (assignedInput) {
var $assignedInput = $(assignedInput);
var assignedChannelId = $assignedInput.attr('data-id');
var newAssignment = Math.floor(assigned / 2) + 1;
logger.debug("re-assigning input channel %o to track: %o", assignedChannelId, newAssignment);
context.jamClient.TrackSetAssignment(assignedChannelId, true, newAssignment);
assigned += 1;
});
}
initializeChannels();
}
// should be called in a ifChanged callback if you want to cancel.
// you have to use this instead of 'return false' like a typical input 'change' event.
function cancelICheckChange($checkbox) {
iCheckIgnore = true;
var checked = $checkbox.is(':checked');
setTimeout(function () {
if (checked) $checkbox.iCheck('uncheck').removeAttr('checked');
else $checkbox.iCheck('check').attr('checked', 'checked');
iCheckIgnore = false;
}, 1);
}
function outputChannelChanged() {
if (iCheckIgnore) return;
var $checkbox = $(this);
var channelId = $checkbox.attr('data-id');
var isChecked = $checkbox.is(':checked');
// don't allow more than 2 output channels selected at once
if ($outputChannels.find('input[type="checkbox"]:checked').length > 2) {
context.JK.Banner.showAlert('You can only have a maximum of 2 output ports selected.');
// can't allow uncheck of last output
cancelICheckChange($checkbox);
return;
}
if (isChecked) {
logger.debug("assigning output channel %o", channelId);
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.OUTPUT);
}
else {
logger.debug("unassigning output channel %o", channelId);
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.UNASSIGNED);
}
initializeChannels();
}
function initializeInputPorts(musicPorts) {
$inputChannels.empty();
var inputPorts = musicPorts.inputs;
context._.each(inputPorts, function (inputChannel) {
var $inputChannel = $(context._.template($templateAudioPort.html(), inputChannel, { variable: 'data' }));
var $checkbox = $inputChannel.find('input');
if (gearUtils.isChannelAssigned(inputChannel)) {
$checkbox.attr('checked', 'checked');
}
context.JK.checkbox($checkbox);
$checkbox.on('ifChanged', inputChannelChanged);
$inputChannels.append($inputChannel);
});
}
function initializeOutputPorts(musicPorts) {
$outputChannels.empty();
var outputChannels = musicPorts.outputs;
context._.each(outputChannels, function (outputChannel) {
var $outputPort = $(context._.template($templateAudioPort.html(), outputChannel, { variable: 'data' }));
var $checkbox = $outputPort.find('input');
if (gearUtils.isChannelAssigned(outputChannel)) {
$checkbox.attr('checked', 'checked');
}
context.JK.checkbox($checkbox);
$checkbox.on('ifChanged', outputChannelChanged);
$outputChannels.append($outputPort);
});
}
function initializeLoopback() {
$launchLoopbackBtn.unbind('click').click(function() {
$(dialog.getLoopbackWizard().getDialog()).one(EVENTS.DIALOG_CLOSED, function() {
loopbackShowing = false;
if(dialog.getLoopbackWizard().getGearTest().isGoodFtue()) {
gearTest.resetScoreReport();
gearTest.showLoopbackDone();
context.JK.prodBubble(dialog.getWizard().getNextButton(), 'move-on-loopback-success', {}, {positions:['top']});
}
initializeNextButtonState();
initializeBackButtonState();
})
loopbackShowing = true;
app.layout.showDialog('loopback-wizard')
return false;
})
}
function initializeFormElements() {
if (!deviceInformation) throw "devices are not initialized";
initializeAudioInput();
initializeAudioOutput();
initializeLoopback();
}
function clearInputPorts() {
$inputChannels.empty();
}
function clearOutputPorts() {
$outputChannels.empty();
}
function audioInputDeviceUnselected() {
validDevice = false;
setOutputAudioDevice('');
resetState();
}
function renderScoringStarted() {
initializeBackButtonState();
initializeNextButtonState();
freezeAudioInteraction();
}
function renderScoringStopped() {
initializeNextButtonState();
initializeBackButtonState();
unfreezeAudioInteraction();
}
function freezeAudioInteraction() {
logger.debug("freezing audio interaction");
$audioInput.attr("disabled", "disabled").easyDropDown('disable');
$audioOutput.attr("disabled", "disabled").easyDropDown('disable');
frameBuffers.disable();
$asioInputControlBtn.on("click", false);
$asioOutputControlBtn.on("click", false);
$resyncBtn.on('click', false);
iCheckIgnore = true;
$inputChannels.find('input[type="checkbox"]').iCheck('disable');
$outputChannels.find('input[type="checkbox"]').iCheck('disable');
}
function unfreezeAudioInteraction() {
logger.debug("unfreezing audio interaction");
$audioInput.removeAttr("disabled").easyDropDown('enable');
$audioOutput.removeAttr("disabled").easyDropDown('enable');
frameBuffers.enable();
$asioInputControlBtn.off("click", false);
$asioOutputControlBtn.off("click", false);
$resyncBtn.off('click', false);
$inputChannels.find('input[type="checkbox"]').iCheck('enable');
$outputChannels.find('input[type="checkbox"]').iCheck('enable');
iCheckIgnore = false;
}
function initializeWatchVideo() {
$watchVideoInput.unbind('click').click(function () {
var audioDevice = findDevice(selectedAudioInput());
if (!audioDevice) {
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 = AUDIO_DEVICE_BEHAVIOR[audioDevice.type].videoURL;
if (videoURL) {
$(this).attr('href', videoURL);
return true;
}
else {
context.JK.Banner.showAlert('No help video for this type of device (' + audioDevice.displayType + ')');
}
}
return false;
});
$watchVideoOutput.unbind('click').click(function () {
var audioDevice = findDevice(selectedAudioOutput());
if (!audioDevice) {
throw "this button should be hidden";
}
else {
var videoURL = AUDIO_DEVICE_BEHAVIOR[audioDevice.type].videoURL;
if (videoURL) {
$(this).attr('href', videoURL);
return true;
}
else {
context.JK.Banner.showAlert('No help video for this type of device (' + audioDevice.displayType + ')');
}
}
return false;
});
}
function invalidateScore() {
gearTest.invalidateScore();
dialog.getLoopbackWizard().getGearTest().invalidateScore();
initializeNextButtonState();
}
function initializeASIOButtons() {
$asioInputControlBtn.unbind('click').click(function () {
if(gearTest.isScoring()) {
return false;
}
context.jamClient.FTUEOpenControlPanel(selectedAudioInput());
return false;
});
$asioOutputControlBtn.unbind('click').click(function () {
if(gearTest.isScoring()) {
return false;
}
context.jamClient.FTUEOpenControlPanel(selectedAudioOutput());
return false;
});
}
function onFramesizeChanged() {
context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
updateDefaultBuffers();
jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
invalidateScore();
}
function onBufferInChanged() {
context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
invalidateScore();
}
function onBufferOutChanged() {
context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
invalidateScore();
}
function getSelectedInputs() {
return $inputChannels.find('input[type="checkbox"]:checked');
}
function getSelectedOutputs() {
return $outputChannels.find('input[type="checkbox"]:checked');
}
function initializeResync() {
$resyncBtn.unbind('click').click(function () {
if (getSelectedInputs().length == 0) {
context.JK.Banner.showAlert("You must have at least one input port to resync.");
return false;
}
if (getSelectedOutputs().length < 2) {
context.JK.Banner.showAlert("You must have exactly two output ports to resync.");
return false;
}
attemptScore();
return false;
})
}
// sets selectedDeviceInfo, which contains id, behavior, and info for input and output device
function cacheCurrentAudioInfo() {
var audioInputDeviceId = selectedAudioInput();
var audioOutputDeviceId = selectedAudioOutput();
if (!audioInputDeviceId) {
audioInputDeviceUnselected();
return false;
}
var audioInputDevice = findDevice(audioInputDeviceId);
if (!audioInputDevice) {
context.JK.alertSupportedNeeded('Unable to find information for input device: ' + audioInputDeviceId);
return false;
}
if (!audioOutputDeviceId) {
audioOutputDeviceId = audioInputDeviceId;
}
var audioOutputDevice = findDevice(audioOutputDeviceId);
if (!audioInputDevice) {
context.JK.alertSupportedNeeded('Unable to find information for output device: ' + audioOutputDeviceId);
return false;
}
if(savedProfile && jamClient.FTUEGetInputMusicDevice() != audioInputDeviceId || jamClient.FTUEGetOutputMusicDevice() != audioOutputDeviceId) {
// if they want to change an input or output device, but we have a saved (named) profile
// then we need to delete the current profile and create a new one
// because there is no way to rename a profile, and the profile name has the device's name in it
var profileName = context.jamClient.FTUEGetMusicProfileName();
logger.debug("invaliding previously saved profile: " + profileName);
dialog.createFTUEProfile();
// restore user selections because newSession is called by createFTUEProfile(), invalidating dropdowns
setInputAudioDevice(audioInputDeviceId);
setOutputAudioDevice(audioOutputDeviceId);
context.jamClient.TrackDeleteProfile(profileName);
}
shownOutputProdOnce = false;
shownInputProdOnce = false;
lastSelectedDeviceInfo = selectedDeviceInfo;
selectedDeviceInfo = gearUtils.selectedDeviceInfo(audioInputDeviceId, audioOutputDeviceId, deviceInformation)
return true;
}
function changeDevice() {
var audioInputDeviceId = selectedDeviceInfo.input.id;
var audioOutputDeviceId = selectedDeviceInfo.output.id;
if(audioInputDeviceId) {
$audioOutput.easyDropDown('enable');
}
// don't re-assign input/output audio devices because it disturbs input/output track association
if (jamClient.FTUEGetInputMusicDevice() != audioInputDeviceId) {
jamClient.FTUESetInputMusicDevice(audioInputDeviceId);
}
if (jamClient.FTUEGetOutputMusicDevice() != audioOutputDeviceId) {
jamClient.FTUESetOutputMusicDevice(audioOutputDeviceId);
}
initializeChannels();
validDevice = autoSelectMinimumValidChannels();
if (!validDevice) {
return false;
}
jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
// prod user to watch video if the previous type and new type changed
if(!shownInputProdOnce && isInputAudioTypeDifferentFromLastTime()) {
context.JK.prodBubble($watchVideoInput, 'ftue-watch-video', {}, {positions:['top', 'right']});
shownInputProdOnce = true;
}
// prod user to watch video if the previous type and new type changed
if(!shownOutputProdOnce && isOutputAudioTypeDifferentFromLastTime()) {
context.JK.prodBubble($watchVideoOutput, 'ftue-watch-video', {}, {positions:['top', 'right']});
shownOutputProdOnce = true;
}
return true;
}
function audioDeviceChanged() {
if(!cacheCurrentAudioInfo()) {
return;
}
updateDialogForCurrentDevices();
if (changeDevice()) {
attemptScore();
}
}
function isInputAudioTypeDifferentFromLastTime() {
return lastSelectedDeviceInfo && (lastSelectedDeviceInfo.input.info.type != selectedDeviceInfo.input.info.type);
}
function isOutputAudioTypeDifferentFromLastTime() {
return lastSelectedDeviceInfo && isInputOutputDifferentTypes() && (lastSelectedDeviceInfo.output.info.type != selectedDeviceInfo.output.info.type)
}
function isInputOutputDifferentTypes() {
return selectedDeviceInfo && (selectedDeviceInfo.input.info.type != selectedDeviceInfo.output.info.type);
}
function updateDialogForCurrentDevices() {
if(selectedDeviceInfo) {
var inputBehavior = selectedDeviceInfo.input.behavior;
var outputBehavior = selectedDeviceInfo.output.behavior;
}
else {
var inputBehavior = null;
var outputBehavior = null;
}
// deal with watch video
if(isInputOutputDifferentTypes()) {
// if we have two types of devices, you need two different videos
$watchVideoOutput.show().find('.video-type').show();
$watchVideoInput.addClass('audio-output-showing').find('.video-type').show();
}
else {
$watchVideoOutput.hide();
$watchVideoInput.removeClass('audio-output-showing').find('.video-type').hide();
}
// handle framesize/buffers
if (inputBehavior && (inputBehavior.showKnobs || outputBehavior.showKnobs)) {
$knobs.show();
}
else {
$knobs.hide();
}
// handle ASIO visibility
if (inputBehavior) {
if (inputBehavior.showASIO) {
$asioInputControlBtn.show();
}
else {
$asioInputControlBtn.hide();
}
if(outputBehavior.showASIO && (selectedDeviceInfo.input.id != selectedDeviceInfo.output.id)) {
$asioOutputControlBtn.show();
}
else {
$asioOutputControlBtn.hide();
}
}
else {
// show no ASIO buttons
$asioInputControlBtn.hide();
$asioOutputControlBtn.hide();
}
// handle resync button
if (inputBehavior) {
$resyncBtn.css('visibility', 'visible');
}
else {
$resyncBtn.css('visibility', 'hidden');
}
updateDefaultFrameSize();
updateDefaultBuffers();
}
function updateDefaultFrameSize() {
if(selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm')) {
frameBuffers.setFramesize('10');
}
else {
frameBuffers.setFramesize('2.5')
}
jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
}
function updateDefaultBuffers() {
// handle specific framesize settings
if(selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm')) {
var framesize = frameBuffers.selectedFramesize();
if(framesize == 2.5) {
logger.debug("setting default buffers to 1/1");
frameBuffers.setBufferIn('1');
frameBuffers.setBufferOut('1');
}
else if(framesize == 5) {
logger.debug("setting default buffers to 3/2");
frameBuffers.setBufferIn('3');
frameBuffers.setBufferOut('2');
}
else {
logger.debug("setting default buffers to 6/5");
frameBuffers.setBufferIn('6');
frameBuffers.setBufferOut('5');
}
}
else {
logger.debug("setting default buffers to 0/0");
frameBuffers.setBufferIn(0);
frameBuffers.setBufferOut(0);
}
jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
}
// refocused affects how IO testing occurs.
// on refocus=true:
// * reuse IO score if it was good/acceptable
// * rescore IO if it was bad or skipped from previous try
function attemptScore(refocused) {
gearTest.attemptScore(selectedDeviceInfo, refocused);
}
function initializeAudioInputChanged() {
$audioInput.unbind('change').change(audioDeviceChanged);
}
function initializeAudioOutputChanged() {
$audioOutput.unbind('change').change(audioDeviceChanged);
}
function onGearTestStarted(e, data) {
renderScoringStarted();
}
function onGearTestDone(e, data) {
renderScoringStopped();
gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
}
function getLastAudioTestFailAnalytics() {
return lastFailureAnalytics;
}
function storeLastFailureForAnalytics(platform, reason, data) {
if(!trackedPass) {
lastFailureAnalytics = {
platform: platform,
reason: reason,
data: data
}
}
}
function onGearTestFail(e, data) {
renderScoringStopped();
gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
if(data.reason == "latency") {
storeLastFailureForAnalytics(context.JK.detectOS(), context.JK.GA.AudioTestFailReasons.latency, data.latencyScore);
}
else if(data.reason = "io") {
if(data.ioTarget == 'bad') {
storeLastFailureForAnalytics(context.JK.detectOS(), context.JK.GA.AudioTestFailReasons.ioTarget, data.ioTargetScore);
}
else {
storeLastFailureForAnalytics(context.JK.detectOS(), context.JK.GA.AudioTestFailReasons.ioVariance, data.ioVarianceScore);
}
}
else {
logger.error("unknown reason in onGearTestFail: " + data.reason)
}
}
function onGearTestInvalidated(e, data) {
initializeNextButtonState();
}
function handleNext() {
if(!savedProfile) {
var $assignedInputs = $inputChannels.find('input[type="checkbox"]:checked');
var $assignedOutputs = $outputChannels.find('input[type="checkbox"]:checked');
var errors = [];
if($assignedInputs.length == 0) {
errors.push("There must be at least one selected input ports.");
}
if($assignedInputs.length > 12) {
errors.push("There can only be up to 12 selected inputs ports.");
}
if($assignedOutputs.length != 2) {
errors.push("There must be exactly 2 selected output ports.");
}
var $errors = $('<ul></ul>');
context._.each(errors, function(error) {
$errors.append('<li>' + error + '</li>');
});
if(errors.length > 0) {
context.JK.Banner.showAlert({html:$errors});
return false;
}
else {
context.jamClient.FTUESetMusicProfileName(gearUtils.createProfileName(selectedDeviceInfo));
var result = context.jamClient.FTUESave(true);
if(result && result != "") {
// failed
logger.warn("unable to FTUESave(true). reason:" + result);
context.JK.Banner.alertSupportedNeeded("Unable to persist the audio profile. " + result);
return false;
}
else {
context.JK.GA.trackAudioTestCompletion(context.JK.detectOS());
trackedPass = true;
lastFailureAnalytics = null;
savedProfile = true;
return true;
}
}
}
}
function onFocus() {
if(validDevice && !loopbackShowing && getSelectedInputs().length > 0 && getSelectedOutputs().length == 2 ) {
attemptScore(true);
}
}
function newSession() {
savedProfile = false;
deviceInformation = gearUtils.loadDeviceInfo();
resetState();
initializeFormElements();
initializeNextButtonState();
initializeWatchVideo();
initializeASIOButtons();
initializeResync();
}
function beforeWizardShow() {
lastFailureAnalytics = null;
trackedPass = false;
}
function beforeShow() {
$(window).on('focus', onFocus);
initializeNextButtonState();
context.JK.onBackendEvent(ALERT_NAMES.AUDIO_DEVICE_NOT_PRESENT, 'gear_test', gearTest.onInvalidAudioDevice);
}
function beforeHide() {
logger.debug("unregistering focus watch")
$(window).off('focus', onFocus);
context.JK.offBackendEvent(ALERT_NAMES.AUDIO_DEVICE_NOT_PRESENT, 'gear_test', gearTest.onInvalidAudioDevice);
}
function resetState() {
selectedDeviceInfo = null;
invalidateScore();
clearInputPorts();
clearOutputPorts();
frameBuffers.resetValues();
updateDialogForCurrentDevices();
}
function initialize(_$step) {
$step = _$step;
$watchVideoInput = $step.find('.watch-video.audio-input');
$watchVideoOutput = $step.find('.watch-video.audio-output');
$audioInput = $step.find('.select-audio-input-device');
$audioOutput = $step.find('.select-audio-output-device');
$inputChannels = $step.find('.input-ports');
$outputChannels = $step.find('.output-ports');
$knobs = $step.find('.frame-and-buffers');
$scoreReport = $step.find('.results');
$asioInputControlBtn = $step.find('.asio-settings-input-btn');
$asioOutputControlBtn = $step.find('.asio-settings-output-btn');
$resyncBtn = $step.find('.resync-btn');
$templateAudioPort = $('#template-audio-port');
$launchLoopbackBtn = $('.loopback-test');
$instructions = $('.instructions');
operatingSystem = context.JK.GetOSAsString();
frameBuffers.initialize($knobs);
$(frameBuffers)
.on(frameBuffers.FRAMESIZE_CHANGED, onFramesizeChanged)
.on(frameBuffers.BUFFER_IN_CHANGED, onBufferInChanged)
.on(frameBuffers.BUFFER_OUT_CHANGED, onBufferOutChanged)
gearTest.initialize($scoreReport, true)
$(gearTest)
.on(gearTest.GEAR_TEST_START, onGearTestStarted)
.on(gearTest.GEAR_TEST_DONE, onGearTestDone)
.on(gearTest.GEAR_TEST_FAIL, onGearTestFail)
.on(gearTest.GEAR_TEST_INVALIDATED_ASYNC, onGearTestInvalidated)
}
this.getLastAudioTestFailAnalytics = getLastAudioTestFailAnalytics;
this.handleNext = handleNext;
this.newSession = newSession;
this.beforeShow = beforeShow;
this.beforeHide = beforeHide;
this.beforeWizardShow = beforeWizardShow;
this.initialize = initialize;
self = this;
return this;
};
})(window, jQuery);