voxa_deepar
DeepAR camera effects for voxa_rtc_engine.
Effects run on the capture path, before the encoder, so they are in the published stream rather than painted over the local preview. What the streamer sees is what the room receives, with no second render path to keep in sync.
Setup
dependencies:
voxa_deepar: ^0.1.0
That is the whole Android integration. No gradle edit, no MainActivity
change, no ProGuard rule, no native code — the package declares DeepAR's Maven
repository, registers the bridge against your Activity, and ships the consumer
ProGuard rules DeepAR's JNI callbacks need.
You supply three things, because only your app can:
| Why it can't be packaged | |
|---|---|
| A licence key | Bound to your application id — get one at developer.deepar.ai |
| Effect files | Your content choice; DeepAR's free filter pack is a good start |
| The UI | Your design |
Use
final effects = VoxaDeepAr(engine);
await effects.setLicenseKey(myDeepArKey);
final path = await VoxaDeepAr.stageAsset('assets/effects/mask.deepar');
await effects.setEffect(path); // enables on first call
await effects.clear(); // back to the raw camera
Gate your control on effects.isSupported rather than assuming — it is false
on platforms this package does not cover, so you show no button instead of one
that always fails.
Call clear() when leaving a call. The native filter is process-global and
outlives any one engine, so an effect left enabled is still attached the next
time a camera starts.
Already using Agora's extension API?
Then skip this class. It is a thin wrapper over calls you can make directly:
await engine.setExtensionProperty(
provider: 'deepar', extension: 'filter', key: 'licenseKey', value: key);
await engine.setExtensionProperty(
provider: 'deepar', extension: 'filter', key: 'effect', value: path);
await engine.enableExtension(provider: 'deepar', extension: 'filter');
An app already driving camera filters through Agora needs no code change.
What to expect
Measured on a Pixel 6 at 576×1024, across nineteen effects: 24 fps, every frame carrying the effect, ~4.5 ms on the capture thread and ~10 ms inside DeepAR off-thread. The published picture is one frame behind the camera (~42 ms), which is what lets the render pipeline keep up.
Frames never cross into Dart. The naive route — pull frames up, filter, push them back — moves roughly 110 MB/s at 720p30 through a platform channel and cannot hold frame rate on a mid-range phone. Output stays on the GPU: DeepAR renders into a Surface backed by the same EGL context the hardware encoder uses, so nothing is copied on the way out.
Costs, stated plainly
- ~24 MB of DeepAR native code across ABIs. An app bundle reduces what each device downloads, not what exists.
- minSdk 23, above
voxa_rtc_engine's 21 — DeepAR's own requirement. - Effects are a few MB each. Bundling more than a handful does not scale; download them on demand and cache to the filesystem, which is where DeepAR reads them from anyway.
Platforms
| Platform | Status |
|---|---|
| Android | Supported |
| iOS | Not yet — isSupported returns false rather than failing at runtime |
Troubleshooting
Effects do nothing and nothing is logged. Check the licence key against your application id. DeepAR fails silently on a mismatch — no error, no callback — and it reads as broken plumbing rather than a licensing problem. Keys are also per-platform.
Works in debug, crashes in release. If you see
NoSuchMethodError: ...playSound(IZ)V and a SIGABRT, the consumer ProGuard
rules did not apply. They ship with this package; confirm your app is not
overriding consumerProguardFiles.
isSupported is false on Android. The plugin registers on
onAttachedToActivity, so it needs a normal FlutterActivity. A custom host
that never attaches an Activity will not register the filter.
Libraries
- voxa_deepar
- DeepAR camera effects for VoxaRTC.