matrix-react-sdk
Version:
SDK for matrix.org using React
202 lines (196 loc) • 29 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.MediaDeviceKindEnum = exports.MediaDeviceHandlerEvent = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _events = _interopRequireDefault(require("events"));
var _logger = require("matrix-js-sdk/src/logger");
var _SettingsStore = _interopRequireDefault(require("./settings/SettingsStore"));
var _SettingLevel = require("./settings/SettingLevel");
var _MatrixClientPeg = require("./MatrixClientPeg");
var _languageHandler = require("./languageHandler");
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
// XXX: MediaDeviceKind is a union type, so we make our own enum
let MediaDeviceKindEnum = exports.MediaDeviceKindEnum = /*#__PURE__*/function (MediaDeviceKindEnum) {
MediaDeviceKindEnum["AudioOutput"] = "audiooutput";
MediaDeviceKindEnum["AudioInput"] = "audioinput";
MediaDeviceKindEnum["VideoInput"] = "videoinput";
return MediaDeviceKindEnum;
}({});
let MediaDeviceHandlerEvent = exports.MediaDeviceHandlerEvent = /*#__PURE__*/function (MediaDeviceHandlerEvent) {
MediaDeviceHandlerEvent["AudioOutputChanged"] = "audio_output_changed";
return MediaDeviceHandlerEvent;
}({});
class MediaDeviceHandler extends _events.default {
static get instance() {
if (!MediaDeviceHandler.internalInstance) {
MediaDeviceHandler.internalInstance = new MediaDeviceHandler();
}
return MediaDeviceHandler.internalInstance;
}
static async hasAnyLabeledDevices() {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.some(d => Boolean(d.label));
}
/**
* Gets the available audio input/output and video input devices
* from the browser: a thin wrapper around mediaDevices.enumerateDevices()
* that also returns results by type of devices. Note that this requires
* user media permissions and an active stream, otherwise you'll get blank
* device labels.
*
* Once the Permissions API
* (https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API)
* is ready for primetime, it might help make this simpler.
*
* @return Promise<IMediaDevices> The available media devices
*/
static async getDevices() {
try {
const devices = await navigator.mediaDevices.enumerateDevices();
const output = {
[MediaDeviceKindEnum.AudioOutput]: [],
[MediaDeviceKindEnum.AudioInput]: [],
[MediaDeviceKindEnum.VideoInput]: []
};
devices.forEach(device => output[device.kind].push(device));
return output;
} catch (error) {
_logger.logger.warn("Unable to refresh WebRTC Devices: ", error);
}
}
/**
* Retrieves devices from the SettingsStore and tells the js-sdk to use them
*/
static async loadDevices() {
const audioDeviceId = _SettingsStore.default.getValue("webrtc_audioinput");
const videoDeviceId = _SettingsStore.default.getValue("webrtc_videoinput");
await _MatrixClientPeg.MatrixClientPeg.safeGet().getMediaHandler().setAudioInput(audioDeviceId);
await _MatrixClientPeg.MatrixClientPeg.safeGet().getMediaHandler().setVideoInput(videoDeviceId);
await MediaDeviceHandler.updateAudioSettings();
}
static async updateAudioSettings() {
await _MatrixClientPeg.MatrixClientPeg.safeGet().getMediaHandler().setAudioSettings({
autoGainControl: MediaDeviceHandler.getAudioAutoGainControl(),
echoCancellation: MediaDeviceHandler.getAudioEchoCancellation(),
noiseSuppression: MediaDeviceHandler.getAudioNoiseSuppression()
});
}
setAudioOutput(deviceId) {
_SettingsStore.default.setValue("webrtc_audiooutput", null, _SettingLevel.SettingLevel.DEVICE, deviceId);
this.emit(MediaDeviceHandlerEvent.AudioOutputChanged, deviceId);
}
/**
* This will not change the device that a potential call uses. The call will
* need to be ended and started again for this change to take effect
* @param {string} deviceId
*/
async setAudioInput(deviceId) {
_SettingsStore.default.setValue("webrtc_audioinput", null, _SettingLevel.SettingLevel.DEVICE, deviceId);
return _MatrixClientPeg.MatrixClientPeg.safeGet().getMediaHandler().setAudioInput(deviceId);
}
/**
* This will not change the device that a potential call uses. The call will
* need to be ended and started again for this change to take effect
* @param {string} deviceId
*/
async setVideoInput(deviceId) {
_SettingsStore.default.setValue("webrtc_videoinput", null, _SettingLevel.SettingLevel.DEVICE, deviceId);
return _MatrixClientPeg.MatrixClientPeg.safeGet().getMediaHandler().setVideoInput(deviceId);
}
async setDevice(deviceId, kind) {
switch (kind) {
case MediaDeviceKindEnum.AudioOutput:
this.setAudioOutput(deviceId);
break;
case MediaDeviceKindEnum.AudioInput:
await this.setAudioInput(deviceId);
break;
case MediaDeviceKindEnum.VideoInput:
await this.setVideoInput(deviceId);
break;
}
}
static async setAudioAutoGainControl(value) {
await _SettingsStore.default.setValue("webrtc_audio_autoGainControl", null, _SettingLevel.SettingLevel.DEVICE, value);
await MediaDeviceHandler.updateAudioSettings();
}
static async setAudioEchoCancellation(value) {
await _SettingsStore.default.setValue("webrtc_audio_echoCancellation", null, _SettingLevel.SettingLevel.DEVICE, value);
await MediaDeviceHandler.updateAudioSettings();
}
static async setAudioNoiseSuppression(value) {
await _SettingsStore.default.setValue("webrtc_audio_noiseSuppression", null, _SettingLevel.SettingLevel.DEVICE, value);
await MediaDeviceHandler.updateAudioSettings();
}
static getAudioOutput() {
return _SettingsStore.default.getValueAt(_SettingLevel.SettingLevel.DEVICE, "webrtc_audiooutput");
}
static getAudioInput() {
return _SettingsStore.default.getValueAt(_SettingLevel.SettingLevel.DEVICE, "webrtc_audioinput");
}
static getVideoInput() {
return _SettingsStore.default.getValueAt(_SettingLevel.SettingLevel.DEVICE, "webrtc_videoinput");
}
static getAudioAutoGainControl() {
return _SettingsStore.default.getValue("webrtc_audio_autoGainControl");
}
static getAudioEchoCancellation() {
return _SettingsStore.default.getValue("webrtc_audio_echoCancellation");
}
static getAudioNoiseSuppression() {
return _SettingsStore.default.getValue("webrtc_audio_noiseSuppression");
}
/**
* Returns the current set deviceId for a device kind
* @param {MediaDeviceKindEnum} kind of the device that will be returned
* @returns {string} the deviceId
*/
static getDevice(kind) {
switch (kind) {
case MediaDeviceKindEnum.AudioOutput:
return this.getAudioOutput();
case MediaDeviceKindEnum.AudioInput:
return this.getAudioInput();
case MediaDeviceKindEnum.VideoInput:
return this.getVideoInput();
}
}
static get startWithAudioMuted() {
return _SettingsStore.default.getValue("audioInputMuted");
}
static set startWithAudioMuted(value) {
_SettingsStore.default.setValue("audioInputMuted", null, _SettingLevel.SettingLevel.DEVICE, value);
}
static get startWithVideoMuted() {
return _SettingsStore.default.getValue("videoInputMuted");
}
static set startWithVideoMuted(value) {
_SettingsStore.default.setValue("videoInputMuted", null, _SettingLevel.SettingLevel.DEVICE, value);
}
}
exports.default = MediaDeviceHandler;
(0, _defineProperty2.default)(MediaDeviceHandler, "internalInstance", void 0);
(0, _defineProperty2.default)(MediaDeviceHandler, "getDefaultDevice", devices => {
// Note we're looking for a device with deviceId 'default' but adding a device
// with deviceId == the empty string: this is because Chrome gives us a device
// with deviceId 'default', so we're looking for this, not the one we are adding.
if (!devices.some(i => i.deviceId === "default")) {
devices.unshift({
deviceId: "",
label: (0, _languageHandler._t)("voip|default_device")
});
return "";
} else {
return "default";
}
});
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZXZlbnRzIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfbG9nZ2VyIiwiX1NldHRpbmdzU3RvcmUiLCJfU2V0dGluZ0xldmVsIiwiX01hdHJpeENsaWVudFBlZyIsIl9sYW5ndWFnZUhhbmRsZXIiLCJNZWRpYURldmljZUtpbmRFbnVtIiwiZXhwb3J0cyIsIk1lZGlhRGV2aWNlSGFuZGxlckV2ZW50IiwiTWVkaWFEZXZpY2VIYW5kbGVyIiwiRXZlbnRFbWl0dGVyIiwiaW5zdGFuY2UiLCJpbnRlcm5hbEluc3RhbmNlIiwiaGFzQW55TGFiZWxlZERldmljZXMiLCJkZXZpY2VzIiwibmF2aWdhdG9yIiwibWVkaWFEZXZpY2VzIiwiZW51bWVyYXRlRGV2aWNlcyIsInNvbWUiLCJkIiwiQm9vbGVhbiIsImxhYmVsIiwiZ2V0RGV2aWNlcyIsIm91dHB1dCIsIkF1ZGlvT3V0cHV0IiwiQXVkaW9JbnB1dCIsIlZpZGVvSW5wdXQiLCJmb3JFYWNoIiwiZGV2aWNlIiwia2luZCIsInB1c2giLCJlcnJvciIsImxvZ2dlciIsIndhcm4iLCJsb2FkRGV2aWNlcyIsImF1ZGlvRGV2aWNlSWQiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJ2aWRlb0RldmljZUlkIiwiTWF0cml4Q2xpZW50UGVnIiwic2FmZUdldCIsImdldE1lZGlhSGFuZGxlciIsInNldEF1ZGlvSW5wdXQiLCJzZXRWaWRlb0lucHV0IiwidXBkYXRlQXVkaW9TZXR0aW5ncyIsInNldEF1ZGlvU2V0dGluZ3MiLCJhdXRvR2FpbkNvbnRyb2wiLCJnZXRBdWRpb0F1dG9HYWluQ29udHJvbCIsImVjaG9DYW5jZWxsYXRpb24iLCJnZXRBdWRpb0VjaG9DYW5jZWxsYXRpb24iLCJub2lzZVN1cHByZXNzaW9uIiwiZ2V0QXVkaW9Ob2lzZVN1cHByZXNzaW9uIiwic2V0QXVkaW9PdXRwdXQiLCJkZXZpY2VJZCIsInNldFZhbHVlIiwiU2V0dGluZ0xldmVsIiwiREVWSUNFIiwiZW1pdCIsIkF1ZGlvT3V0cHV0Q2hhbmdlZCIsInNldERldmljZSIsInNldEF1ZGlvQXV0b0dhaW5Db250cm9sIiwidmFsdWUiLCJzZXRBdWRpb0VjaG9DYW5jZWxsYXRpb24iLCJzZXRBdWRpb05vaXNlU3VwcHJlc3Npb24iLCJnZXRBdWRpb091dHB1dCIsImdldFZhbHVlQXQiLCJnZXRBdWRpb0lucHV0IiwiZ2V0VmlkZW9JbnB1dCIsImdldERldmljZSIsInN0YXJ0V2l0aEF1ZGlvTXV0ZWQiLCJzdGFydFdpdGhWaWRlb011dGVkIiwiZGVmYXVsdCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJpIiwidW5zaGlmdCIsIl90Il0sInNvdXJjZXMiOlsiLi4vc3JjL01lZGlhRGV2aWNlSGFuZGxlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMSDFoGltb24gQnJhbmRuZXIgPHNpbW9uLmJyYS5hZ0BnbWFpbC5jb20+XG5Db3B5cmlnaHQgMjAxNyBNaWNoYWVsIFRlbGF0eW5za2kgPDd0M2NoZ3V5QGdtYWlsLmNvbT5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IEV2ZW50RW1pdHRlciBmcm9tIFwiZXZlbnRzXCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5cbmltcG9ydCBTZXR0aW5nc1N0b3JlIGZyb20gXCIuL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7IFNldHRpbmdMZXZlbCB9IGZyb20gXCIuL3NldHRpbmdzL1NldHRpbmdMZXZlbFwiO1xuaW1wb3J0IHsgTWF0cml4Q2xpZW50UGVnIH0gZnJvbSBcIi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQgeyBfdCB9IGZyb20gXCIuL2xhbmd1YWdlSGFuZGxlclwiO1xuXG4vLyBYWFg6IE1lZGlhRGV2aWNlS2luZCBpcyBhIHVuaW9uIHR5cGUsIHNvIHdlIG1ha2Ugb3VyIG93biBlbnVtXG5leHBvcnQgZW51bSBNZWRpYURldmljZUtpbmRFbnVtIHtcbiAgICBBdWRpb091dHB1dCA9IFwiYXVkaW9vdXRwdXRcIixcbiAgICBBdWRpb0lucHV0ID0gXCJhdWRpb2lucHV0XCIsXG4gICAgVmlkZW9JbnB1dCA9IFwidmlkZW9pbnB1dFwiLFxufVxuXG5leHBvcnQgdHlwZSBJTWVkaWFEZXZpY2VzID0gUmVjb3JkPE1lZGlhRGV2aWNlS2luZEVudW0sIEFycmF5PE1lZGlhRGV2aWNlSW5mbz4+O1xuXG5leHBvcnQgZW51bSBNZWRpYURldmljZUhhbmRsZXJFdmVudCB7XG4gICAgQXVkaW9PdXRwdXRDaGFuZ2VkID0gXCJhdWRpb19vdXRwdXRfY2hhbmdlZFwiLFxufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNZWRpYURldmljZUhhbmRsZXIgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICAgIHByaXZhdGUgc3RhdGljIGludGVybmFsSW5zdGFuY2U/OiBNZWRpYURldmljZUhhbmRsZXI7XG5cbiAgICBwdWJsaWMgc3RhdGljIGdldCBpbnN0YW5jZSgpOiBNZWRpYURldmljZUhhbmRsZXIge1xuICAgICAgICBpZiAoIU1lZGlhRGV2aWNlSGFuZGxlci5pbnRlcm5hbEluc3RhbmNlKSB7XG4gICAgICAgICAgICBNZWRpYURldmljZUhhbmRsZXIuaW50ZXJuYWxJbnN0YW5jZSA9IG5ldyBNZWRpYURldmljZUhhbmRsZXIoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gTWVkaWFEZXZpY2VIYW5kbGVyLmludGVybmFsSW5zdGFuY2U7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBhc3luYyBoYXNBbnlMYWJlbGVkRGV2aWNlcygpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgY29uc3QgZGV2aWNlcyA9IGF3YWl0IG5hdmlnYXRvci5tZWRpYURldmljZXMuZW51bWVyYXRlRGV2aWNlcygpO1xuICAgICAgICByZXR1cm4gZGV2aWNlcy5zb21lKChkKSA9PiBCb29sZWFuKGQubGFiZWwpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBhdmFpbGFibGUgYXVkaW8gaW5wdXQvb3V0cHV0IGFuZCB2aWRlbyBpbnB1dCBkZXZpY2VzXG4gICAgICogZnJvbSB0aGUgYnJvd3NlcjogYSB0aGluIHdyYXBwZXIgYXJvdW5kIG1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzKClcbiAgICAgKiB0aGF0IGFsc28gcmV0dXJucyByZXN1bHRzIGJ5IHR5cGUgb2YgZGV2aWNlcy4gTm90ZSB0aGF0IHRoaXMgcmVxdWlyZXNcbiAgICAgKiB1c2VyIG1lZGlhIHBlcm1pc3Npb25zIGFuZCBhbiBhY3RpdmUgc3RyZWFtLCBvdGhlcndpc2UgeW91J2xsIGdldCBibGFua1xuICAgICAqIGRldmljZSBsYWJlbHMuXG4gICAgICpcbiAgICAgKiBPbmNlIHRoZSBQZXJtaXNzaW9ucyBBUElcbiAgICAgKiAoaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL1Blcm1pc3Npb25zX0FQSSlcbiAgICAgKiBpcyByZWFkeSBmb3IgcHJpbWV0aW1lLCBpdCBtaWdodCBoZWxwIG1ha2UgdGhpcyBzaW1wbGVyLlxuICAgICAqXG4gICAgICogQHJldHVybiBQcm9taXNlPElNZWRpYURldmljZXM+IFRoZSBhdmFpbGFibGUgbWVkaWEgZGV2aWNlc1xuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgYXN5bmMgZ2V0RGV2aWNlcygpOiBQcm9taXNlPElNZWRpYURldmljZXMgfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGRldmljZXMgPSBhd2FpdCBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmVudW1lcmF0ZURldmljZXMoKTtcbiAgICAgICAgICAgIGNvbnN0IG91dHB1dDogUmVjb3JkPE1lZGlhRGV2aWNlS2luZEVudW0sIE1lZGlhRGV2aWNlSW5mb1tdPiA9IHtcbiAgICAgICAgICAgICAgICBbTWVkaWFEZXZpY2VLaW5kRW51bS5BdWRpb091dHB1dF06IFtdLFxuICAgICAgICAgICAgICAgIFtNZWRpYURldmljZUtpbmRFbnVtLkF1ZGlvSW5wdXRdOiBbXSxcbiAgICAgICAgICAgICAgICBbTWVkaWFEZXZpY2VLaW5kRW51bS5WaWRlb0lucHV0XTogW10sXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBkZXZpY2VzLmZvckVhY2goKGRldmljZSkgPT4gb3V0cHV0W2RldmljZS5raW5kXS5wdXNoKGRldmljZSkpO1xuICAgICAgICAgICAgcmV0dXJuIG91dHB1dDtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiVW5hYmxlIHRvIHJlZnJlc2ggV2ViUlRDIERldmljZXM6IFwiLCBlcnJvcik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGdldERlZmF1bHREZXZpY2UgPSAoZGV2aWNlczogQXJyYXk8UGFydGlhbDxNZWRpYURldmljZUluZm8+Pik6IHN0cmluZyA9PiB7XG4gICAgICAgIC8vIE5vdGUgd2UncmUgbG9va2luZyBmb3IgYSBkZXZpY2Ugd2l0aCBkZXZpY2VJZCAnZGVmYXVsdCcgYnV0IGFkZGluZyBhIGRldmljZVxuICAgICAgICAvLyB3aXRoIGRldmljZUlkID09IHRoZSBlbXB0eSBzdHJpbmc6IHRoaXMgaXMgYmVjYXVzZSBDaHJvbWUgZ2l2ZXMgdXMgYSBkZXZpY2VcbiAgICAgICAgLy8gd2l0aCBkZXZpY2VJZCAnZGVmYXVsdCcsIHNvIHdlJ3JlIGxvb2tpbmcgZm9yIHRoaXMsIG5vdCB0aGUgb25lIHdlIGFyZSBhZGRpbmcuXG4gICAgICAgIGlmICghZGV2aWNlcy5zb21lKChpKSA9PiBpLmRldmljZUlkID09PSBcImRlZmF1bHRcIikpIHtcbiAgICAgICAgICAgIGRldmljZXMudW5zaGlmdCh7IGRldmljZUlkOiBcIlwiLCBsYWJlbDogX3QoXCJ2b2lwfGRlZmF1bHRfZGV2aWNlXCIpIH0pO1xuICAgICAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gXCJkZWZhdWx0XCI7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmV0cmlldmVzIGRldmljZXMgZnJvbSB0aGUgU2V0dGluZ3NTdG9yZSBhbmQgdGVsbHMgdGhlIGpzLXNkayB0byB1c2UgdGhlbVxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgYXN5bmMgbG9hZERldmljZXMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGF1ZGlvRGV2aWNlSWQgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwid2VicnRjX2F1ZGlvaW5wdXRcIik7XG4gICAgICAgIGNvbnN0IHZpZGVvRGV2aWNlSWQgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwid2VicnRjX3ZpZGVvaW5wdXRcIik7XG5cbiAgICAgICAgYXdhaXQgTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5nZXRNZWRpYUhhbmRsZXIoKS5zZXRBdWRpb0lucHV0KGF1ZGlvRGV2aWNlSWQpO1xuICAgICAgICBhd2FpdCBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpLmdldE1lZGlhSGFuZGxlcigpLnNldFZpZGVvSW5wdXQodmlkZW9EZXZpY2VJZCk7XG5cbiAgICAgICAgYXdhaXQgTWVkaWFEZXZpY2VIYW5kbGVyLnVwZGF0ZUF1ZGlvU2V0dGluZ3MoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBhc3luYyB1cGRhdGVBdWRpb1NldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpLmdldE1lZGlhSGFuZGxlcigpLnNldEF1ZGlvU2V0dGluZ3Moe1xuICAgICAgICAgICAgYXV0b0dhaW5Db250cm9sOiBNZWRpYURldmljZUhhbmRsZXIuZ2V0QXVkaW9BdXRvR2FpbkNvbnRyb2woKSxcbiAgICAgICAgICAgIGVjaG9DYW5jZWxsYXRpb246IE1lZGlhRGV2aWNlSGFuZGxlci5nZXRBdWRpb0VjaG9DYW5jZWxsYXRpb24oKSxcbiAgICAgICAgICAgIG5vaXNlU3VwcHJlc3Npb246IE1lZGlhRGV2aWNlSGFuZGxlci5nZXRBdWRpb05vaXNlU3VwcHJlc3Npb24oKSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIHNldEF1ZGlvT3V0cHV0KGRldmljZUlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcIndlYnJ0Y19hdWRpb291dHB1dFwiLCBudWxsLCBTZXR0aW5nTGV2ZWwuREVWSUNFLCBkZXZpY2VJZCk7XG4gICAgICAgIHRoaXMuZW1pdChNZWRpYURldmljZUhhbmRsZXJFdmVudC5BdWRpb091dHB1dENoYW5nZWQsIGRldmljZUlkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIHdpbGwgbm90IGNoYW5nZSB0aGUgZGV2aWNlIHRoYXQgYSBwb3RlbnRpYWwgY2FsbCB1c2VzLiBUaGUgY2FsbCB3aWxsXG4gICAgICogbmVlZCB0byBiZSBlbmRlZCBhbmQgc3RhcnRlZCBhZ2FpbiBmb3IgdGhpcyBjaGFuZ2UgdG8gdGFrZSBlZmZlY3RcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gZGV2aWNlSWRcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2V0QXVkaW9JbnB1dChkZXZpY2VJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJ3ZWJydGNfYXVkaW9pbnB1dFwiLCBudWxsLCBTZXR0aW5nTGV2ZWwuREVWSUNFLCBkZXZpY2VJZCk7XG4gICAgICAgIHJldHVybiBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpLmdldE1lZGlhSGFuZGxlcigpLnNldEF1ZGlvSW5wdXQoZGV2aWNlSWQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoaXMgd2lsbCBub3QgY2hhbmdlIHRoZSBkZXZpY2UgdGhhdCBhIHBvdGVudGlhbCBjYWxsIHVzZXMuIFRoZSBjYWxsIHdpbGxcbiAgICAgKiBuZWVkIHRvIGJlIGVuZGVkIGFuZCBzdGFydGVkIGFnYWluIGZvciB0aGlzIGNoYW5nZSB0byB0YWtlIGVmZmVjdFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBkZXZpY2VJZFxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZXRWaWRlb0lucHV0KGRldmljZUlkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcIndlYnJ0Y192aWRlb2lucHV0XCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIGRldmljZUlkKTtcbiAgICAgICAgcmV0dXJuIE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkuZ2V0TWVkaWFIYW5kbGVyKCkuc2V0VmlkZW9JbnB1dChkZXZpY2VJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNldERldmljZShkZXZpY2VJZDogc3RyaW5nLCBraW5kOiBNZWRpYURldmljZUtpbmRFbnVtKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHN3aXRjaCAoa2luZCkge1xuICAgICAgICAgICAgY2FzZSBNZWRpYURldmljZUtpbmRFbnVtLkF1ZGlvT3V0cHV0OlxuICAgICAgICAgICAgICAgIHRoaXMuc2V0QXVkaW9PdXRwdXQoZGV2aWNlSWQpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBNZWRpYURldmljZUtpbmRFbnVtLkF1ZGlvSW5wdXQ6XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zZXRBdWRpb0lucHV0KGRldmljZUlkKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgTWVkaWFEZXZpY2VLaW5kRW51bS5WaWRlb0lucHV0OlxuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuc2V0VmlkZW9JbnB1dChkZXZpY2VJZCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGFzeW5jIHNldEF1ZGlvQXV0b0dhaW5Db250cm9sKHZhbHVlOiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJ3ZWJydGNfYXVkaW9fYXV0b0dhaW5Db250cm9sXCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIHZhbHVlKTtcbiAgICAgICAgYXdhaXQgTWVkaWFEZXZpY2VIYW5kbGVyLnVwZGF0ZUF1ZGlvU2V0dGluZ3MoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGFzeW5jIHNldEF1ZGlvRWNob0NhbmNlbGxhdGlvbih2YWx1ZTogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCBTZXR0aW5nc1N0b3JlLnNldFZhbHVlKFwid2VicnRjX2F1ZGlvX2VjaG9DYW5jZWxsYXRpb25cIiwgbnVsbCwgU2V0dGluZ0xldmVsLkRFVklDRSwgdmFsdWUpO1xuICAgICAgICBhd2FpdCBNZWRpYURldmljZUhhbmRsZXIudXBkYXRlQXVkaW9TZXR0aW5ncygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgYXN5bmMgc2V0QXVkaW9Ob2lzZVN1cHByZXNzaW9uKHZhbHVlOiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJ3ZWJydGNfYXVkaW9fbm9pc2VTdXBwcmVzc2lvblwiLCBudWxsLCBTZXR0aW5nTGV2ZWwuREVWSUNFLCB2YWx1ZSk7XG4gICAgICAgIGF3YWl0IE1lZGlhRGV2aWNlSGFuZGxlci51cGRhdGVBdWRpb1NldHRpbmdzKCk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBnZXRBdWRpb091dHB1dCgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZUF0KFNldHRpbmdMZXZlbC5ERVZJQ0UsIFwid2VicnRjX2F1ZGlvb3V0cHV0XCIpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZ2V0QXVkaW9JbnB1dCgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZUF0KFNldHRpbmdMZXZlbC5ERVZJQ0UsIFwid2VicnRjX2F1ZGlvaW5wdXRcIik7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBnZXRWaWRlb0lucHV0KCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlQXQoU2V0dGluZ0xldmVsLkRFVklDRSwgXCJ3ZWJydGNfdmlkZW9pbnB1dFwiKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGdldEF1ZGlvQXV0b0dhaW5Db250cm9sKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcIndlYnJ0Y19hdWRpb19hdXRvR2FpbkNvbnRyb2xcIik7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBnZXRBdWRpb0VjaG9DYW5jZWxsYXRpb24oKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwid2VicnRjX2F1ZGlvX2VjaG9DYW5jZWxsYXRpb25cIik7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBnZXRBdWRpb05vaXNlU3VwcHJlc3Npb24oKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwid2VicnRjX2F1ZGlvX25vaXNlU3VwcHJlc3Npb25cIik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgY3VycmVudCBzZXQgZGV2aWNlSWQgZm9yIGEgZGV2aWNlIGtpbmRcbiAgICAgKiBAcGFyYW0ge01lZGlhRGV2aWNlS2luZEVudW19IGtpbmQgb2YgdGhlIGRldmljZSB0aGF0IHdpbGwgYmUgcmV0dXJuZWRcbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSB0aGUgZGV2aWNlSWRcbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhdGljIGdldERldmljZShraW5kOiBNZWRpYURldmljZUtpbmRFbnVtKTogc3RyaW5nIHtcbiAgICAgICAgc3dpdGNoIChraW5kKSB7XG4gICAgICAgICAgICBjYXNlIE1lZGlhRGV2aWNlS2luZEVudW0uQXVkaW9PdXRwdXQ6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QXVkaW9PdXRwdXQoKTtcbiAgICAgICAgICAgIGNhc2UgTWVkaWFEZXZpY2VLaW5kRW51bS5BdWRpb0lucHV0OlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF1ZGlvSW5wdXQoKTtcbiAgICAgICAgICAgIGNhc2UgTWVkaWFEZXZpY2VLaW5kRW51bS5WaWRlb0lucHV0OlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmdldFZpZGVvSW5wdXQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZ2V0IHN0YXJ0V2l0aEF1ZGlvTXV0ZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiYXVkaW9JbnB1dE11dGVkXCIpO1xuICAgIH1cbiAgICBwdWJsaWMgc3RhdGljIHNldCBzdGFydFdpdGhBdWRpb011dGVkKHZhbHVlOiBib29sZWFuKSB7XG4gICAgICAgIFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJhdWRpb0lucHV0TXV0ZWRcIiwgbnVsbCwgU2V0dGluZ0xldmVsLkRFVklDRSwgdmFsdWUpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZ2V0IHN0YXJ0V2l0aFZpZGVvTXV0ZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwidmlkZW9JbnB1dE11dGVkXCIpO1xuICAgIH1cbiAgICBwdWJsaWMgc3RhdGljIHNldCBzdGFydFdpdGhWaWRlb011dGVkKHZhbHVlOiBib29sZWFuKSB7XG4gICAgICAgIFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJ2aWRlb0lucHV0TXV0ZWRcIiwgbnVsbCwgU2V0dGluZ0xldmVsLkRFVklDRSwgdmFsdWUpO1xuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFTQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxPQUFBLEdBQUFELE9BQUE7QUFFQSxJQUFBRSxjQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRyxhQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxnQkFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssZ0JBQUEsR0FBQUwsT0FBQTtBQWZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFVQTtBQUFBLElBQ1lNLG1CQUFtQixHQUFBQyxPQUFBLENBQUFELG1CQUFBLDBCQUFuQkEsbUJBQW1CO0VBQW5CQSxtQkFBbUI7RUFBbkJBLG1CQUFtQjtFQUFuQkEsbUJBQW1CO0VBQUEsT0FBbkJBLG1CQUFtQjtBQUFBO0FBQUEsSUFRbkJFLHVCQUF1QixHQUFBRCxPQUFBLENBQUFDLHVCQUFBLDBCQUF2QkEsdUJBQXVCO0VBQXZCQSx1QkFBdUI7RUFBQSxPQUF2QkEsdUJBQXVCO0FBQUE7QUFJcEIsTUFBTUMsa0JBQWtCLFNBQVNDLGVBQVksQ0FBQztFQUd6RCxXQUFrQkMsUUFBUUEsQ0FBQSxFQUF1QjtJQUM3QyxJQUFJLENBQUNGLGtCQUFrQixDQUFDRyxnQkFBZ0IsRUFBRTtNQUN0Q0gsa0JBQWtCLENBQUNHLGdCQUFnQixHQUFHLElBQUlILGtCQUFrQixDQUFDLENBQUM7SUFDbEU7SUFDQSxPQUFPQSxrQkFBa0IsQ0FBQ0csZ0JBQWdCO0VBQzlDO0VBRUEsYUFBb0JDLG9CQUFvQkEsQ0FBQSxFQUFxQjtJQUN6RCxNQUFN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