Skip to content

Ai Conversation Translation

Mr.P edited this page Aug 29, 2026 · 2 revisions

Conversation Translation

Build a two-person, turn-based translation experience by starting a short simultaneous-interpretation session for the active speaker and swapping source and target languages for the other participant.

This is a product workflow demonstrated by ConversationTranslationDemoController; it does not introduce a separate ConversationTranslationAPI.

One conversation turn

Each speaker turn owns one interpretation session. Reverse the language direction for the partner's turn and never run both turns concurrently.

  1. Choose Active Speaker — Resolve source and target languages from the selected side.
  2. Configure Turn — Create a simultaneous-interpretation configuration for this direction.
  3. Start Session — Start interpretation and retain the returned session.
  4. Provide Speech — Use AIBuds AI SDK internal recording, or feed external PCM from the host app or connected device.
  5. Render Translation — Order definite source and target segments from streaming callbacks.
  6. Finish Turn — Stop external recording first, then stop the interpretation service.

Prerequisites

  • Meet all prerequisites from Simultaneous Interpretation.
  • Use different hyphenated source and target language identifiers.
  • Track the active speaker, current session, start/stop state, and rendered turn messages in the host app.
  • Prevent both speakers from starting sessions simultaneously.

API Reference

Conversation Translation uses startSimultaneousInterpretation, stopSimultaneousInterpretation, and SimultaneousInterpretationConfig.

See Simultaneous Interpretation for the complete public declarations and callback contract.

Usage Examples

Start a Speaker Turn

The Demo maps “Me” to myLanguage → partnerLanguage and “Partner” to the reverse direction. The following helpers accept the resolved direction, making that product state explicit.

Swift

func startConversationTurn(source: String, target: String) {
    guard currentSession == nil, source != target else { return }

    let config = SimultaneousInterpretationConfig.default
    config.sourceLanguage = source
    config.targetLanguage = target
    config.usesInternalAudioRecording = true
    config.preferSpeakerOutput = true
    config.enableVoicePlayback = true

    AIBudsAISDK.startSimultaneousInterpretation(
        config,
        onStartSuccess: { session in
            currentSession = session
            setTurnActive(true)
        },
        onStartFailure: { error in
            currentSession = nil
            setTurnActive(false)
            show(error)
        },
        onStopByInterruption: { error in
            currentSession = nil
            setTurnActive(false)
            if let error { show(error) }
        },
        onException: { error in
            showRecoverable(error)
        },
        streamResultHandler: { _, response, error in
            if let error {
                show(error)
                return
            }
            guard let response else { return }
            if response.isSourceTextDefinite { renderSource(response) }
            if response.isTargetTextDefinite { renderTarget(response) }
        },
        onEvent: { event in
            handle(event)
        },
        onFinish: { report in
            currentSession = nil
            setTurnActive(false)
            save(report)
        }
    )
}

Objective-C

- (void)startConversationTurnFrom:(NSString *)source to:(NSString *)target {
    if (self.currentSession != nil || [source isEqualToString:target])
        return;

    AIBudsSimultaneousInterpretationConfig *config =
        [AIBudsSimultaneousInterpretationConfig defaultConfig];
    config.sourceLanguage = source;
    config.targetLanguage = target;
    config.usesInternalAudioRecording = YES;
    config.preferSpeakerOutput = YES;
    config.enableVoicePlayback = YES;

    [AIBudsAISDK startSimultaneousInterpretationWithConfig:config
        onStartSuccess:^(id<AIBudsSimultaneousInterpretationSessionConvertible> session) {
            self.currentSession = session;
            [self setTurnActive:YES];
        }
        onStartFailure:^(NSError *error) {
            self.currentSession = nil;
            [self setTurnActive:NO];
            [self showError:error];
        }
        onStopByInterruption:^(NSError *error) {
            self.currentSession = nil;
            [self setTurnActive:NO];
            if (error != nil)
                [self showError:error];
        }
        onException:^(NSError *error) {
            [self showRecoverableError:error];
        }
        streamResultHandler:^(
            BOOL isFinal, AIBudsSimultaneousInterpretationDataModel *response, NSError *error) {
            if (error != nil) {
                [self showError:error];
                return;
            }
            if (response.isSourceTextDefinite)
                [self renderSource:response];
            if (response.isTargetTextDefinite)
                [self renderTarget:response];
        }
        onEvent:^(AIBudsSimultaneousInterpretationEventModel *event) {
            [self handleEvent:event];
        }
        onFinish:^(AIBudsSimultaneousInterpretationReportModel *report) {
            self.currentSession = nil;
            [self setTurnActive:NO];
            [self saveReport:report];
        }];
}

Stop the Active Turn

When currentSession.isRecordingInternally is false, stop device-side AI recording before stopping the service so the final audio is delivered in order.

Swift

func stopConversationTurn() {
    guard let session = currentSession else { return }

    if !session.isRecordingInternally,
        let recordingDevice = device as? DeviceAudioRecordingAPI
    {
        recordingDevice.stopAIAudioRecording(.onSite) { _, _ in
            AIBudsAISDK.stopSimultaneousInterpretation()
        }
    } else {
        AIBudsAISDK.stopSimultaneousInterpretation()
    }
}

Objective-C

- (void)stopConversationTurn {
    if (self.currentSession == nil)
        return;

    if (!self.currentSession.isRecordingInternally) {
        id<AIBudsDeviceAudioRecordingAPI> recordingDevice =
            (id<AIBudsDeviceAudioRecordingAPI>)self.device;
        if ([recordingDevice conformsToProtocol:@protocol(AIBudsDeviceAudioRecordingAPI)]) {
            [recordingDevice
                stopAIAudioRecordingWithScene:AIBudsRecordingSceneOnSite
                                   completion:^(__unused BOOL success, __unused NSError *error) {
                                       [AIBudsAISDK stopSimultaneousInterpretation];
                                   }];
            return;
        }
    }
    [AIBudsAISDK stopSimultaneousInterpretation];
}

Error Handling

Handle startup failure, interruption, recoverable exception, stream error, device-recording failure, and final completion separately. If a stop is requested while device recording is still starting, defer the service stop until the device start callback has completed; the Demo tracks this race explicitly.

Notes

  • A conversation can contain many turns, but only one interpretation session should be active at a time.
  • Swap languages only while no turn is active.
  • Use source and target sequence fields to order definite segments instead of blindly appending every callback.
  • When external device recording is used, register the retained interpretation session with the application's PCM forwarding path before starting device audio so the first packet is not lost.

AIBuds SDK iOS Wiki

Clone this wiki locally