# FFI (Foreign Function Interface) Guide
This document describes how to use AIP from iOS and Android applications.
## Overview
AIP provides C-compatible FFI bindings that allow integration with:
- **iOS**: Swift/Objective-C via XCFramework
- **Android**: Kotlin/Java via JNI
## API Reference
### Error Codes
| 0 | `AIP_SUCCESS` | Success |
| -1 | `AIP_ERROR_NULL_POINTER` | Null pointer passed |
| -2 | `AIP_ERROR_INVALID_DATA` | Invalid data format |
| -3 | `AIP_ERROR_MODEL_NOT_LOADED` | Model not loaded |
| -4 | `AIP_ERROR_INFERENCE_FAILED` | Inference failed |
| -5 | `AIP_ERROR_FILE_NOT_FOUND` | Model file not found |
| -6 | `AIP_ERROR_LOAD_FAILED` | Model load failed |
### EDM (Emotion Data Model)
```c
// Create/Destroy
void* aip_edm_create();
void aip_edm_destroy(void* model);
// Load model from file
int aip_edm_load(void* model, const char* path);
// Inference
typedef struct {
const float* data;
size_t len; // Must be 15
} AipFeatureArray;
typedef struct {
float valence;
float arousal;
float dominance;
int error_code;
} AipEmotionResult;
AipEmotionResult aip_edm_infer(void* model, AipFeatureArray features);
```
### Director (Interaction Strategy)
```c
// Create/Destroy
void* aip_director_create();
void aip_director_destroy(void* model);
// Load model from file
int aip_director_load(void* model, const char* path);
// Decision making
typedef struct {
const float* data;
size_t len; // Must be 8
} AipUserTraits;
typedef struct {
const float* data;
size_t len; // Must be 6
} AipEnvState;
typedef struct {
float valence;
float arousal;
float dominance;
} AipEmotionInput;
typedef struct {
float intensity_factor;
float feedback_intensity;
float pace_speed;
float reward_scarcity;
float env_arousal;
float rhythm_modulation;
float challenge_curve;
int error_code;
} AipDecisionResult;
AipDecisionResult aip_director_decide(
void* model,
AipUserTraits user_traits,
AipEnvState env_state,
AipEmotionInput emotion
);
```
### Utility Functions
```c
const char* aip_get_version();
const char* aip_error_message(int code);
void aip_free_string(char* s);
```
## iOS Integration
### Build
```bash
./scripts/build_ios.sh
```
This generates `target/ios/Aip.xcframework`.
### Xcode Setup
1. Add `Aip.xcframework` to your project
2. Add to "Frameworks, Libraries, and Embedded Content"
3. Import the header:
```objc
#import <Aip/Aip.h>
```
### Swift Usage
```swift
// Create models
guard let edm = AipEdmModel(),
let director = AipDirectorModel() else {
print("Failed to create models")
return
}
// Load pre-trained models
try edm.load(from: modelPath)
try director.load(from: directorPath)
// EDM inference
let features: [Float] = [0.5, 0.6, 0.4, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
let emotion = try edm.infer(features: features)
// Director decision
let userTraits: [Float] = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
let envState: [Float] = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
let decision = try director.decide(
userTraits: userTraits,
envState: envState,
emotion: emotion
)
print("Intensity: \(decision.intensityFactor)")
print("Pace: \(decision.paceSpeed)")
```
## Android Integration
### Build
```bash
export ANDROID_NDK_HOME=/path/to/ndk
./scripts/build_android.sh
```
This generates `target/android/aip-ffi.aar`.
### Gradle Setup
1. Copy `aip-ffi.aar` to `app/libs/`
2. Add to `build.gradle`:
```gradle
android {
// ...
}
dependencies {
implementation files('libs/aip-ffi.aar')
}
```
### Kotlin Usage
```kotlin
import com.aip.ffi.*
class GameManager {
private var edm: AipEdmModel? = null
private var director: AipDirectorModel? = null
fun initialize(edmPath: String, directorPath: String) {
edm = AipEdmModel.create()
director = AipDirectorModel.create()
edm?.load(edmPath)
director?.load(directorPath)
}
fun processGameState(features: FloatArray): AipDecision {
val emotion = edm?.infer(features)
?: throw IllegalStateException("EDM not initialized")
val userTraits = floatArrayOf(0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f)
val envState = floatArrayOf(0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f)
return director?.decide(userTraits, envState, emotion)
?: throw IllegalStateException("Director not initialized")
}
fun cleanup() {
edm?.close()
director?.close()
}
}
```
## Unity Integration
### Build Native Library
```bash
# iOS
./scripts/build_ios.sh
# Android
./scripts/build_android.sh
```
### C# Wrapper
```csharp
using System;
using System.Runtime.InteropServices;
public class AipNative {
[DllImport("aip")]
public static extern IntPtr aip_edm_create();
[DllImport("aip")]
public static extern void aip_edm_destroy(IntPtr model);
[DllImport("aip")]
public static extern int aip_edm_load(IntPtr model, string path);
// ... other declarations
}
public class AipEdmModel {
private IntPtr handle;
public AipEdmModel() {
handle = AipNative.aip_edm_create();
}
~AipEdmModel() {
if (handle != IntPtr.Zero) {
AipNative.aip_edm_destroy(handle);
}
}
public void Load(string path) {
AipNative.aip_edm_load(handle, path);
}
// ... other methods
}
```
## Performance Considerations
- **Model Size**: EDM ~170KB, Director ~158KB
- **Inference Latency**: <1ms on modern mobile CPUs
- **Memory**: ~10MB runtime footprint
- **Thread Safety**: Models are NOT thread-safe. Use separate instances per thread.
## Model Training
Models must be trained and exported before use:
```bash
# Train EDM
cargo run --features edm_roguelite_training -- train-edm --output models/edm.safetensors
# Train Director
cargo run --features director_roguelite_training -- train-director --output models/director.safetensors
```
## Troubleshooting
### iOS: "Library not loaded"
Ensure the framework is properly embedded:
1. Target → Build Phases → Embed Frameworks
2. Add `Aip.xcframework`
3. Set "Embed & Sign"
### Android: "UnsatisfiedLinkError"
1. Verify `libaip.so` exists in the correct `jniLibs/<arch>/` directory
2. Check ABI compatibility (arm64-v8a, armeabi-v7a, x86, x86_64)
3. Ensure `System.loadLibrary("aip")` is called before use
### Model Load Fails
1. Verify model file exists at specified path
2. Check file permissions
3. Ensure model was trained with compatible version