/* * 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 * (`dev`/`release`/`server-release` — see docs/building.md) that's the real M1–M3 implementation; * under the no-deps `skeleton` 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_output_volume(vc_client* c, float gain) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_output_volume(gain); } 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_remote_stream(vc_client* c, uint32_t user_id, uint32_t stream_id, vc_remote_stream_state* out) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->get_remote_stream(user_id, stream_id, out); } 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_set_capture_channels(vc_client* c, uint32_t stream_id, uint32_t channels) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_capture_channels(stream_id, channels); } 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[i].topic; } 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); } vc_result vc_kick_user(vc_client* c, uint32_t user_id, const char* reason) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->kick_user(user_id, reason); } vc_result vc_ban_user(vc_client* c, uint32_t user_id, const char* reason, uint64_t expires_unix_ms) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->ban_user(user_id, reason, expires_unix_ms); } vc_result vc_set_permission(vc_client* c, uint32_t user_id, const vc_permissions* perms) { if (c == nullptr || perms == nullptr) return VC_ERR_INVALID_ARG; return c->set_permission(user_id, perms); } vc_result vc_set_server_mute(vc_client* c, uint32_t user_id, int muted, int deafened) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->set_server_mute(user_id, muted != 0, deafened != 0); } vc_result vc_move_user(vc_client* c, uint32_t user_id, uint32_t channel_id) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->move_user(user_id, channel_id); } vc_result vc_create_channel(vc_client* c, const vc_channel_info* info) { if (c == nullptr || info == nullptr) return VC_ERR_INVALID_ARG; return c->create_channel(info); } vc_result vc_edit_channel(vc_client* c, const vc_channel_info* info) { if (c == nullptr || info == nullptr) return VC_ERR_INVALID_ARG; return c->edit_channel(info); } vc_result vc_delete_channel(vc_client* c, uint32_t channel_id) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->delete_channel(channel_id); } vc_result vc_create_account(vc_client* c, const char* username, const char* password) { if (c == nullptr || username == nullptr || password == nullptr) return VC_ERR_INVALID_ARG; return c->create_account(username, password); } vc_result vc_reset_password(vc_client* c, const char* username, const char* new_password) { if (c == nullptr || username == nullptr || new_password == nullptr) return VC_ERR_INVALID_ARG; return c->reset_password(username, new_password); } vc_result vc_delete_account(vc_client* c, const char* username) { if (c == nullptr || username == nullptr) return VC_ERR_INVALID_ARG; return c->delete_account(username); } vc_result vc_list_accounts(vc_client* c) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->list_accounts(); } vc_result vc_get_account_list(vc_client* c, vc_account_list* out) { if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG; return c->get_account_list(out); } void vc_free_account_list(vc_account_list* list) { if (list == nullptr || list->items == nullptr) return; for (size_t i = 0; i < list->count; ++i) delete[] list->items[i].username; delete[] list->items; list->items = nullptr; list->count = 0; } vc_result vc_get_permissions(vc_client* c, vc_permissions* out) { if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG; return c->get_permissions(out); } vc_result vc_audio_suspend(vc_client* c) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->audio_suspend(); } vc_result vc_audio_resume(vc_client* c) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->audio_resume(); } vc_result vc_audio_restart(vc_client* c) { if (c == nullptr) return VC_ERR_INVALID_ARG; return c->audio_restart(); } } // extern "C"