Skip to content

Commit 1511aca

Browse files
Reef-7sanchitmonga22
authored andcommitted
Fix initialization race and FFI memory leaks in voice agent bridge
1 parent 352a363 commit 1511aca

1 file changed

Lines changed: 17 additions & 12 deletions

File tree

sdk/runanywhere-flutter/packages/runanywhere/lib/native/dart_bridge_voice_agent.dart

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,18 @@ class DartBridgeVoiceAgent {
7272
final completer = Completer<RacHandle>();
7373
_initFuture = completer.future;
7474

75-
// Use shared component handles (matches Swift approach)
76-
// This allows the voice agent to use already-loaded models from the
77-
// individual component bridges (STT, LLM, TTS, VAD)
78-
final llmHandle = DartBridgeLLM.shared.getHandle();
79-
final sttHandle = DartBridgeSTT.shared.getHandle();
80-
final ttsHandle = DartBridgeTTS.shared.getHandle();
81-
final vadHandle = DartBridgeVAD.shared.getHandle();
75+
try {
76+
// Use shared component handles (matches Swift approach)
77+
// This allows the voice agent to use already-loaded models from the
78+
// individual component bridges (STT, LLM, TTS, VAD)
79+
final llmHandle = await DartBridgeLLM.shared.getHandle();
80+
final sttHandle = await DartBridgeSTT.shared.getHandle();
81+
final ttsHandle = await DartBridgeTTS.shared.getHandle();
82+
final vadHandle = await DartBridgeVAD.shared.getHandle();
8283

83-
_logger.debug(
84-
'Creating voice agent with shared handles: LLM=$llmHandle, STT=$sttHandle, TTS=$ttsHandle, VAD=$vadHandle');
84+
_logger.debug(
85+
'Creating voice agent with shared handles: LLM=$llmHandle, STT=$sttHandle, TTS=$ttsHandle, VAD=$vadHandle');
8586

86-
try {
8787
final handlePtr = calloc<RacHandle>();
8888
try {
8989
final result = NativeFunctions.voiceAgentCreate(
@@ -334,7 +334,7 @@ class DartBridgeVoiceAgent {
334334
}
335335

336336
// Parse result while still in isolate (before freeing memory)
337-
return _parseVoiceTurnResultStatic(resultPtr.ref, _voiceAgentLib);
337+
return _parseVoiceTurnResultStatic(resultPtr.ref);
338338
} finally {
339339
// Free audio data
340340
calloc.free(audioPtr);
@@ -354,7 +354,6 @@ class DartBridgeVoiceAgent {
354354
/// using rac_audio_float32_to_wav, so synthesized_audio is WAV data.
355355
static VoiceTurnResult _parseVoiceTurnResultStatic(
356356
RacVoiceAgentResultStruct result,
357-
DynamicLibrary lib,
358357
) {
359358
final transcription = result.transcription != nullptr
360359
? result.transcription.toDartString()
@@ -410,6 +409,9 @@ class DartBridgeVoiceAgent {
410409
return resultPtr.value != nullptr ? resultPtr.value.toDartString() : '';
411410
} finally {
412411
calloc.free(audioPtr);
412+
if (resultPtr.value != nullptr) {
413+
NativeFunctions.racFree(resultPtr.value.cast<Void>());
414+
}
413415
calloc.free(resultPtr);
414416
}
415417
}
@@ -433,6 +435,9 @@ class DartBridgeVoiceAgent {
433435
return resultPtr.value != nullptr ? resultPtr.value.toDartString() : '';
434436
} finally {
435437
calloc.free(promptPtr);
438+
if (resultPtr.value != nullptr) {
439+
NativeFunctions.racFree(resultPtr.value.cast<Void>());
440+
}
436441
calloc.free(resultPtr);
437442
}
438443
}

0 commit comments

Comments
 (0)