/* * voicecat.cpp — C ABI implementation. * * Lifecycle (create/destroy) and trivial accessors are always real. Everything else below * just delegates to vc_client (core/src/core/client.cpp): under VOICECAT_HAS_NET * (`m1-dev`/`server-release` — see docs/building.md) that's the real M1–M3 implementation; * under the no-deps `dev` preset, client.cpp's `#else` branch returns VC_ERR_NOT_IMPLEMENTED * for all of it, to keep that skeleton build green. */ #include "voicecat.h" #include #include "core/client.h" #define VC_STR2(x) #x #define VC_STR(x) VC_STR2(x) extern "C" { const char* vc_version_string(void) { static const char* kVersion = VC_STR(VOICECAT_VERSION_MAJOR) "." VC_STR( VOICECAT_VERSION_MINOR) "." VC_STR(VOICECAT_VERSION_PATCH); return kVersion; } const char* vc_result_string(vc_result code) { switch (code) { case VC_OK: return "ok"; case VC_ERR_NOT_IMPLEMENTED: return "not implemented"; case VC_ERR_INVALID_ARG: return "invalid argument"; case VC_ERR_NOT_CONNECTED: return "not connected"; case VC_ERR_ALREADY: return "already in requested state"; case VC_ERR_AUTH_FAILED: return "authentication failed"; case VC_ERR_PERMISSION_DENIED: return "permission denied"; case VC_ERR_TIMEOUT: return "timeout"; case VC_ERR_IO: return "i/o error"; case VC_ERR_PROTOCOL: return "protocol error"; case VC_ERR_CRYPTO: return "crypto error"; case VC_ERR_AUDIO: return "audio error"; case VC_ERR_INTERNAL: return "internal error"; } return "unknown"; } vc_client* vc_client_create(const vc_config* cfg, vc_callbacks cb) { if (cfg == nullptr) return nullptr; return new (std::nothrow) vc_client(*cfg, cb); } void vc_client_destroy(vc_client* c) { delete c; } /* ── Everything below delegates to vc_client (real or stub, per preset above). ───────── */ vc_result vc_connect(vc_client* c, const char* host, uint16_t port) { if (c == nullptr || host == nullptr) return VC_ERR_INVALID_ARG; return c->connect(host, port); } vc_result vc_disconnect(vc_client* c) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->disconnect(); } vc_result vc_authenticate_guest(vc_client* c, const char* nickname) { if (c == nullptr || nickname == nullptr) return VC_ERR_INVALID_ARG; return c->authenticate_guest(nickname); } vc_result vc_authenticate_user(vc_client* c, const char* username, const char* password) { if (c == nullptr || username == nullptr || password == nullptr) return VC_ERR_INVALID_ARG; return c->authenticate_user(username, password); } vc_result vc_join_channel(vc_client* c, uint32_t channel_id, const char* password) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->join_channel(channel_id, password); } vc_result vc_leave_channel(vc_client* c) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->leave_channel(); } vc_result vc_stream_start(vc_client* c, const vc_stream_desc* desc, uint32_t* out_stream_id) { if (c == nullptr || desc == nullptr) return VC_ERR_INVALID_ARG; return c->stream_start(*desc, out_stream_id); } vc_result vc_stream_stop(vc_client* c, uint32_t stream_id) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->stream_stop(stream_id); } vc_result vc_set_input_device(vc_client* c, uint32_t stream_id, const char* device_id) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_input_device(stream_id, device_id); } vc_result vc_set_input_mode(vc_client* c, vc_input_mode mode) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_input_mode(mode); } vc_result vc_set_vad_threshold(vc_client* c, float threshold) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_vad_threshold(threshold); } vc_result vc_set_push_to_talk(vc_client* c, int active) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_push_to_talk(active != 0); } vc_result vc_set_self_mute(vc_client* c, int mic_muted, int deafened) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_self_mute(mic_muted != 0, deafened != 0); } vc_result vc_set_remote_stream(vc_client* c, uint32_t user_id, uint32_t stream_id, float gain, int muted, int noise_reduction) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_remote_stream(user_id, stream_id, gain, muted != 0, noise_reduction != 0); } vc_result vc_get_stream_audio_config(vc_client* c, uint32_t user_id, uint32_t stream_id, vc_audio_config* out) { if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG; return c->get_stream_audio_config(user_id, stream_id, out); } vc_result vc_test_inject_capture(vc_client* c, uint32_t stream_id, const int16_t* pcm, size_t samples) { if (c == nullptr || pcm == nullptr) return VC_ERR_INVALID_ARG; return c->test_inject_capture(stream_id, pcm, samples); } vc_result vc_send_text(vc_client* c, vc_text_scope scope, uint32_t target_id, const char* utf8) { if (c == nullptr || utf8 == nullptr) return VC_ERR_INVALID_ARG; return c->send_text(scope, target_id, utf8); } vc_result vc_list_devices(vc_client* c, vc_device_kind kind, vc_device_list* out) { if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG; return c->list_devices(kind, out); } void vc_free_device_list(vc_device_list* list) { if (list == nullptr || list->items == nullptr) return; for (size_t i = 0; i < list->count; ++i) { delete[] list->items[i].id; delete[] list->items[i].name; } delete[] list->items; list->items = nullptr; list->count = 0; } vc_result vc_list_channels(vc_client* c, vc_channel_list* out) { if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG; return c->list_channels(out); } void vc_free_channel_list(vc_channel_list* list) { if (list == nullptr || list->items == nullptr) return; for (size_t i = 0; i < list->count; ++i) delete[] list->items[i].name; delete[] list->items; list->items = nullptr; list->count = 0; } vc_result vc_list_users(vc_client* c, vc_user_list* out) { if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG; return c->list_users(out); } void vc_free_user_list(vc_user_list* list) { if (list == nullptr || list->items == nullptr) return; for (size_t i = 0; i < list->count; ++i) delete[] list->items[i].nickname; delete[] list->items; list->items = nullptr; list->count = 0; } vc_result vc_list_user_streams(vc_client* c, uint32_t user_id, vc_stream_summary_list* out) { if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG; return c->list_user_streams(user_id, out); } void vc_free_stream_summary_list(vc_stream_summary_list* list) { if (list == nullptr || list->items == nullptr) return; for (size_t i = 0; i < list->count; ++i) delete[] list->items[i].label; delete[] list->items; list->items = nullptr; list->count = 0; } vc_result vc_confirm_server_identity(vc_client* c, int accept) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->confirm_server_identity(accept != 0); } vc_result vc_get_server_identity_display(vc_client* c, char* out_buf, size_t buf_cap, size_t* out_len) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->get_server_identity_display(out_buf, buf_cap, out_len); } } // extern "C"