@geheimgang188/fmod-service-api
Version:
FMOD service API
496 lines • 40.6 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FmodZeromqApi = exports.ConnectionState = void 0;
const zmq = __importStar(require("zeromq"));
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
const small_state_machine_1 = require("small-state-machine");
const semaphore_promise_1 = __importDefault(require("semaphore-promise"));
const events_1 = require("events");
const marker_data_1 = require("./marker-data");
var ConnectionState;
(function (ConnectionState) {
ConnectionState["Disconnected"] = "Disconnected";
ConnectionState["Connecting"] = "Connecting";
ConnectionState["Connected"] = "Connected";
ConnectionState["Disconnecting"] = "Disconnecting";
})(ConnectionState || (exports.ConnectionState = ConnectionState = {}));
var Events;
(function (Events) {
Events["connect"] = "connect";
Events["connected"] = "connected";
Events["disconnect"] = "disconnect";
Events["disconnected"] = "disconnected";
})(Events || (Events = {}));
class FmodZeromqApi extends tiny_typed_emitter_1.TypedEmitter {
static getEventIdFromResponse(response) {
const spacePos = response.indexOf(' ');
if (spacePos === -1) {
return undefined;
}
return response.substring(spacePos + 1);
}
constructor(address, args) {
var _a, _b;
super();
this._events = new events_1.EventEmitter();
this._singleShotEventIds = new Map();
this._verboseLogging = false;
this._subRunning = false;
this._logger = args === null || args === void 0 ? void 0 : args.logger;
this._verboseLogging = (args === null || args === void 0 ? void 0 : args.logger) !== undefined;
this._zmqAddress = address;
this._heartbeatInterval = (_a = args === null || args === void 0 ? void 0 : args.heartbeatIntervalMillis) !== null && _a !== void 0 ? _a : 4000;
this._socketStatusInterval = (_b = args === null || args === void 0 ? void 0 : args.socketStatusIntervalMillis) !== null && _b !== void 0 ? _b : 4000;
this._socketSempahore = new semaphore_promise_1.default(1);
if (args === null || args === void 0 ? void 0 : args.subscriberAddress) {
this._subscriberAddress = args.subscriberAddress;
}
else {
// Derive subscriber address from main address by incrementing the port
const match = address.match(/^(.*:)(\d+)$/);
this._subscriberAddress = match
? `${match[1]}${parseInt(match[2], 10) + 1}`
: address.replace(/:\d+$/, ':3001');
}
this._sm = new small_state_machine_1.SmallStateMachine(ConnectionState.Disconnected);
this._sm.configure(ConnectionState.Disconnected)
.onEntry(() => this.onDisconnected())
.permit(Events.connect, ConnectionState.Connecting) // Manually calling connect()
.permit(Events.connected, ConnectionState.Connected) // Socket became available again
.ignore(Events.disconnected);
this._sm.configure(ConnectionState.Connecting)
.onEntry(() => this.onConnecting())
.permit(Events.connected, ConnectionState.Connected)
.permit(Events.disconnected, ConnectionState.Disconnected)
.ignore(Events.connect);
this._sm.configure(ConnectionState.Connected)
.onEntry(() => this.onConnected())
.permit(Events.disconnected, ConnectionState.Disconnected)
.permit(Events.disconnect, ConnectionState.Disconnecting)
.ignore(Events.connect)
.ignore(Events.connected);
this._sm.configure(ConnectionState.Disconnecting)
.onEntry(() => this.onDisconnecting())
.permit(Events.disconnected, ConnectionState.Disconnected)
.ignore(Events.disconnect);
this._sm.onStateChange(newState => { var _a; return (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Now in state ${newState}`); });
}
get connectionState() {
return this._sm.currentState;
}
get verboseLogging() {
return this._verboseLogging;
}
set verboseLogging(verbose) {
this._verboseLogging = verbose;
}
connect() {
this._sm.fire(Events.connect);
}
disconnect() {
this._sm.fire(Events.disconnect);
}
/**
* Register a callback for marker events from FMOD.
*/
onMarker(cb) {
this._events.on('marker', cb);
}
/**
* Unregister a marker event callback.
*/
offMarker(cb) {
this._events.off('marker', cb);
}
/**
* Start an event; it can be stopped again
*/
start(event) {
return __awaiter(this, void 0, void 0, function* () {
const command = `start-event:${event}`;
yield this.sendCommand(command);
});
}
/**
* Stop a running event
*/
stop(event) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
const command = `stop-event:${event}`;
let stoppedEvents = 0;
stoppedEvents += yield this.stopSingleShotEvents(event);
try {
yield this.sendCommand(command);
stoppedEvents++;
}
catch (err) {
if (stoppedEvents === 0) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn(`Failed stopping event ${event}: ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err}`);
}
}
return stoppedEvents;
});
}
stopStartedEvents() {
return __awaiter(this, void 0, void 0, function* () {
const command = 'stop-started-events';
yield this.sendCommand(command);
});
}
/**
* Play an event (fire-and-forget)
* @param event
*/
play(event) {
return __awaiter(this, void 0, void 0, function* () {
const command = `play-event:${event}`;
const result = yield this.sendCommand(command);
this.addSingleShotId(event, command, result);
});
}
loadBank(bankName) {
return __awaiter(this, void 0, void 0, function* () {
const command = `load-bank:${bankName}`;
yield this.sendCommand(command);
});
}
unloadBank(bankName) {
return __awaiter(this, void 0, void 0, function* () {
const command = `unload-bank:${bankName}`;
yield this.sendCommand(command);
});
}
setParameter(eventId, name, value) {
return __awaiter(this, void 0, void 0, function* () {
const command = `set-parameter:${eventId};${name};${value}`;
yield this.sendCommand(command);
});
}
playVoice(eventId, key) {
return __awaiter(this, void 0, void 0, function* () {
const command = `play-voice:${eventId};${key}`;
const result = yield this.sendCommand(command);
const mapId = FmodZeromqApi.toEventMapId(eventId, key);
this.addSingleShotId(mapId, command, result);
});
}
stopVoice(eventId, key) {
return __awaiter(this, void 0, void 0, function* () {
const mapId = FmodZeromqApi.toEventMapId(eventId, key);
return this.stopSingleShotEvents(mapId);
});
}
isPlaying(eventId) {
throw new Error('Method not implemented.');
}
listLoadedBankPaths() {
return __awaiter(this, void 0, void 0, function* () {
const command = 'list-bank-paths';
const list = yield this.sendCommand(command);
return list
.split(';')
.map(el => el.replace(/^bank:\//, ''))
.filter(el => el.length > 0);
});
}
stopSingleShotEvents(eventIdentifier) {
return __awaiter(this, void 0, void 0, function* () {
const entries = this._singleShotEventIds.get(eventIdentifier);
if (entries === undefined) {
return 0;
}
let stoppedCount = 0;
for (const entry of entries) {
const command = `stop-event:${entry.uniqueEventId}`;
const result = yield this.sendCommand(command);
if (result.startsWith('OK')) {
stoppedCount++;
}
}
entries.length = 0;
this.printSingleShotLength();
return stoppedCount;
});
}
addSingleShotId(eventIdentifier, fmodAction, fmodResponse) {
var _a, _b, _c;
const uniqueEventId = FmodZeromqApi.getEventIdFromResponse(fmodResponse);
this._verboseLogging && ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.trace(`Answer from ${fmodAction}: ${fmodResponse}; extracted ID: ${uniqueEventId}`));
if (uniqueEventId !== undefined) {
this._verboseLogging && ((_b = this._logger) === null || _b === void 0 ? void 0 : _b.trace(`Event ID received: ${uniqueEventId}`));
const eventList = (_c = this._singleShotEventIds.get(eventIdentifier)) !== null && _c !== void 0 ? _c : [];
eventList.push({
tAdded: Date.now(),
uniqueEventId,
});
this._singleShotEventIds.set(eventIdentifier, eventList);
}
this.cleanupOldEventIds();
}
cleanupOldEventIds() {
var _a;
const now = Date.now();
const minutes = 60 * 1000;
for (const [key, val] of this._singleShotEventIds.entries()) {
const cleaned = val.filter(el => (now - el.tAdded) < 10 * minutes);
const delta = val.length - cleaned.length;
if (delta > 0) {
this._singleShotEventIds.set(key, cleaned);
this._verboseLogging && ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Old event IDs cleaned up: ${delta} removed`));
}
}
this.printSingleShotLength();
}
printSingleShotLength() {
var _a;
const totalIds = Array.from(this._singleShotEventIds.values())
.map(el => el.length)
.reduce((acc, cur) => acc + cur, 0);
this._verboseLogging && ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Single-shot event list contains ${totalIds} unique IDs`));
}
doConnect() {
var _a, _b;
if (this._socket !== undefined)
throw new Error('Socket already exists!');
this._socket = new zmq.Request();
/*
// Connection timeouts may be helpful against calls piling up
this._socket.connectTimeout = 2000;
this._socket.sendTimeout = 200;
this._socket.receiveTimeout = 2000;
*/
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`ZMQ socket connecting to ${this._zmqAddress}`);
this._socket.connect(this._zmqAddress);
this.connectSubscriber();
this._verboseLogging && ((_b = this._logger) === null || _b === void 0 ? void 0 : _b.debug(`Setting up heartbeat and status polling`));
// Regularly send message to the API to check if it is still online
if (this._heartbeatPoll === undefined) {
this._heartbeatPoll = setInterval(() => this.checkHeartbeat(), this._heartbeatInterval);
}
// Check if socket is writable; changes to false when it goes offline
if (this._socketStatusPoll === undefined) {
let lastWritableStatus = false;
// TODO When the socket is not available, the calls pile up and are sent all at once when the socket becomes available.
// Is there a better way? Not sending calls at all does not update socket.writable status …
const checkConnection = () => __awaiter(this, void 0, void 0, function* () {
var _a, _b;
if (this._socket === undefined)
return;
const release = yield this._socketSempahore.acquire();
try {
// Socket can be …
// closed → no connection
// writable → all fine. This is how it should be after sending and receiving a message.
// readable → only when we did not read the response, but the API should always read after writing
// undefined (because disconnected) → no connection
const writableStatus = (_b = (_a = this._socket) === null || _a === void 0 ? void 0 : _a.writable) !== null && _b !== void 0 ? _b : false;
if (writableStatus !== lastWritableStatus) {
lastWritableStatus = writableStatus;
this._sm.fire(writableStatus ? Events.connected : Events.disconnected);
}
}
finally {
release();
}
});
this._socketStatusPoll = setInterval(checkConnection, this._socketStatusInterval);
setImmediate(checkConnection);
}
}
doDisconnect() {
var _a;
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug('Disconnecting …');
this.disconnectSubscriber();
if (this._socket !== undefined) {
this._socket.disconnect(this._zmqAddress);
this._socket = undefined;
}
if (this._heartbeatPoll !== undefined) {
clearInterval(this._heartbeatPoll);
this._heartbeatPoll = undefined;
}
if (this._socketStatusPoll !== undefined) {
clearInterval(this._socketStatusPoll);
this._socketStatusPoll = undefined;
}
const fireDisconnect = () => this._sm.fire(Events.disconnected);
setImmediate(fireDisconnect);
}
sendCommand(command) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
if (this._socket === undefined)
throw new Error(`Socket not initialised; did you call init()?`);
let msg = '';
const release = yield this._socketSempahore.acquire();
this._verboseLogging && ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.trace(`Sending: ${command}`));
try {
/*
// Setting the sending timeout may be helpful. Needs further examination.
this._logger?.info( `Send timeout is ${this._socket.sendTimeout}` );
this._socket.sendTimeout = 200;
this._logger?.info( `Send timeout set to ${this._socket.sendTimeout}` );
*/
// After sending a message to the socket, it is not writable anymore (and hopefully not closed)
const sendPromise = this._socket.send(command);
const [response] = yield this._socket.receive();
this._verboseLogging && ((_b = this._logger) === null || _b === void 0 ? void 0 : _b.trace(`Received: ${response}`));
msg = response.toString('utf-8');
if (msg.startsWith('Error:')) {
throw new Error(msg);
}
}
finally {
release();
}
this._verboseLogging && ((_c = this._logger) === null || _c === void 0 ? void 0 : _c.trace(`Done sending ${command}`));
return msg;
});
}
checkHeartbeat() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
try {
const id = yield this.sendCommand('get:id');
if (this._lastId !== id) {
if (this._lastId !== undefined) {
process.nextTick(() => this.emit('reconnect'));
}
this._lastId = id;
}
this._sm.fire(Events.connected);
}
catch (err) {
if (this._sm.currentState !== ConnectionState.Disconnected) {
this._sm.fire(Events.disconnected);
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn('FMOD has gone:', err);
}
}
});
}
onConnecting() {
this.doConnect();
}
onConnected() {
process.nextTick(() => this.emit('connect'));
}
onDisconnecting() {
this.doDisconnect();
}
onDisconnected() {
process.nextTick(() => this.emit('disconnect'));
}
connectSubscriber() {
var _a;
if (this._subSocket !== undefined)
return;
this._subSocket = new zmq.Subscriber();
this._subSocket.connect(this._subscriberAddress);
this._subSocket.subscribe('');
this._subRunning = true;
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`ZMQ subscriber connecting to ${this._subscriberAddress}`);
this.runSubscriberLoop()
.catch((err) => { var _a, _b; return (_a = this._logger) === null || _a === void 0 ? void 0 : _a.error(`Error in subscriber loop: ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err}`); });
}
disconnectSubscriber() {
this._subRunning = false;
if (this._subSocket !== undefined) {
this._subSocket.close();
this._subSocket = undefined;
}
}
runSubscriberLoop() {
return __awaiter(this, void 0, void 0, function* () {
var _a, e_1, _b, _c;
var _d, _e, _f;
const socket = this._subSocket;
if (!socket)
return;
try {
try {
for (var _g = true, socket_1 = __asyncValues(socket), socket_1_1; socket_1_1 = yield socket_1.next(), _a = socket_1_1.done, !_a; _g = true) {
_c = socket_1_1.value;
_g = false;
const [msg] = _c;
if (!this._subRunning)
break;
const message = msg.toString('utf-8');
this._verboseLogging && ((_d = this._logger) === null || _d === void 0 ? void 0 : _d.trace(`Sub received: ${message}`));
const parsed = (0, marker_data_1.parseMarkerMessage)(message);
if (parsed) {
this._events.emit('marker', parsed);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_g && !_a && (_b = socket_1.return)) yield _b.call(socket_1);
}
finally { if (e_1) throw e_1.error; }
}
}
catch (err) {
if (this._subRunning) {
(_e = this._logger) === null || _e === void 0 ? void 0 : _e.warn(`Subscriber loop error: ${(_f = err === null || err === void 0 ? void 0 : err.message) !== null && _f !== void 0 ? _f : err}`);
}
}
});
}
}
exports.FmodZeromqApi = FmodZeromqApi;
FmodZeromqApi.toEventMapId = (eventId, key) => `${eventId};;${key}`;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm1vZC16ZXJvbXEtYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9mbW9kLXplcm9tcS1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUNBLDRDQUE4QjtBQUM5QiwyREFBa0Q7QUFDbEQsNkRBQXdEO0FBQ3hELDBFQUEwQztBQUMxQyxtQ0FBc0M7QUFJdEMsK0NBQStEO0FBRy9ELElBQVksZUFLWDtBQUxELFdBQVksZUFBZTtJQUN2QixnREFBNkIsQ0FBQTtJQUM3Qiw0Q0FBeUIsQ0FBQTtJQUN6QiwwQ0FBdUIsQ0FBQTtJQUN2QixrREFBK0IsQ0FBQTtBQUNuQyxDQUFDLEVBTFcsZUFBZSwrQkFBZixlQUFlLFFBSzFCO0FBRUQsSUFBSyxNQUtKO0FBTEQsV0FBSyxNQUFNO0lBQ1AsNkJBQW1CLENBQUE7SUFDbkIsaUNBQXVCLENBQUE7SUFDdkIsbUNBQXlCLENBQUE7SUFDekIsdUNBQTZCLENBQUE7QUFDakMsQ0FBQyxFQUxJLE1BQU0sS0FBTixNQUFNLFFBS1Y7QUFnQkQsTUFBYSxhQUFjLFNBQVEsaUNBQThCO0lBRTdELE1BQU0sQ0FBQyxzQkFBc0IsQ0FBRSxRQUFnQjtRQUMzQyxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFFLEdBQUcsQ0FBRSxDQUFDO1FBQ3pDLElBQUssUUFBUSxLQUFLLENBQUMsQ0FBQyxFQUFHLENBQUM7WUFDcEIsT0FBTyxTQUFTLENBQUM7UUFDckIsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDLFNBQVMsQ0FBRSxRQUFRLEdBQUcsQ0FBQyxDQUFFLENBQUM7SUFDOUMsQ0FBQztJQTJCRCxZQUFhLE9BQWUsRUFBRSxJQUF3Qjs7UUFDbEQsS0FBSyxFQUFFLENBQUM7UUFiSyxZQUFPLEdBQUcsSUFBSSxxQkFBWSxFQUFFLENBQUM7UUFJN0Isd0JBQW1CLEdBQUcs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