XmaxSDK — Realtime Interactive Video Generation

Flutter 3.35+ Dart 3.9+ iOS 15.0+ Android API 26+ Realtime AI MIT License

A Flutter SDK, providing access to Xmax's real-time, interactive video generation models. The models are optimized for low latency and cost efficiency, enabling instantaneous video transformations across diverse characters, outfits, and aesthetic styles. Also, they can dynamically respond to user gestures, allowing interactive virtual subjects to blend into real-world footage for immersive experiences. XmaxSDK implements an end-to-end pipeline to leverage these novel capabilities through concise Dart APIs and Flutter widgets, making it easy for developers to build next-generation interactive video experiences across iOS and Android.

X-Lab realtime generation demoX-Lab index demoX-Lab storage demo


What XmaxSDK does

XmaxSDK offers a complete workflow that covers media acquisition, low-latency video communication, frame-by-frame generation, and in-app rendering. When processing live camera feeds, it streams media to our cloud inference service, applies on-device enhancement to the returned video, and renders the result to screen. With the entire workflow abstracted into simple API calls, integrating real-time video generation is seamless and intuitive.


What you can build with XmaxSDK

Realtime Use Case Description Demo
Character Swapping Replace anyone in your live feed with a designated avatar in real time. Play the Character Swapping demo
▶ Play demo
Prompt: 视频中角色替换成参考图中角色

Reference image: Select a clear image of the desired character with a clean background.
Virtual Try-On Seamlessly change outfits, preserving exact body shape, natural motion, and an authentic fit. Play the Virtual Try-On demo
▶ Play demo
Prompt: 视频中人物衣服替换成参考图中衣服

Reference image: Select a clear image of the target outfit with a clean background.
Video Restyling Reimagine your world in any style with an immersive visual experience. Play the Video Restyling demo
▶ Play demo
Prompt: 视频风格变为参考图指定的风格

Reference image: Select an image that captures the artistic style you want to apply.
AI Companions Summon virtual characters into your live camera feed and interact with them through gestures. Play the AI Companions demo
▶ Play demo
Prompt: 指定角色在场景中互动

Reference image: Select a clear image of the virtual character you want to summon with a clean background.

Why XmaxSDK?

Low latency
Low latency
Cost efficiency
Cost efficiency
High fidelity
High fidelity
End-to-end latency is measured in hundreds of milliseconds, ensuring that updates to generation conditions and interaction controls are reflected instantly. Run on a single RTX 5090, reducing inference costs by orders of magnitude versus datacenter GPUs like H100. Our models support real-time generation at up to 1080p, delivering production-ready, high-quality video output.

Prerequisites

  • Flutter 3.35 or later
  • Dart 3.9 or later
  • iOS 15.0 or later, or Android API 26 or later
  • Java 17 for Android builds
  • An Xmax API key

Warning

Never commit your Xmax API key to version control. Pass it securely at runtime or use short-lived temporary keys issued by the Xmax API. For step-by-step instructions, see Authentication.


Installation

XmaxSDK is published on pub.flutter-io.cn and can also be integrated from a Git revision or a local source checkout.

pub.flutter-io.cn

Add XmaxSDK to your application's pubspec.yaml:

dependencies:
  xmax_sdk: ^1.0.2

Git

To use a release tag or commit directly from GitHub:

dependencies:
  xmax_sdk:
    git:
      url: https://github.com/XingMai/XmaxSDK-Flutter.git
      ref: 1.0.2

Local path

To use a local source checkout during development:

dependencies:
  xmax_sdk:
    path: ../XmaxSDK

Install the dependencies:

flutter pub get

Host Configuration

iOS

Set the deployment target to iOS 15.0 or later and add the VolcEngine CocoaPods spec source before the CocoaPods CDN source in ios/Podfile:

source 'https://github.com/volcengine/volcengine-specs.git'
source 'https://cdn.cocoapods.org/'

platform :ios, '15.0'

target 'Runner' do
  use_frameworks!

  # Keep the Flutter pod installation generated by the Flutter template here.
end

Enable the camera permission handler in the existing post_install block:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',
        'PERMISSION_CAMERA=1',
      ]
    end
  end
end

Add a camera usage description to ios/Runner/Info.plist:

<key>NSCameraUsageDescription</key>
<string>This app uses the camera for real-time video input.</string>

Customize this message to match your application's user experience. XmaxSDK automatically prompts for camera access when creating the video stream and throws an XmaxError if permission is denied or unavailable.

See the complete example/ios/Podfile for a working setup.

Android

Set the application's minimum SDK to 26 and compile with Java 17 in android/app/build.gradle.kts:

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    defaultConfig {
        minSdk = 26
    }
}

Add the VolcEngine repository to the project dependency repositories in android/build.gradle.kts:

allprojects {
    repositories {
        maven(url = "https://artifact.bytedance.com/repository/Volcengine/")
        google()
        mavenCentral()
    }
}

Also make it available while Flutter plugins are resolved in android/settings.gradle.kts:

pluginManagement {
    repositories {
        maven(url = "https://artifact.bytedance.com/repository/Volcengine/")
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

Enable AndroidX and Jetifier in android/gradle.properties:

android.useAndroidX=true
android.enableJetifier=true

Declare the required permissions in android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

The camera-only SDK does not capture microphone audio, share the screen, use legacy external storage, read phone state, or draw overlays. The full VolcEngine RTC AAR declares permissions and components for those capabilities, so remove them during manifest merging. Copy the cleanup declarations from the example's AndroidManifest.xml, and see build.gradle.kts for the AndroidX vector dependency constraints used by the example.

The full VolcEngine RTC AAR also contains optional native extensions that link against the shared NDK C++ runtime without bundling it. Ensure the host APK includes libc++_shared.so for every enabled ABI. The example's build.gradle.kts includes a cross-platform prepareRtcCppRuntime task that copies the matching runtime from the pinned NDK; apply the same host configuration when integrating XmaxSDK into another Android app.

Release builds with R8 must also suppress warnings for optional device and serializer APIs referenced by VolcEngine RTC and Tencent COS. Add the following rules to the host application's Release ProGuard configuration:

-dontwarn com.hihonor.android.magicx.media.audio.interfaces.**
-dontwarn java.awt.**
-dontwarn javax.money.**
-dontwarn com.google.common.collect.ArrayListMultimap
-dontwarn com.google.common.collect.Multimap
-dontwarn org.javamoney.moneta.**
-dontwarn org.joda.time.**
-dontwarn springfox.documentation.spring.web.json.Json

The same configuration is available in the example's proguard-rules.pro.


Quick Start

XmaxConfiguration uses XmaxEnvironment.china by default. For the overseas service, set environment: XmaxEnvironment.global when creating XmaxClient. The XLab example follows the selected interface language: Simplified Chinese uses China, and English uses Global.

Generate and display video

The following Flutter widget creates a camera stream, starts real-time generation, and binds the local and generated video tracks. Keep the manager and streams in widget state for the lifetime of the screen.

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:xmax_sdk/xmax_sdk.dart';

class RealtimePage extends StatefulWidget {
  const RealtimePage({super.key});

  @override
  State<RealtimePage> createState() => _RealtimePageState();
}

class _RealtimePageState extends State<RealtimePage> {
  static const _model = RealtimeModel.x2_0;
  late final XmaxRealtimeManaging _realtime;
  RealtimeMediaStream? _localStream;
  RealtimeMediaStream? _remoteStream;

  @override
  void initState() {
    super.initState();

    final client = XmaxClient(
      configuration: XmaxConfiguration(apiKey: 'YOUR_XMAX_API_KEY'),
    );
    _realtime = client.createRealtimeManager(
      options: const RealtimeConfiguration(model: _model),
    );
    unawaited(_start());
  }

  Future<void> _start() async {
    final localStream = await _realtime.createLocalCameraStream(
      videoFormat: _model.defaultCameraVideoFormat,
      position: CameraPosition.front,
    );
    if (!mounted) return;
    setState(() => _localStream = localStream);

    final remoteStream = await _realtime.startGeneration(
      localStream: localStream,
      context: RealtimeContext(
        prompt: '视频中角色替换成参考图中角色',
        referencePath:
            'https://platform.xmaxai.com/images/source/charx/chatx_image1.jpg',
      ),
    );
    if (!mounted) return;
    setState(() => _remoteStream = remoteStream);
  }

  @override
  void dispose() {
    unawaited(_realtime.close());
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final localStream = _localStream;
    if (localStream == null) {
      return const Center(child: CircularProgressIndicator());
    }

    return XmaxRealtimeVideoView(
      localTrack: localStream.videoTrack,
      remoteTrack: _remoteStream?.videoTrack,
      videoContentMode: VideoContentMode.fill,
    );
  }
}

Use RealtimeModel.x2_0_pro for X2.0 Pro. Its camera default is 1024×1920 at 30 fps, and it accepts only 1024×1920 or 1920×1024 input resolutions. Keep the selected model and camera format together as shown above; XLab also persists the model selected on its home screen.

The widget keeps the local camera preview underneath the generated video, enables touch interaction by default, and returns to the local preview after stopGeneration() or disconnect().

To display a loading overlay, keep it visible after startGeneration() returns and bind the returned remote track. Dismiss the overlay in the optional onRemoteVideoReady callback, which fires when the first remote frame has been rendered and the view starts showing it. Condition updates do not repeat this notification; a new remote binding cycle does.

Camera generation audio is muted by default. To hear it, call await _realtime.setRemoteAudioVolume(0.8) after creating the local stream; the setting is applied when the generated stream is selected. Read it with await _realtime.remoteAudioVolume (rounded to hundredths). Stopping generation or disconnecting preserves the setting; creating a new camera stream resets it to zero. Before the first stream is created, remote volume defaults to 1.0.

The camera-only SDK has no local file-video audio preview. Matching iOS, await _realtime.localAudioVolume returns 0.45, and valid calls to setLocalAudioVolume() succeed without changing it. Both volume setters reject non-finite values and values outside 0...1.

To update an active generation task, submit a new context without another local stream:

await realtime.startGeneration(
  context: RealtimeContext(
    prompt: '视频中人物衣服替换成参考图中衣服',
    referencePath: anotherReferenceImageURL,
  ),
);

Switch between the front and rear cameras without rebuilding the manager:

final switchedStream = await realtime.switchCamera();

Listen for events

After creating realtime, register the listeners you need before creating the input stream or starting generation.

Listener Purpose
setStateListener Observe idle → preparing → ready → connecting → connected → generating and any failure reason. ready follows the first camera frame and mounted preview.
setNetworkQualityListener Monitor uplink and downlink network quality.
setPerformanceAlarmListener Detect device performance limitations or recovery, with a suggested video format when available.

For example, monitor state changes and errors:

await realtime.setStateListener((state) {
  debugPrint('State: ${state.connectionState.value}');
  final error = state.reason?.error;
  if (error != null) {
    debugPrint('Error: ${error.code.value} ${error.message}');
  }
});

Handle errors from explicit method calls with try / catch around the awaited call. Runtime failures are reported through state.reason?.error.


Resource Cleanup

  • stopGeneration() — Stop the Current Task

    Stops the active generation task while keeping the remote session and local camera preview available:

    await realtime.stopGeneration();
    
  • disconnect() — Stop Remote Generation

    Ends the remote session and cancels billing while keeping the local camera stream and preview active. A new session can later use the same local stream:

    await realtime.disconnect();
    
  • close() — Full Teardown & Release

    Ends the remote session, stops local media capture, and releases all RTC resources. Use this when leaving the generation screen:

    await realtime.close();
    

Note: disconnect() and close() are alternatives, not sequential steps. When exiting a screen, call close() directly—there is no need to call disconnect() first.


Touch interaction

During an active generation task, XmaxRealtimeVideoView captures multi-touch trajectories over the generated video, converts them into video coordinates, and submits them to the active task. Trajectory interaction and the default visual effect are enabled by default.

Disable interaction when touch input belongs to the surrounding interface:

XmaxRealtimeVideoView(
  localTrack: localStream.videoTrack,
  remoteTrack: remoteStream?.videoTrack,
  isInteractionEnabled: false,
)

Provide a TrajectoryEffectRendering implementation to customize the local touch effect. A runnable implementation is available in xlab_trajectory_renderer.dart.


Reference image upload

RealtimeContext.referencePath accepts a supported remote reference-image URL. Upload an on-device image through the storage manager before using it as a generation condition:

final storage = client.createStorageManager();

final uploaded = await storage.uploadImage(
  at: Uri.file('/path/to/reference.jpg'),
  contentType: 'image/jpeg',
);

final referenceImageURL = uploaded.url.toString();

Use uploadImageWithSafetyCheck() when the image must pass the Xmax safety check. The storage manager obtains temporary credentials from Xmax; Tencent Cloud credentials are not embedded in the host application.


Logging

SDK logging is disabled by default. Enable business logs, performance logs, or both when creating the client:

final client = XmaxClient(
  configuration: XmaxConfiguration(
    apiKey: 'YOUR_XMAX_API_KEY',
    loggerOptions: XmaxLoggerOption.all,
  ),
);

Logging configuration is process-wide and shared by all XmaxClient instances. Log titles remain bilingual. Detail labels use Chinese for XmaxEnvironment.china and English for XmaxEnvironment.global; the most recently created client's configuration applies process-wide, matching the iOS SDK.

Enabled logs are sent to iOS unified logging (ai.xmax.XmaxSDK / XmaxSDK) or Android Logcat (XmaxSDK), and are also available in Dart DevTools. Native logging is registered automatically with the SDK; no host-app setup is required.


Example Project

A complete example application for both iOS and Android is available in example. It demonstrates real-time generation using live camera feeds.

X-Lab homeX-Lab SDK featuresX-Lab storage serviceX-Lab realtime generationX-Lab trajectory generation


Dependencies

  • VolcEngine RTC SDK enables low-latency, real-time audio and video communication.
  • Tencent Cloud COS SDK handles media upload and download via object storage.

Contact us

For bug reports and feature requests, please open a GitHub Issue. For integration assistance and technical support, contact us at sdk@xmax.ai.


License

XmaxSDK is available under the terms of the MIT License.

Libraries

xmax_sdk
Xmax SDK for Flutter.
XmaxSDK
Xmax SDK for Flutter.