splive

Flutter package for adding live voice rooms to your app with Specular.Live: realtime room events and chat over a WebSocket, and voice over LiveKit, with microphone and speaker controls.

You pay only for the voice minutes you use. See the pricing and the full quick start.

How it works

your Flutter app  ──(1) join request──▶  YOUR backend
                                             │ (2) X-Specular-Key (server secret)
                                             ▼
                                        Specular.Live
                                             │ (3) short-lived tokens
your Flutter app  ◀──────────────────────────┘
       │ (4) connect with the tokens using this package
       ▼
   voice room
  • Your API key never goes into the app. Your backend keeps it and asks Specular.Live for a short-lived session for each user who wants to join.
  • This package connects the app using those short-lived tokens.

Install

dependencies:
  splive: ^2.0.2
flutter pub get

Developer accounts, projects and API keys are managed in your developer dashboard. New verified accounts receive free trial minutes.

Connect to a room

1. On your backend, request a session. Full details are in the quick start.

curl -X POST 'https://specular.live/api/developer/v1/voice/sessions' \
  -H 'Accept: application/json' -H 'Content-Type: application/json' \
  -H 'X-Specular-Key: YOUR_SERVER_KEY' \
  -d '{"group_uuid":"...","room_uuid":"...","participant_id":"your-user-id","display_name":"Sara","can_publish":true}'

Return only the tokens from the answer to your app.

2. In your Flutter app:

import 'package:splive/splive.dart';

final sdk = SpliveSdk();

// 'session' is the JSON your backend returned.
await sdk.connectRoomSocket(
  websocketUrl: session['websocket_url'],
  roomId: session['websocket_room_id'],
  token: session['websocket_token'],
);

await sdk.connect(SpliveSessionConfig(
  serverUrl: session['media_url'],
  accessToken: session['media_token'],
  roomId: session['websocket_room_id'],
  userId: currentUserId,
  displayName: currentDisplayName,
));

await sdk.enableMicrophone();

Session tokens are short-lived (15 minutes by default). Ask your backend for a new one when it expires.

3. When the user leaves:

await sdk.disconnectRoomSocket();
await sdk.disconnect();
await sdk.dispose(); // when the SDK object itself is no longer needed

Voice

Member What it does
enableMicrophone(), disableMicrophone(), toggleMicrophone() Control your microphone
isMicrophoneEnabled Whether your microphone is on
setSpeakerOutput(bool) Switch speaker output
participants Stream<List<SpliveParticipant>> of who is in the room and who is speaking
currentParticipants() The current list
connectionStates, connectionState, isConnected Voice connection state (connecting, connected, reconnecting, ...)
mediaEvents Voice events such as reconnecting and active speakers
sdk.participants.listen((list) {
  for (final p in list) {
    print('${p.displayName} speaking: ${p.isSpeaking}');
  }
});

sdk.connectionStates.listen((state) {
  if (state == SpliveConnectionState.reconnecting) {
    // show a "reconnecting…" banner
  }
});

Realtime events and chat

Member What it does
roomEvents Stream<Map<String, dynamic>> of every realtime room event
roomMessages Stream<RoomChatMessage> of chat messages
sendRoomMessage(roomId:, message:) Send a text message
sendRoomEmoji(roomId:, emoji:) Send an emoji
sendRoomEvent(type:, data:) Send your own event to the room
isRoomSocketConnected Whether the realtime connection is open
sdk.roomMessages.listen((message) => print(message));

await sdk.sendRoomMessage(roomId: session['websocket_room_id'], message: 'Hello!');
await sdk.sendRoomEmoji(roomId: session['websocket_room_id'], emoji: '🎉');

Use sendRoomEvent for anything specific to your app (game moves, reactions, gift animations). The package only carries the events; what they mean is up to your app.

Android and iOS setup

Android — in android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

To keep a room's audio going when the app is in the background, run an Android foreground service (for example with the flutter_foreground_task package).

iOS — in ios/Runner/Info.plist:

<key>NSMicrophoneUsageDescription</key>
<string>Voice rooms need your microphone.</string>
<key>UIBackgroundModes</key>
<array><string>audio</string></array>

Errors

Failures throw SpliveException (or a StateError / ArgumentError for missing arguments). Common causes when getting a session from your backend:

Response Meaning
401 The key is missing, wrong or revoked
402 developer_prepaid_balance_exhausted Your voice minutes are used up
429 developer_concurrency_limit_reached Too many people connected at once for this environment; retry shortly
503 developer_capacity_reached The platform is at capacity; retry shortly

What this package does not do

It is a transport for voice and realtime events. Accounts, payments, wallets, gifts, moderation rules and your app's own features belong in your app and your backend.

More

License

See LICENSE.

Libraries

splive