383 lines
16 KiB
JavaScript
383 lines
16 KiB
JavaScript
/**
|
|
* FtueAudioSelectionScreen
|
|
* Javascript that goes with the screen where initial
|
|
* selection of the audio devices takes place.
|
|
* Corresponds to /#ftue2
|
|
*/
|
|
(function(context,$) {
|
|
|
|
"use strict";
|
|
|
|
context.JK = context.JK || {};
|
|
context.JK.FtueWizard = function(app) {
|
|
context.JK.FtueWizard.latencyTimeout = true;
|
|
context.JK.FtueWizard.latencyMS = Number.MAX_VALUE;
|
|
|
|
var logger = context.JK.logger;
|
|
var jamClient = context.jamClient;
|
|
var win32 = true;
|
|
|
|
var deviceSetMap = {
|
|
'audio-input': jamClient.FTUESetMusicInput,
|
|
'audio-output': jamClient.FTUESetMusicOutput,
|
|
'voice-chat-input': jamClient.FTUESetChatInput
|
|
};
|
|
|
|
var faderMap = {
|
|
'ftue-audio-input-fader': jamClient.FTUESetInputVolume,
|
|
'ftue-voice-input-fader': jamClient.FTUESetChatInputVolume,
|
|
'ftue-audio-output-fader': jamClient.FTUESetOutputVolume
|
|
};
|
|
|
|
function latencyTimeoutCheck() {
|
|
if (context.JK.FtueWizard.latencyTimeout) {
|
|
jamClient.FTUERegisterLatencyCallback('');
|
|
context.JK.app.setWizardStep("5");
|
|
}
|
|
}
|
|
|
|
function afterHide(data) {
|
|
// Unsubscribe from FTUE VU callbacks.
|
|
jamClient.FTUERegisterVUCallbacks('','','');
|
|
}
|
|
|
|
function beforeShow(data) {
|
|
var vuMeters = [
|
|
'#ftue-audio-input-vu-left',
|
|
'#ftue-audio-input-vu-right',
|
|
'#ftue-voice-input-vu-left',
|
|
'#ftue-voice-input-vu-right',
|
|
'#ftue-audio-output-vu-left',
|
|
'#ftue-audio-output-vu-right'
|
|
];
|
|
$.each(vuMeters, function() {
|
|
context.JK.VuHelpers.renderVU(this,
|
|
{vuType:"horizontal", lightCount: 12, lightWidth: 15, lightHeight: 3});
|
|
});
|
|
|
|
var faders = context._.keys(faderMap);
|
|
$.each(faders, function() {
|
|
var fid = this;
|
|
context.JK.FaderHelpers.renderFader('#' + fid,
|
|
{faderId: fid, faderType:"horizontal", width:163});
|
|
});
|
|
context.JK.FaderHelpers.subscribe('ftue', faderChange);
|
|
}
|
|
|
|
function afterShow(data) {}
|
|
|
|
function faderChange(faderId, newValue, dragging) {
|
|
var setFunction = faderMap[faderId];
|
|
// TODO - using hardcoded range of -80 to 20 for output levels.
|
|
var mixerLevel = newValue - 80; // Convert our [0-100] to [-80 - +20] range
|
|
setFunction(mixerLevel);
|
|
}
|
|
|
|
function settingsInit() {
|
|
jamClient.FTUEInit();
|
|
// Set all mixer levels to -80
|
|
// Using the Session* apis to do so.
|
|
var trackIds = jamClient.SessionGetIDs();
|
|
var controlStates = jamClient.SessionGetControlState(trackIds);
|
|
$.each(controlStates, function(index, value) {
|
|
context.JK.Mixer.fillTrackVolume(value, false);
|
|
context.trackVolumeObject.volL = -80;
|
|
context.trackVolumeObject.volR = -80;
|
|
jamClient.SessionSetControlState(trackIds[index]);
|
|
});
|
|
}
|
|
|
|
function updateGauge() {
|
|
var latencyMS = context.JK.FtueWizard.latencyMS;
|
|
logger.debug("Latency Value: " + latencyMS);
|
|
if (latencyMS > 20) {
|
|
$('#ftue-latency-congrats').hide();
|
|
$('#ftue-latency-fail').show();
|
|
} else {
|
|
$('#ftue-latency-ms').html(latencyMS);
|
|
$('#ftue-latency-congrats').show();
|
|
$('#ftue-latency-fail').hide();
|
|
if (latencyMS <= 10) {
|
|
$('[layout-wizard-step="6"] .btnHelp').hide();
|
|
$('[layout-wizard-step="6"] .btnRepeat').hide();
|
|
}
|
|
setNeedleValue(latencyMS);
|
|
}
|
|
}
|
|
|
|
// Function to calculate an absolute value and an absolute value range into
|
|
// a number of degrees on a circualar "speedometer" gauge. The 0 degrees value
|
|
// points straight up to the middle of the real-world value range.
|
|
// Arguments:
|
|
// value: The real-world value (e.g. 20 milliseconds)
|
|
// minValue: The real-world minimum value (e.g. 0 milliseconds)
|
|
// maxValue: The real-world maximum value (e.g. 40 milliseconds)
|
|
// degreesUsed: The number of degrees used to represent the full real-world
|
|
// range. 360 would be the entire circle. 270 would be 3/4ths
|
|
// of the circle. The unused gap will be at the bottom of the
|
|
// gauge.
|
|
// (e.g. 300)
|
|
function degreesFromRange(value, minValue, maxValue, degreesUsed) {
|
|
if (value > maxValue) { value = maxValue; }
|
|
if (value < minValue) { value = minValue; }
|
|
var range = maxValue-minValue;
|
|
var floatVal = value/range;
|
|
var degrees = Math.round(floatVal * degreesUsed);
|
|
degrees -= Math.round(degreesUsed/2);
|
|
if (degrees < 0) {
|
|
degrees += 360;
|
|
}
|
|
return degrees;
|
|
}
|
|
|
|
// Given a number of MS, and assuming the gauge has a range from
|
|
// 0 to 40 ms. Update the gauge to the proper value.
|
|
function setNeedleValue(ms) {
|
|
var deg = degreesFromRange(ms, 0, 40, 300);
|
|
|
|
// Supporting Firefix, Chrome, Safari, Opera and IE9+.
|
|
// Should we need to support < IE9, this will need more work
|
|
// to compute the matrix transformations in those browsers -
|
|
// and I don't believe they support transparent PNG graphic
|
|
// rotation, so we'll have to change the needle itself.
|
|
var css = {
|
|
//"behavior":"url(-ms-transform.htc)",
|
|
/* Firefox */
|
|
"-moz-transform":"rotate(" + deg + "deg)",
|
|
/* Safari and Chrome */
|
|
"-webkit-transform":"rotate(" + deg + "deg)",
|
|
/* Opera */
|
|
"-o-transform":"rotate(" + deg + "deg)",
|
|
/* IE9 */
|
|
"-ms-transform":"rotate(" + deg + "deg)"
|
|
/* IE6,IE7 */
|
|
//"filter": "progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)",
|
|
/* IE8 */
|
|
//"-ms-filter": '"progid:DXImageTransform.Microsoft.Matrix(SizingMethod=\'auto expand\', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"'
|
|
};
|
|
|
|
$('#ftue-latency-numerical').html(ms);
|
|
$('#ftue-latency-needle').css(css);
|
|
|
|
}
|
|
|
|
function testLatency() {
|
|
// we'll just register for call back right here and unregister in the callback.
|
|
context.JK.FtueWizard.latencyTimeout = true;
|
|
var cbFunc = 'JK.ftueLatencyCallback';
|
|
logger.debug("Registering latency callback: " + cbFunc);
|
|
jamClient.FTUERegisterLatencyCallback('JK.ftueLatencyCallback');
|
|
var now = new Date();
|
|
logger.debug("Starting Latency Test..." + now);
|
|
context.setTimeout(latencyTimeoutCheck, 5000); // Timeout in 5 seconds
|
|
jamClient.FTUEStartLatency();
|
|
}
|
|
|
|
function openASIOControlPanel(evt) {
|
|
if (win32) {
|
|
jamClient.FTUEOpenControlPanel();
|
|
}
|
|
}
|
|
|
|
function asioResync(evt) {
|
|
jamClient.FTUESave();
|
|
}
|
|
|
|
function setAsioFrameSize(evt) {
|
|
var val = $(evt.currentTarget).val();
|
|
jamClient.FTUESetFrameSize(val);
|
|
}
|
|
function setAsioInputLatency(evt) {
|
|
var val = $(evt.currentTarget).val();
|
|
jamClient.FTUESetInputLatency(val);
|
|
}
|
|
function setAsioOutputLatency(evt) {
|
|
var val = $(evt.currentTarget).val();
|
|
jamClient.FTUESetOutputLatency(val);
|
|
}
|
|
|
|
function events() {
|
|
$('[layout-wizard-step="2"] .settings-driver select').on('change', audioDriverChanged);
|
|
$('[layout-wizard-step="2"] .settings-controls select').on('change', audioDeviceChanged);
|
|
$('#btn-asio-control-panel').on('click', openASIOControlPanel);
|
|
$('#btn-asio-resync').on('click', asioResync);
|
|
$('#asio-framesize').on('change', setAsioFrameSize);
|
|
$('#asio-input-latency').on('change', setAsioInputLatency);
|
|
$('#asio-output-latency').on('change', setAsioOutputLatency);
|
|
}
|
|
|
|
/**
|
|
* This function loads the available audio devices from jamClient, and
|
|
* builds up the select dropdowns in the audio-settings step of the FTUE wizard.
|
|
*/
|
|
function loadAudioDevices() {
|
|
var funcs = [
|
|
jamClient.FTUEGetMusicInputs,
|
|
jamClient.FTUEGetChatInputs,
|
|
jamClient.FTUEGetMusicOutputs
|
|
];
|
|
var selectors = [
|
|
'[layout-wizard-step="2"] .audio-input select',
|
|
'[layout-wizard-step="2"] .voice-chat-input select',
|
|
'[layout-wizard-step="2"] .audio-output select'
|
|
];
|
|
var optionsHtml = '';
|
|
var deviceOptionFunc = function(deviceKey, index, list) {
|
|
optionsHtml += '<option value="' + deviceKey + '">' +
|
|
devices[deviceKey] + '</option>';
|
|
};
|
|
for (var i=0; i<funcs.length; i++) {
|
|
optionsHtml = '<option selected="selected" value="">Choose...</option>';
|
|
var devices = funcs[i](); // returns hash of device id: device name
|
|
var $select = $(selectors[i]);
|
|
$select.empty();
|
|
var sortedDeviceKeys = context._.keys(devices).sort();
|
|
context._.each(sortedDeviceKeys, deviceOptionFunc);
|
|
$select.html(optionsHtml);
|
|
$select.removeAttr("disabled");
|
|
$('[layout-wizard-step="2"] .settings-asio select').removeAttr("disabled");
|
|
// Set selects to lowest possible values to start:
|
|
$('#asio-framesize').val('2.5').change();
|
|
$('#asio-input-latency').val('120').change();
|
|
$('#asio-output-latency').val('120').change();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load available drivers and populate the driver select box.
|
|
*/
|
|
function loadAudioDrivers() {
|
|
|
|
var drivers = jamClient.FTUEGetDevices();
|
|
|
|
var driverOptionFunc = function(driverKey, index, list) {
|
|
optionsHtml += '<option value="' + driverKey + '">' +
|
|
drivers[driverKey] + '</option>';
|
|
};
|
|
|
|
var optionsHtml = '<option selected="selected" value="">Choose...</option>';
|
|
var $select = $('[layout-wizard-step="2"] .settings-driver select');
|
|
$select.empty();
|
|
var sortedDeviceKeys = context._.keys(drivers).sort();
|
|
context._.each(sortedDeviceKeys, driverOptionFunc);
|
|
$select.html(optionsHtml);
|
|
}
|
|
|
|
function audioDriverChanged(evt) {
|
|
var $select = $(evt.currentTarget);
|
|
var driverId = $select.val();
|
|
jamClient.FTUESetMusicDevice(driverId);
|
|
loadAudioDevices();
|
|
}
|
|
|
|
function audioDeviceChanged(evt) {
|
|
var $select = $(evt.currentTarget);
|
|
var device = $select.data('device');
|
|
var deviceId = $select.val();
|
|
// Note: We always set, even on the "Choose" value of "", which clears
|
|
// the current setting.
|
|
var setFunction = deviceSetMap[device];
|
|
setFunction(deviceId);
|
|
|
|
if (musicInAndOutSet()) {
|
|
jamClient.FTUESave();
|
|
setVuCallbacks();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return a boolean indicating whether both the MusicInput
|
|
* and MusicOutput devices are set.
|
|
*/
|
|
function musicInAndOutSet() {
|
|
var audioInput = $('[layout-wizard-step="2"] .audio-input select').val();
|
|
var audioOutput = $('[layout-wizard-step="2"] .audio-output select').val();
|
|
return (audioInput && audioOutput);
|
|
}
|
|
|
|
function setVuCallbacks() {
|
|
// jamClient.FTUERegisterVUCallbacks(
|
|
// output_callback, input_callback, chat_input_callback);
|
|
jamClient.FTUERegisterVUCallbacks(
|
|
"JK.ftueAudioOutputVUCallback",
|
|
"JK.ftueAudioInputVUCallback",
|
|
"JK.ftueChatInputVUCallback"
|
|
);
|
|
jamClient.SetVURefreshRate(200);
|
|
}
|
|
|
|
function initialize() {
|
|
// If not on windows, hide ASIO settings
|
|
if (jamClient.GetOSAsString() != "Win32") {
|
|
logger.debug("Not on Win32 - modifying UI for Mac/Linux");
|
|
win32 = false;
|
|
$('[layout-wizard-step="2"] p[os="win32"]').hide();
|
|
$('[layout-wizard-step="2"] p[os="mac"]').show();
|
|
$('[layout-wizard-step="2"] .settings-driver').hide();
|
|
// Slide columns:
|
|
$('[layout-wizard-step="2"] .settings-asio').addClass('mac');
|
|
$('[layout-wizard-step="2"] .settings-asio-button').addClass('mac');
|
|
|
|
$('#btn-asio-control-panel').hide();
|
|
$('[layout-wizard-step="2"] .settings-controls select').removeAttr("disabled");
|
|
loadAudioDevices();
|
|
}
|
|
|
|
events();
|
|
var dialogBindings = { 'beforeShow': beforeShow,
|
|
'afterShow': afterShow, 'afterHide': afterHide };
|
|
app.bindDialog('ftue', dialogBindings);
|
|
app.registerWizardStepFunction("2", settingsInit);
|
|
app.registerWizardStepFunction("4", testLatency);
|
|
app.registerWizardStepFunction("6", updateGauge);
|
|
loadAudioDrivers();
|
|
}
|
|
|
|
// Expose publics
|
|
this.initialize = initialize;
|
|
|
|
// Expose degreesFromRange outside for testing
|
|
this._degreesFromRange = degreesFromRange;
|
|
|
|
return this;
|
|
};
|
|
|
|
|
|
|
|
// Common VU updater taking a dbValue (-80 to 20) and a CSS selector for the VU.
|
|
context.JK.ftueVUCallback = function(dbValue, selector) {
|
|
// Convert DB into a value from 0.0 - 1.0
|
|
var floatValue = (dbValue + 80) / 100;
|
|
context.JK.VuHelpers.updateVU(selector, floatValue);
|
|
};
|
|
|
|
context.JK.ftueAudioInputVUCallback = function(dbValue) {
|
|
context.JK.ftueVUCallback(dbValue, '#ftue-audio-input-vu-left');
|
|
context.JK.ftueVUCallback(dbValue, '#ftue-audio-input-vu-right');
|
|
};
|
|
context.JK.ftueAudioOutputVUCallback = function(dbValue) {
|
|
context.JK.ftueVUCallback(dbValue, '#ftue-audio-output-vu-left');
|
|
context.JK.ftueVUCallback(dbValue, '#ftue-audio-output-vu-right');
|
|
};
|
|
context.JK.ftueChatInputVUCallback = function(dbValue) {
|
|
context.JK.ftueVUCallback(dbValue, '#ftue-voice-input-vu-left');
|
|
context.JK.ftueVUCallback(dbValue, '#ftue-voice-input-vu-right');
|
|
};
|
|
|
|
// Latency Callback
|
|
context.JK.ftueLatencyCallback = function(latencyMicroSeconds) {
|
|
// We always show gauge screen if we hit this.
|
|
// Clear out the 'timeout' variable.
|
|
context.JK.FtueWizard.latencyTimeout = false;
|
|
var now = new Date();
|
|
context.console.debug("ftueLatencyCallback: " + now);
|
|
context.JK.FtueWizard.latencyMS = latencyMicroSeconds/1000;
|
|
|
|
// Unregister callback:
|
|
context.jamClient.FTUERegisterLatencyCallback('');
|
|
// Go to 'congrats' screen -- although latency may be too high.
|
|
context.JK.app.setWizardStep("6");
|
|
};
|
|
|
|
|
|
})(window,jQuery); |