> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ai-coustics.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rust

> Build a Rust WAV-processing program with the published crate and explicit native linking.

**ai-coustics** Rust bindings wrap the native SDK with owned types and `Result` errors. This page uses the published 0.25.0 crates. Use the [Rust API reference](/reference/sdk/api/rust/index) for types, methods, features and errors. The [generated crate documentation](https://docs.rs/aic-sdk/0.25.0/aic_sdk/) and [released source](https://docs.rs/crate/aic-sdk/0.25.0/source/) are hosted on docs.rs.

## Installation

Use Rust with Cargo, a native linker and libclang on a [supported platform](/reference/sdk/compatibility-matrix). The published SDK crate declares Rust 1.88 or later. Its build script generates C bindings with libclang; install your platform's compiler tools before building. See the [released linking guide](https://docs.rs/aic-sdk/0.25.0/aic_sdk/docs/linking/index.html) for local-library and deployment options.

Create a project:

```bash theme={null}
cargo new aic-rust-quickstart
cd aic-rust-quickstart
```

Replace `Cargo.toml` with the following. `download-lib` downloads the matching native library during the first build; it requires network access. The explicit `aic-sdk-sys` pin keeps the native dependency at the documented release. `hound` reads and writes WAV files.

```toml Cargo.toml theme={null}
[package]
name = "aic-rust-quickstart"
version = "0.1.0"
edition = "2024"

[dependencies]
aic-sdk = { version = "=0.25.0", features = ["download-lib"] }
aic-sdk-sys = "=0.25.0"
hound = "=3.5.1"
```

Keep the generated `Cargo.lock` in your application to preserve resolved dependency versions.

## Quickstart

### Prepare the key, model and input

Generate an SDK key on the [developer platform](https://developers.ai-coustics.com). Set it in the terminal where you will run the program. Keep it out of source control and shared logs.

<CodeGroup>
  ```bash macOS / Linux theme={null}
  export AIC_SDK_LICENSE="YOUR_SDK_KEY"
  curl -fL -o model.aicmodel "https://artifacts.ai-coustics.io/models/quail-vf-2-2-l-16khz/v7/quail_vf_2_2_l_16khz_horgwub0_v14.aicmodel"
  ```

  ```powershell Windows PowerShell theme={null}
  $env:AIC_SDK_LICENSE = "YOUR_SDK_KEY"
  Invoke-WebRequest "https://artifacts.ai-coustics.io/models/quail-vf-2-2-l-16khz/v7/quail_vf_2_2_l_16khz_horgwub0_v14.aicmodel" -OutFile model.aicmodel
  ```
</CodeGroup>

Replace `YOUR_SDK_KEY` with your key. This pins a format-7 build of `quail-vf-2.2-l-16khz`. Quail Voice Focus isolates the primary speaker for speech-to-text (STT) input. Downloading the model in advance does not remove SDK key authorization requirements; see [authentication](/models/get-started/authenticate-apps).

Download the [noisy speech fixture](/assets/audio/noisy-speech.wav) and save it as `input.wav` in this project directory. It contains 56,080 mono PCM16 samples at 16 kHz (3.505 seconds). The [fixture guide](/guides/test-audio) includes attribution, checksums and the aligned clean reference.

For your own recording, export **mono, 16 kHz, signed 16-bit PCM WAV**, at most 60 seconds long. Renaming a file does not convert it.

### Save and run

Replace `src/main.rs` with:

```rust src/main.rs theme={null}
use aic_sdk::{Model, Processor, ProcessorConfig};
use hound::{SampleFormat, WavReader, WavSpec, WavWriter};
use std::error::Error;

fn run() -> Result<(), Box<dyn Error>> {
    let key = std::env::var("AIC_SDK_LICENSE")
        .map_err(|_| "Set AIC_SDK_LICENSE to your SDK key, then retry.")?;
    if key.is_empty() || key == "YOUR_SDK_KEY" {
        return Err("Set AIC_SDK_LICENSE to your SDK key, then retry.".into());
    }
    let mut reader = WavReader::open("input.wav")?;
    let spec = reader.spec();
    if spec.channels != 1 || spec.sample_rate != 16000 || spec.bits_per_sample != 16 ||
        spec.sample_format != SampleFormat::Int || reader.duration() == 0 || reader.duration() > 960000 {
        return Err("Use a nonempty mono, 16 kHz, PCM16 input.wav, at most 60 seconds.".into());
    }
    let input: Vec<f32> = reader.samples::<i16>()
        .map(|sample| sample.map(|value| value as f32 / 32768.0))
        .collect::<Result<_, _>>()?;
    let model = Model::from_file("model.aicmodel")?;
    let config = ProcessorConfig {
        sample_rate: 16000,
        block_size: model.optimal_block_size(16000),
        variable_block_size: false,
    };
    let mut processor = Processor::new(&model, &key)?.with_config(&config)?;
    let delay = processor.context().audio_delay();
    let padded_count = input.len().checked_add(delay)
        .and_then(|n| n.checked_add(config.block_size - 1))
        .ok_or("Audio buffer size overflow")? / config.block_size * config.block_size;
    let mut output = vec![0.0_f32; padded_count];
    output[..input.len()].copy_from_slice(&input);
    for block in output.chunks_exact_mut(config.block_size) {
        processor.process(block)?;
    }
    // Flush with silence, then omit the initial delay to align the files.
    let enhanced = &output[delay..delay + input.len()];
    if enhanced.iter().any(|sample| !sample.is_finite()) {
        return Err("Non-finite output sample; no output written.".into());
    }
    let mut writer = WavWriter::create("enhanced.wav", WavSpec {
        channels: 1, sample_rate: 16000, bits_per_sample: 32, sample_format: SampleFormat::Float,
    })?;
    for &sample in enhanced { writer.write_sample(sample)?; }
    writer.finalize()?;
    println!("SDK {}, model {}", aic_sdk::get_sdk_version(), model.id());
    println!("Processed {} samples at 16000 Hz; wrote enhanced.wav", input.len());
    // Drop releases the processor and ends its session, including on an error return.
    Ok(())
}

fn main() {
    if let Err(error) = run() {
        eprintln!("{error}");
        std::process::exit(1);
    }
}
```

Build and run from `aic-rust-quickstart`:

```bash theme={null}
cargo run --release
```

The program propagates SDK and file errors with `?`. Rust drops the processor and model on a normal return or an error return from `run`, releasing native resources.

### Check the result

A successful run exits with code zero, prints the native SDK version and resolved model ID, then reports `Processed N samples at 16000 Hz; wrote enhanced.wav`, where `N` is your input's sample count (`56080` for the supplied fixture). Open `enhanced.wav` in your audio editor: it should be mono, 16 kHz and the same duration as `input.wav`. The output is a **32-bit float WAV**; the input is PCM16.

The program pads the final block, flushes the delayed tail and removes the initial [processing delay](/reference/concepts/latency), preserving the original sample count. File writes are checked; discard any incomplete file if writing fails.

Listen to both files and compare them with the same STT settings to evaluate quality.

### Recover from an error

| Problem | Cause and retry |
| - | - |
| **Build cannot find libclang or a linker** | Install the platform compiler tools and libclang. Set `LIBCLANG_PATH` to your libclang library directory if discovery fails, then rerun `cargo build --release`. |
| **Native library download fails** | Check network access and target platform. For a preinstalled SDK, use `AIC_LIB_PATH` as described in the [linking guide](https://docs.rs/aic-sdk/0.25.0/aic_sdk/docs/linking/index.html). |
| **Missing or invalid SDK key** | Set `AIC_SDK_LICENSE` in this terminal to the complete SDK key, then rerun `cargo run --release`. |
| **Processing is not allowed or the key expired** | Check key validity, entitlement and [required connectivity](/models/get-started/authenticate-apps). Correct the cause and restart the program. |
| **Input file rejected** | Save a nonempty mono, 16 kHz, PCM16 WAV of at most 60 seconds as `input.wav`, then retry. |
| **Model loading fails** | Run from the project directory containing `model.aicmodel`. Re-download the exact file above for SDK 0.25.0. |
| **Audio configuration mismatch** | Keep each `process` call at `config.block_size` samples. The example pads the final block before processing. |
| **Output write fails** | Check free space and write permission. Discard the incomplete output, correct the cause and retry. |

### Adapt this example

Keep one processor per stream and process blocks in order. Reset its context on a discontinuity or before unrelated audio. Downmix stereo or use a processor per channel. See [audio format](/reference/concepts/audio-format) and [streams and state](/reference/concepts/streams-and-state).

The helper reads a short recording into memory. For long files and live audio, use bounded buffers and keep file I/O, model loading and session teardown outside the audio callback. For human-listening enhancement, evaluate [Rook Multi Speaker](/models/perceptual-speech-enhancement/rook-multi-speaker).

## Integration behavior

| Concern | Rust crate 0.25.0 behavior |
| - | - |
| **Input and output** | `Processor::process(&mut [f32])` enhances a mono sample slice in place. Samples are normalized float32 values, nominally -1.0 to 1.0. |
| **Initialization** | Build a `ProcessorConfig`, then call `initialize` or use `with_config`. Both return a `Result`; use `?` or handle the error before processing. |
| **Block size** | Fixed-size processing requires exactly `config.block_size` samples per call. `variable_block_size: true` permits shorter calls, with additional buffering delay. Larger blocks are rejected. |
| **State and control** | Keep one processor per stream. `processor.context()` returns a control handle with parameter access, `audio_delay()` and `reset()`. Reset clears stream state while retaining configuration. |
| **Ownership** | Rust drops processor and model handles when their owners leave scope, including error returns. A file-backed model must remain unchanged on disk while its dependent objects are alive. |
| **Session termination** | Stop submitting audio before calling `terminate_session()`. It requests termination and returns a `Result`; processing may be disabled after the call returns. `Drop` releases the native object automatically. |
| **Model loading** | `Model::from_file` loads a runtime file. `include_model!` embeds aligned model data at compile time for `Model::from_buffer`. The embedded file must exist at build time. |
| **Async option** | The `async` feature enables async processing types. Await each operation on a stream before submitting the next block. Use separate instances for independent streams. |

## Select crate features

| Feature | Purpose |
| - | - |
| **`download-lib`** | Fetch the matching prebuilt native library during the build. Without it, provide a local library with `AIC_LIB_PATH`. |
| **`download-model`** | Enable `Model::download` for runtime model provisioning. The tutorial uses an explicit model file and does not need this feature. |
| **`async`** | Enable async wrappers and their processing worker pool. |
| **`dynamic-linking`** | Link against the native shared library at build time. Deploy that library with your application. |
| **`runtime-linking`** | Load a native shared library at runtime. Configure its location as described in the released linking guide. |

Static linking is the default. Select one linking strategy deliberately; Cargo features are additive. See the [linking guide](https://docs.rs/aic-sdk/0.25.0/aic_sdk/docs/linking/index.html), [integration guide](https://docs.rs/aic-sdk/0.25.0/aic_sdk/docs/guide/index.html) and [examples](https://docs.rs/aic-sdk/0.25.0/aic_sdk/docs/examples/index.html) for detailed configuration, async behavior and model embedding.

For voice activity detection (VAD) or Tyto analysis, use the dedicated types and matching models. An enhancement processor can also report speech through [`energy_vad_context()`](/reference/sdk/api/rust/enhancement#rust-aic_sdk-Processor-energy_vad_context), without a second model. Keep initialization, model loading and teardown outside the real-time audio callback, and follow [streams and state](/reference/concepts/streams-and-state) for interruptions and concurrency.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.