Skip to content

Device Integration

The goal of device integration is to establish a TiRTC connection with the peer_id and token delivered by your application server, then handle uplink and downlink audio, room events, and cleanup when leaving the room.

This page assumes that the device has completed TiRTC SDK integration. If not, complete the TiRTC device integration first.

Prerequisites

Before calling TiRtcWhipConnect, the device must complete the TiRTC device-side startup flow:

  1. Call TiRtcInit() to initialize the SDK.
  2. Set device_secret_key according to the TiRTC device integration requirements, then call TiRtcStart(device_id, &callbacks) to start the device side.
  3. Wait for TIRTC_EVENT_SYS_STARTED, then call TiRtcWhipConnect(peer_id, token, ...) to join Room.

Calling TiRtcWhipConnect immediately after TiRtcInit() is not the minimum Room device connection path and may leave the SDK without the required device identity or platform connection context. For the TiRTC startup flow, see Connect Devices.

Connection Steps

  1. Complete TiRTC initialization and device-side startup, then wait for TIRTC_EVENT_SYS_STARTED.
  2. Obtain peer_id and token from your application server.
  3. Call TiRTC TiRtcWhipConnect with the peer_id and token delivered by your application server.
  4. Wait for TiRTC to report the connection result.
  5. After the connection is ready, send join_room, then start uplink audio only after validation succeeds.
  6. Listen for downlink audio and decode it according to output_audio in the join_room response.
  7. Listen on command channel 0x2200 for room snapshots and participant events.
  8. When actively leaving, send leave_room first. Enter resource cleanup after receiving a room close notification or after the signaling is sent.

Pass both peer_id and token to the TiRTC TiRtcWhipConnect API unchanged. Do not parse peer_id or rewrite it into another parameter set on the device side.

Connection Example

After receiving peer_id and token, call the TiRTC SDK directly to establish the connection. A 0 return value from TiRtcWhipConnect only means the connection request was submitted. Treat the callback with err == 0 as the success signal.

c
#include "tiRTC.h"
#include <stdbool.h>
#include <string.h>

static tirtc_conn_t g_room_conn = NULL;
static bool g_tirtc_ready = false;

static int room_tirtc_runtime_init(const char *device_id)
{
    if (g_tirtc_ready) {
        return 0;
    }

    int ret = TiRtcInit();
    if (ret != 0) {
        return ret;
    }

    TIRTCCALLBACKS cbs;
    memset(&cbs, 0, sizeof(cbs));
    ret = TiRtcStart(device_id, &cbs);
    if (ret != 0) {
        TiRtcUninit();
        return ret;
    }

    g_tirtc_ready = true;
    return 0;
}

static void on_room_whip(int err, tirtc_conn_t hconn, void *user_data)
{
    (void)user_data;
    if (err != 0) {
        /* Connection failed: log the error and clear local room state */
        return;
    }

    g_room_conn = hconn;
    /* After connection succeeds, start uplink audio and listen on command 0x2200 */
}

int start_room_tirtc_connect(const char *device_id,
                             const char *peer_id,
                             const char *token)
{
    int ret = 0;

    if (device_id == NULL || device_id[0] == '\0' ||
        peer_id == NULL || peer_id[0] == '\0' ||
        token == NULL || token[0] == '\0') {
        return -1;
    }

    ret = room_tirtc_runtime_init(device_id);
    if (ret != 0) {
        return ret;
    }

    return TiRtcWhipConnect(peer_id, token, on_room_whip, NULL);
}

void stop_room_tirtc_connect(void)
{
    if (g_room_conn != NULL) {
        TiRtcClose(g_room_conn);
        g_room_conn = NULL;
    }

    if (g_tirtc_ready) {
        TiRtcStop();
        TiRtcUninit();
        g_tirtc_ready = false;
    }
}

TiRtcWhipConnect returning 0 only means that the connection request was submitted. Treat the callback with err == 0 as the success signal. Start the connection only after receiving TIRTC_EVENT_SYS_STARTED.

Send join_room

After the TiRTC connection is established, the device must send a JSON-RPC Request on command channel 0x2200 within 10 seconds. room_id and device_id must match the values used to request the credentials.

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "join_room",
  "params": {
    "room_id": "room-001",
    "device_id": "device-001",
    "input_audio": {"codec": "pcm", "sample_rate": 16000, "channels": 1},
    "output_audio": {"codec": "g711a", "sample_rate": 16000, "channels": 1}
  }
}

The device joins the room only after a successful response. The response contains session_id and the normalized audio formats. Identity or format validation failures return a JSON-RPC error.

The legacy start_session method is no longer supported. The device must complete join_room immediately after TiRTC connects before sending audio or any other room signaling.

Supported Audio Format and Sample Rate

The current Room device path supports the following format in both directions:

codecSample rate (Hz)Channels
opus8000, 160001
pcm8000, 160001
g711a8000, 160001
amr8000 (AMR-NB), 16000 (AMR-WB)1

The device can specify the codec and sample rate for input_audio and output_audio independently in join_room. It must use the formats echoed in the successful response, and its media and flags values must match input_audio.

Send audio frames from the capture thread at a fixed interval. A 20 ms frame is recommended.

c
#include <stdint.h>
#include <string.h>
#include "tiRTC.h"

static const uint8_t kRoomAudioStreamId = 1;

int room_send_audio_opus(tirtc_conn_t hconn,
                         const void *opus_data,
                         uint32_t len,
                         uint32_t ts_ms)
{
    TIRTCFRAMEINFO fi;
    memset(&fi, 0, sizeof(fi));
    fi.stream_id = kRoomAudioStreamId;
    fi.media = TIRTC_AUDIO_OPUS;
    /* Must match the uplink audio format configured on the platform side */
    fi.flags = TIRTC_AUDIOSAMPLE_16K16B1C;
    fi.ts = ts_ms;
    fi.length = len;
    return TiRtcSendAudioStream(hconn, &fi, opus_data);
}

Audio parameters must match across:

  1. The format actually captured and encoded by the device.
  2. fi.media assigned in C code.
  3. Audio sample specification fi.flags assigned in C code.

For example, opus/16000/mono corresponds to TIRTC_AUDIO_OPUS and TIRTC_AUDIOSAMPLE_16K16B1C.

Room downlink audio is delivered through a TiRTC audio stream. Decode it according to output_audio in the join_room response and send it to the playback pipeline:

  • Filter room downlink audio by stream_id.
  • Decode according to the audio frame's media and flags, and verify them against output_audio.
  • Support continuous streaming playback instead of waiting for a whole audio segment.
  • Stop playback and clear buffers after receiving room_closed or leaving the room locally.

Command Channel

Room uses TiRTC command channel 0x2200 to carry JSON-RPC 2.0 messages:

  • After the connection is ready, the device must send join_room. Once the join succeeds, Room service sends room_snapshot to initialize the local participant list.
  • When actively leaving, the device must send a leave_room Notification without id.
  • The device can send get_room_snapshot to actively request the participant list.
  • When the local microphone state changes, the device can send set_mic_state with on, speaking, or off.
  • Update local participant state when receiving participant_joined, participant_left, or participant_mic_state_changed.
  • Enter resource cleanup after receiving room_closed.

For complete fields, see Room Signaling.

Command Receive Example

The following example shows command filtering and event dispatching. Implement jsonrpc_method, method_equals, and handle_* functions in your business code using a JSON library.

c
#include <stdint.h>
#include "tiRTC.h"

#define TIRTC_ROOM_SIGNALING 0x2200

static const char *jsonrpc_method(const void *data, uint32_t len);
static int method_equals(const char *method, const char *expected);
static void handle_room_snapshot(const void *data, uint32_t len);
static void handle_participant_joined(const void *data, uint32_t len);
static void handle_participant_left(const void *data, uint32_t len);
static void handle_participant_mic_state_changed(const void *data, uint32_t len);
static void handle_room_closed(const void *data, uint32_t len);

static void on_room_command(tirtc_conn_t hconn, uint32_t cmdw,
                            const void *data, uint32_t len)
{
    const char *method;
    (void)hconn;

    if (cmdw != TIRTC_ROOM_SIGNALING || data == NULL || len == 0) {
        return;
    }

    /* data is a UTF-8 JSON-RPC string. Use a JSON library in production. */
    method = jsonrpc_method(data, len);
    if (method_equals(method, "room_snapshot")) {
        handle_room_snapshot(data, len);
        return;
    }
    if (method_equals(method, "participant_joined")) {
        handle_participant_joined(data, len);
        return;
    }
    if (method_equals(method, "participant_left")) {
        handle_participant_left(data, len);
        return;
    }
    if (method_equals(method, "participant_mic_state_changed")) {
        handle_participant_mic_state_changed(data, len);
        return;
    }
    if (method_equals(method, "room_closed")) {
        handle_room_closed(data, len);
        return;
    }
}

Handling recommendations:

  • room_snapshot: initialize the local participant list from the snapshot.
  • participant_joined: add the new participant to the local participant list.
  • participant_left: remove the participant from the local participant list.
  • participant_mic_state_changed: update the specified participant's microphone state.
  • set_mic_state: send it when the local microphone switch or speaking state changes. It only synchronizes state and does not replace local capture or uplink control.
  • room_closed: stop capture and playback, then enter resource cleanup.

Resource Cleanup

The device should route active leave, network disconnect, business timeout, and room close notifications to the same cleanup flow:

  • For an active leave, first send a leave_room Notification without id on command channel 0x2200.
  • Stop capture and playback.
  • Close the TiRTC connection.
  • Clear local room state and playback buffers.
  • Discard expired token values and request a new credential for the next join.

Minimal Run-Through Path

To quickly eliminate environment and configuration issues, run this end-to-end path first:

  1. Server Request Test: Use your application server to call POST /v1/token/room and ensure it returns valid peer_id and token. For complete fields, see Server API.
  2. Device Startup Test: Confirm that the device has completed TiRtcInit() and TiRtcStart(), and has received TIRTC_EVENT_SYS_STARTED.
  3. Device Connection Test: Pass device_id, peer_id, and token to start_room_tirtc_connect, then verify that on_room_whip returns err == 0.
  4. Join And Snapshot Verification: After the connection succeeds, send join_room. After its success response, the device should receive room_snapshot on command channel 0x2200.
  5. Multi-Device Join Verification: Let two devices request credentials for the same business room_id and join the room. The first device should receive participant_joined.
  6. Microphone State Verification: One device sends set_mic_state to switch among on, speaking, and off. Other online devices should receive participant_mic_state_changed.
  7. Audio And Leave Verification: One device sends test audio continuously, and another device should receive downlink audio. When either device sends leave_room, the other online devices should receive participant_left.

Room