@applooma/rtc-server-participant
v0.1.0
Published
AppLooma RTC server participant for Node.js — join a channel as a bot, publish and receive raw audio and video frames, exchange messages
Maintainers
Readme
@applooma/rtc-server-participant
Join an AppLooma RTC channel from Node.js as a participant: a voice agent, a transcription listener, a media relay, a moderation bot. The bot publishes raw PCM audio and raw video frames, receives everyone else's audio and video as raw frames, and exchanges messages with the Web, Android, iOS, Flutter and React Native SDKs.
Status: 0.1.0, beta. The API may change before 1.0.
Install
npm install @applooma/rtc-server-participantNode 18 or newer. The media stack ships as prebuilt native binaries for
linux-x64, linux-arm64, darwin-arm64, darwin-x64 and win32-x64, so no compiler
is needed. On any other platform AppBot.join() rejects with an
AppBotError whose code is unsupported_platform.
Tokens
A bot uses the same tokens as any client. Mint one on your server with
createToken() from @applooma/server-sdk, with an identity of your choosing
and role host (to publish) or audience (to listen only). url is the same
wsUrl your token endpoint returns to clients.
Example: an echo bot
Plays every speaker's voice back into the channel.
import { AppBot } from '@applooma/rtc-server-participant';
import { createToken } from '@applooma/server-sdk';
const token = await createToken({ /* your API key, channel, identity 'echo-bot', role 'host' */ });
const bot = await AppBot.join({ url: process.env.APPLOOMA_WS_URL!, token, receiveSampleRate: 48000, receiveChannels: 1 });
bot.on('userJoined', (u) => console.log(`${u.uid} joined`));
bot.on('userLeft', (u) => console.log(`${u.uid} left`));
bot.on('audioFrame', (frame, from) => {
// 10 ms of 16-bit mono PCM at 48 kHz per frame. Send it straight back.
bot.publishAudio(frame).catch((e) => console.error(e.code, e.message));
});
bot.on('message', async (m) => {
if (m.text === '!bye') await bot.leave();
else await bot.sendMessage(`echo: ${m.text ?? JSON.stringify(m.data)}`);
});
process.on('SIGINT', () => bot.leave().then(() => process.exit(0)));API
AppBot.join({ url, token, ... }): Promise<AppBot>
| Option | Default | |
| --- | --- | --- |
| url | required | The channel server URL (wsUrl). |
| token | required | A token from your server. |
| autoSubscribe | true | Receive other participants' media. |
| receiveSampleRate | 48000 | Rate of audioFrame events; incoming audio is resampled. |
| receiveChannels | 1 | Channels of audioFrame events. |
| receiveVideoFormat | 'rgba' | 'rgba' or 'i420' for videoFrame events. |
Publishing
publishAudio(frame | Int16Array, { sampleRate, channels }?): interleaved 16-bit PCM. The first call publishes the bot's microphone. Every frame must keep the same rate and channel count. Awaiting each call paces you to real time; 10 ms or 20 ms frames work well.publishVideo({ data, width, height, format: 'i420' | 'rgba' }): the first call publishes the bot's camera. I420 is the Y plane, then U, then V.
Receiving
on(event, listener) with:
| Event | Arguments |
| --- | --- |
| audioFrame | (frame: { data: Int16Array, sampleRate, channels, samplesPerChannel }, user) |
| videoFrame | (frame: { data: Uint8Array, width, height, format, timestampUs }, user) |
| message | (message: { id, text?, data?, from?, sentAt }) |
| userJoined / userLeft | (user: { uid, displayName, role, attributes }) |
| disconnected | (reason?) |
| error | (error: AppBotError) |
Frames are only decoded for tracks subscribed while an audioFrame or
videoFrame listener is attached, so register listeners before other people
start publishing if you need their media.
Messages and leaving
sendMessage(text | object, { reliable }?): arrives on the client SDKs'messageevent, exactly like a message from another app user.leave(): leaves the channel and frees native resources.
Errors
Everything throws or emits AppBotError with a code: unsupported_platform,
join_failed, not_joined, invalid_frame, send_failed.
Logging
The bot logs nothing on its own. Log from your listeners.
Docs: https://applooma.dev/sdk/server-participant
