mugib_voice 0.3.1 copy "mugib_voice: ^0.3.1" to clipboard
mugib_voice: ^0.3.1 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 / errorEvents streams

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));

Error codes — MugibVoiceErrorCode #

Every MugibVoiceError (and MugibVoiceException.code) carries one of these. Branch on the code; show error.message for a human-readable description.

Code Meaning / typical fix
microphonePermissionDenied User denied mic access — prompt to enable it in settings
invalidApiKey API key missing/invalid (HTTP 401/403 or UNAUTHORIZED)
agentNotFound agentId does not exist (HTTP 404 or NOT_FOUND)
agentInactive Agent exists but is disabled — activate it in the dashboard
notConfigured Provider/credentials not set on the server, or missing token fields
quotaExceeded Monthly voice-minutes quota reached (HTTP 429) — upgrade plan
network Transport failure / WebSocket dropped (auto-reconnect retried first)
connectionTimeout Session did not become ready within the timeout
alreadyInProgress start() called while a call is active — end() first
disposed Client/session was disposed — create a new client
providerError The voice provider reported an error mid-call
unsupportedProvider Provider returned by Mugib is not supported by this SDK version
unknown Cause could not be determined (e.g. malformed server response)

Latency metrics — MugibCallMetrics #

All fields are null until the relevant event occurs. Per-response latency is only populated for Gemini Live; VAPI reports timeToFirstAudio only.

Field Meaning
timeToFirstAudio start() → first audio frame (connection + greeting)
lastResponseLatency User stopped speaking → first audio of the reply
averageResponseLatency Rolling average of lastResponseLatency
responseSamples Number of measured responses in the average

Auto-reconnect (Gemini Live) #

If the WebSocket drops unexpectedly mid-call, the SDK reconnects automatically (state goes back to connecting, then connected) while the mic and player keep running. Mugib starts a fresh session and replays the greeting. After maxReconnectAttempts failures it emits a network error. Tune with maxReconnectAttempts and reconnectBackoff. VAPI handles reconnection internally.

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


License #

MIT — see LICENSE.

0
likes
150
points
--
downloads

Documentation

API reference

Publisher

unverified uploader

Official Flutter SDK for Mugib voice agents. One client for VAPI and Google Gemini Live — pass apiKey and agentId only.

Homepage
Repository (GitHub)
View/report issues

Topics

#voice #ai #vapi #websocket #sdk

License

MIT (license)

Dependencies

flutter, flutter_pcm_sound, http, permission_handler, record, vapi, web_socket_channel

More

Packages that depend on mugib_voice