MCPcopy Create free account
hub / github.com/RunanywhereAI/RCLI / rcli_speak

Function rcli_speak

src/api/rcli_api.cpp:1420–1485  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1418}
1419
1420int rcli_speak(RCLIHandle handle, const char* text) {
1421 if (!handle || !text) return -1;
1422 auto* engine = static_cast<RCLIEngine*>(handle);
1423 if (!engine->initialized) return -1;
1424
1425 LOG_TRACE("RCLI", "[speak] entry, text='%.40s'", text);
1426
1427 // Kill any currently playing TTS first
1428 rcli_stop_speaking(handle);
1429
1430 // Ensure CoreAudio playback is running (stop_capture_and_transcribe stops it)
1431 if (!engine->pipeline.audio().is_running()) {
1432 engine->pipeline.audio().start();
1433 }
1434
1435 std::string clean_text = rastack::sanitize_for_tts(std::string(text));
1436 if (clean_text.empty()) { LOG_TRACE("RCLI", "[speak] clean_text empty, returning 0"); return 0; }
1437
1438 LOG_TRACE("RCLI", "[speak] clean_text='%.40s' (%zu chars)", clean_text.c_str(), clean_text.size());
1439
1440 std::vector<float> audio;
1441 int sample_rate;
1442 if (engine->pipeline.using_metalrt_tts()) {
1443 LOG_TRACE("RCLI", "[speak] calling metalrt_tts().synthesize() ...");
1444 audio = engine->pipeline.metalrt_tts().synthesize(clean_text);
1445 LOG_TRACE("RCLI", "[speak] synthesize returned %zu samples", audio.size());
1446 sample_rate = engine->pipeline.metalrt_tts().sample_rate();
1447 } else if (engine->pipeline.using_metalrt()) {
1448 LOG_ERROR("RCLI", "MetalRT is active but TTS is not on GPU — aborting TTS. "
1449 "Reinstall MetalRT components with: rcli setup --metalrt");
1450 return -1;
1451 } else {
1452 audio = engine->pipeline.tts().synthesize(clean_text);
1453 sample_rate = engine->pipeline.tts().sample_rate();
1454 }
1455 if (audio.empty()) { LOG_TRACE("RCLI", "[speak] audio empty, returning -1"); return -1; }
1456
1457 LOG_TRACE("RCLI", "[speak] saving WAV (%zu samples, sr=%d) ...", audio.size(), sample_rate);
1458 std::string tmp_path = "/tmp/rcli_speak_" + std::to_string(getpid()) + ".wav";
1459 if (!AudioIO::save_wav(tmp_path, audio.data(), static_cast<int>(audio.size()), sample_rate)) {
1460 LOG_ERROR("RCLI", "Failed to write TTS audio to %s", tmp_path.c_str());
1461 return -1;
1462 }
1463
1464 LOG_TRACE("RCLI", "[speak] forking afplay for %s ...", tmp_path.c_str());
1465 pid_t pid = fork();
1466 if (pid == 0) {
1467 execl("/usr/bin/afplay", "afplay", tmp_path.c_str(), nullptr);
1468 _exit(127);
1469 } else if (pid > 0) {
1470 engine->tts_pid.store(pid, std::memory_order_release);
1471 LOG_TRACE("RCLI", "[speak] afplay pid=%d, returning 0", pid);
1472 std::thread([engine, pid, tmp_path]() {
1473 int status = 0;
1474 waitpid(pid, &status, 0);
1475 pid_t expected = pid;
1476 engine->tts_pid.compare_exchange_strong(expected, 0, std::memory_order_release);
1477 unlink(tmp_path.c_str());

Callers 8

cmd_listenFunction · 0.85
cmd_askFunction · 0.85
cmd_cameraFunction · 0.85
cmd_screenFunction · 0.85
run_camera_vlmMethod · 0.85
process_inputMethod · 0.85
test_apiFunction · 0.85
rcli_speak_streamingFunction · 0.85

Calls 10

rcli_stop_speakingFunction · 0.85
sanitize_for_ttsFunction · 0.85
is_runningMethod · 0.80
emptyMethod · 0.80
using_metalrt_ttsMethod · 0.80
using_metalrtMethod · 0.80
startMethod · 0.45
sizeMethod · 0.45
synthesizeMethod · 0.45
sample_rateMethod · 0.45

Tested by 1

test_apiFunction · 0.68