1243 lines
46 KiB
JavaScript
1243 lines
46 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 modUtils = context.JK.ModUtils;
|
|
|
|
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;
|
|
var adjustGearSettingsShowing = false;
|
|
var wizard = null;
|
|
|
|
// 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 $adjustSettingsLink = null;
|
|
var $adjustGearForIoFail = null;
|
|
var $scoreReport = null;
|
|
var $asioInputControlBtn = null;
|
|
var $asioOutputControlBtn = null;
|
|
var $resyncBtn = null;
|
|
var $templateAudioPort = null;
|
|
var $launchLoopbackBtn = null;
|
|
var $instructions = null;
|
|
var $templateDeviceNotValid = null;
|
|
var $resyncStatus = null;
|
|
var $resyncStatusText = 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;
|
|
var queueUpdateDeviceList = false;
|
|
var cancelRescanFunc = null;
|
|
var initialScan = 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() || dialog.getAdjustGearSettings().getGearTest().isGoodFtue());
|
|
}
|
|
|
|
function initializeBackButtonState() {
|
|
dialog.setBackState(!gearTest.isScoring());
|
|
}
|
|
|
|
function allInputDevices() {
|
|
var allInputDevices = [];
|
|
context._.each(deviceInformation, function (deviceInfo, deviceId) {
|
|
|
|
if(deviceInfo.inputCount > 0) {
|
|
allInputDevices.push({deviceId: deviceId, deviceInfo: deviceInfo});
|
|
}
|
|
});
|
|
return allInputDevices;
|
|
}
|
|
|
|
function allOutputDevices() {
|
|
var allOutputDevices = [];
|
|
context._.each(deviceInformation, function (deviceInfo, deviceId) {
|
|
|
|
if(deviceInfo.outputCount > 0) {
|
|
allOutputDevices.push({deviceId: deviceId, deviceInfo: deviceInfo});
|
|
}
|
|
});
|
|
return allOutputDevices;
|
|
}
|
|
|
|
function initializeAudioInput() {
|
|
var optionsHtml = '';
|
|
optionsHtml = '<option value="">Choose...</option>';
|
|
context._.each(allInputDevices(), function (device) {
|
|
optionsHtml += '<option title="' + device.deviceInfo.displayName + '" value="' + device.deviceId + '">' + device.deviceInfo.displayName + '</option>';
|
|
});
|
|
|
|
$audioInput.html(optionsHtml);
|
|
context.JK.dropdown($audioInput);
|
|
$audioInput.easyDropDown('enable')
|
|
|
|
initializeAudioInputChanged();
|
|
}
|
|
|
|
function initializeAudioOutput() {
|
|
var optionsHtml = '';
|
|
optionsHtml = '<option value="">Same as Input</option>';
|
|
context._.each(allOutputDevices(), function (device) {
|
|
optionsHtml += '<option title="' + device.deviceInfo.displayName + '" value="' + device.deviceId + '">' + device.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 = context.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 reassignInputChannels() {
|
|
assertFTUEProfile();
|
|
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;
|
|
});
|
|
}
|
|
|
|
function reassignOutputChannels() {
|
|
assertFTUEProfile();
|
|
var $assignedOutputs = $outputChannels.find('input[type="checkbox"]:checked');
|
|
context._.each($assignedOutputs, function (assignedOutput) {
|
|
var $assignedOutput = $(assignedOutput);
|
|
var assignedChannelId = $assignedOutput.attr('data-id');
|
|
logger.debug("re-assigning output channel %o", assignedChannelId);
|
|
context.jamClient.TrackSetAssignment(assignedChannelId, true, ASSIGNMENT.OUTPUT);
|
|
});
|
|
}
|
|
|
|
function inputChannelChanged() {
|
|
if (iCheckIgnore) return;
|
|
|
|
assertFTUEProfile();
|
|
|
|
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
|
|
reassignInputChannels();
|
|
}
|
|
|
|
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();
|
|
setTimeout(function() {
|
|
context.JK.prodBubble(dialog.getWizard().getNextButton(), 'can-move-on', {}, {positions:['top'], offsetParent: dialog.getWizard().getDialog()});
|
|
}, 300);
|
|
}
|
|
|
|
initializeNextButtonState();
|
|
initializeBackButtonState();
|
|
})
|
|
|
|
loopbackShowing = true;
|
|
app.layout.showDialog('loopback-wizard')
|
|
return false;
|
|
})
|
|
}
|
|
|
|
function onAdjustGearRequested()
|
|
{
|
|
if(gearTest.isScoring()) {logger.debug("ignoring adjust-gear request while scoring"); return false;}
|
|
|
|
app.layout.showDialog('adjust-gear-speed-dialog').one(EVENTS.DIALOG_CLOSED, function(e, data) {
|
|
adjustGearSettingsShowing = false;
|
|
|
|
var adjustGearTest = data.result;
|
|
|
|
if(!data.canceled) {
|
|
if(adjustGearTest.isGoodFtue()) {
|
|
// update our own frame buffers to reflect any changes made by the adjust dialog
|
|
frameBuffers.setFramesize(context.jamClient.FTUEGetFrameSize())
|
|
frameBuffers.setBufferIn(context.jamClient.FTUEGetInputLatency())
|
|
frameBuffers.setBufferOut(context.jamClient.FTUEGetOutputLatency())
|
|
|
|
gearTest.resetScoreReport();
|
|
gearTest.showGearAdjustmentDone();
|
|
|
|
setTimeout(function() {
|
|
context.JK.prodBubble(dialog.getWizard().getNextButton(), 'can-move-on', {}, {positions:['top'], offsetParent: dialog.getWizard().getDialog()});
|
|
}, 300);
|
|
}
|
|
|
|
initializeNextButtonState();
|
|
initializeBackButtonState();
|
|
}
|
|
else {
|
|
logger.debug("adjust-gear-speed was cancelled; ignoring")
|
|
}
|
|
})
|
|
|
|
adjustGearSettingsShowing = true;
|
|
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).addClass('disabled');
|
|
$asioOutputControlBtn.on("click", false).addClass('disabled');
|
|
$resyncBtn.on('click', false).addClass('disabled');
|
|
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).removeClass('disabled');
|
|
$asioOutputControlBtn.off("click", false).removeClass('disabled')
|
|
$resyncBtn.off('click', false).removeClass('disabled')
|
|
$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();
|
|
dialog.getAdjustGearSettings().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 () {
|
|
|
|
scheduleRescanSystem(function() {
|
|
if (getSelectedInputs().length > 0 && getSelectedOutputs().length == 2) {
|
|
logger.debug("after rescan, ready to attempt score")
|
|
attemptScore();
|
|
}
|
|
else {
|
|
logger.debug("after rescan, not ready to attempt score")
|
|
}
|
|
}, 3000, false);
|
|
return false;
|
|
})
|
|
}
|
|
|
|
function rescan() {
|
|
|
|
// start audio if already running, false = don't reload last audio configuration, true = re-init tracks
|
|
var result = context.jamClient.ReloadAudioSystem(context.jamClient.IsAudioStarted(), false, true);
|
|
|
|
// get the current list of input devices, and output devices, in the UI
|
|
|
|
// these are arrays with this structure
|
|
// {deviceId: id, deviceInfo: deviceInfo}
|
|
var originalInputDevices = allInputDevices();
|
|
var originalOutputDevices = allOutputDevices();
|
|
var originalInputDeviceIds = originalInputDevices.map(function(device){return device.deviceId});
|
|
var originalOutputDevicesId = originalOutputDevices.map(function(device){return device.deviceId});
|
|
var selectedInput = selectedAudioInput();
|
|
var selectedOutput = selectedAudioOutput();
|
|
|
|
// reload device info now that the scan is complete
|
|
deviceInformation = gearUtils.loadDeviceInfo();
|
|
|
|
var inputDevices = allInputDevices();
|
|
var outputDevices = allOutputDevices();
|
|
var inputDeviceIds = inputDevices.map(function(device){return device.deviceId});
|
|
var outputDeviceIds = outputDevices.map(function(device){return device.deviceId});
|
|
|
|
var missingInputDeviceIds = $(originalInputDeviceIds).not(inputDeviceIds).get();
|
|
var newInputDeviceIds = $(inputDeviceIds).not(originalInputDeviceIds).get();
|
|
|
|
var missingOutputDeviceIds = $(originalOutputDevicesId).not(outputDeviceIds).get();
|
|
var newOutputDeviceIds = $(outputDeviceIds).not(originalOutputDevicesId).get();
|
|
|
|
// these are used later to show prod bubbles
|
|
var missingInputDevice = null;
|
|
var newInputDevice = null;
|
|
var missingOutputDevice = null;
|
|
var newOutputDevice = null;
|
|
|
|
if(missingInputDeviceIds.length > 0 || newOutputDeviceIds.length > 0) {
|
|
|
|
initializeAudioInput();
|
|
|
|
if(missingInputDeviceIds.indexOf(selectedInput) > -1) {
|
|
// the user had a device selected that's no longer here. we need to notify them of this, and auto-select 'no device'
|
|
audioInputDeviceUnselected();
|
|
|
|
missingInputDevice = originalInputDevices.filter(function(inputDevice) { return selectedInput == inputDevice.deviceId })[0].deviceInfo.displayName;
|
|
}
|
|
else {
|
|
setInputAudioDevice(selectedInput);
|
|
|
|
if(missingInputDeviceIds.length > 0) {
|
|
missingInputDevice = originalInputDevices.filter(function(inputDevice) { return missingInputDeviceIds[0] == inputDevice.deviceId })[0].deviceInfo.displayName;
|
|
}
|
|
if(newInputDeviceIds.length > 0) {
|
|
newInputDevice = inputDevices.filter(function(inputDevice) { return newInputDeviceIds[0] == inputDevice.deviceId })[0].deviceInfo.displayName;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(missingOutputDeviceIds.length > 0 || newOutputDeviceIds.length > 0) {
|
|
|
|
initializeAudioOutput();
|
|
|
|
if(missingOutputDeviceIds.indexOf(selectedOutput) > -1) {
|
|
// the user had a device selected that's no longer here. we need to notify them of this, and auto-select 'no device'
|
|
setOutputAudioDevice('');
|
|
|
|
missingInputDevice = originalOutputDevices.filter(function(outputDevice) { return selectedOutput == outputDevice.deviceId })[0].deviceInfo.displayName;
|
|
}
|
|
else {
|
|
setOutputAudioDevice(selectedOutput);
|
|
if(missingOutputDeviceIds.length > 0) {
|
|
missingOutputDevice = originalOutputDevices.filter(function(outputDevice) { return missingOutputDeviceIds[0] == outputDevice.deviceId })[0].deviceInfo.displayName;
|
|
}
|
|
if(newOutputDeviceIds.length > 0) {
|
|
newOutputDevice = outputDevices.filter(function(outputDevice) { return newOutputDeviceIds[0] == outputDevice.deviceId })[0].deviceInfo.displayName;
|
|
}
|
|
}
|
|
}
|
|
|
|
// handle prod bubbles in case devices are gone
|
|
if(missingInputDevice || missingOutputDevice || newInputDevice || newOutputDevice) {
|
|
if(missingInputDevice == missingOutputDevice || newInputDevice == newOutputDevice) {
|
|
// we only notify over the input device in the case the device is new/missing from both input/output, to reduce too much bubble action
|
|
context.JK.prodBubble($audioInput.closest('.easydropdown-wrapper'), 'gear-wizard-inputs-changed', {missingInputDevice: missingInputDevice, newInputDevice: newInputDevice}, {positions:['top'], duration:8000});
|
|
}
|
|
else {
|
|
if(missingInputDevice || newInputDevice) {
|
|
context.JK.prodBubble($audioInput.closest('.easydropdown-wrapper'), 'gear-wizard-inputs-changed', {missingInputDevice: missingInputDevice, newInputDevice: newInputDevice}, {positions:['top'], duration:8000});
|
|
}
|
|
if(missingOutputDevice || newOutputDevice) {
|
|
context.JK.prodBubble($audioOutput.closest('.easydropdown-wrapper'), 'gear-wizard-outputs-changed', {missingOutputDevice: missingOutputDevice, newOutputDevice: newOutputDevice}, {positions:[ 'top'], duration:8000});
|
|
}
|
|
}
|
|
}
|
|
|
|
// repair channel selections, because the backend cleared them in RebuildAudioSystem
|
|
reassignInputChannels();
|
|
reassignOutputChannels();
|
|
}
|
|
|
|
function cancelRescan() {
|
|
if(cancelRescanFunc) {
|
|
cancelRescanFunc();
|
|
cancelRescanFunc = null;
|
|
}
|
|
}
|
|
|
|
function scheduleRescanSystem(after, time, checkingForGear) {
|
|
|
|
cancelRescanFunc = gearUtils.scheduleAudioRestart('gear-wizard-select-gear', time,
|
|
function() {
|
|
freezeAudioInteraction();
|
|
$resyncBtn.addClass('scanning').text('RESYNC')
|
|
|
|
$resyncStatusText.text(checkingForGear ? 'CHECKING GEAR' : 'RESYNCING...');
|
|
$resyncStatus.show();
|
|
},
|
|
function(cancel) {
|
|
$resyncBtn.removeClass('scanning').text('RESYNC')
|
|
unfreezeAudioInteraction();
|
|
$resyncStatus.hide();
|
|
|
|
if(!cancel) {
|
|
rescan();
|
|
|
|
if(after) {
|
|
after();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// 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) {
|
|
$adjustSettingsLink.hide();
|
|
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;
|
|
}
|
|
|
|
// further, check if we have both inputs and outputs defined; if so, show ? to allow launch of adjust gear settings dialog
|
|
if(modUtils.getGear('show_frame_options')) {
|
|
$adjustSettingsLink.show();
|
|
}
|
|
|
|
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 || modUtils.getGear('show_frame_options'))) {
|
|
$knobs.show();
|
|
}
|
|
else {
|
|
$knobs.hide();
|
|
$adjustSettingsLink.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();
|
|
}
|
|
|
|
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() {
|
|
gearUtils.updateDefaultBuffers(selectedDeviceInfo, frameBuffers)
|
|
}
|
|
|
|
// 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);
|
|
if(queueUpdateDeviceList) {
|
|
queueUpdateDeviceList = false;
|
|
updateDeviceList();
|
|
}
|
|
}
|
|
|
|
function getLastAudioTestFailAnalytics() {
|
|
return lastFailureAnalytics;
|
|
}
|
|
|
|
function storeLastFailureForAnalytics(platform, reason, data) {
|
|
if(!trackedPass) {
|
|
lastFailureAnalytics = {
|
|
platform: platform,
|
|
reason: reason,
|
|
data: data
|
|
}
|
|
}
|
|
}
|
|
|
|
function prodUserToTweakASIOSettings($btn) {
|
|
setTimeout(function() {
|
|
context.JK.prodBubble($btn, 'tweak-asio-settings', {}, {positions:['top']});
|
|
}, 300)
|
|
}
|
|
|
|
function onGearTestFail(e, data) {
|
|
renderScoringStopped();
|
|
gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
|
|
|
|
if(data.reason == "latency") {
|
|
|
|
console.log("selectedDeviceInfo", selectedDeviceInfo)
|
|
if(selectedDeviceInfo.input.info.type.indexOf('Win32_asio') > -1) {
|
|
prodUserToTweakASIOSettings($asioInputControlBtn)
|
|
}
|
|
else if(selectedDeviceInfo.output.info.type.indexOf('Win32_asio') > -1) {
|
|
prodUserToTweakASIOSettings($asioOutputControlBtn)
|
|
}
|
|
|
|
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 if(data.reason == 'invalid_configuration') {
|
|
if(data.data.reason == 'device_failure') {
|
|
|
|
var specificErrors = [];
|
|
if(selectedDeviceInfo.input.id == selectedDeviceInfo.output.id && data.data.input) {
|
|
specificErrors.push("The configured device (" + selectedDeviceInfo.input.info.displayName + ") is not connected or not functioning.");
|
|
}
|
|
else {
|
|
if(data.data.input) {
|
|
specificErrors.push("The configured input device (" + selectedDeviceInfo.input.info.displayName + ") is not connected or not functioning.");
|
|
}
|
|
if(data.data.output) {
|
|
specificErrors.push("The configured output device (" + selectedDeviceInfo.output.info.displayName + ") is not connected or not functioning.");
|
|
}
|
|
}
|
|
|
|
var specificResolutions = [];
|
|
|
|
if(selectedDeviceInfo.input.info.type.indexOf('Win32_asio') > -1 || selectedDeviceInfo.output.info.type.indexOf('Win32_asio') > -1) {
|
|
// specificResolutions.push("Read over this <a rel='external' href='https://jamkazam.desk.com/customer/portal/articles/1723489-jamkazam-thinks-your-gear-is-disconnected---windows-only'>article</a>")
|
|
specificResolutions.push("Select the ASIO SETTINGS... button and try different settings.");
|
|
}
|
|
|
|
if(selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm') {
|
|
// specificResolutions.push("Read over this <a rel='external' href='https://jamkazam.desk.com/customer/portal/articles/1723489-jamkazam-thinks-your-gear-is-disconnected---windows-only'>article</a>")
|
|
specificResolutions.push("Change the Frame, Buffer In, or Buffer Out settings.");
|
|
}
|
|
|
|
specificResolutions.push("Reconnect the device if possible.");
|
|
specificResolutions.push("Restart the JamKazam application.");
|
|
specificResolutions.push("Make sure you have the latest drivers installed for your gear.");
|
|
specificResolutions.push("In rare cases, restarting your computer can help.");
|
|
|
|
context.JK.Banner.showAlert('Invalid Audio Device',
|
|
$(context._.template($templateDeviceNotValid.html(), {specific_errors: specificErrors, specific_resolutions: specificResolutions }, { variable: 'data' })));
|
|
}
|
|
else {
|
|
context.JK.alertSupportedNeeded("Unable to configure device. " + data.data)
|
|
}
|
|
}
|
|
else {
|
|
logger.error("unknown reason in onGearTestFail: " + data.reason)
|
|
}
|
|
|
|
if(queueUpdateDeviceList) {
|
|
queueUpdateDeviceList = false;
|
|
updateDeviceList();
|
|
}
|
|
}
|
|
|
|
function onGearTestInvalidated(e, data) {
|
|
initializeNextButtonState();
|
|
}
|
|
|
|
function handleHelp() {
|
|
if(operatingSystem == "Win32") {
|
|
return "https://jamkazam.desk.com/customer/portal/articles/1599818-first-time-setup---step-2---select-and-test-audio-gear---windows-";
|
|
}
|
|
else {
|
|
return "https://jamkazam.desk.com/customer/portal/articles/1599845-first-time-setup---step-2---select-and-test-audio-gear---mac";
|
|
}
|
|
}
|
|
|
|
function handleNext() {
|
|
|
|
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;
|
|
}
|
|
|
|
if(!savedProfile) {
|
|
context.jamClient.FTUESetMusicProfileName(gearUtils.createProfileName(selectedDeviceInfo));
|
|
var result = context.jamClient.FTUESave(true);
|
|
if(result && result.error) {
|
|
// failed
|
|
logger.warn("unable to FTUESave(true). reason:" + result.detail);
|
|
context.JK.alertSupportedNeeded("Unable to persist the audio profile. " + result.detail);
|
|
return false;
|
|
}
|
|
else {
|
|
context.JK.GA.trackAudioTestCompletion(context.JK.detectOS());
|
|
trackedPass = true;
|
|
lastFailureAnalytics = null;
|
|
savedProfile = true;
|
|
}
|
|
}
|
|
// keep the shared state between step 2 and step 3 up-to-date
|
|
wizard.setChosenInputs(context._.map($assignedInputs, function(input) { return $(input).attr('data-id') }));
|
|
return true;
|
|
}
|
|
|
|
function onFocus() {
|
|
if(validDevice && !loopbackShowing && !adjustGearSettingsShowing && !gearTest.isScoring() && getSelectedInputs().length > 0 && getSelectedOutputs().length == 2 ) {
|
|
scheduleRescanSystem(function() { attemptScore(true); }, 3000, false)
|
|
}
|
|
}
|
|
|
|
function newSession() {
|
|
savedProfile = false;
|
|
initialScan = false;
|
|
deviceInformation = gearUtils.loadDeviceInfo();
|
|
resetState();
|
|
initializeFormElements();
|
|
initializeNextButtonState();
|
|
initializeWatchVideo();
|
|
initializeASIOButtons();
|
|
initializeResync();
|
|
}
|
|
|
|
function beforeWizardShow() {
|
|
lastFailureAnalytics = null;
|
|
trackedPass = false;
|
|
}
|
|
|
|
function beforeShow() {
|
|
$(window).on('focus', onFocus);
|
|
context.JK.onBackendEvent(ALERT_NAMES.USB_CONNECTED, 'select-gear', onUsbDeviceConnected);
|
|
context.JK.onBackendEvent(ALERT_NAMES.USB_DISCONNECTED, 'select-gear', onUsbDeviceDisconnected);
|
|
|
|
initializeNextButtonState();
|
|
context.JK.onBackendEvent(ALERT_NAMES.AUDIO_DEVICE_NOT_PRESENT, 'gear_test', gearTest.onInvalidAudioDevice);
|
|
|
|
if(!initialScan) {
|
|
scheduleRescanSystem(null, 3000, true);
|
|
initialScan = true;
|
|
}
|
|
}
|
|
|
|
function beforeHide() {
|
|
cancelRescan();
|
|
logger.debug("unregistering focus watch")
|
|
context.JK.offBackendEvent(ALERT_NAMES.USB_CONNECTED, 'select-gear', onUsbDeviceConnected);
|
|
context.JK.offBackendEvent(ALERT_NAMES.USB_DISCONNECTED, 'select-gear', onUsbDeviceDisconnected);
|
|
$(window).off('focus', onFocus);
|
|
context.JK.offBackendEvent(ALERT_NAMES.AUDIO_DEVICE_NOT_PRESENT, 'gear_test', gearTest.onInvalidAudioDevice);
|
|
}
|
|
|
|
function onUsbDeviceConnected() {
|
|
if(!context.jamClient.IsFrontendVisible()) {return;} // don't handle USB events when minimized
|
|
|
|
updateDeviceList();
|
|
}
|
|
|
|
function onUsbDeviceDisconnected() {
|
|
if(!context.jamClient.IsFrontendVisible()) {return;} // don't handle USB events when minimized
|
|
|
|
updateDeviceList();
|
|
}
|
|
|
|
function updateDeviceList() {
|
|
if(gearTest.isScoring()) {
|
|
queueUpdateDeviceList = true;
|
|
}
|
|
else {
|
|
scheduleRescanSystem(null, 5000, false);
|
|
}
|
|
}
|
|
function resetState() {
|
|
selectedDeviceInfo = null;
|
|
invalidateScore();
|
|
clearInputPorts();
|
|
clearOutputPorts();
|
|
frameBuffers.resetValues();
|
|
updateDialogForCurrentDevices();
|
|
}
|
|
|
|
function assertFTUEProfile() {
|
|
if(savedProfile) {return;} // once we save the profile, it's name no longer starts with FTUE
|
|
var profileName = context.jamClient.FTUEGetMusicProfileName();
|
|
|
|
if(profileName && profileName.indexOf('FTUE') != 0) {
|
|
logger.debug("the profile name *must* start with FTUE during step 2. name=" + profileName)
|
|
context.JK.alertSupportedNeeded('The application is no longer modifying a new profile. Please restart the application and try the gear wizard again.');
|
|
}
|
|
}
|
|
|
|
function initialize(_$step, _wizard) {
|
|
$step = _$step;
|
|
wizard = _wizard;
|
|
|
|
$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');
|
|
$templateDeviceNotValid = $('#device-not-valid');
|
|
|
|
$inputChannels = $step.find('.input-ports');
|
|
$outputChannels = $step.find('.output-ports');
|
|
$knobs = $step.find('.frame-and-buffers');
|
|
$adjustSettingsLink = $knobs.find('.adjust-gear-settings')
|
|
$adjustGearForIoFail = $step.find(".adjust-gear-for-io-fail")
|
|
$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 = $step.find('.loopback-test');
|
|
$instructions = $step.find('.instructions');
|
|
$resyncStatus = $step.find('.resync-status');
|
|
$resyncStatusText = $step.find('.resynctext');
|
|
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)
|
|
.on(frameBuffers.ADJUST_GEAR_LINK_CLICKED, onAdjustGearRequested)
|
|
|
|
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)
|
|
$adjustGearForIoFail.click(onAdjustGearRequested);
|
|
}
|
|
|
|
this.getLastAudioTestFailAnalytics = getLastAudioTestFailAnalytics;
|
|
this.handleNext = handleNext;
|
|
this.newSession = newSession;
|
|
this.handleHelp = handleHelp;
|
|
this.beforeShow = beforeShow;
|
|
this.beforeHide = beforeHide;
|
|
this.beforeWizardShow = beforeWizardShow;
|
|
this.initialize = initialize;
|
|
|
|
self = this;
|
|
return this;
|
|
};
|
|
|
|
})(window, jQuery); |