Contact Us

CATEGORIES

Whoops…Nothing found

Try other keywords in your search

Pixera Native API Introduction

 16 Minutes

 0 Likes

 13 Views

 

The Pixera Native API provides external access to Pixera functionality through network-based interfaces such as TCP, UDP, HTTP, OSC, and related integration modes configured in Pixera's settings. This document is an introduction and practical entry point for working with that Native API. It is not intended to replace the generated API command reference, but to explain the surrounding concepts needed to use those commands correctly.

The API is not tied to a single transport or implementation. Within the Pixera code base, the main API code establishes a bridge between internal Pixera objects and the outside world. Automatic code generation is then used to create interpreters for different concrete forms of access to the API. For example, both JSON-RPC and scripting interfaces can be used to access logically similar functionality.

The purpose of this shared API structure is conceptual stability: the same Pixera functions, classes and methods can be exposed through different access paths, allowing users and client applications to choose the form of access that best fits the workflow.

JSON/TCP and JSON/TCP(dl) should be treated as the primary Native API transport for workflows that depend on complete request/response behavior. Other transports can be useful for specific integration scenarios, but they do not all provide the same return-value and monitoring capabilities.

The core of the API represents concepts that are part of Pixera. Beyond this core, API-related mechanisms can also be used for integration with external protocols, external devices, or Control modules, depending on the selected access mode.

The core of the API is bidirectional in the sense that many of the available functions and methods return values. All of this exchange is expressed with the semantics of Pixera, though. If, in contrast, output is needed that is geared towards external devices, the API offers output channels that simply transport strings or binary data to whatever is attached to them.


API Interfaces Overview

Pixera exposes several API-related interfaces. This document mainly describes the Native API: the external API access configured in Pixera's settings and described in Configuration in Pixera. Modes such as JSON/TCP, JSON/TCP (dl), JSON/UDP, HTTP/TCP, Binary/TCP, OSC/UDP and the other settings listed there belong to this Native API access layer.

The Native API is used by external clients to send commands to Pixera. JSON/TCP is the most complete Native API transport because it supports full request/response handling and all API return values.

The Native API can also be used to access and execute modules and actions inside the Pixera Control workspace. In that case the request is still sent through a Native API access point such as JSON over TCP or HTTP, but the method can target a Control module action. Control module parameters are passed as an array rather than as named JSON-RPC parameters. See the Pixera help article Trigger Modules and Actions via API.

Pixera also provides API usage inside Control itself:

  • Control API: Used inside Pixera Control, for example from Lua scripts, to execute Pixera commands or retrieve data from Pixera. The API command structure is conceptually the same as the external Native API, but it is used directly inside the Control environment. See Find and use API commands inside Control.
  • Direct API: Used inside Control for fast tracking-related data paths. It is designed for workflows where tracking data must be processed efficiently, especially when screen or camera movement is updated many times per second. Tracking modules and the DirectNetworkOsc module use this API path. See Direct API.

Quick Start

For a basic JSON/TCP (dl) workflow:

  1. Open Pixera's settings and configure an API access port as JSON/TCP (dl).
  2. Connect a TCP client to the configured IP address and port.
  3. Build a JSON-RPC command with "jsonrpc", "id", "method" and, if needed, "params".
  4. Append the delimiter 0xPX directly after the JSON string.
  5. Send the resulting string to Pixera.
  6. Read the response and match it to the request by using the JSON-RPC "id".

Example command:

{"jsonrpc":"2.0","id":1,"method":"Pixera.Utility.getApiRevision"}0xPX

In this delimiter mode, no pxr1 header and no packet-size calculation are required. Pixera reads until it reaches 0xPX and treats the bytes before it as one complete JSON-RPC message.

Use JSON/TCP without delimiter only if the client implements Pixera's packet header format. In that mode the client must prefix every JSON payload with the pxr1 header and the 32-bit little-endian UTF-8 payload size.


Configuration in Pixera

The starting point for working with the API is the sub-tab labelled "API" in the settings. The available API access modes have expanded beyond the older five-mode list.

The current API-related options are:

Mode Description
JSON/TCP Processes requests and sends replies in the JSON-RPC format via TCP/IP. This is the primary mode for full API interaction.
JSON/TCP (dl) Like JSON/TCP, but with delimiter-based packet separation. Each sent JSON command must end with the delimiter 0xPX.
JSON/UDP Sends JSON API commands via UDP. Because UDP is connectionless, this mode is not suitable for commands that require full request/response handling.
HTTP/TCP Allows Pixera to serve common web files such as HTML, CSS, and PNG, and to receive JSON-RPC messages through HTTP POST requests.
Binary/TCP Uses a binary representation of the API.
Plain String/TCP Sends plain string data via TCP. This mode is not the structured JSON-RPC API transport.
Art-Net Uses Art-Net / DMX-oriented communication and does not follow the API structure shown in the generated HTML API reference.
sACN Uses sACN / DMX-oriented communication and does not follow the generated HTML API structure.
Plain String/UDP Sends plain string data via UDP. This mode is not the structured JSON-RPC API transport.
OSC/UDP Sends OSC messages via UDP. This mode does not support full API return handling like JSON/TCP.
Engine Direct Uses a separate engine-oriented mechanism and does not follow the API structure shown in the generated HTML API reference.
Pixera 2 Avio Uses a separate Pixera-to-Avio integration mechanism and does not follow the API structure shown in the generated HTML API reference.

Tip

Only JSON/TCP supports all API return values reliably. This is important for commands that expect a real return value, such as monitoring-related calls or other request/response workflows. HTTP, UDP and OSC based modes can be useful for sending commands, but they should not be treated as equivalent transports for API features that depend on complete return handling.

 

The modes Art-Net, sACN, Engine Direct and Pixera 2 Avio work fundamentally differently from the API structure documented in pixera_api_documentation.html. They should be treated as separate integration mechanisms rather than as alternative transports for the same JSON-RPC command set.


Transport Capability Matrix

Mode Uses Native API command structure Supports API return values Packet boundary method Recommended use
JSON/TCP Yes Full support pxr1 header plus UTF-8 payload size Reliable command/response workflows, monitoring, state queries
JSON/TCP (dl) Yes Full support 0xPX delimiter Simpler TCP clients that prefer delimiter-based framing
JSON/UDP Yes No reliable return handling UDP datagram Fire-and-forget commands
HTTP/TCP Yes Limited compared to JSON/TCP, No Monitoring possible HTTP request/response Web clients and browser-based tools
Binary/TCP Yes, binary representation Transport-specific pxr1 header plus binary payload size Binary API clients
Plain String/TCP No No structured API returns TCP stream/string handling Plain string output or integrations
Plain String/UDP No No structured API returns UDP datagram Plain string UDP integrations
OSC/UDP Partial command mapping No full API return handling OSC packet over UDP OSC-based triggering
Art-Net No No Art-Net / DMX protocol DMX/lighting integration
sACN No No sACN / DMX protocol DMX/lighting integration
Engine Direct No Separate mechanism Engine-specific Engine-level integration
Pixera 2 Avio No Separate mechanism Avio-specific Pixera-to-Avio integration

Note that multiple clients may connect to each TCP port.

The next port is an optional heartbeat port. If a valid port number is entered then the information in the API sub tab regarding the available ports will be sent every second in the form of a JSON string. Use a multicast IP to send to a multicast group. This allows clients to listen for the heartbeat and connect as soon as they receive the port and IP information.

String or binary output can currently only be triggered from cues in the timeline. To edit the output, use the appropriate field in the cue inspector. Strings can be entered directly, binary data should be entered in the form of two-character hexadecimal bytes, e.g. "FF 7B 0A" for the value 255 followed by 123 and 10.

Tip

Please note that Pixera must be restarted for changes in this sub-tab to take effect.

 

Current API Structure Documents

The core of the API consists of a set of functions, classes and methods that represent Pixera entities. Several generated documents describe these elements. They are generated automatically from the Pixera code base and reflect the structure of the current API revision. The revision number is in the name of the revisioned documents.

  • pixera_api_plain_rev[num].txt: Shows the API in its most reduced form, giving only the names and data types that make up the definitions. This document provides the easiest way to get an overview of the currently available functionality.
  • pixera_api_comments_rev[num].txt: Like the document above, but with comments that provide additional context for individual functions and methods.
  • pixera_api_examples.txt_rev[num]: Like the document above, but with JSON syntax examples for every function and method invocation, including the structure of the expected reply.
  • pixera_api_documentation.html: A generated HTML reference containing API command examples. The JSON examples shown there follow the JSON-RPC structure used by the API, e.g. a "jsonrpc" version, an "id", a "method" such as "Pixera.Utility.getApiRevision", and optional "params".

All the examples are generated automatically. This means that some of the used parameter values may not make perfect sense. But the syntax is guaranteed to be correct. So the examples are an easy way to get started in that they can be copy/pasted and then customized with parameter values to quickly create valid JSON requests.

A quick glance at the "plain" description of the API should quickly show one of its most important features: it is object oriented. The basic approach is that, within a subset of the API, a namespace, there are functions that provide access to different Pixera objects, a timeline, for example.

The objects have a class definition that describes what they can be asked to do. These actions can include changing their state or providing information on it. Part of an object's information can relate to child objects that it contains. These objects are accessed by asking the parent for a handle to one of them. When the handle is available then those methods defined in the child's class definition can be used with it.

A result of this approach is that all class methods defined in the API expect a handle value to be set as the first parameter. In the interests of concise description, the handle parameters are omitted in the reduced definitions in pixera_api_plain_rev[num].txt. But examples of specifying a handle can be found in all the JSON invocations that relate to a class instance in pixera_api_examples_rev[num].txt.

In the JSON implementation, a special flag can be set which places the method and handle used in an invocation into the response. This provides an alternative besides the message id for matching invocation and response. To set this flag, send the following JSON request to Pixera:

{
  "jsonrpc": "2.0",
  "id": 49,
  "method": "Pixera.Utility.setShowContextInReplies",
  "params": {
    "doShow": true
  }
}

When this setting is active, JSON responses will contain a "context" sub-object with "method" and "handle" keys that have the same values as those in the last request sent to the connection.


JSON-RPC Request IDs

In JSON-RPC, the "id" field is used to match a response to the request that caused it. Pixera returns the same "id" value in the response that was sent in the request.

For example, a request may look like this:

{
  "jsonrpc": "2.0",
  "id": 12,
  "method": "Pixera.Utility.getApiRevision"
}

The corresponding response uses the same "id":

{
  "jsonrpc": "2.0",
  "id": 12,
  "result": 147
}

This is especially important when a client sends multiple commands quickly or in parallel. Responses may not always be processed in the same order as the requests were sent, so the "id" allows the client to reliably identify which response belongs to which command.

If no response is expected, JSON-RPC also supports notifications where the "id" field is omitted. For normal Pixera API commands, especially commands that expect a return value, an "id" should be included.


Packaging API Invocations

The main underlying protocol for accessing Pixera is TCP/IP. Since this protocol is stream-oriented, it is not possible to send Pixera, for example, a JSON string without any further information. Rather, packets must be built so that Pixera knows where one packet ends and the next one begins.

This is done with a very simple header. The header starts with a tag consisting of the four characters "pxr1". It is then followed by four bytes containing an unsigned integer, least significant byte first, the value of which corresponds to the size of the packet payload, i.e. the size of the entire packet excluding the tag and the size integer itself. This is followed by the payload data. In the case of JSON, that payload is the JSON message in UTF-8 format.

For JSON/TCP, the client must calculate the byte size of the JSON payload before sending the packet. The size value in the header must already be known when the packet is built, because Pixera uses it to determine how many bytes belong to the current request. The size is the number of bytes in the UTF-8 encoded JSON string only. It does not include the four "pxr1" tag bytes and it does not include the four size bytes.

In pseudocode, the packet construction looks like this:

jsonString = '{"jsonrpc":"2.0","id":20,"method":"Pixera.Timelines.getTimelineAtIndex","params":{"index":1}}'
payload = utf8Encode(jsonString)
payloadSize = payload.lengthInBytes

packet =
  asciiBytes("pxr1") +
  uint32LittleEndian(payloadSize) +
  payload

The important point is that payloadSize must be calculated from the encoded byte array, not from the number of visible characters in a text editor. This matters whenever non-ASCII characters are present, because UTF-8 characters can use more than one byte.

Consider the function Pixera.Timelines.getTimelineAtIndex. The example given in pixera_api_examples.txt is:

{
  "jsonrpc": "2.0",
  "id": 20,
  "method": "Pixera.Timelines.getTimelineAtIndex",
  "params": {
    "index": 1
  }
}

A valid packet for that invocation starts with the four bytes "pxr1". This is followed by 5d, i.e. 93. That is the length of the JSON string without spaces. The other three size bytes are null since the size of the string fits in the first, least significant, byte.

An alternative packet-border approach based on a delimiter is also available. This requires the mode of the API access port to be "JSON/TCP (dl)". The connection then expects each individual JSON message to have the four characters "0xPX" appended to it. A leading tag/size pair is not used in this mode.

With the delimiter method, the client does not need to calculate or send the packet size in advance. Pixera reads until it reaches the delimiter and treats the bytes before it as one complete JSON message. When replies are produced in this mode, returned results also start directly with the JSON string and end with the delimiter.

In the binary implementation of the API, the main part of the payload is described by pairs of tokens and values. In requests, the token/value pairs are used to describe the parameters of the function. In replies, they describe the return value or values.

The token is an unsigned byte that describes the type of the value that follows in the stream. The currently used tokens are:

TYPE_TOK_HANDLE = 1
TYPE_TOK_STRING = 2
TYPE_TOK_BOOL = 3
TYPE_TOK_INT = 4
TYPE_TOK_DOUBLE = 5
TYPE_TOK_FLOAT = 6
TYPE_TOK_UCHAR = 7
TYPE_TOK_UINT = 8
TYPE_TOK_HANDLE_ARRAY = 64
TYPE_TOK_STRING_ARRAY = 65
TYPE_TOK_BOOL_ARRAY = 66
TYPE_TOK_INT_ARRAY = 67
TYPE_TOK_DOUBLE_ARRAY = 68
TYPE_TOK_FLOAT_ARRAY = 69
TYPE_TOK_UCHAR_ARRAY = 70
TYPE_TOK_UINT_ARRAY = 71

The following conventions are also used:

  • The payload begins with a sequence number. It is a 32 bit unsigned integer, least significant byte first. Pixera will place the same value in a reply to the message so that the client can relate requests and replies to one another. The sequence number is not preceded by a type token.
  • The sequence number is followed by four bytes that can be used to further specify the context of the request. They are also placed into the reply. These bytes are not preceded by a type token.
  • The order of parameter values in a packet is the same order that they are listed in the documentation. If the function returns a struct, the order of the return values is the same as the order in which the struct members are listed in the documentation.
  • Handles are 64 bit unsigned integers. However, only the first 53 bits are used so that conversion to and from double is lossless.
  • INT and UINT are assumed to be four bytes in size.
  • All integers are transferred least significant byte first.
  • A float is assumed to be four bytes in size, a double eight bytes.
  • All floating point values are represented in conformance with IEEE 754.
  • String data is preceded by a signed 32 bit integer giving the size of the string.
  • Array data is preceded by a signed 32 bit integer giving the number of array elements.
  • Each array element is a standard token/data pair.

When accessing the Pixera API via HTTP, the JSON messages must be sent to the server as part of a POST request. This is easiest if Pixera is hosting the page because in that case the server URL is implied.

To use this mechanism:

  1. Place a folder called html_root in the data subdirectory of a Pixera installation.
  2. Place a HTML page there.
  3. Make sure the Pixera access port is set to "HTTP/TCP".
  4. Access the page by entering the Pixera system's IP, the port and the path to the page, starting from html_root, into a browser.

The URL should look something like this:

http://192.168.178.52:1400/api_test.html

Within the page, use a XMLHttpRequest to send JSON messages to Pixera. The following is an example Javascript function that sends the passed-in command, a JSON string, and then passes the result to the passed-in resultFunc.

function pixeraApi(cmd, resultFunc) {
  var request = new XMLHttpRequest();
  request.open('POST', '', true);
  request.setRequestHeader("Content-type", "application/json");
  request.send(cmd);
  request.onload = function () {
    resultFunc(request.status, request.responseText);
  };
}

Pixera need not host the HTML pages that access the API, though, since cross-domain access is supported. If Pixera is not the source of the pages then the Javascript for posting the requests needs to be amended to take the Pixera system's IP into account.

For example:

function pixeraApi(ip, port, cmd, resultFunc) {
  var request = new XMLHttpRequest();
  request.open('POST', 'http://' + ip + ':' + port, true);
  request.setRequestHeader("Content-type", "application/json");
  request.send(cmd);
  request.onload = function () {
    resultFunc(request.status, request.responseText);
  };
}

The code above allows Pixera API access from any web page.

Another form of invoking the API is to use Javascript code not to transfer JSON strings but, rather, to manipulate Pixera objects directly. In the near future, Pixera will provide opportunities for users to enter Javascript that is programmed against the API and have it execute immediately.

Currently, Javascript must be sent to Pixera as the parameter of a special JSON method. This would, for example, be a way for client programs to provide their users with the ability to write and execute macros that manipulate Pixera.

The special JSON-RPC function needed for this is called "Pixera.Utility.runJsScript". It has two parameters:

  • jsCode: The Javascript code to be loaded by Pixera.
  • jsFunction: The name of a function defined in the Javascript code that Pixera should execute.

The following script sets some position, rotation and scale values in the first layer of the first timeline. It then assigns the first resource in the folder "Media" to the layer. The line tl.store() saves all the changes to the timeline.

When asking Pixera to execute this, the code would be the value of the jsCode parameter and onTest would be the value of the jsFunction parameter.

function onTest() {
  var odb = Pixera.Utility.outputDebug;
  var tns = Pixera.Timelines;
  var tl = tns.getTimelineAtIndex(0);
  var layer = tl.getLayerAtIndex(0);
  var param = layer.getNodeWithName("Position").getParamWithName("x");

  param.setValue(0);
  layer.getNodeWithName("Position").setValues([6, 1, 3]);
  layer.getNodeWithName("Position").setValues([2, 4, 9.5]);
  layer.getNodeWithName("Scale").setValues([2.0, 1.0, 0.5]);
  setVals(tl, 0, "Rotation", [10, 30, 40]);

  var resFolder = Pixera.Resources.getResourceFolderWithNamePath("Media");
  var resources = resFolder.getResources();
  var ctRes = resources.length;

  if (ctRes > 0) {
    odb("assigning: " + resources[0].getName());
    layer.assignResource(resources[0].getId());
  }

  tl.store();
}

Another aspect of this example script is worth noting. Due to a limitation in the current implementation of the Javascript interpreter in Pixera, object instances can not be passed as parameters to Javascript functions. This is why getId() is used to assign the resource to the layer in the next to last statement in the script.


Handling Changes to the API

In general, AV Stumpfl will try to minimize changes to the API and will try to maintain compatibility with older uses of the API if doing so does not place undue burdens on users of the current version.

But the API is under active development and will evolve. And even in those case where old functionality does not change the question arises of how to deal with newly introduced functionality when clients can not be updated in parallel. Or, vice versa, how a newer client can deal with an older version of Pixera.

The API currently provides two approaches for handling this:

  • Use the function Pixera.Utility.getApiRevision(). This function will return a new value on every update of the API and will thus allow exact matching of clients to the API supported by a particular Pixera installation.
  • Use the function Pixera.Utility.getHasFunction. It returns true if the passed-in function name is known to the active Pixera instance.

The downside of the first approach is that any changes to the API, even those in areas irrelevant to a particular client application, may then be seen as constituting an incompatibility.

A more fine-grained approach is available in the form of Pixera.Utility.getHasFunction. Using this approach a client application could first check if all the functions it needs are available and proceed if and only if that is the case. This could allow the application to function as expected in all situations where the functionality is in fact available. At the same time, users of the application would not have to worry about API changes that do not concern the features they are interested in.


Accessing State Updates Monitoring

The API provides a means for clients to keep up to date on state changes in Pixera. The current approach is based on a polling model so it harmonizes well with the request/reply structure of communication via JSON-RPC.

Tip

Monitoring requires a transport with proper return and event handling. Use JSON/TCP for reliable monitoring workflows. UDP and OSC based access do not provide the full return/event behavior needed for monitoring, and HTTP should not be treated as equivalent to a persistent JSON/TCP monitoring connection.

 

 

To request the current state, send the method invocation with no parameters:

Pixera.Utility.pollMonitoring

The data is maintained separately for each connection to Pixera and is stored until the client requests it. It is worth noting that this constitutes an important difference to a "pure" polling model. Using only polling in the narrow sense state changes that are not in effect at the time of the polling could be missed by the client.

In the monitoring approach taken here, though, a discrete change like adding a cue is stored as an entry for the connection and this information remains available until whichever time the client decides to request it. This allows the client to optimize the polling interval for the frequency at which it wants to process the data without having to worry that it will miss any data.

This approach also allows the data to be stored and transferred more efficiently. Assume, for example, that two cues were changed since the monitoring state was last requested. This can then be represented with a string denoting the action, "cueChanged", along with a list of cue handles that were affected. It is not necessary to transfer the "cueChanged" string for every cue.

Some of the information available via monitoring represents values that change rapidly over time, e.g. the current position of a timeline. For these changes to conceptually continuous variables, only the most recent value is retained and that value is guaranteed to be present in the next monitoring data set that is transferred to the client.

As a result, a client monitoring all timeline positions at a rate lower than any of the timelines' FPS would only have precisely the data transferred that is relevant for the update frequency it is using.

The data is flushed from memory after it was returned to the caller on a connection. This means that only information that was generated since the last polling invocation is returned and the caller does not have to be able to identify and ignore stale data.

The returned data is organized by subjects. The range of subjects will be expanded as Pixera development continues. If a client is not interested in a subject, it can send the following request, e.g. for the subject "timelinePositions":

{
  "jsonrpc": "2.0",
  "id": 31,
  "method": "Pixera.Utility.unsubscribeMonitoringSubject",
  "params": {
    "subject": "timelinePositions"
  }
}

This will remove the subject from the updates for that particular connection. The function "Pixera.Utility.subscribeMonitoringSubject" can be used to re-subscribe to a subject.

Each monitoring response has an array named "result" with one entry for each subject. Each subject has a name and an array called "entries" with information on individual occurrences.

The currently available subjects are:

  • clipAdded: The entries array contains a single JSON array called "handles". It contains the handles of all clips added since the last time the monitoring results were requested for the connection.
  • clipChanged: As above, but for all clips that were changed.
  • clipRemoved: As above, but for all clips that were removed.
  • cueAdded: The entries array contains a single JSON array called "handles". It contains the handles of all cues added since the last time the monitoring results were requested for the connection.
  • cueChanged: As above, but for all cues that were changed.
  • cueRemoved: As above, but for all cues that were removed.
  • cueApplied: As above, but for all cues that were applied, either by way of a running timeline reaching them or by other means, e.g. an API invocation.
  • timelineAdded: The entries array contains a single JSON array called "handles". It contains the handles of all timelines added since the last time the monitoring results were requested for the connection.
  • timelineRemoved: As above, but for all timelines that were removed.
  • timelineTransport: The entries array contains "handle" / "value" pairs. The "value" holds the transport mode, as in the parameter to Pixera.Timelines.Timeline.setTransportMode, of the timeline with the "handle".
  • timelinePositions: The entries array contains "handle" / "value" pairs. The "value" gives the time in frames of the timeline with the "handle".
  • timelineCountdowns: The entries array contains "handle" / "value" / "flag" tuples. The "value" gives the time in frames of the current countdown of the timeline with the "handle". If the countdown is a result of the timeline moving towards the next cue the "flag" value will be 1. If the countdown is due to the timeline pausing while the wait duration of a cue is counted down then the "flag" value will be 2.

Monitoring Event Orientation

The state access mechanism discussed above gathers together all state changes for each connection and then transfers them all at once when the client requests it, via "Pixera.Utility.pollMonitoring".

Alternatively, monitoring can be used in an event-oriented mode in which monitoring entries are sent to the client connection as soon as they occur. To change the mode, send a message of the following form:

{
  "jsonrpc": "2.0",
  "id": 32,
  "method": "Pixera.Utility.setMonitoringEventMode",
  "params": {
    "mode": "all"
  }
}

The "mode" parameter can take three values:

  • none (default): Entries are never sent directly. Rather, all data is transferred as a reply to the pollMonitoring request.
  • all: All entries are immediately sent. With this setting, pollMonitoring need never be called. If it is called, the result will never contain any entries.
  • onlyDiscrete: In this mode, those state changes which do not involve continuously changing values are sent immediately while state changes that consist of rapidly updating a value are only delivered as a response to pollMonitoring.

Clients can recognize incoming monitoring events by the fact that they have a "type" attribute with the value "monEvent".

For example, an event communicating that a cue has been added could look like this:

{
  "jsonrpc": "2.0",
  "id": -1,
  "type": "monEvent",
  "name": "cueAdded",
  "entries": [
    {
      "handles": [
        6511533668781846
      ]
    }
  ]
}

PIXERA 26.1 | 19. May 2026 | J.B.

Was this article helpful?