voxa_rtc_engine

A drop-in, Agora-API-compatible RTC engine for Flutter — on infrastructure you own.

VoxaRTC replicates the public API of agora_rtc_engine (compat line 6.x, pinned to 6.6.3). Same classes, same method signatures, same enums, same error codes, same callback ordering — so an existing Agora Flutter app migrates without rewriting business logic.

Full documentation: voxa.zamansheikh.com/docs/

⚠️ Early release. The Tier-1/Tier-2 surface listed below is implemented and behaviour-verified against recordings from the live Agora service, and is carrying real traffic. Anything outside it fails gracefully rather than silently. Test your own call flows before you switch a production app over.

Migration from Agora

1. Swap the dependency:

dependencies:
  voxa_rtc_engine: ^0.3.0   # was: agora_rtc_engine: ^6.6.3

2. Swap the import (find & replace):

// before
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
// after
import 'package:voxa_rtc_engine/voxa_rtc_engine.dart';

3. Point the SDK at your VoxaRTC endpoint — the only new line:

import 'package:voxa_rtc_engine/voxa.dart';

void main() {
  VoxaRtc.serverUrl = 'https://gate.example.com';
  runApp(const MyApp());
}

Everything else stays: createAgoraRtcEngine(), RtcEngine, joinChannel(), RtcEngineEventHandler, AgoraVideoView, and your existing tokens — both Agora token formats are verified (legacy 006 and 007 AccessToken2), so most token servers migrate by pointing at new credentials, or by importing the ones they already sign with and changing nothing at all.

Android permissions

The package's Android module declares the RTC permissions (CAMERA, RECORD_AUDIO, MODIFY_AUDIO_SETTINGS, INTERNET, ACCESS_NETWORK_STATE, Bluetooth), so they merge into your app exactly as agora_rtc_engine does — no manifest edit needed when migrating. Your app still requests them at runtime as before (e.g. with permission_handler).

On iOS/macOS, add the usual usage descriptions to Info.plist (NSCameraUsageDescription, NSMicrophoneUsageDescription) — same as with Agora.

Known dependency conflict: wakelock_plus

Apps that use wakelock_plus (common in live-streaming apps) will hit a version-solve failure: the media engine pulls device_info_plus 12.x, which pins win32 5.x, while wakelock_plus needs win32 6.x. Lift device_info_plus — 13.x uses win32 6.x and satisfies both:

dependency_overrides:
  device_info_plus: ^13.2.0

Do not pin win32 directly: Dart type-checks a package's Windows sources even in an Android-only build, so forcing it produces analysis errors in files that never run.

Quick example

final engine = createAgoraRtcEngine();
await engine.initialize(const RtcEngineContext(
  appId: '<your VoxaRTC app id>',
  channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
));

engine.registerEventHandler(RtcEngineEventHandler(
  onJoinChannelSuccess: (connection, elapsed) => print('joined'),
  onUserJoined: (connection, remoteUid, elapsed) => print('peer $remoteUid'),
));

await engine.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
await engine.enableVideo();
await engine.startPreview();
await engine.joinChannel(
  token: token, channelId: 'demo', uid: 0,
  options: const ChannelMediaOptions(),
);

// Rendering — unchanged from Agora:
AgoraVideoView(
  controller: VideoViewController(
    rtcEngine: engine,
    canvas: const VideoCanvas(uid: 0),
  ),
);

What's implemented

Channel & lifecycleinitialize, release, joinChannel, leaveChannel, renewToken, connection-state machine, auto-reconnect (onRejoinChannelSuccess), token lifecycle (onTokenPrivilegeWillExpire, onRequestToken).

Media — enable/disable audio & video, local/remote mute (incl. muteAllRemote*), roles (broadcaster/audience) via setClientRole or updateChannelMediaOptions, switchCamera, speakerphone routing, pre-join startPreview, setVideoEncoderConfiguration, dual-stream/simulcast (enableDualStreamMode, setRemoteVideoStreamType), screen share, volume indication, in-call stats (onRtcStats, onNetworkQuality).

In-room musicstartAudioMixing and family. The file is mixed into the outgoing microphone stream natively, so remote participants hear it as part of your audio, exactly as with Agora. Playout and publish volumes, duration, position, seek, looping, and the state callbacks. (Pitch, playback speed and dual-mono are not implemented.)

Behavioural compatibility — callback order, error codes, and idempotency quirks (double-join, mute-before-join, uid 0 auto-assign…) are verified against recordings from the real Agora service via a golden-transcript test harness, not just written from documentation.

Not supported at this stage (calls return AgoraRtcException(-4, errNotSupported) instead of crashing): media player, spatial audio, channel media relay, raw frame observers, RTM.

Platform Status
Android ✅ tested on devices
macOS ✅ tested
iOS 🟡 expected to work (same media engine + audio mixing code as macOS), not yet device-verified
Web ❌ not yet

What you need on the server

This SDK connects to a VoxaRTC endpoint, which verifies your Agora-format tokens and issues the media session. Use a managed one, or run it yourself — setup, tokens and the full integration guide are at voxa.zamansheikh.com/docs/.

License

MIT © Zaman Sheikh (VoxaRTC). Portions of the API-surface declarations are derived from agora_rtc_engine (MIT) — see THIRD_PARTY_LICENSES. "Agora" is a trademark of Agora, Inc.; this project is an independent, API-compatible implementation and is not affiliated with or endorsed by Agora, Inc.

Libraries

voxa
VoxaRTC-specific configuration.
voxa_rtc_engine
VoxaRTC — Agora-API-compatible RTC engine for Flutter.