mugib_voice 0.3.0
mugib_voice: ^0.3.0 copied to clipboard
Official Flutter SDK for Mugib voice agents. One client for VAPI and Google Gemini Live — pass apiKey and agentId only.
mugib_voice #
Official Flutter SDK for Mugib real-time voice agents.
Add a voice call to your mobile app: the user talks to your Mugib AI agent by microphone, hears the reply, sees live transcripts, and can mute or hang up. You do not choose or configure a voice provider — Mugib does that on the server. Your app only needs a project API key and a voice agent id.
What you need (from Mugib dashboard) #
| Item | Where |
|---|---|
| Project API key | Project → Settings → API Key |
| Voice agent id | Project → Voice Agents → numeric id |
| API base URL | https://api.mugib.com (default; use your self-hosted URL if applicable) |
Everything else — knowledge base, system/voice prompts, language, voice personality, and which voice engine runs the call — is configured in the Mugib project. No provider keys or assistant IDs in your app.
Install #
dependencies:
mugib_voice: ^0.3.0
flutter pub get
Requirements: Flutter 3.24+ / Dart 3.5+ · iOS & Android (see permissions below).
Monorepo dev:
path: ../sdk/flutter/mugib_voice
Platform permissions #
iOS — ios/Runner/Info.plist #
<key>NSMicrophoneUsageDescription</key>
<string>We need the microphone for voice conversations with our support agent.</string>
ios/Podfile: platform :ios, '12.0'
Android — AndroidManifest.xml #
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
minSdkVersion 23 or higher.
Quick start #
import 'package:mugib_voice/mugib_voice.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await MugibVoice.initialize(); // once at startup
runApp(const MyApp());
}
// Inside your screen / button handler:
final call = MugibVoiceClient(
apiKey: 'YOUR_PROJECT_API_KEY',
agentId: 34,
);
call.state.listen((state) {
// idle → connecting → connected → listening / speaking → ended / error
});
call.transcripts.listen((line) {
// line.role: "user" | "assistant"
// line.text: live transcription
});
call.errors.listen((message) {
// show snackbar / dialog
});
await call.start(); // Mugib connects the call — you do nothing else
// … user talks …
call.mute();
call.unmute();
await call.end(); // hang up
await call.start(); // same client can call again
await call.dispose(); // when screen is destroyed
That is the full integration surface for most apps: apiKey + agentId +
start().
Optional: voice agent picker #
If the project has multiple voice agents, list them and let the user pick
one. You only need id and display fields (name, language, …) — not the
provider.
final agents = await MugibVoice.listAgents(apiKey: 'YOUR_PROJECT_API_KEY');
// Example UI: show agent.name, agent.language
final selectedId = agents.first.id;
final call = MugibVoiceClient(apiKey: 'YOUR_PROJECT_API_KEY', agentId: selectedId);
await call.start();
The provider field on each agent is informational only (e.g. for an
admin/debug label). The SDK reads it from Mugib when connecting; your code
must not branch on it.
Call states #
MugibCallState |
Meaning |
|---|---|
idle |
Not in a call |
connecting |
Opening the Mugib voice session |
connected |
Call is live |
listening |
Agent is waiting for the user |
speaking |
Agent is talking |
ended |
Call finished normally |
error |
Failed — see errors stream |
API reference #
MugibVoice #
| Method | Description |
|---|---|
initialize() |
Call once in main() before any voice call |
listAgents({apiKey, baseUrl}) |
Active voice agents for a project (picker UI) |
MugibVoiceClient #
| Parameter | Description |
|---|---|
apiKey |
Project API key |
agentId |
Voice agent id from Mugib dashboard |
baseUrl |
Default https://api.mugib.com |
| Parameter (optional) | Description |
|---|---|
feedThresholdFrames |
Gemini Live playback buffer in output samples (default 4000 ≈ 166ms). Lower = less latency, higher underrun risk |
maxReconnectAttempts |
Gemini Live auto-reconnect attempts after a drop (default 3) |
reconnectBackoff |
Base delay between reconnect attempts, multiplied by attempt number (default 600ms) |
| Method / property | Description |
|---|---|
start() |
Start a voice call (Mugib picks connection details) |
end() |
End the call |
mute() / unmute() / toggleMute() |
Microphone control |
dispose() |
Release resources; client cannot be reused |
state |
Stream of MugibCallState |
transcripts |
Stream of MugibTranscript |
errors |
Stream of error message strings |
errorEvents |
Stream of MugibVoiceError (with MugibVoiceErrorCode) |
metrics / currentMetrics |
Stream / snapshot of MugibCallMetrics (latency) |
callDuration / durationTicks |
Elapsed call time (snapshot / per-second stream) |
token |
Last session metadata from Mugib (optional; for debugging) |
Errors, metrics & call timer #
// Branch on a machine-readable code instead of matching strings.
call.errorEvents.listen((e) {
switch (e.code) {
case MugibVoiceErrorCode.microphonePermissionDenied:
// prompt the user to enable mic
break;
case MugibVoiceErrorCode.quotaExceeded:
// show "upgrade plan"
break;
case MugibVoiceErrorCode.network:
// SDK auto-reconnects (Gemini); show a "reconnecting…" hint
break;
default:
// e.message has a human-readable description
}
});
// Latency metrics (time-to-first-audio, per-response latency).
call.metrics.listen((m) {
print('first audio: ${m.timeToFirstAudio?.inMilliseconds} ms');
print('avg response: ${m.averageResponseLatency?.inMilliseconds} ms');
});
// Live call timer.
call.durationTicks.listen((d) => setState(() => _elapsed = d));
Latency tuning (Gemini Live) #
Gemini Live has no provider-side latency knob; the only client-tunable lever is the playback buffer. Lower it for snappier audio at the cost of underrun risk:
final call = MugibVoiceClient(
apiKey: 'YOUR_KEY',
agentId: 34,
feedThresholdFrames: 2400, // ≈100ms (default 4000 ≈ 166ms)
);
What Mugib handles for you #
You do not configure these in the app:
- Knowledge base & MCP tool calls during the call
- System / voice prompts and agent personality
- Language, dialect, voice, greeting
- Voice transport and provider selection
- Barge-in (user interrupting the agent)
The SDK handles microphone capture, playback, transcripts, mute, and hang-up on the device. Mugib handles the AI and business logic on the server.
Architecture (for curious developers) #
Your app Mugib cloud
──────── ───────────
apiKey + agentId → validates project & agent
→ loads KB, prompts, voice settings
→ starts the right voice backend (transparent)
← audio, transcripts, call state
Your integration code stays the same even if the project owner changes the voice backend in the Mugib dashboard.
Troubleshooting #
| Symptom | Check |
|---|---|
Microphone permission denied |
iOS Info.plist / Android RECORD_AUDIO |
Invalid API Key |
API key from correct project |
Voice agent not found |
agentId exists and is active in Voice Agents |
Call already in progress |
Call end() before start() again, or use a new client after dispose() |
| No audio on emulator | Test on a real device; emulators have unreliable audio |
Example app #
See example/ in this package for a minimal call screen with agent picker.
Maintainers #
cd sdk/flutter/mugib_voice
make help
make check
make release-patch # bump version + publish to pub.dev
Links #
- Package: https://pub.dev/packages/mugib_voice
- Mugib: https://mugib.com
- Integration guide:
docs/voice-integration.mdin the Mugib repo
License #
MIT — see LICENSE.