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.