# Which Swift Actor Serializes CoreML Operations in FluidVoice?

> Discover how the TranscriptionExecutor Swift actor in FluidVoice serializes CoreML operations, preventing race conditions and ensuring smooth performance. Learn more now.

- Repository: [ALTIC/FluidVoice](https://github.com/altic-dev/FluidVoice)
- Tags: internals
- Published: 2026-07-07

---

**FluidVoice uses a dedicated private Swift actor named `TranscriptionExecutor` to guarantee that only one Core ML transcription runs at a time, preventing simultaneous access that leads to race conditions and memory corruption.**

FluidVoice, an open-source transcription app, relies on strict concurrency control when interacting with Core ML models. The `TranscriptionExecutor` actor in [`Sources/Fluid/Services/ASRService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/ASRService.swift) serves as the gatekeeper for all transcription operations, ensuring thread-safe execution across the application.

## How TranscriptionExecutor Serializes CoreML Work

The `TranscriptionExecutor` actor lives inside [`ASRService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/ASRService.swift) (lines 13-30) and provides a `run(_:)` method that queues async transcription tasks. This design ensures that each Core ML operation awaits the previous task before starting the next, eliminating race conditions when multiple providers attempt to invoke Core ML simultaneously.

### Key Responsibilities

- **Queueing**: The actor stores the last submitted `Task` in a property named `lastTask`. Each new `Task` first awaits the previous one's result (`_ = await previous?.result`), creating a serial execution chain.
- **Cancellation**: The `cancelAndAwaitPending()` method cancels any in-flight `currentOperationTask` and then awaits the final task in the chain, ensuring clean shutdowns.
- **Isolation**: As a Swift `actor`, the compiler guarantees that mutable state (`lastTask`, `currentOperationTask`) is accessed serially, even from concurrent callers.

## Implementation Details

In [`Sources/Fluid/Services/ASRService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/ASRService.swift), the actor definition enforces exclusive access to the underlying Core ML model:

```swift
// Conceptual implementation based on lines 13-30
actor TranscriptionExecutor {
    private var lastTask: Task<Void, Never>?
    private var currentOperationTask: Task<Void, Error>?
    
    func run<T>(_ operation: @escaping () async throws -> T) async throws -> T {
        // Queues work sequentially
        let newTask = Task { [weak self] in
            _ = await self?.lastTask?.result
            return try await operation()
        }
        lastTask = newTask
        return try await newTask.value
    }
    
    func cancelAndAwaitPending() async {
        // Cancels and awaits cleanup
        currentOperationTask?.cancel()
        _ = await lastTask?.result
    }
}

```

## Real-World Usage in FluidVoice

All transcription calls in `ASRService` route through this actor. Here are the practical patterns used throughout the codebase.

### Basic Transcription Pattern

When transcribing the final audio buffer, the service invokes the actor at lines 68-78:

```swift
// Inside ASRService.stop()
let finalResult: ASRTranscriptionResult = try await transcriptionExecutor.run { [provider] in
    try await provider.transcribeFinal(pcm)   // Core ML work happens here
}

```

### Dictionary Training Operations

The same actor serializes dictionary-training buffer transcription, ensuring that training data processing never collides with real-time transcription:

```swift
let result: ASRTranscriptionResult = try await transcriptionExecutor.run {
    try await provider.transcribeFinal(pcmSamples)
}

```

### Cancellation Handling

When a user aborts a recording, the service calls:

```swift
await transcriptionExecutor.cancelAndAwaitPending()

```

This immediately cancels any pending Core ML work and waits for the actor to reach a clean state before proceeding.

## Why Actor Isolation Prevents CoreML Crashes

Core ML models are not inherently thread-safe for concurrent inference. When multiple providers—such as `ExternalCoreMLTranscriptionProvider` or `ParakeetRealtimeProvider`—attempt to run transcription simultaneously without coordination, the resulting memory corruption can crash the application.

The `TranscriptionExecutor` actor solves this by:

1. **Enforcing Serial Access**: Swift's actor model guarantees that only one task executes within the actor's isolated context at any moment.
2. **Preventing Resource Contention**: By awaiting the previous task before starting a new one, the actor ensures the Core ML model is never accessed concurrently.
3. **Safe Cancellation**: The `cancelAndAwaitPending()` method provides a race-free way to abort long-running transcription without leaving the model in an undefined state.

## Summary

- **FluidVoice** uses the `TranscriptionExecutor` actor to serialize all Core ML transcription operations.
- Located in [`Sources/Fluid/Services/ASRService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/ASRService.swift) (lines 13-30), this actor guarantees that only one transcription runs at a time.
- The `run(_:)` method queues tasks sequentially, while `cancelAndAwaitPending()` handles cancellation safely.
- This pattern prevents race conditions and memory corruption when multiple providers like `ExternalCoreMLTranscriptionProvider` or `ParakeetRealtimeProvider` access Core ML models.

## Frequently Asked Questions

### What is the name of the Swift actor that serializes CoreML operations in FluidVoice?

The actor is named **`TranscriptionExecutor`**. It is defined as a private actor within [`ASRService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/ASRService.swift) and ensures that only one Core ML transcription operation executes at a time by serializing access through its `run(_:)` method.

### Where is the TranscriptionExecutor implemented in the FluidVoice codebase?

The `TranscriptionExecutor` actor is implemented in [`Sources/Fluid/Services/ASRService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/ASRService.swift) at lines 13-30. All transcription calls throughout the application route through this actor, including final buffer transcription (lines 68-78) and dictionary training operations.

### How does TranscriptionExecutor prevent concurrent CoreML access?

The actor prevents concurrent access by storing the last submitted task in a `lastTask` property and requiring each new task to await the previous one's completion before starting. Because `TranscriptionExecutor` is a Swift actor, the compiler enforces that its mutable state (`lastTask`, `currentOperationTask`) can only be accessed serially, even when called from concurrent contexts.

### Can pending transcription operations be cancelled in FluidVoice?

Yes. The `TranscriptionExecutor` provides a `cancelAndAwaitPending()` method that cancels any in-flight `currentOperationTask` and awaits the final task in the chain. This allows the application to safely abort transcription when a user stops recording without risking memory corruption or leaving the Core ML model in an inconsistent state.