ODIN is a versatile cross-platform Software Development Kit (SDK) engineered to seamlessly integrate real-time voice chat into multiplayer games, applications, and websites. Regardless of whether you're employing a native application or your preferred web browser, ODIN simplifies the process of maintaining connections with your significant contacts. Through its intuitive interface and robust functionality, ODIN enhances interactive experiences, fostering real-time engagement and collaboration across various digital platforms.
You can choose between a managed cloud and a self-hosted solution. Let 4Players GmbH deal with the setup, administration and bandwidth costs or run our server software on your own infrastructure allowing you complete control and customization of your deployment environment.
The current release of ODIN is shipped with native pre-compiled binaries for the following platforms:
Platform | x86_64 | aarch64 | x86 | armv7a |
---|---|---|---|---|
Windows | ✅ | ✅ | ✅ | |
Linux | ✅ | ✅ | ✅ | |
macOS | ✅ | ✅ | ||
Android | ✅ | ✅ | ✅ | ✅ |
iOS | ✅ | ✅ |
Support for gaming consoles is available upon request and covers Microsoft Xbox, Sony PlayStation 4/5 and Nintendo Switch.
If your project requires support for any additional platform, please contact us.
To check out the SDK for development, clone the git repo into a working directory of your choice.
This repository uses LFS (large file storage) to manage pre-compiled binaries. Note that a standard clone of the repository might only retrieve the metadata about these files managed with LFS. In order to retrieve the actual data with LFS, please follow these steps:
-
Clone the repository:
git clone https://github.com/4Players/odin-sdk.git
-
Cache the actual LFS data on your local machine:
git lfs fetch
-
Replaces the metadata in the binary files with their actual contents:
git lfs checkout
The following code snippet illustrates how to join a designated room on a specified server using a room token acquired externally:
#include <stdio.h>
#include "odin.h"
int main(int argc, const char *argv[])
{
odin_startup(ODIN_VERSION);
OdinRoomHandle room = odin_room_create();
odin_room_join(room, "<SERVER_URL>", "<TOKEN>");
getchar();
return 0;
}
To enter a room, an authentication token is requisite. ODIN employs the creation of signed JSON Web Tokens (JWT) to ensure a secure authentication pathway. These tokens encapsulate the details of the room(s) you wish to join alongside a customizable identifier for the user, which can be leveraged to reference an existing record within your specific service.
char token[512];
OdinTokenGenerator *generator = odin_token_generator_create("<ACCESS_KEY>");
odin_token_generator_create_token_ex(generator, "<ROOM_ID>", "<USER_ID>", token, sizeof(token));
As ODIN is fully user agnostic, 4Players GmbH does not store any of this information on its servers.
Tokens are signed employing an Ed25519 key pair derived from your distinctive access key. Think of an access key as a singular, unique authentication credential, crucial for generating room tokens to access the ODIN server network. It essentially combines the roles of a username and password into a singular, unobtrusive string of characters, necessitating a comparable degree of protection. For bolstered security, it is strongly recommended to refrain from incorporating an access key in your client-side code. We've created a very basic Node.js server here, to showcase how to issue ODIN tokens to your client apps without exposing your access key.
The ODIN API operates on an event-driven paradigm. In order to manage events, it's necessary to create a callback function in the following manner:
void handle_odin_event(OdinRoomHandle room, const OdinEvent *event, void *data)
{
switch (event->tag)
{
case OdinEvent_RoomConnectionStateChanged:
// Triggered when the room's connectivity state transitions
break;
case OdinEvent_Joined:
// Triggered post successful room entry, rendering the initial state fully accessible
break;
case OdinEvent_RoomUserDataChanged:
// Triggered when the room's arbitrary user data changed
break;
case OdinEvent_PeerJoined:
// Triggered when a new user enters the room
break;
case OdinEvent_PeerLeft:
// Triggered when a user exits the room
break;
case OdinEvent_PeerUserDataChanged:
// Triggered when a peers's arbitrary user data changed
break;
case OdinEvent_MediaAdded:
// Triggered when a peer introduces a media stream into the room
break;
case OdinEvent_MediaRemoved:
// Triggered when a peer withdraws a media stream from the room
break;
case OdinEvent_MediaActiveStateChanged:
// Triggered on change of media stream activity (e.g. user started/stopped talking)
break;
case OdinEvent_MessageReceived:
// Triggered upon receipt of a message containing arbitrary data from a peer
break;
default:
// Optionally handle unexpected events
break;
}
}
To register your callback function as an handler for ODIN events for a room, use the following command:
odin_room_set_event_callback(room, handle_odin_event, NULL);
Each peer within an ODIN room has the capability to attach media streams for the transmission of voice data. The snippet below illustrates the procedure to establish a new input media stream:
OdinAudioStreamConfig config = {
.sample_rate = 48000,
.channel_count = 1,
};
OdinMediaStreamHandle stream = odin_audio_stream_create(config);
odin_room_add_media(room, stream);
For the handling of audio data through input/output media streams, employ the odin_audio_push_data
and odin_audio_read_data
functions. These functions enable the conveyance of audio data from your local microphone to your audio engine, and the playback of audio data received from other peers, respectively. For a comprehensive working example, refer to the Testing section below, which employs the miniaudio library for cross-platform audio capture and playback.
Each ODIN room handle is equipped with a dedicated Audio Processing Module (APM) responsible for executing a spectrum of audio filters including, but not limited to, echo cancellation, noise suppression, and sophisticated voice activity detection. This module is designed to accommodate on-the-fly adjustments, empowering you to fine-tune audio settings in real time to suit evolving conditions. The snippet below demonstrates how you might alter the APM settings:
OdinApmConfig apm_config = {
.voice_activity_detection = true,
.voice_activity_detection_attack_probability = 0.9,
.voice_activity_detection_release_probability = 0.8,
.volume_gate = false,
.volume_gate_attack_loudness = -30,
.volume_gate_release_loudness = -40,
.echo_canceller = true,
.high_pass_filter = false,
.pre_amplifier = false,
.noise_suppression_level = OdinNoiseSuppressionLevel_Moderate,
.transient_suppressor = false,
.gain_controller = true,
};
odin_room_configure_apm(room, apm_config);
The ODIN APM provides the following features:
When enabled, ODIN will analyze the audio input signal using smart voice detection algorithm to determine the presence of speech. You can define both the probability required to start and stop transmitting.
When enabled, the volume gate will measure the volume of the input audio signal, thus deciding when a user is speaking loud enough to transmit voice data. You can define both the root mean square power (dBFS) for when the gate should engage and disengage.
When enabled the echo canceller will try to subtract echoes, reverberation, and unwanted added sounds from the audio input signal. Note, that you need to process the reverse audio stream, also known as the loopback data to be used in the ODIN echo canceller.
When enbabled, the noise suppressor will remove distracting background noise from the input audio signal. You can control the aggressiveness of the suppression. Increasing the level will reduce the noise level at the expense of a higher speech distortion.
When enabled, the high-pass filter will remove low-frequency content from the input audio signal, thus making it sound cleaner and more focused.
When enabled, the preamplifier will boost the signal of sensitive microphones by taking really weak audio signals and making them louder.
When enabled, the transient suppressor will try to detect and attenuate keyboard clicks.
When enabled, the gain controller will bring the input audio signal to an appropriate range when it's either too loud or too quiet.
Each peer within a room is associated with a unique user data represented as a byte array (uint8_t *
). This data is synchronized automatically across all peers, facilitating the storage of bespoke information for every individual peer. Peers have the autonomy to modify their respective user data at any juncture, inclusive of before room entry to set an initial user data value.
char *user_data = "{\"foo\":\"bar\"}";
odin_room_update_peer_user_data(room, (uint8_t *)user_data, strlen(user_data));
ODIN allows you to send arbitrary to every other peer in the room or even individual targets. Just like user data, a message is a byte array (uint8_t *
).
Note: Messages are always sent to all targets in the room, even when they moved out of proximity using setPosition.
struct MyMessage msg = {
.foo = 1,
.bar = 2,
};
odin_room_send_message(room, NULL, 0, (uint8_t *)&msg, sizeof(msg));
In addition to the latest binaries and C header files, this repository also contains a simple test client in the test
sub-directory. Please note, that the configure process will try to download, verify and extract dependencies (e.g. miniaudio), which are specified in the CMakeLists.txt
file. miniaudio is used to provide basic audio capture and playback functionality in the test client.
-
Create a build directory:
mkdir -p build && cd build
-
Generate build scripts for your preferred build system:
- For make ...
cmake ../
- ... or for ninja ...
cmake -GNinja ../
- For make ...
-
Build the test client:
- Using make ...
make
- ... or ninja ...
ninja
- Using make ...
On Windows, calling cmake
from the build directory will create a Visual Studio solution, which can be built using the following command:
msbuild odin_minimal.sln
The test client accepts several arguments to control its functions, but the following three options are particularly crucial for its intended purpose:
odin_minimal -r <room_id> -k <access_key> -s <server_url>
The -r
argument (or --room-id
) is used to specify the name of the room to join. If no room name is provided, the client will automatically join a room called default.
The -k
argument (or --access-key
) is used to specify an access key for generating tokens. If no access key is provided, the test client will auto-generate a key and display it in the console. An access key is a unique authentication key used to generate room tokens for accessing the 4Players ODIN server network. It is important to use the same access key for all clients that wish to join the same ODIN room. For more information about access keys, please refer to our documentation.
The -s
argument (or --server-url
) allows you to specify an alternate ODIN server address. This address can be either the URL to an ODIN gateway or an ODIN server. You may need to specify an alternate server if you are hosting your own fleet of ODIN servers. If you do not specify an ODIN server URL, the test client will use the default gateway, which is located at https://gateway.odin.4players.io.
Note: You can use the --help
argument to get a full list of options provided by the console client.
Contact us through the listed methods below to receive answers to your questions and learn more about ODIN.
Join our official Discord server to chat with us directly and become a part of the 4Players ODIN community.
Have a quick question? Tweet us at @ODIN4Players and we’ll help you resolve any issues.
Don’t use Discord or Twitter? Send us an email and we’ll get back to you as soon as possible.