Skip to content

Commit

Permalink
Implement UI for controlling ATEN-specific settings
Browse files Browse the repository at this point in the history
Add video settings change callback to Ast2100Decoder for UI integration.

Implement slider widget (used to select AST2100 quantization tables).
  • Loading branch information
kelleyk committed Jan 17, 2017
1 parent 0d048ac commit eb386b7
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 25 deletions.
5 changes: 5 additions & 0 deletions app/styles/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ input[type=button]:active, select:active {
background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250));
}

/* Settings slider: video quality (quantization table selector) in AST2100 mode. */
#noVNC_settings #noVNC_setting_ast2100_quality {
margin: 0 10px;
}

/* ----------------------------------------
* WebKit centering hacks
* ----------------------------------------
Expand Down
107 changes: 105 additions & 2 deletions app/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ var UI;
lastKeyboardinput: null,
defaultKeyboardinputLen: 100,

// True if we are connected to an ATEN iKVM server speaking the AST2100 video encoding.
// This variable tracks whether the extra UI elements used to configure video settings
// for the AST2100 encoding have been shown yet; it's set on the first FramebufferUpdate
// message that we receive.
_ast2100_videoSettingsInitialized: false,

// Setup rfb object, load settings from browser storage, then call
// UI.init to setup the UI/menus
load: function(callback) {
Expand Down Expand Up @@ -392,7 +398,9 @@ var UI;
'onBell': UI.bell,
'onFBUComplete': UI.initialResize,
'onFBResize': UI.updateSessionSize,
'onDesktopName': UI.updateDesktopName});
'onDesktopName': UI.updateDesktopName,
'ast2100_onVideoSettingsChanged': UI.ast2100_handleVideoSettingsChanged
});
return true;
} catch (exc) {
var msg = "Unable to create RFB client -- " + exc;
Expand Down Expand Up @@ -436,7 +444,9 @@ var UI;
document.documentElement.classList.add("noVNC_disconnecting");
break;
case 'disconnected':
UI.connected = false;
UI.showStatus(_("Disconnected"));
UI.ast2100_reset();
break;
default:
msg = "Invalid UI state";
Expand Down Expand Up @@ -843,6 +853,15 @@ var UI;
UI.saveSetting('path');
UI.saveSetting('repeaterID');
UI.saveSetting('logging');

if (UI._ast2100_videoSettingsInitialized) {
var videoSettings = UI.ast2100_getConfiguredSettings();
if (videoSettings != UI._ast2100_serverVideoSettings)
UI.rfb.atenChangeVideoSettings(
videoSettings.quantTableSelectorLuma,
videoSettings.quantTableSelectorChroma,
videoSettings.subsamplingMode);
}

// Settings with immediate (non-connected related) effect
WebUtil.init_logging(UI.getSetting('logging'));
Expand Down Expand Up @@ -963,9 +982,93 @@ var UI;
/* ------^-------
* /XVP
* ==============
* CLIPBOARD
* AST2100
* ------v------*/

ast2100_handleVideoSettingsChanged: function (settings) {
if (!UI._ast2100_videoSettingsInitialized)
UI.ast2100_setDefaultSettings(settings);
UI.ast2100_updateVideoSettings(settings);
},

// Called the first time we receive a FramebufferUpdate object. Responsible
// for telling the server about any configured default settings.
ast2100_setDefaultSettings: function (settings) {
// Convert the settings that noVNC has been configured to set for all
// AST2100 servers to the familiar videoSettings format.
var defaultQuality = parseInt(UI.ast2100_quality);
var defaultSettings = {
quantTableSelectorLuma: defaultQuality,
quantTableSelectorChroma: defaultQuality,
subsamplingMode: parseInt(UI.ast2100_subsamplingMode)
};

// If defaults were not given or were invalid, stick with what the
// server is already using.
if (!(defaultSettings.subsamplingMode == 422 || defaultSettings.subsamplingMode == 444))
defaultSettings.subsamplingMode = settings.subsamplingMode;
if (!inRangeIncl(defaultQuality, 0x0, 0xB)) {
defaultSettings.quantTableSelectorLuma = settings.quantTableSelectorLuma;
defaultSettings.quantTableSelectorChroma = settings.quantTableSelectorChroma;
}

if (defaultSettings != settings)
UI.rfb.atenChangeVideoSettings(
defaultSettings.quantTableSelectorLuma,
defaultSettings.quantTableSelectorChroma,
defaultSettings.subsamplingMode);
},

// Should be called at init time and after disconnects. This is sort
// of the opposite of _init().
ast2100_reset: function() {
document.getElementById("noVNC_ast2100_settings").classList.add('noVNC_hidden');
UI._ast2100_videoSettingsInitialized = false;
UI._ast2100_serverVideoSettings = undefined;
},

// Updates the UI to reflect values received from the server.
ast2100_updateVideoSettings: function (videoSettings) {
Util.Info("AST2100 video settings changed:");
Util.Info(videoSettings);

// We use this to tell if the user changed anything when they apply
// settings.
UI._ast2100_serverVideoSettings = videoSettings;

// First run: tell UI to show video quality controls, now that we
// know we are on a machine that supports them, and we know their
// current values.
if (!UI._ast2100_videoSettingsInitialized) {
document.getElementById("noVNC_ast2100_settings").classList.remove('noVNC_hidden');
UI._ast2100_videoSettingsInitialized = true;
}

// Average the two quant table selectors as a poor way of dealing
// with the fact that they can, technically, be different.
var quality = ~~((videoSettings.quantTableSelectorLuma + videoSettings.quantTableSelectorChroma) / 2);
document.getElementById("noVNC_setting_ast2100_quality").value = quality;

// Either 444 or 422 (which is really 4:2:0).
document.getElementById("noVNC_setting_ast2100_subsampling").value = videoSettings.subsamplingMode;
},

// Returns the current state of the UI.
ast2100_getConfiguredSettings: function () {
var quality = +document.getElementById("noVNC_setting_ast2100_quality").value;
return {
quantTableSelectorLuma: quality,
quantTableSelectorChroma: quality,
subsamplingMode: +document.getElementById("noVNC_setting_ast2100_subsampling").value
};
},

/* ------^-------
* /AST2100
* ==============
* CLIPBOARD
* ------v------*/

openClipboardPanel: function() {
UI.closeAllPanels();
UI.openControlbar();
Expand Down
22 changes: 22 additions & 0 deletions core/ast2100/ast2100.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var Ast2100Decoder;
Ast2100Decoder = function (defaults) {

this._blitCallback = defaults.blitCallback;
this._videoSettingsChangedCallback = defaults.videoSettingsChangedCallback;
this._frame_width = defaults.width;
this._frame_height = defaults.height;

Expand Down Expand Up @@ -157,6 +158,18 @@ var Ast2100Decoder;
this._frame_width = width;
this._frame_height = height;
},

// Each quant table selector is between 0x0 (lowest quality) and 0xB (highest quality). The ATEN client shows a
// single quality slider, which changes both values in tandem. The server sends all three values with each
// FramebufferUpdate message, so these values are updated with every call to decode(). They will be -1 before
// the first frame is decoded.
getVideoSettings: function () {
return {
quantTableSelectorLuma: this._loadedQuantTables[0],
quantTableSelectorChroma: this._loadedQuantTables[1],
subsamplingMode: this.subsamplingMode
};
},

decode: function (data) {

Expand All @@ -174,10 +187,13 @@ var Ast2100Decoder;
var quantTableSelectorLuma = data[0]; // 0 <= x <= 0xB
var quantTableSelectorChroma = data[1]; // 0 <= x <= 0xB
var subsamplingMode = (data[2] << 8) | data[3]; // 422u or 444u

var changedSettings = false;
if (this.subsamplingMode != subsamplingMode) {
if (verboseVideoSettings)
console.log('decode(): new subsampling mode: '+subsamplingMode);
this.subsamplingMode = subsamplingMode;
changedSettings = true;
}

// The remainder of the stream is byte-swapped in four-byte chunks.
Expand All @@ -193,6 +209,7 @@ var Ast2100Decoder;
console.log('decode(): loading new luma quant table: '+fmt_u8(quantTableSelectorLuma));
this._loadQuantTable(0, ATEN_QT_LUMA[quantTableSelectorLuma]);
this._loadedQuantTables[0] = quantTableSelectorLuma;
changedSettings = true;
}
if (quantTableSelectorChroma != this._loadedQuantTables[1]) {
if (!inRangeIncl(quantTableSelectorChroma, 0, 0xB))
Expand All @@ -201,9 +218,14 @@ var Ast2100Decoder;
console.log('decode(): loading new chroma quant table: '+fmt_u8(quantTableSelectorChroma));
this._loadQuantTable(1, ATEN_QT_CHROMA[quantTableSelectorChroma]);
this._loadedQuantTables[1] = quantTableSelectorChroma;
changedSettings = true;
}

if (this.subsamplingMode != 422 && this.subsamplingMode != 444)
throw 'Unexpected value for subsamplingMode: 0x' + fmt_u16(this.subsamplingMode);

if (changedSettings && this._videoSettingsChangedCallback)
this._videoSettingsChangedCallback(this.getVideoSettings());

// The remainder of the stream is byte-swapped in four-byte chunks. BitStream takes care of this.
this._stream = new BitStream({data: data});
Expand Down
Loading

2 comments on commit eb386b7

@ashphx
Copy link

@ashphx ashphx commented on eb386b7 Apr 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very awesome, one small thing i noticed anyways, when trying to use the password url param with vnc_auto.html, get a weird message about unsupported security. i am not a nodejs person, i ended up hacking around it happy to make a pull request to your repo but its really gross so i dont think you would like it:)

@kelleyk
Copy link
Owner Author

@kelleyk kelleyk commented on eb386b7 May 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the note! Would you mind opening an issue, and describing the exact commit that you're using and the hardware and BMC software version that you're trying to connect to? Thanks in advance!

Please sign in to comment.