The AgentBox AIRA SDK provides a comprehensive solution for integrating Android cloud instances into web applications. With rich configuration options and extensive callback support, it handles screen casting, device control, and real-time communication for cloud-based mobile environments.
- Real-time Screen Casting: High-quality video streaming from Android instances
- Device Control: Complete input simulation including touch, keyboard, and hardware buttons
- Multi-user Support: Collaborative access with permission management
- Network Optimization: Automatic reconnection and ISP node switching
- Camera Integration: Support for custom camera input sources
- Sensor Simulation: GPS, accelerometer, and other sensor data injection
Add the SDK script tag to your HTML file (before your application code):
<script src="https://unpkg.com/@agentbox-sdk/aira@2.16.2/dist/index.js"></script>
// Initialize the SDK (using global variable from CDN)
const sdk = new window.NzCp();
// Configuration parameters
const config = {
mountId: 'android-screen', // ID of container element
userId: 'unique-user-id', // Your user identifier
instanceNo: 'instance-123', // Instance number
width: 720, // Screen width
height: 1280, // Screen height
bitrate: 2048, // Video bitrate
fps: 30 // Frame rate
};
// Callback handlers
const callbacks = {
onStartSuccess: () => {
console.log('Connected to Android instance');
},
onStartFail: (code) => {
console.error('Connection failed:', code);
},
onError: (code) => {
console.error('Playback error:', code);
}
};
// Initialize the SDK
sdk.init(config, callbacks);
// Start screen casting with credentials
sdk.start('your-access-key', 'your-secret-key');
// Use global variable from CDN script tag
const sdk = new window.NzCp();
sdk.init(params, callbacks);
| Parameter | Type | Description |
|---|
mountId | string | ID of the HTML container element where the Android screen will be rendered |
userId | string | Unique identifier for the current user session |
instanceNo | string | Instance number |
| Parameter | Type | Default | Description |
|---|
width | number | 720 | Video stream width in pixels |
height | number | 1280 | Video stream height in pixels |
bitrate | number | 2048 | Video bitrate in kbps (higher = better quality, more bandwidth) |
fps | number | 30 | Target frame rate (15-60 fps recommended) |
| Parameter | Type | Default | Description |
|---|
isMute | boolean | false | Start with audio muted |
isShowPausedDialog | boolean | true | Show dialog when video is paused |
| Parameter | Type | Default | Description |
|---|
inputMode | number | 0 | Input handling: 0 = cloud device, 1 = local device |
cameraSourceMode | number | 0 | Camera source: 0 = automatic, 1 = custom resource input |
| Parameter | Type | Default | Description |
|---|
logLevel | number | 1 | Logging verbosity: 1 = debug, 2 = info, 3 = warn, 4 = error |
reconnectAttempts | number | 10 | Maximum automatic reconnection attempts |
reconnectCycle | number | 5000 | Time between reconnection attempts (milliseconds) |
| Callback | Parameters | Description |
|---|
onStartSuccess | () | Successfully connected to Android instance |
onStartFail | (code: number) | Failed to connect - see error codes |
onInitFail | (code: number) | SDK initialization failed |
onError | (code: number) | Runtime error occurred during streaming |
onStop | () | Screen casting session ended |
const callbacks = {
onStartSuccess: () => {
console.log('Ready to interact with Android instance');
// Enable UI controls, show success message, etc.
},
onStartFail: (code) => {
console.error(`Connection failed with code: ${code}`);
// Handle connection failure, retry logic, etc.
}
};
| Callback | Parameters | Description |
|---|
onPlayInfo | (info: object) | Real-time streaming statistics (called every second) |
onRotationChange | (rotation: number) | Screen orientation changed: 0=0°, 1=270°, 2=180°, 3=90° |
onResolutionChange | (width: number, height: number) | Video resolution changed |
onBitrateChange | (bitrate: number) | Video bitrate adjusted |
onFpsChange | (fps: number) | Frame rate changed |
onPaused | () | Video/audio playback was unexpectedly paused |
| Callback | Parameters | Description |
|---|
onReconnect | () | Network reconnection attempt started |
onReconnectEnd | (result: number) | Reconnection finished: 0 = failed, 1 = succeeded |
onAccessKeyExp | (reconnectCallback: function) | Access credentials expired - call reconnectCallback(ak, sk) with new credentials |
onNetworkConfig | (ispList: object[]) | Available network nodes received |
onNetworkChangeError | (errCode: number) | Failed to switch network node |
const callbacks = {
onAccessKeyExp: (reconnectCallback) => {
// Fetch new credentials from your auth service
getNewCredentials().then(({ak, sk}) => {
reconnectCallback(ak, sk);
});
},
onNetworkConfig: (ispList) => {
// ispList example: [{ispCode: 'DEFAULT', label: 'Default'}, {ispCode: 'TELECOM', label: 'China Telecom'}]
console.log('Available network nodes:', ispList);
}
};
| Callback | Parameters | Description |
|---|
onCameraOpen | () | Camera was opened (only when cameraSourceMode=1) |
onCameraClose | () | Camera was closed (only when cameraSourceMode=1) |
| Callback | Parameters | Description |
|---|
onApplyCtrl | (msg: {applyUserId, instanceNo}) | Another user requests control of the instance |
onApplyCtrlAnswer | (msg: {applyUserId, instanceNo, accept}) | Response to control request received |
const callbacks = {
onApplyCtrl: ({applyUserId, instanceNo}) => {
// Show UI to let current user approve/deny the request
const allow = confirm(`User ${applyUserId} wants to control this instance. Allow?`);
sdk.sendApplyCtrlAnswer(applyUserId, allow);
}
};
| Callback | Parameters | Description |
|---|
onTransMessage | (packageName: string, msg: string) | Received message from Android app |
onSendTransMessageRes | () | Message successfully sent to Android app |
| Callback | Parameters | Description |
|---|
onSensorChange | (type: number, state: number) | Sensor state changed • type: Sensor type identifier • state: 0 = closed/disabled, 1 = open/enabled |
onGameKeysMenuClose | () | Game key configuration menu was closed |
onOutClipperChange | (str: string) | Android device clipboard content changed |
| Callback | Parameters | Description |
|---|
onOutCloudNotify | (type: number, msg: any) | System notification from cloud device • type: Notification type (0, 1, or 2) • msg: Type-specific message data |
Notification Types:
type: 0 - App switch: msg = package name (string)
type: 1 - App crash: msg = package name (string)
type: 2 - User status change: msg = array of user objects
For type 2, msg format:
msg: [{
userId: 'a123', // User identifier
mediaStatus: 'PLAYING', // Playback status
manipulatePermission: 'MANIPULATE' // User permission level
}]
Field descriptions:
userId: User identifier string
mediaStatus: Playback status
'PLAYING' - Currently displaying video stream
'STOPPED' - Video stream stopped
manipulatePermission: User access level
'MANIPULATE' - Full control (can interact with device)
'WATCH' - View only (cannot control device)
const callbacks = {
onOutCloudNotify: (type, msg) => {
switch(type) {
case 0:
console.log('App switched to:', msg);
break;
case 1:
console.log('App crashed:', msg);
break;
case 2:
// msg = [{userId, mediaStatus, manipulatePermission}, ...]
msg.forEach(user => {
console.log(`User ${user.userId}:`);
console.log(` Status: ${user.mediaStatus}`);
console.log(` Permission: ${user.manipulatePermission}`);
// Handle different permission levels
if (user.manipulatePermission === 'MANIPULATE') {
console.log(` ${user.userId} can control the device`);
} else if (user.manipulatePermission === 'WATCH') {
console.log(` ${user.userId} can only view`);
}
});
break;
}
}
};
// Start screen casting with credentials
sdk.start(accessKey, secretKey);
// Stop and cleanup
sdk.destroy();
// Get instance number (call after onStartSuccess)
const instanceNo = sdk.getInstanceNo();
// Change stream quality during runtime
const profile = {
width: 1080,
height: 1920,
fps: 60,
bitrate: 4096
};
sdk.setStreamProfile(profile);
// Resume playback after pause
sdk.resumePlay();
// Volume control
sdk.setVolumeUp();
sdk.setVolumeDown();
// Mute/unmute
sdk.setMute(true); // Mute
sdk.setMute(false); // Unmute
// Navigate the Android device
sdk.home(); // Home button
sdk.back(); // Back button
sdk.menu(); // Menu button
// Send text to focused input field
sdk.sendText('Hello World');
// Set clipboard content
sdk.sendInClipper('Text to copy');
// Set GPS coordinates
sdk.sendGps(longitude, latitude);
// Trigger sensor data (accelerometer, gyroscope, etc.)
sdk.doSensor(type, x, y, z);
// Control screen rotation
sdk.setPhoneRotation(
1, // autoRotation: 0=disable, 1=enable
0 // userRotation: 0=portrait, 1=landscape
);
// Switch between input modes
sdk.changeInputMode(0); // 0: cloud device input
sdk.changeInputMode(1); // 1: local device input
// Switch to different ISP node for better performance
sdk.changeNetwork('TELECOM'); // Use ISP code from onNetworkConfig
// Respond to control requests
sdk.sendApplyCtrlAnswer(userId, true); // Accept
sdk.sendApplyCtrlAnswer(userId, false); // Reject
// Send message to specific Android app
sdk.sendTransMessage('com.example.app', 'Hello from web');
// For cameraSourceMode=1, set camera configuration
const cameraHead = {
type: 264, // Video format: 1=JPEG, 263=H263, 264=H264
width: 1280, // Camera resolution width
height: 720, // Camera resolution height
spspps: new Uint8Array(/* SPS/PPS data for H264 */)
};
sdk.inCameraHead(cameraHead);
// Send camera frame data
const frameData = new Uint8Array(/* video frame data */);
sdk.inCameraResource(frameData);
| Code | Issue | Solution |
|---|
60401002 | Invalid parameters | Check all required parameters and their types |
60401006 | Streaming configuration error | Verify video settings (resolution, bitrate, fps) |
60401007 | Reconnection failed | Check network connectivity and credentials |
60401008 | Browser not supported | Use a modern browser with WebRTC support |
60401012 | Access key expired | Implement onAccessKeyExp callback to refresh credentials |
| Code | Issue | Solution |
|---|
60401003 | Network error | Check internet connection and firewall settings |
60401004 | Network timeout | Increase timeout settings or check network stability |
60401009 | Streaming connection failed | Verify WebRTC ports and NAT traversal |
| Code | Issue | Solution |
|---|
60100014 | Credential decryption failed | Verify access key and secret key are correct |
60102022 | AccessKey/userId mismatch | Ensure the access key belongs to the specified user |
60102029 | Invalid access key | Check if access key is active and not expired |
| Code | Issue | Solution |
|---|
60401005 | API call failed | Check API status and retry with exponential backoff |
60401010 | Authorization API network error | Verify API endpoint accessibility |
60401011 | Authorization API failure | Check account status and permissions |
60401013 | Authorization API failure | Contact support if persistent |
60401014 | Authorization API failure | Contact support if persistent |
| Code | Issue | Solution |
|---|
60103002 | Instance not assigned | Request instance assignment through your dashboard |
60103034 | Instance not found | Verify instance ID and availability |
const callbacks = {
onStartFail: (code) => {
switch(code) {
case 60401002:
console.error('Invalid configuration parameters');
// Show parameter validation errors
break;
case 60401003:
case 60401004:
console.error('Network connectivity issues');
// Show retry button or network troubleshooting
break;
case 60100014:
case 60102022:
case 60102029:
console.error('Authentication failed');
// Redirect to login or refresh credentials
break;
case 60103002:
case 60103034:
console.error('Instance unavailable');
// Show instance selection or request new instance
break;
default:
console.error(`Unknown error: ${code}`);
// Generic error handling
}
},
onAccessKeyExp: (reconnectCallback) => {
// Automatically refresh credentials
refreshAccessKey().then(({ak, sk}) => {
reconnectCallback(ak, sk);
}).catch(err => {
console.error('Failed to refresh credentials:', err);
// Redirect to login
});
}
};
- Adjust stream quality based on network conditions
- Use appropriate bitrate: 1-2 Mbps for mobile, 2-4 Mbps for desktop
- Monitor
onPlayInfo callback for real-time performance metrics
- Implement exponential backoff for failed reconnections
- Always implement
onAccessKeyExp for seamless credential renewal
- Handle network interruptions gracefully with reconnection logic
- Validate parameters before calling
sdk.init()
- Provide user feedback for all error states
- Call
sdk.destroy() when leaving the page or component
- Remove event listeners when no longer needed
- Limit concurrent instances to avoid resource conflicts