Message System
Message Types
In the TEN framework, messages are categorized into four types:
Command
Data
Video Frame
Audio Frame
The primary difference between a command and non-command message types is that commands have a result, while non-commands do not.
Corresponding to these types, extensions have four message callbacks:
OnCmd
OnData
OnVideoFrame
OnAudioFrame
Here is a classification diagram of TEN framework messages:
Message Name
A message name in the TEN framework is used to differentiate messages of the same type but with different purposes. Extensions use different message names to determine the actions they need to take.
Naming rules for message names are as follows:
The first character must be a letter (
a-z
,A-Z
) or an underscore (_
).Subsequent characters can be letters (
a-z
,A-Z
), digits (0-9
), or underscores (_
).
Message Flow
The TEN framework supports three message flow patterns:
One message, one result.
Suitable when an action produces a single result.
One message, multiple results.
Suitable when an action produces multiple results.
Multiple messages.
Suitable for actions that do not require results.
Extension Message Interface
The api
field in an extension's manifest presents the extension's external message interface. The api
field in the manifest can contain the following types of API information:
cmd_in
cmd_out
data_in
data_out
audio_frame_in
audio_frame_out
video_frame_in
video_frame_out
An example of these API definitions is as follows:
The message pairing mechanism between different extensions in the TEN framework is similar to function calls in traditional programming languages. Here's a simple analogy:
The message name is akin to a function name, and the pairing mechanism between extensions' messages is like the function call mechanism.
Message properties are similar to function parameters.
When the TEN framework determines that an output message
foo
from extension A pairs with an input messagefoo
from extension B, it's analogous to a function pointer in extension A pointing to the functionfoo
in extension B.The pairing is based solely on the message name, not the message properties. This means the TEN framework does not support a mechanism analogous to function overloading.
Therefore, the message name is crucial for the input/output messages of each extension, serving as the control plane interface for that extension.
Although the TEN framework provides a language-agnostic calling mechanism at the single-message level, it also allows static and dynamic checks on the calling relationships between extensions through the TEN schema. This helps detect potential issues, such as differing interpretations of a property type between a source and a destination extension. Users can define their message names and determine the calling relationships between extensions through graphs. The TEN framework also offers static check tools to ensure these relationships do not cause any problems.
Message Ownership Concept in the TEN Framework
In the TEN framework, once a message is successfully sent, the extension that sent the message can no longer use it. This concept is crucial for maintaining message safety and thread safety within the framework.
There are two directions in which messages can be sent: send and return. Only command messages have a return direction; data, audio_frame, and video_frame messages do not. After a message is sent, it may go through various processing steps, and allowing an extension to continue using the message could lead to thread safety issues. For instance, another extension handling the message might be running in a different thread. Even if the initial extension continues to use the message without any visible issues, this behavior is undefined and should not be relied upon by developers.
The TEN runtime enforces various safeguards to ensure that an extension cannot use a message after it has been successfully sent.
Message Ownership Transfer to the Extension
When the TEN framework delivers a message to an extension via the OnCmd
, OnData
, OnVideoFrame
, or OnAudioFrame
callbacks, the framework transfers ownership of the message to the extension. This transfer of ownership means that the TEN framework guarantees that only the receiving extension has access to the message, ensuring message safety and thread safety. The extension can freely use the message and must return ownership to the TEN framework when it no longer needs the message. After returning ownership, the extension must not interact with the message any further.
Message Ownership Transfer to the TEN Framework
When an extension sends a message back to the TEN runtime using APIs like SendCmd
, ReturnResult
, SendData
, SendVideoFrame
, or SendAudioFrame
, the extension transfers ownership of the message back to the TEN framework.
Ownership of Data Related to Messages
The concept of ownership extends beyond the message itself to all resources associated with that message. Just like the message, each resource's ownership can only belong to one extension at a time, and it mirrors the message's ownership. This design ensures both message and thread safety within the TEN framework.
For example, if extension A owns a message and uses a buffer within that message, it must return ownership of both the message and the buffer to the TEN runtime when it no longer needs them.
Copy Semantics by Default
To prevent issues such as data races caused by multiple extensions handling the same resource simultaneously, the TEN framework defaults to copy semantics when transmitting data across TEN runtime and extension boundaries. Copying ensures that ownership is separated, maintaining safety.
Borrowing Semantics
The TEN framework also supports borrowing semantics, allowing an extension to use a resource without taking ownership. This approach enhances resource utilization while maintaining message and thread safety. Borrowing APIs must be used in conjunction with GiveBack APIs to ensure the safety and integrity of resources.
When an extension returns ownership of a message to the TEN runtime, the runtime will only accept the message if all associated resources have also been returned. For instance, if extension A borrows a data message's buffer but does not return the buffer's ownership before returning the message itself, the TEN runtime will reject the message (e.g., SendData
will fail).
Borrowing API
Extensions can directly access resources within a message using borrowing APIs, allowing temporary use without transferring ownership.
GiveBack API
The GiveBack APIs are used to return the ownership of resources back to the TEN framework, ensuring that resources are safely managed and freed when no longer needed.
Command
TEN clients and TEN extensions can send commands to other TEN extensions.
If a command is used in a situation where the result isn't needed, it's fine. TEN runtime will automatically discard any unnecessary results.
Result
A result is the response to a command. For example, when TEN extension A sends command X to TEN extension B, after processing the command, TEN extension B will send a result back to TEN extension A. The result may include any meaningful details, allowing TEN extension A to gain more information about the execution outcome.
A typical result's JSON representation might look like this:
Last updated