diff --git a/.vscode/launch.json b/.vscode/launch.json index 1427927ac..535f673e2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -137,7 +137,7 @@ "request": "launch", "program": "${workspaceFolder}/out/linux/x64/tests/standalone/ten_runtime_smoke_test", "args": [ - "--gtest_filter=StandaloneTest.BasicGraphCrossApp" + "--gtest_filter=AudioFrameTest.Basic" ], "cwd": "${workspaceFolder}/out/linux/x64/tests/standalone/", "env": { @@ -440,9 +440,9 @@ "name": "app (C/C++) (lldb, launch)", "type": "lldb", "request": "launch", - "program": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/cpp/standalone_test_cpp/default_extension_cpp/out/linux/x64/tests/default_extension_cpp_test", + "program": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/python/cpp_app_multi_process_python/cpp_app_multi_process_python_app/bin/cpp_app_multi_process_python_app_source", "args": [], - "cwd": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/cpp/standalone_test_cpp/default_extension_cpp/out/linux/x64/tests/", + "cwd": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/python/cpp_app_multi_process_python/cpp_app_multi_process_python_app/", "env": { "ASAN_OPTIONS": "use_sigaltstack=0", }, @@ -565,6 +565,36 @@ } }, }, + { + "name": "app (Python Standalone Test) (cppdbg, launch)", + "type": "cppdbg", + "request": "launch", + "program": "/usr/bin/python3", + "args": [ + "tests/test_basic.py" + ], + "environment": [ + { + "name": "PYTHONPATH", + "value": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/.ten/app/ten_packages/system/ten_runtime_python/lib:${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/.ten/app/ten_packages/system/ten_runtime_python/interface" + }, + { + "name": "LD_PRELOAD", + "value": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/.ten/app/ten_packages/system/ten_runtime/lib/libasan.so" + }, + { + "name": "PYTHONMALLOC", + "value": "malloc" + }, + { + "name": "PYTHONDEVMODE", + "value": "1" + } + ], + "cwd": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python", + "additionalSOLibSearchPath": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/.ten/app/ten_packages/system/ten_runtime_python/lib:${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/.ten/app/ten_packages/system/ten_runtime/lib", + "MIMode": "gdb", + }, { "name": "app (Java) (cppdbg, attach)", "type": "cppdbg", diff --git a/core/include/ten_runtime/addon/addon.h b/core/include/ten_runtime/addon/addon.h index 310c6b7eb..6b5ead7c7 100644 --- a/core/include/ten_runtime/addon/addon.h +++ b/core/include/ten_runtime/addon/addon.h @@ -44,15 +44,19 @@ typedef void (*ten_addon_on_destroy_instance_func_t)(ten_addon_t *addon, void *instance, void *context); +typedef void (*ten_addon_on_destroy_func_t)(ten_addon_t *addon); + TEN_RUNTIME_API ten_addon_t *ten_addon_create( ten_addon_on_init_func_t on_init, ten_addon_on_deinit_func_t on_deinit, ten_addon_on_create_instance_func_t on_create_instance, - ten_addon_on_destroy_instance_func_t on_destroy_instance); + ten_addon_on_destroy_instance_func_t on_destroy_instance, + ten_addon_on_destroy_func_t on_destroy); TEN_RUNTIME_API void ten_addon_init( ten_addon_t *self, ten_addon_on_init_func_t on_init, ten_addon_on_deinit_func_t on_deinit, ten_addon_on_create_instance_func_t on_create_instance, - ten_addon_on_destroy_instance_func_t on_destroy_instance); + ten_addon_on_destroy_instance_func_t on_destroy_instance, + ten_addon_on_destroy_func_t on_destroy); TEN_RUNTIME_API void ten_addon_destroy(ten_addon_t *self); diff --git a/core/include/ten_runtime/addon/addon_manager.h b/core/include/ten_runtime/addon/addon_manager.h new file mode 100644 index 000000000..86b1342d6 --- /dev/null +++ b/core/include/ten_runtime/addon/addon_manager.h @@ -0,0 +1,19 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#pragma once + +#include "ten_runtime/ten_config.h" + +typedef struct ten_addon_manager_t ten_addon_manager_t; + +typedef void (*ten_addon_registration_func_t)(void *register_ctx); + +TEN_RUNTIME_API ten_addon_manager_t *ten_addon_manager_get_instance(void); + +TEN_RUNTIME_API void ten_addon_manager_add_addon( + ten_addon_manager_t *self, const char *name, + ten_addon_registration_func_t func); diff --git a/core/include/ten_runtime/addon/extension/extension.h b/core/include/ten_runtime/addon/extension/extension.h index 38e4a78db..d37dc42ce 100644 --- a/core/include/ten_runtime/addon/extension/extension.h +++ b/core/include/ten_runtime/addon/extension/extension.h @@ -21,16 +21,10 @@ typedef struct ten_extension_t ten_extension_t; typedef struct ten_addon_host_t ten_addon_host_t; typedef ten_addon_host_t *(*ten_addon_register_extension_func_t)( - const char *name, const char *base_dir, ten_addon_t *addon); - -typedef ten_addon_host_t *(*ten_addon_register_extension_v2_func_t)( const char *name, const char *base_dir, ten_addon_t *addon, void *register_ctx); TEN_RUNTIME_API ten_addon_host_t *ten_addon_register_extension( - const char *name, const char *base_dir, ten_addon_t *addon); - -TEN_RUNTIME_API ten_addon_host_t *ten_addon_register_extension_v2( const char *name, const char *base_dir, ten_addon_t *addon, void *register_ctx); @@ -38,10 +32,10 @@ TEN_RUNTIME_API ten_addon_t *ten_addon_unregister_extension(const char *name); TEN_RUNTIME_API bool ten_addon_create_extension( ten_env_t *ten_env, const char *addon_name, const char *instance_name, - ten_env_addon_on_create_instance_async_cb_t cb, void *user_data, + ten_env_addon_create_instance_done_cb_t cb, void *user_data, ten_error_t *err); TEN_RUNTIME_API bool ten_addon_destroy_extension( ten_env_t *ten_env, ten_extension_t *extension, - ten_env_addon_on_destroy_instance_async_cb_t cb, void *user_data, + ten_env_addon_destroy_instance_done_cb_t cb, void *user_data, ten_error_t *err); diff --git a/core/include/ten_runtime/binding/cpp/detail/addon.h b/core/include/ten_runtime/binding/cpp/detail/addon.h index 24e18bbf3..cb3f33c2c 100644 --- a/core/include/ten_runtime/binding/cpp/detail/addon.h +++ b/core/include/ten_runtime/binding/cpp/detail/addon.h @@ -23,7 +23,7 @@ class addon_t { addon_t() : c_addon(ten_addon_create(proxy_on_init, proxy_on_deinit, proxy_on_create_instance, - proxy_on_destroy_instance)) { + proxy_on_destroy_instance, proxy_on_destroy)) { ten_binding_handle_set_me_in_target_lang( reinterpret_cast(c_addon), this); } @@ -174,6 +174,16 @@ class addon_t { cpp_addon->invoke_cpp_addon_on_destroy_instance(*cpp_ten_env, cpp_instance, context); } + + static void proxy_on_destroy(ten_addon_t *addon) { + TEN_ASSERT(addon, "Invalid argument."); + + auto *cpp_addon = + static_cast(ten_binding_handle_get_me_in_target_lang( + reinterpret_cast(addon))); + + delete cpp_addon; + } }; namespace { diff --git a/core/include/ten_runtime/binding/cpp/detail/addon_manager.h b/core/include/ten_runtime/binding/cpp/detail/addon_manager.h index 39c83c3cc..ebdcc392f 100644 --- a/core/include/ten_runtime/binding/cpp/detail/addon_manager.h +++ b/core/include/ten_runtime/binding/cpp/detail/addon_manager.h @@ -9,66 +9,35 @@ #include #include -#define TEN_CPP_REGISTER_ADDON_AS_EXTENSION(NAME, CLASS) \ - class NAME##_default_extension_addon_t : public ten::extension_addon_t { \ - public: \ - void on_create_instance(ten::ten_env_t &ten_env, const char *name, \ - void *context) override { \ - auto *instance = new CLASS(name); \ - ten_env.on_create_instance_done(instance, context); \ - } \ - void on_destroy_instance(ten::ten_env_t &ten_env, void *instance, \ - void *context) override { \ - delete static_cast(instance); \ - ten_env.on_destroy_instance_done(context); \ - } \ - }; \ - static ten::addon_t *g_##NAME##_default_extension_addon = nullptr; \ - TEN_CONSTRUCTOR(____ctor_ten_declare_##NAME##_extension_addon____) { \ - g_##NAME##_default_extension_addon = \ - new NAME##_default_extension_addon_t(); \ - ten_string_t *base_dir = \ - ten_path_get_module_path(/* NOLINTNEXTLINE */ \ - (void *) \ - ____ctor_ten_declare_##NAME##_extension_addon____); \ - ten_addon_register_extension( \ - #NAME, ten_string_get_raw_str(base_dir), \ - g_##NAME##_default_extension_addon->get_c_addon()); \ - ten_string_destroy(base_dir); \ - } \ - TEN_DESTRUCTOR(____dtor_ten_declare_##NAME##_extension_addon____) { \ - ten_addon_unregister_extension(#NAME); \ - delete g_##NAME##_default_extension_addon; \ - } +#include "ten_runtime/addon/addon_manager.h" // IWYU pragma: export -#define TEN_CPP_REGISTER_ADDON_AS_EXTENSION_V2(NAME, CLASS) \ - class NAME##_default_extension_addon_t : public ten::extension_addon_t { \ - public: \ - void on_create_instance(ten::ten_env_t &ten_env, const char *name, \ - void *context) override { \ - auto *instance = new CLASS(name); \ - ten_env.on_create_instance_done(instance, context); \ - } \ - void on_destroy_instance(ten::ten_env_t &ten_env, void *instance, \ - void *context) override { \ - delete static_cast(instance); \ - ten_env.on_destroy_instance_done(context); \ - } \ - }; \ - static ten::addon_t *g_##NAME##_default_extension_addon = nullptr; \ - TEN_CONSTRUCTOR(____ctor_ten_declare_##NAME##_extension_addon____) { \ - g_##NAME##_default_extension_addon = \ - new NAME##_default_extension_addon_t(); \ - ten_string_t *base_dir = \ - ten_path_get_module_path(/* NOLINTNEXTLINE */ \ - (void *) \ - ____ctor_ten_declare_##NAME##_extension_addon____); \ - ten_addon_register_extension( \ - #NAME, ten_string_get_raw_str(base_dir), \ - g_##NAME##_default_extension_addon->get_c_addon()); \ - ten_string_destroy(base_dir); \ - } \ - TEN_DESTRUCTOR(____dtor_ten_declare_##NAME##_extension_addon____) { \ - ten_addon_unregister_extension(#NAME); \ - delete g_##NAME##_default_extension_addon; \ - } +#define TEN_CPP_REGISTER_ADDON_AS_EXTENSION(NAME, CLASS) \ + class NAME##_default_extension_addon_t : public ten::extension_addon_t { \ + public: \ + void on_create_instance(ten::ten_env_t &ten_env, const char *name, \ + void *context) override { \ + auto *instance = new CLASS(name); \ + ten_env.on_create_instance_done(instance, context); \ + } \ + void on_destroy_instance(ten::ten_env_t &ten_env, void *instance, \ + void *context) override { \ + delete static_cast(instance); \ + ten_env.on_destroy_instance_done(context); \ + } \ + }; \ + static void ____ten_addon_##NAME##_register_handler__(void *register_ctx) { \ + auto *addon_instance = new NAME##_default_extension_addon_t(); \ + ten_string_t *base_dir = \ + ten_path_get_module_path(/* NOLINTNEXTLINE */ \ + (void *) \ + ____ten_addon_##NAME##_register_handler__); \ + ten_addon_register_extension(#NAME, ten_string_get_raw_str(base_dir), \ + addon_instance->get_c_addon(), register_ctx); \ + ten_string_destroy(base_dir); \ + } \ + TEN_CONSTRUCTOR(____ten_addon_##NAME##_registrar____) { \ + /* Add addon registration function into addon manager. */ \ + ten_addon_manager_t *manager = ten_addon_manager_get_instance(); \ + ten_addon_manager_add_addon(manager, #NAME, \ + ____ten_addon_##NAME##_register_handler__); \ + }\ diff --git a/core/include/ten_runtime/ten_env/ten_env.h b/core/include/ten_runtime/ten_env/ten_env.h index bd079b6c3..6b3d4d94f 100644 --- a/core/include/ten_runtime/ten_env/ten_env.h +++ b/core/include/ten_runtime/ten_env/ten_env.h @@ -18,12 +18,12 @@ typedef struct ten_env_t ten_env_t; typedef struct ten_extension_group_t ten_extension_group_t; -typedef void (*ten_env_addon_on_create_instance_async_cb_t)(ten_env_t *ten_env, - void *instance, - void *cb_data); +typedef void (*ten_env_addon_create_instance_done_cb_t)(ten_env_t *ten_env, + void *instance, + void *cb_data); -typedef void (*ten_env_addon_on_destroy_instance_async_cb_t)(ten_env_t *ten_env, - void *cb_data); +typedef void (*ten_env_addon_destroy_instance_done_cb_t)(ten_env_t *ten_env, + void *cb_data); typedef void (*ten_env_is_cmd_connected_async_cb_t)(ten_env_t *ten_env, bool result, void *cb_data, diff --git a/core/include/ten_utils/lib/string.h b/core/include/ten_utils/lib/string.h index 4e2b58ddd..ea0610648 100644 --- a/core/include/ten_utils/lib/string.h +++ b/core/include/ten_utils/lib/string.h @@ -18,13 +18,22 @@ #define TEN_STRING_SIGNATURE 0x178445C0402E320DU +#define MAX_BUFFER_SIZE (10 * 1024 * 1024) // 10 M + #if defined(NDEBUG) #define TEN_STRING_PRE_BUF_SIZE 256 +#define BUFFER_ENLARGE_RATIO 2 #else // In debug mode, significantly reduce the size of `prebuf` so that // `ten_string_reserve` is actually triggered. This way, we can test that even // if `malloc` occurs within `ten_string_reserve`, there will be no memory leak. #define TEN_STRING_PRE_BUF_SIZE 8 + +// Because the initial buffer size of a string in debug mode is relatively +// small, the enlargement ratio is set higher each time capacity needs to be +// reserved. This helps avoid frequent capacity reservations, which could +// otherwise lead to poor performance. +#define BUFFER_ENLARGE_RATIO 30 #endif typedef struct ten_list_t ten_list_t; diff --git a/core/include_internal/ten_runtime/addon/addon.h b/core/include_internal/ten_runtime/addon/addon.h index 845d86385..b3015a9fb 100644 --- a/core/include_internal/ten_runtime/addon/addon.h +++ b/core/include_internal/ten_runtime/addon/addon.h @@ -32,12 +32,11 @@ typedef enum TEN_ADDON_TYPE { typedef struct ten_addon_context_t { ten_env_t *caller_ten; - ten_env_addon_on_create_instance_async_cb_t addon_on_create_instance_async_cb; - void *addon_on_create_instance_async_cb_data; + ten_env_addon_create_instance_done_cb_t create_instance_done_cb; + void *create_instance_done_cb_data; - ten_env_addon_on_destroy_instance_async_cb_t - addon_on_destroy_instance_async_cb; - void *addon_on_destroy_instance_async_cb_data; + ten_env_addon_destroy_instance_done_cb_t destroy_instance_done_cb; + void *destroy_instance_done_cb_data; } ten_addon_context_t; typedef struct ten_addon_t { @@ -51,6 +50,8 @@ typedef struct ten_addon_t { ten_addon_on_create_instance_func_t on_create_instance; ten_addon_on_destroy_instance_func_t on_destroy_instance; + ten_addon_on_destroy_func_t on_destroy; + void *user_data; } ten_addon_t; @@ -81,14 +82,14 @@ typedef struct ten_addon_on_create_instance_info_t { ten_string_t addon_name; ten_string_t instance_name; TEN_ADDON_TYPE addon_type; // Used to retrieve addon from the correct store. - ten_env_addon_on_create_instance_async_cb_t cb; + ten_env_addon_create_instance_done_cb_t cb; void *cb_data; } ten_addon_on_create_instance_info_t; typedef struct ten_addon_on_destroy_instance_info_t { ten_addon_host_t *addon_host; void *instance; - ten_env_addon_on_destroy_instance_async_cb_t cb; + ten_env_addon_destroy_instance_done_cb_t cb; void *cb_data; } ten_addon_on_destroy_instance_info_t; @@ -125,7 +126,7 @@ TEN_RUNTIME_API ten_addon_host_t *ten_addon_host_find(const char *addon_name, TEN_RUNTIME_PRIVATE_API ten_addon_on_create_instance_info_t * ten_addon_on_create_instance_info_create( const char *addon_name, const char *instance_name, - TEN_ADDON_TYPE addon_type, ten_env_addon_on_create_instance_async_cb_t cb, + TEN_ADDON_TYPE addon_type, ten_env_addon_create_instance_done_cb_t cb, void *cb_data); TEN_RUNTIME_PRIVATE_API void ten_addon_on_create_instance_info_destroy( @@ -134,7 +135,7 @@ TEN_RUNTIME_PRIVATE_API void ten_addon_on_create_instance_info_destroy( TEN_RUNTIME_PRIVATE_API ten_addon_on_destroy_instance_info_t * ten_addon_host_on_destroy_instance_info_create( ten_addon_host_t *self, void *instance, - ten_env_addon_on_destroy_instance_async_cb_t cb, void *cb_data); + ten_env_addon_destroy_instance_done_cb_t cb, void *cb_data); TEN_RUNTIME_PRIVATE_API void ten_addon_on_destroy_instance_info_destroy( ten_addon_on_destroy_instance_info_t *self); @@ -143,12 +144,12 @@ TEN_RUNTIME_PRIVATE_API ten_addon_store_t *ten_addon_get_store(void); TEN_RUNTIME_PRIVATE_API bool ten_addon_create_instance_async( ten_env_t *ten_env, const char *addon_name, const char *instance_name, - TEN_ADDON_TYPE type, ten_env_addon_on_create_instance_async_cb_t cb, + TEN_ADDON_TYPE type, ten_env_addon_create_instance_done_cb_t cb, void *cb_data); TEN_RUNTIME_PRIVATE_API bool ten_addon_host_destroy_instance_async( ten_addon_host_t *self, ten_env_t *ten_env, void *instance, - ten_env_addon_on_destroy_instance_async_cb_t cb, void *cb_data); + ten_env_addon_destroy_instance_done_cb_t cb, void *cb_data); TEN_RUNTIME_PRIVATE_API bool ten_addon_host_destroy_instance( ten_addon_host_t *self, ten_env_t *ten_env, void *instance); diff --git a/core/include_internal/ten_runtime/addon/addon_manager.h b/core/include_internal/ten_runtime/addon/addon_manager.h new file mode 100644 index 000000000..b21543f84 --- /dev/null +++ b/core/include_internal/ten_runtime/addon/addon_manager.h @@ -0,0 +1,39 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#pragma once + +#include "ten_runtime/ten_config.h" + +#include "ten_runtime/addon/addon_manager.h" +#include "ten_utils/container/list.h" +#include "ten_utils/lib/mutex.h" +#include "ten_utils/lib/string.h" + +typedef struct ten_app_t ten_app_t; + +typedef struct ten_addon_registration_t { + ten_string_t name; + ten_addon_registration_func_t func; +} ten_addon_registration_t; + +typedef struct ten_addon_register_ctx_t { + ten_app_t *app; +} ten_addon_register_ctx_t; + +typedef struct ten_addon_manager_t { + ten_list_t registry; // ten_addon_registration_t* + ten_mutex_t *mutex; +} ten_addon_manager_t; + +TEN_RUNTIME_API void ten_addon_manager_register_all_addons( + ten_addon_manager_t *self, void *register_ctx); + +TEN_RUNTIME_PRIVATE_API ten_addon_register_ctx_t *ten_addon_register_ctx_create( + void); + +TEN_RUNTIME_PRIVATE_API void ten_addon_register_ctx_destroy( + ten_addon_register_ctx_t *self); diff --git a/core/include_internal/ten_runtime/addon/common/store.h b/core/include_internal/ten_runtime/addon/common/store.h index 8c61add84..dbe58c92f 100644 --- a/core/include_internal/ten_runtime/addon/common/store.h +++ b/core/include_internal/ten_runtime/addon/common/store.h @@ -29,5 +29,7 @@ TEN_RUNTIME_PRIVATE_API bool ten_addon_store_add(ten_addon_store_t *store, TEN_RUNTIME_PRIVATE_API ten_addon_t *ten_addon_store_del( ten_addon_store_t *store, const char *name); +TEN_RUNTIME_PRIVATE_API void ten_addon_store_del_all(ten_addon_store_t *store); + TEN_RUNTIME_PRIVATE_API ten_addon_host_t *ten_addon_store_find( ten_addon_store_t *store, const char *name); diff --git a/core/include_internal/ten_runtime/addon/extension/extension.h b/core/include_internal/ten_runtime/addon/extension/extension.h index f840976dd..6abc5fff9 100644 --- a/core/include_internal/ten_runtime/addon/extension/extension.h +++ b/core/include_internal/ten_runtime/addon/extension/extension.h @@ -12,3 +12,5 @@ typedef struct ten_addon_store_t ten_addon_store_t; typedef struct ten_addon_t ten_addon_t; TEN_RUNTIME_PRIVATE_API ten_addon_store_t *ten_extension_get_global_store(void); + +TEN_RUNTIME_API void ten_addon_unregister_all_extension(void); diff --git a/core/include_internal/ten_runtime/addon/extension_group/extension_group.h b/core/include_internal/ten_runtime/addon/extension_group/extension_group.h index 80ef8cc54..dd849fa25 100644 --- a/core/include_internal/ten_runtime/addon/extension_group/extension_group.h +++ b/core/include_internal/ten_runtime/addon/extension_group/extension_group.h @@ -25,14 +25,15 @@ TEN_RUNTIME_PRIVATE_API ten_addon_store_t *ten_extension_group_get_global_store( TEN_RUNTIME_PRIVATE_API bool ten_addon_create_extension_group( ten_env_t *ten_env, const char *addon_name, const char *instance_name, - ten_env_addon_on_create_instance_async_cb_t cb, void *user_data); + ten_env_addon_create_instance_done_cb_t cb, void *user_data); TEN_RUNTIME_PRIVATE_API bool ten_addon_destroy_extension_group( ten_env_t *ten_env, ten_extension_group_t *extension_group, - ten_env_addon_on_destroy_instance_async_cb_t cb, void *user_data); + ten_env_addon_destroy_instance_done_cb_t cb, void *user_data); TEN_RUNTIME_PRIVATE_API ten_addon_host_t *ten_addon_register_extension_group( - const char *name, const char *base_dir, ten_addon_t *addon); + const char *name, const char *base_dir, ten_addon_t *addon, + void *register_ctx); TEN_RUNTIME_PRIVATE_API ten_addon_t *ten_addon_unregister_extension_group( const char *name); diff --git a/core/include_internal/ten_runtime/binding/cpp/detail/addon.h b/core/include_internal/ten_runtime/binding/cpp/detail/addon.h deleted file mode 100644 index d632ed412..000000000 --- a/core/include_internal/ten_runtime/binding/cpp/detail/addon.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright © 2024 Agora -// This file is part of TEN Framework, an open source project. -// Licensed under the Apache License, Version 2.0, with certain conditions. -// Refer to the "LICENSE" file in the root directory for more information. -// -#pragma once - -class extension_group_addon_t : public addon_t { - private: - void on_create_instance_impl(ten_env_t &ten_env, const char *name, - void *context) override { - auto *cpp_context = new addon_context_t(); - cpp_context->task = ADDON_TASK_CREATE_EXTENSION_GROUP; - cpp_context->c_context = context; - - on_create_instance(ten_env, name, cpp_context); - } -}; - -#define TEN_CPP_REGISTER_ADDON_AS_EXTENSION_GROUP(NAME, CLASS) \ - class NAME##_default_extension_group_addon_t \ - : public ten::extension_group_addon_t { \ - public: \ - void on_create_instance(ten::ten_env_t &ten_env, const char *name, \ - void *context) override { \ - auto *instance = new CLASS(name); \ - ten_env.on_create_instance_done(instance, context); \ - } \ - void on_destroy_instance(ten::ten_env_t &ten_env, void *instance, \ - void *context) override { \ - delete static_cast(instance); \ - ten_env.on_destroy_instance_done(context); \ - } \ - }; \ - static ten::addon_t *g_##NAME##_default_extension_group_addon = nullptr; \ - TEN_CONSTRUCTOR(____ctor_ten_declare_##NAME##_extension_group_addon____) { \ - g_##NAME##_default_extension_group_addon = \ - new NAME##_default_extension_group_addon_t(); \ - ten_string_t *base_dir = \ - ten_path_get_module_path(/* NOLINTNEXTLINE */ \ - (void *) \ - ____ctor_ten_declare_##NAME##_extension_group_addon____); \ - ten_addon_register_extension_group( \ - #NAME, ten_string_get_raw_str(base_dir), \ - g_##NAME##_default_extension_group_addon->get_c_addon()); \ - ten_string_destroy(base_dir); \ - } \ - TEN_DESTRUCTOR(____dtor_ten_declare_##NAME##_extension_group_addon____) { \ - ten_addon_unregister_extension_group(#NAME); \ - delete g_##NAME##_default_extension_group_addon; \ - } diff --git a/core/include_internal/ten_runtime/binding/go/extension/extension.h b/core/include_internal/ten_runtime/binding/go/extension/extension.h index 6118c973d..3c7da0057 100644 --- a/core/include_internal/ten_runtime/binding/go/extension/extension.h +++ b/core/include_internal/ten_runtime/binding/go/extension/extension.h @@ -29,11 +29,5 @@ TEN_RUNTIME_PRIVATE_API ten_go_extension_t *ten_go_extension_reinterpret( TEN_RUNTIME_PRIVATE_API ten_go_handle_t ten_go_extension_go_handle(ten_go_extension_t *self); -TEN_RUNTIME_PRIVATE_API ten_go_extension_t *ten_go_extension_create_internal( - ten_go_handle_t go_extension, const char *name); - TEN_RUNTIME_PRIVATE_API ten_extension_t *ten_go_extension_c_extension( ten_go_extension_t *self); - -TEN_RUNTIME_PRIVATE_API void ten_go_extension_set_go_handle( - ten_go_extension_t *self, ten_go_handle_t go_handle); diff --git a/core/include_internal/ten_runtime/binding/python/addon/addon_manager.h b/core/include_internal/ten_runtime/binding/python/addon/addon_manager.h index 92438d94b..e5b4b39ad 100644 --- a/core/include_internal/ten_runtime/binding/python/addon/addon_manager.h +++ b/core/include_internal/ten_runtime/binding/python/addon/addon_manager.h @@ -11,22 +11,11 @@ #include #include "include_internal/ten_runtime/binding/python/common/python_stuff.h" -#include "ten_utils/lib/string.h" typedef struct ten_py_addon_manager_register_addon_decorator_t { PyObject_HEAD - ten_string_t addon_name; - ten_string_t base_dir; } ten_py_addon_manager_register_addon_decorator_t; -typedef struct ten_py_addon_manager_register_addon_decorator_v2_t { - PyObject_HEAD -} ten_py_addon_manager_register_addon_decorator_v2_t; - -TEN_RUNTIME_PRIVATE_API bool -ten_py_addon_manager_register_addon_as_extension_decorator_init_for_module( - PyObject *module); - -TEN_RUNTIME_PRIVATE_API bool -ten_py_addon_manager_register_addon_as_extension_decorator_init_for_module_v2( - PyObject *module); +TEN_RUNTIME_PRIVATE_API PyObject * +ten_py_addon_manager_register_addon_as_extension(PyObject *self, + PyObject *args); diff --git a/core/include_internal/ten_utils/lib/env.h b/core/include_internal/ten_utils/lib/env.h new file mode 100644 index 000000000..4a78a3e07 --- /dev/null +++ b/core/include_internal/ten_utils/lib/env.h @@ -0,0 +1,13 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#pragma once + +#include "ten_utils/ten_config.h" + +#include + +TEN_UTILS_API bool ten_env_set(const char *name, const char *value); diff --git a/core/src/ten_runtime/addon/addon.c b/core/src/ten_runtime/addon/addon.c index f0fdce470..639192b23 100644 --- a/core/src/ten_runtime/addon/addon.c +++ b/core/src/ten_runtime/addon/addon.c @@ -49,7 +49,8 @@ bool ten_addon_check_integrity(ten_addon_t *self) { void ten_addon_init(ten_addon_t *self, ten_addon_on_init_func_t on_init, ten_addon_on_deinit_func_t on_deinit, ten_addon_on_create_instance_func_t on_create_instance, - ten_addon_on_destroy_instance_func_t on_destroy_instance) { + ten_addon_on_destroy_instance_func_t on_destroy_instance, + ten_addon_on_destroy_func_t on_destroy) { ten_binding_handle_set_me_in_target_lang((ten_binding_handle_t *)self, NULL); ten_signature_set(&self->signature, TEN_ADDON_SIGNATURE); @@ -57,6 +58,7 @@ void ten_addon_init(ten_addon_t *self, ten_addon_on_init_func_t on_init, self->on_deinit = on_deinit; self->on_create_instance = on_create_instance; self->on_destroy_instance = on_destroy_instance; + self->on_destroy = on_destroy; self->user_data = NULL; } @@ -64,12 +66,13 @@ void ten_addon_init(ten_addon_t *self, ten_addon_on_init_func_t on_init, ten_addon_t *ten_addon_create( ten_addon_on_init_func_t on_init, ten_addon_on_deinit_func_t on_deinit, ten_addon_on_create_instance_func_t on_create_instance, - ten_addon_on_destroy_instance_func_t on_destroy_instance) { + ten_addon_on_destroy_instance_func_t on_destroy_instance, + ten_addon_on_destroy_func_t on_destroy) { ten_addon_t *self = TEN_MALLOC(sizeof(ten_addon_t)); TEN_ASSERT(self, "Failed to allocate memory."); ten_addon_init(self, on_init, on_deinit, on_create_instance, - on_destroy_instance); + on_destroy_instance, on_destroy); return self; } @@ -207,9 +210,9 @@ void ten_addon_register(ten_addon_store_t *addon_store, addon_host->addon = addon; addon_host->store = addon_store; - if (!addon_host->ten_env) { - addon_host->ten_env = ten_env_create_for_addon(addon_host); - } + + TEN_ASSERT(!addon_host->ten_env, "Should not happen."); + addon_host->ten_env = ten_env_create_for_addon(addon_host); ten_string_set_formatted(&addon_host->name, "%s", name); @@ -217,7 +220,7 @@ void ten_addon_register(ten_addon_store_t *addon_store, // require a base directory at all, so `NULL` might be passed as the base_dir // parameter value. if (base_dir) { - TEN_LOGI("Addon %s base_dir: %s", name, base_dir); + TEN_LOGD("Addon %s base_dir: %s", name, base_dir); ten_addon_find_and_set_base_dir(addon_host, base_dir); } TEN_LOGI("Register addon: %s as %s", name, @@ -229,7 +232,7 @@ void ten_addon_register(ten_addon_store_t *addon_store, ten_addon_on_create_instance_info_t *ten_addon_on_create_instance_info_create( const char *addon_name, const char *instance_name, - TEN_ADDON_TYPE addon_type, ten_env_addon_on_create_instance_async_cb_t cb, + TEN_ADDON_TYPE addon_type, ten_env_addon_create_instance_done_cb_t cb, void *cb_data) { TEN_ASSERT(addon_name && instance_name, "Should not happen."); @@ -260,7 +263,7 @@ void ten_addon_on_create_instance_info_destroy( ten_addon_on_destroy_instance_info_t * ten_addon_host_on_destroy_instance_info_create( ten_addon_host_t *self, void *instance, - ten_env_addon_on_destroy_instance_async_cb_t cb, void *cb_data) { + ten_env_addon_destroy_instance_done_cb_t cb, void *cb_data) { TEN_ASSERT(self && instance, "Should not happen."); ten_addon_on_destroy_instance_info_t *info = @@ -367,9 +370,9 @@ void ten_addon_context_destroy(ten_addon_context_t *self) { * later in the call flow when the 'ten' object at that time belongs to a more * specific scope, so that we can minimize the parameters count then. */ -static void ten_addon_host_on_create_instance_async( +static void ten_addon_host_create_instance_async( ten_addon_host_t *self, ten_env_t *ten_env, const char *name, - ten_env_addon_on_create_instance_async_cb_t cb, void *cb_data) { + ten_env_addon_create_instance_done_cb_t cb, void *cb_data) { TEN_ASSERT(self && ten_addon_host_check_integrity(self) && name, "Should not happen."); TEN_ASSERT(ten_env && ten_env_check_integrity(ten_env, true), @@ -377,8 +380,8 @@ static void ten_addon_host_on_create_instance_async( ten_addon_context_t *addon_context = ten_addon_context_create(); addon_context->caller_ten = ten_env; - addon_context->addon_on_create_instance_async_cb = cb; - addon_context->addon_on_create_instance_async_cb_data = cb_data; + addon_context->create_instance_done_cb = cb; + addon_context->create_instance_done_cb_data = cb_data; if (self->addon->on_create_instance) { TEN_ASSERT(self->addon->on_create_instance, "Should not happen."); @@ -408,10 +411,11 @@ static void ten_addon_host_on_create_instance_async( * later in the call flow when the 'ten' object at that time belongs to a more * specific scope, so that we can minimize the parameters count then. */ -bool ten_addon_create_instance_async( - ten_env_t *ten_env, const char *addon_name, const char *instance_name, - TEN_ADDON_TYPE type, ten_env_addon_on_create_instance_async_cb_t cb, - void *cb_data) { +bool ten_addon_create_instance_async(ten_env_t *ten_env, const char *addon_name, + const char *instance_name, + TEN_ADDON_TYPE type, + ten_env_addon_create_instance_done_cb_t cb, + void *cb_data) { // We increase the refcount of the 'addon' here, and will decrease the // refcount in "ten_(extension/extension_group)_set_addon" after the // extension/extension_group instance has been created. @@ -425,8 +429,8 @@ bool ten_addon_create_instance_async( TEN_ASSERT(ten_env && ten_env_check_integrity(ten_env, true), "Should not happen."); - ten_addon_host_on_create_instance_async(addon, ten_env, instance_name, cb, - cb_data); + ten_addon_host_create_instance_async(addon, ten_env, instance_name, cb, + cb_data); return true; } @@ -449,7 +453,7 @@ bool ten_addon_create_instance_async( */ bool ten_addon_host_destroy_instance_async( ten_addon_host_t *self, ten_env_t *ten_env, void *instance, - ten_env_addon_on_destroy_instance_async_cb_t cb, void *cb_data) { + ten_env_addon_destroy_instance_done_cb_t cb, void *cb_data) { TEN_ASSERT(self && ten_addon_host_check_integrity(self), "Should not happen."); TEN_ASSERT(ten_env && ten_env_check_integrity(ten_env, true), @@ -458,8 +462,8 @@ bool ten_addon_host_destroy_instance_async( ten_addon_context_t *addon_context = ten_addon_context_create(); addon_context->caller_ten = ten_env; - addon_context->addon_on_destroy_instance_async_cb = cb; - addon_context->addon_on_destroy_instance_async_cb_data = cb_data; + addon_context->destroy_instance_done_cb = cb; + addon_context->destroy_instance_done_cb_data = cb_data; if (self->addon->on_destroy_instance) { TEN_ASSERT(self->addon->on_destroy_instance, "Should not happen."); diff --git a/core/src/ten_runtime/addon/addon_autoload.c b/core/src/ten_runtime/addon/addon_autoload.c index 29457ce68..75e2dc28c 100644 --- a/core/src/ten_runtime/addon/addon_autoload.c +++ b/core/src/ten_runtime/addon/addon_autoload.c @@ -18,13 +18,13 @@ #endif #include "include_internal/ten_runtime/addon/addon.h" +#include "include_internal/ten_runtime/addon/addon_manager.h" #include "include_internal/ten_runtime/addon/extension/extension.h" #include "include_internal/ten_runtime/app/app.h" #include "include_internal/ten_runtime/common/constant_str.h" #include "include_internal/ten_runtime/global/global.h" #include "include_internal/ten_runtime/global/signal.h" #include "include_internal/ten_runtime/metadata/manifest.h" -#include "include_internal/ten_runtime/ten_env/ten_env.h" #include "include_internal/ten_utils/log/log.h" #include "ten_runtime/app/app.h" #include "ten_utils/container/list.h" @@ -51,8 +51,6 @@ */ #if defined(OS_MACOS) || defined(OS_LINUX) || defined(OS_WINDOWS) static void load_all_dynamic_libraries_under_path(ten_app_t *app, - TEN_ADDON_TYPE addon_type, - const char *addon_name, const char *path) { TEN_ASSERT(app && ten_app_check_integrity(app, true), "Invalid argument."); TEN_ASSERT(path, "Invalid argument."); @@ -113,38 +111,8 @@ static void load_all_dynamic_libraries_under_path(ten_app_t *app, goto continue_loop; } - ten_string_t register_func_name; - ten_string_init(®ister_func_name); - ten_string_append_formatted( - ®ister_func_name, "%s%s%s", TEN_STR_ADDON_REGISTER_FUNCTION_PREFIX, - addon_name, TEN_STR_ADDON_REGISTER_FUNCTION_POSTFIX); - - void *symbol = ten_module_get_symbol( - module_handle, ten_string_get_raw_str(®ister_func_name)); - if (symbol) { - ten_addon_register_func_t register_func = - (ten_addon_register_func_t)symbol; - - addon_host = ten_addon_host_create(addon_type); - TEN_ASSERT(addon_host, "Should not happen."); - - addon_host->user_data = app; - addon_host->ten_env = ten_env_create_for_addon(addon_host); - TEN_ASSERT(addon_host->ten_env, "Should not happen."); - - register_func((void *)addon_host); - - TEN_LOGI("Register addon using function: %s", - ten_string_get_raw_str(®ister_func_name)); - } else { - TEN_LOGD("Registration function not found for module: %s", - ten_string_get_raw_str(file_path)); - } - TEN_LOGD("Loaded module: %s", ten_string_get_raw_str(file_path)); - ten_string_deinit(®ister_func_name); - continue_loop: if (file_path) { ten_string_destroy(file_path); @@ -165,10 +133,7 @@ static void load_all_dynamic_libraries_under_path(ten_app_t *app, } } -static void ten_addon_load_from_base_dir(ten_app_t *app, - TEN_ADDON_TYPE addon_type, - const char *addon_name, - const char *path) { +static void ten_addon_load_from_base_dir(ten_app_t *app, const char *path) { ten_string_t lib_dir; ten_string_init_formatted(&lib_dir, "%s", path); @@ -191,15 +156,13 @@ static void ten_addon_load_from_base_dir(ten_app_t *app, } // Load self first. - load_all_dynamic_libraries_under_path(app, addon_type, addon_name, - ten_string_get_raw_str(&lib_dir)); + load_all_dynamic_libraries_under_path(app, ten_string_get_raw_str(&lib_dir)); done: ten_string_deinit(&lib_dir); } static void load_all_dynamic_libraries(ten_app_t *app, const char *path, - TEN_ADDON_TYPE addon_type, ten_list_t *dependencies) { ten_string_t *cur = NULL; ten_string_t *short_name = NULL; @@ -258,9 +221,7 @@ static void load_all_dynamic_libraries(ten_app_t *app, const char *path, goto continue_loop; } - ten_addon_load_from_base_dir(app, addon_type, - ten_string_get_raw_str(short_name), - ten_string_get_raw_str(cur)); + ten_addon_load_from_base_dir(app, ten_string_get_raw_str(cur)); ten_string_destroy(cur); cur = NULL; @@ -370,7 +331,6 @@ bool ten_addon_load_all_from_app_base_dir( // app has been installed. if (ten_path_exists(ten_string_get_raw_str(&module_path))) { load_all_dynamic_libraries(app, ten_string_get_raw_str(&module_path), - folders[i].addon_type, folders[i].dependencies); } } while (0); @@ -421,8 +381,7 @@ bool ten_addon_load_all_from_ten_package_base_dirs(ten_app_t *app, ten_string_deinit(&manifest_json_file_path); - ten_addon_load_from_base_dir(app, addon_type, - ten_string_get_raw_str(&addon_name), + ten_addon_load_from_base_dir(app, ten_string_get_raw_str(ten_package_base_dir)); ten_string_deinit(&addon_name); diff --git a/core/src/ten_runtime/addon/addon_manager.c b/core/src/ten_runtime/addon/addon_manager.c new file mode 100644 index 000000000..cfc3e9821 --- /dev/null +++ b/core/src/ten_runtime/addon/addon_manager.c @@ -0,0 +1,122 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "include_internal/ten_runtime/addon/addon_manager.h" + +#include "ten_utils/lib/string.h" +#include "ten_utils/log/log.h" +#include "ten_utils/macro/memory.h" + +ten_addon_manager_t *ten_addon_manager_get_instance(void) { + static ten_addon_manager_t *instance = NULL; + static ten_mutex_t *init_mutex = NULL; + + if (!init_mutex) { + init_mutex = ten_mutex_create(); + TEN_ASSERT(init_mutex, "Failed to create initialization mutex."); + } + + ten_mutex_lock(init_mutex); + + if (!instance) { + instance = (ten_addon_manager_t *)ten_malloc(sizeof(ten_addon_manager_t)); + TEN_ASSERT(instance, "Failed to allocate memory for ten_addon_manager_t."); + + ten_list_init(&instance->registry); + + instance->mutex = ten_mutex_create(); + TEN_ASSERT(instance->mutex, "Failed to create addon manager mutex."); + } + + ten_mutex_unlock(init_mutex); + + return instance; +} + +static void ten_addon_registration_destroy(void *ptr) { + ten_addon_registration_t *reg = (ten_addon_registration_t *)ptr; + if (reg) { + ten_string_deinit(®->name); + + TEN_FREE(reg); + } +} + +void ten_addon_manager_add_addon(ten_addon_manager_t *self, const char *name, + ten_addon_registration_func_t func) { + TEN_ASSERT(self && name && func, "Invalid argument."); + + ten_mutex_lock(self->mutex); + + // Check if addon with the same name already exists. + bool exists = false; + ten_list_foreach (&self->registry, iter) { + ten_addon_registration_t *reg = + (ten_addon_registration_t *)ten_ptr_listnode_get(iter.node); + if (reg && ten_string_is_equal_c_str(®->name, name)) { + exists = true; + break; + } + } + + if (!exists) { + // Create a new ten_addon_registration_t. + ten_addon_registration_t *reg = (ten_addon_registration_t *)TEN_MALLOC( + sizeof(ten_addon_registration_t)); + TEN_ASSERT(reg, "Failed to allocate memory for ten_addon_registration_t."); + + ten_string_init_from_c_str(®->name, name, strlen(name)); + reg->func = func; + + // Add to the registry. + ten_list_push_ptr_back(&self->registry, reg, + ten_addon_registration_destroy); + } else { + // Handle the case where the addon is already registered. + // For now, log a warning. + TEN_LOGW("Addon '%s' is already registered.", name); + } + + ten_mutex_unlock(self->mutex); +} + +void ten_addon_manager_register_all_addons(ten_addon_manager_t *self, + void *register_ctx) { + TEN_ASSERT(self, "Invalid argument."); + + ten_mutex_lock(self->mutex); + + ten_list_iterator_t iter = ten_list_begin(&self->registry); + while (!ten_list_iterator_is_end(iter)) { + ten_listnode_t *node = iter.node; + ten_addon_registration_t *reg = + (ten_addon_registration_t *)ten_ptr_listnode_get(node); + + if (reg && reg->func) { + reg->func(register_ctx); + } + + iter = ten_list_iterator_next(iter); + } + + // Clear the registry after loading. + ten_list_clear(&self->registry); + + ten_mutex_unlock(self->mutex); +} + +ten_addon_register_ctx_t *ten_addon_register_ctx_create(void) { + ten_addon_register_ctx_t *self = TEN_MALLOC(sizeof(ten_addon_register_ctx_t)); + TEN_ASSERT(self, "Failed to allocate memory."); + + return self; +} + +void ten_addon_register_ctx_destroy(ten_addon_register_ctx_t *self) { + TEN_ASSERT(self, "Invalid argument."); + + TEN_FREE(self); +} diff --git a/core/src/ten_runtime/addon/common/store.c b/core/src/ten_runtime/addon/common/store.c index 7ff6aeff8..9e9ddfad7 100644 --- a/core/src/ten_runtime/addon/common/store.c +++ b/core/src/ten_runtime/addon/common/store.c @@ -101,6 +101,18 @@ ten_addon_t *ten_addon_store_del(ten_addon_store_t *store, const char *name) { return addon; } +void ten_addon_store_del_all(ten_addon_store_t *store) { + TEN_ASSERT(store, "Invalid argument."); + + ten_mutex_lock(store->lock); + + // Clear the store's list, which will call the destroy function for each node, + // properly decreasing the refcount of each addon. + ten_list_clear(&store->store); + + ten_mutex_unlock(store->lock); +} + ten_addon_host_t *ten_addon_store_find(ten_addon_store_t *store, const char *name) { TEN_ASSERT(store, "Invalid argument."); diff --git a/core/src/ten_runtime/addon/extension/extension.c b/core/src/ten_runtime/addon/extension/extension.c index cce5c7c8d..ac8d47097 100644 --- a/core/src/ten_runtime/addon/extension/extension.c +++ b/core/src/ten_runtime/addon/extension/extension.c @@ -7,7 +7,9 @@ #include "ten_runtime/addon/extension/extension.h" #include "include_internal/ten_runtime/addon/addon.h" +#include "include_internal/ten_runtime/addon/addon_manager.h" #include "include_internal/ten_runtime/addon/common/store.h" +#include "include_internal/ten_runtime/addon/extension/extension.h" #include "include_internal/ten_runtime/extension/extension.h" #include "include_internal/ten_runtime/extension_group/extension_group.h" #include "include_internal/ten_runtime/extension_thread/extension_thread.h" @@ -31,7 +33,7 @@ ten_addon_store_t *ten_extension_get_global_store(void) { bool ten_addon_create_extension(ten_env_t *ten_env, const char *addon_name, const char *instance_name, - ten_env_addon_on_create_instance_async_cb_t cb, + ten_env_addon_create_instance_done_cb_t cb, void *cb_data, TEN_UNUSED ten_error_t *err) { TEN_ASSERT(addon_name && instance_name, "Should not happen."); @@ -73,10 +75,9 @@ bool ten_addon_create_extension(ten_env_t *ten_env, const char *addon_name, } } -bool ten_addon_destroy_extension( - ten_env_t *ten_env, ten_extension_t *extension, - ten_env_addon_on_destroy_instance_async_cb_t cb, void *cb_data, - TEN_UNUSED ten_error_t *err) { +bool ten_addon_destroy_extension(ten_env_t *ten_env, ten_extension_t *extension, + ten_env_addon_destroy_instance_done_cb_t cb, + void *cb_data, TEN_UNUSED ten_error_t *err) { TEN_ASSERT(ten_env, "Invalid argument."); TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Invalid use of ten_env %p.", ten_env); @@ -117,7 +118,8 @@ bool ten_addon_destroy_extension( ten_addon_host_t *ten_addon_register_extension(const char *name, const char *base_dir, - ten_addon_t *addon) { + ten_addon_t *addon, + void *register_ctx) { if (!name || strlen(name) == 0) { TEN_LOGE("The addon name is required."); exit(EXIT_FAILURE); @@ -132,27 +134,12 @@ ten_addon_host_t *ten_addon_register_extension(const char *name, addon_host = ten_addon_host_create(TEN_ADDON_TYPE_EXTENSION); TEN_ASSERT(addon_host, "Should not happen."); - ten_addon_register(ten_extension_get_global_store(), addon_host, name, - base_dir, addon); - - return addon_host; -} - -ten_addon_host_t *ten_addon_register_extension_v2(const char *name, - const char *base_dir, - ten_addon_t *addon, - void *register_ctx) { - if (!name || strlen(name) == 0) { - TEN_LOGE("The addon name is required."); - exit(EXIT_FAILURE); - } - - ten_addon_host_t *addon_host = (ten_addon_host_t *)register_ctx; - - // If no `addon_host` is provided, create one here. Whether it is created here - // or received, pass it out in the end. - if (!addon_host) { - addon_host = ten_addon_host_create(TEN_ADDON_TYPE_EXTENSION); + if (register_ctx) { + // If `register_ctx` exists, its content will be used to assist in the addon + // registration process. + ten_addon_register_ctx_t *register_ctx_ = + (ten_addon_register_ctx_t *)register_ctx; + addon_host->user_data = register_ctx_->app; } ten_addon_register(ten_extension_get_global_store(), addon_host, name, @@ -166,3 +153,7 @@ ten_addon_t *ten_addon_unregister_extension(const char *name) { return ten_addon_unregister(ten_extension_get_global_store(), name); } + +void ten_addon_unregister_all_extension(void) { + ten_addon_store_del_all(ten_extension_get_global_store()); +} diff --git a/core/src/ten_runtime/addon/extension_group/extension_group.c b/core/src/ten_runtime/addon/extension_group/extension_group.c index 5bdc27a77..d9bdfcc53 100644 --- a/core/src/ten_runtime/addon/extension_group/extension_group.c +++ b/core/src/ten_runtime/addon/extension_group/extension_group.c @@ -26,7 +26,8 @@ ten_addon_store_t *ten_extension_group_get_global_store(void) { ten_addon_host_t *ten_addon_register_extension_group(const char *name, const char *base_dir, - ten_addon_t *addon) { + ten_addon_t *addon, + void *register_ctx) { if (!name || strlen(name) == 0) { TEN_LOGE("The addon name is required."); exit(EXIT_FAILURE); @@ -50,7 +51,7 @@ ten_addon_t *ten_addon_unregister_extension_group(const char *name) { bool ten_addon_create_extension_group( ten_env_t *ten_env, const char *addon_name, const char *instance_name, - ten_env_addon_on_create_instance_async_cb_t cb, void *user_data) { + ten_env_addon_create_instance_done_cb_t cb, void *user_data) { TEN_ASSERT(addon_name && instance_name, "Should not happen."); TEN_ASSERT(ten_env && ten_env_check_integrity(ten_env, true), "Should not happen."); @@ -74,7 +75,7 @@ bool ten_addon_create_extension_group( bool ten_addon_destroy_extension_group( ten_env_t *ten_env, ten_extension_group_t *extension_group, - ten_env_addon_on_destroy_instance_async_cb_t cb, void *cb_data) { + ten_env_addon_destroy_instance_done_cb_t cb, void *cb_data) { TEN_ASSERT(ten_env && ten_env_check_integrity(ten_env, true) && cb, "Should not happen."); TEN_ASSERT(extension_group && diff --git a/core/src/ten_runtime/addon/ten_env/on_xxx.c b/core/src/ten_runtime/addon/ten_env/on_xxx.c index 86f4da607..c779b215d 100644 --- a/core/src/ten_runtime/addon/ten_env/on_xxx.c +++ b/core/src/ten_runtime/addon/ten_env/on_xxx.c @@ -114,6 +114,10 @@ void ten_addon_on_deinit_done(ten_env_t *self) { TEN_ASSERT(addon_host && ten_addon_host_check_integrity(addon_host), "Should not happen."); + if (addon_host->addon->on_destroy) { + addon_host->addon->on_destroy(addon_host->addon); + } + ten_addon_host_destroy(addon_host); } @@ -142,8 +146,7 @@ static void ten_addon_extension_on_create_instance_done(ten_env_t *self, TEN_ASSERT(ten_env_check_integrity(caller_ten, false), "Invalid use of ten_env %p.", caller_ten); - TEN_ASSERT(addon_context->addon_on_create_instance_async_cb, - "Should not happen."); + TEN_ASSERT(addon_context->create_instance_done_cb, "Should not happen."); switch (caller_ten->attach_to) { case TEN_ENV_ATTACH_TO_EXTENSION_GROUP: { @@ -223,8 +226,7 @@ static void ten_addon_extension_group_on_create_instance_done(ten_env_t *self, TEN_ASSERT(ten_env_check_integrity(caller_ten, false), "Invalid use of ten_env %p.", caller_ten); - TEN_ASSERT(addon_context->addon_on_create_instance_async_cb, - "Should not happen."); + TEN_ASSERT(addon_context->create_instance_done_cb, "Should not happen."); switch (caller_ten->attach_to) { case TEN_ENV_ATTACH_TO_ENGINE: { @@ -300,8 +302,7 @@ void ten_addon_protocol_on_create_instance_done(ten_env_t *self, TEN_ASSERT(ten_env_check_integrity(caller_ten, true), "Invalid use of ten_env %p.", caller_ten); - TEN_ASSERT(addon_context->addon_on_create_instance_async_cb, - "Should not happen."); + TEN_ASSERT(addon_context->create_instance_done_cb, "Should not happen."); switch (caller_ten->attach_to) { case TEN_ENV_ATTACH_TO_ENGINE: { @@ -418,8 +419,7 @@ void ten_addon_on_destroy_instance_done(ten_env_t *self, void *context) { TEN_ASSERT(ten_env_check_integrity(caller_ten, false), "Invalid use of ten_env %p.", caller_ten); - TEN_ASSERT(addon_context->addon_on_destroy_instance_async_cb, - "Should not happen."); + TEN_ASSERT(addon_context->destroy_instance_done_cb, "Should not happen."); switch (caller_ten->attach_to) { case TEN_ENV_ATTACH_TO_ENGINE: { diff --git a/core/src/ten_runtime/app/on_xxx.c b/core/src/ten_runtime/app/on_xxx.c index 1f4b6fc0d..2c387146d 100644 --- a/core/src/ten_runtime/app/on_xxx.c +++ b/core/src/ten_runtime/app/on_xxx.c @@ -41,10 +41,9 @@ void ten_app_thread_on_addon_create_protocol_done(void *self, void *arg) { TEN_ASSERT(addon_context, "Invalid argument."); - if (addon_context->addon_on_create_instance_async_cb) { - addon_context->addon_on_create_instance_async_cb( - app->ten_env, protocol, - addon_context->addon_on_create_instance_async_cb_data); + if (addon_context->create_instance_done_cb) { + addon_context->create_instance_done_cb( + app->ten_env, protocol, addon_context->create_instance_done_cb_data); } ten_addon_context_destroy(addon_context); diff --git a/core/src/ten_runtime/app/ten_env/on_xxx.c b/core/src/ten_runtime/app/ten_env/on_xxx.c index f6ff218ed..453e3bcf6 100644 --- a/core/src/ten_runtime/app/ten_env/on_xxx.c +++ b/core/src/ten_runtime/app/ten_env/on_xxx.c @@ -5,6 +5,8 @@ // Refer to the "LICENSE" file in the root directory for more information. // #include "include_internal/ten_runtime/addon/addon_autoload.h" +#include "include_internal/ten_runtime/addon/addon_manager.h" +#include "include_internal/ten_runtime/addon/extension/extension.h" #include "include_internal/ten_runtime/addon/protocol/protocol.h" #include "include_internal/ten_runtime/app/app.h" #include "include_internal/ten_runtime/app/base_dir.h" @@ -169,6 +171,13 @@ void ten_app_on_configure_done(ten_env_t *ten_env) { ten_list_clear(&extension_group_dependencies); ten_list_clear(&protocol_dependencies); + // Register all addons. + ten_addon_manager_t *manager = ten_addon_manager_get_instance(); + ten_addon_register_ctx_t *register_ctx = ten_addon_register_ctx_create(); + register_ctx->app = self; + ten_addon_manager_register_all_addons(manager, (void *)register_ctx); + ten_addon_register_ctx_destroy(register_ctx); + if (!ten_app_get_predefined_graphs_from_property(self)) { goto error; } @@ -249,9 +258,28 @@ void ten_app_on_init_done(ten_env_t *ten_env) { ten_app_on_init_done_internal(self); } +static void ten_app_unregister_addons_after_app_close(ten_app_t *self) { + TEN_ASSERT(self && ten_app_check_integrity(self, true), "Should not happen."); + + const char *disabled = getenv("TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"); + if (disabled && !strcmp(disabled, "true")) { + return; + } + + ten_addon_unregister_all_extension(); +} + void ten_app_on_deinit(ten_app_t *self) { TEN_ASSERT(self && ten_app_check_integrity(self, true), "Should not happen."); + // At the final stage of addon deinitialization, `ten_env_t::on_deinit_done` + // is required, which in turn depends on the runloop. Therefore, the addon + // deinitialization process must be performed before the app's runloop ends. + // After `app::on_deinit`, the app's runloop will be terminated soon, leaving + // no runloop within the TEN runtime. As a result, addon cleanup must be + // performed during the app's `on_deinit` phase. + ten_app_unregister_addons_after_app_close(self); + // The world outside of TEN would do some operations after the app_run() // returns, so it's best to perform the on_deinit callback _before_ the // runloop is stopped. diff --git a/core/src/ten_runtime/binding/go/interface/ten/addon.go b/core/src/ten_runtime/binding/go/interface/ten/addon.go index 336e7648b..6c16233c3 100644 --- a/core/src/ten_runtime/binding/go/interface/ten/addon.go +++ b/core/src/ten_runtime/binding/go/interface/ten/addon.go @@ -54,8 +54,10 @@ type addon struct { baseTenObject[C.uintptr_t] } +type ExtensionConstructor func(name string) Extension + // NewDefaultExtensionAddon creates a new default extension addon. -func NewDefaultExtensionAddon(constructor func(name string) Extension) Addon { +func NewDefaultExtensionAddon(constructor ExtensionConstructor) Addon { return &DefaultAddon{ onCreateInstanceImpl: func(tenEnv TenEnv, name string, context uintptr) { ext := constructor(name) diff --git a/core/src/ten_runtime/binding/go/interface/ten/addon.h b/core/src/ten_runtime/binding/go/interface/ten/addon.h index 684c6ef67..9fa6239bd 100644 --- a/core/src/ten_runtime/binding/go/interface/ten/addon.h +++ b/core/src/ten_runtime/binding/go/interface/ten/addon.h @@ -14,10 +14,6 @@ void ten_go_addon_unregister(uintptr_t bridge_addr); ten_go_error_t ten_go_addon_register_extension( - const void *addon_name, int addon_name_len, const void *base_dir, - int base_dir_len, uintptr_t go_addon, uintptr_t *bridge_addr); - -ten_go_error_t ten_go_addon_register_extension_v2( const void *addon_name, int addon_name_len, const void *base_dir, int base_dir_len, uintptr_t go_addon, uintptr_t *register_ctx, uintptr_t *bridge_addr); diff --git a/core/src/ten_runtime/binding/go/interface/ten/addon_manager.go b/core/src/ten_runtime/binding/go/interface/ten/addon_manager.go index b3e4f9dd5..6ca335422 100644 --- a/core/src/ten_runtime/binding/go/interface/ten/addon_manager.go +++ b/core/src/ten_runtime/binding/go/interface/ten/addon_manager.go @@ -22,69 +22,19 @@ type AddonManager struct { // Define a registry map to store addon registration functions. // The key is the addonName (string), and the value is a function that takes // a registerCtx (interface{}) and returns an error. - addonRegistry map[string]func(interface{}) error + registry map[string]func(interface{}) error - addonRegistryMutex sync.RWMutex + registryMutex sync.RWMutex } func newAddonManager() *AddonManager { return &AddonManager{ - addonRegistry: make(map[string]func(interface{}) error), + registry: make(map[string]func(interface{}) error), } } // RegisterAddonAsExtension registers the addon as an extension. -func RegisterAddonAsExtension(addonName string, instance Addon) error { - if len(addonName) == 0 { - return newTenError( - ErrnoInvalidArgument, - "addon name is empty", - ) - } - - _, file, _, ok := runtime.Caller(1) - if !ok { - return newTenError(ErrnoGeneric, "Failed to get the caller information") - } - - baseDir := filepath.Dir(file) - - absBaseDir, err := filepath.Abs(baseDir) - if err != nil { - return newTenError( - ErrnoGeneric, - fmt.Sprintf("Failed to get the absolute file path: %v", err), - ) - } - - addonWrapper := &addon{ - Addon: instance, - } - - addonID := newImmutableHandle(addonWrapper) - - var bridge C.uintptr_t - status := C.ten_go_addon_register_extension( - unsafe.Pointer(unsafe.StringData(addonName)), - C.int(len(addonName)), - unsafe.Pointer(unsafe.StringData(absBaseDir)), - C.int(len(absBaseDir)), - cHandle(addonID), - &bridge, - ) - - if err := withCGoError(&status); err != nil { - loadAndDeleteImmutableHandle(addonID) - return err - } - - addonWrapper.cPtr = bridge - - return nil -} - -// RegisterAddonAsExtensionV2 registers the addon as an extension. -func (am *AddonManager) RegisterAddonAsExtensionV2( +func (am *AddonManager) RegisterAddonAsExtension( addonName string, instance Addon, ) error { @@ -111,7 +61,7 @@ func (am *AddonManager) RegisterAddonAsExtensionV2( } // Define the registration function that will be stored in the registry. - registerFunc := func(registerCtx interface{}) error { + registerHandler := func(registerCtx interface{}) error { addonWrapper := &addon{ Addon: instance, } @@ -119,18 +69,23 @@ func (am *AddonManager) RegisterAddonAsExtensionV2( addonID := newImmutableHandle(addonWrapper) var bridge C.uintptr_t - status := C.ten_go_addon_register_extension_v2( + cgo_error := C.ten_go_addon_register_extension( unsafe.Pointer(unsafe.StringData(addonName)), C.int(len(addonName)), unsafe.Pointer(unsafe.StringData(absBaseDir)), C.int(len(absBaseDir)), cHandle(addonID), - // TODO(Wei): Pass `register_ctx` to the actual cgo function. + // In the current use of the TEN framework's GO environment, there + // is no need to pass any `register_ctx` object into the register + // handler of the GO addon. Therefore, for now, simply passing `nil` + // is sufficient. If needed in the future, we can consider what + // information should be passed to the register handler of the GO + // addon. nil, &bridge, ) - if err := withCGoError(&status); err != nil { + if err := withCGoError(&cgo_error); err != nil { loadAndDeleteImmutableHandle(addonID) return err } @@ -141,34 +96,34 @@ func (am *AddonManager) RegisterAddonAsExtensionV2( } // Store the registration function in the registry map. - am.addonRegistryMutex.Lock() - defer am.addonRegistryMutex.Unlock() + am.registryMutex.Lock() + defer am.registryMutex.Unlock() - if _, exists := am.addonRegistry[addonName]; exists { + if _, exists := am.registry[addonName]; exists { return newTenError( ErrnoInvalidArgument, - fmt.Sprintf("addon '%s' is already registered", addonName), + fmt.Sprintf("Addon '%s' is already registered", addonName), ) } - am.addonRegistry[addonName] = registerFunc + am.registry[addonName] = registerHandler return nil } -// LoadAllAddons executes all registered addon registration functions. -func (am *AddonManager) LoadAllAddons(registerCtx interface{}) error { - am.addonRegistryMutex.Lock() - defer am.addonRegistryMutex.Unlock() +// RegisterAllAddons executes all registered addon registration functions. +func (am *AddonManager) RegisterAllAddons(registerCtx interface{}) error { + am.registryMutex.Lock() + defer am.registryMutex.Unlock() - for name, registerFunc := range am.addonRegistry { - if err := registerFunc(registerCtx); err != nil { - return fmt.Errorf("failed to register addon %s: %w", name, err) + for name, registerHandler := range am.registry { + if err := registerHandler(registerCtx); err != nil { + return fmt.Errorf("Failed to register addon %s: %w", name, err) } } - // Clear the addonRegistry to free up memory. - am.addonRegistry = make(map[string]func(interface{}) error) + // Clear the registry to free up memory. + am.registry = make(map[string]func(interface{}) error) return nil } @@ -186,10 +141,10 @@ func (am *AddonManager) unloadAllAddons() error { var defaultAddonManager = newAddonManager() -func RegisterAddonAsExtensionV2(addonName string, instance Addon) error { - return defaultAddonManager.RegisterAddonAsExtensionV2(addonName, instance) +func RegisterAddonAsExtension(addonName string, instance Addon) error { + return defaultAddonManager.RegisterAddonAsExtension(addonName, instance) } -func LoadAllAddons(registerCtx interface{}) error { - return defaultAddonManager.LoadAllAddons(registerCtx) +func RegisterAllAddons(registerCtx interface{}) error { + return defaultAddonManager.RegisterAllAddons(registerCtx) } diff --git a/core/src/ten_runtime/binding/go/interface/ten/app.go b/core/src/ten_runtime/binding/go/interface/ten/app.go index 34b368fa9..c06853830 100644 --- a/core/src/ten_runtime/binding/go/interface/ten/app.go +++ b/core/src/ten_runtime/binding/go/interface/ten/app.go @@ -12,7 +12,6 @@ import "C" import ( "fmt" - "log" "runtime" "unsafe" ) @@ -67,10 +66,6 @@ type App interface { } func (p *app) Run(runInBackground bool) { - if err := LoadAllAddons(nil); err != nil { - log.Fatalf("Failed to load all GO addons: %v", err) - } - C.ten_go_app_run(p.cPtr, C.bool(runInBackground)) } @@ -136,6 +131,14 @@ func tenGoAppOnConfigure( ) } + tenEnvInstance, ok := tenEnvObj.(*tenEnv) + if !ok { + // Should not happen. + panic("Invalid ten object type.") + } + + tenEnvInstance.attachToApp(appObj) + appObj.OnConfigure(tenEnvObj) } diff --git a/core/src/ten_runtime/binding/go/interface/ten/extension.go b/core/src/ten_runtime/binding/go/interface/ten/extension.go index e63e2b5c8..886d14fdc 100644 --- a/core/src/ten_runtime/binding/go/interface/ten/extension.go +++ b/core/src/ten_runtime/binding/go/interface/ten/extension.go @@ -83,7 +83,6 @@ func (p *DefaultExtension) OnAudioFrame( // Via embedding, the `extension` struct "inherits" all methods of Extension. type extension struct { Extension - baseTenObject[C.uintptr_t] } @@ -98,13 +97,13 @@ func WrapExtension( extObjID := newImmutableHandle(extInstance) var bridge C.uintptr_t - status := C.ten_go_extension_create( + cgo_error := C.ten_go_extension_create( cHandle(extObjID), unsafe.Pointer(unsafe.StringData(name)), C.int(len(name)), &bridge, ) - if err := withCGoError(&status); err != nil { + if err := withCGoError(&cgo_error); err != nil { log.Printf("Failed to create extension, %v\n", err) return nil } diff --git a/core/src/ten_runtime/binding/go/interface/ten/extension_tester.go b/core/src/ten_runtime/binding/go/interface/ten/extension_tester.go index c637da79d..d768d96b8 100644 --- a/core/src/ten_runtime/binding/go/interface/ten/extension_tester.go +++ b/core/src/ten_runtime/binding/go/interface/ten/extension_tester.go @@ -67,11 +67,11 @@ func WrapExtensionTester( extTesterObjID := newImmutableHandle(extTesterInstance) var bridge C.uintptr_t - status := C.ten_go_extension_tester_create( + cgo_error := C.ten_go_extension_tester_create( cHandle(extTesterObjID), &bridge, ) - if err := withCGoError(&status); err != nil { + if err := withCGoError(&cgo_error); err != nil { log.Printf("Failed to create extension tester, %v\n", err) return nil } diff --git a/core/src/ten_runtime/binding/go/interface/ten/ten_env.go b/core/src/ten_runtime/binding/go/interface/ten/ten_env.go index 83cb28974..722481f97 100644 --- a/core/src/ten_runtime/binding/go/interface/ten/ten_env.go +++ b/core/src/ten_runtime/binding/go/interface/ten/ten_env.go @@ -102,6 +102,15 @@ func (p *tenEnv) attachToExtension(ext *extension) { p.attachTo = unsafe.Pointer(ext) } +func (p *tenEnv) attachToApp(app *app) { + if p.attachToType != tenAttachToInvalid { + panic("The ten object can only be attached once.") + } + + p.attachToType = tenAttachToApp + p.attachTo = unsafe.Pointer(app) +} + func (p *tenEnv) postSyncJob(payload job) any { // To prevent deadlock, we refuse to post jobs to the pool. So it's // recommended for developers to call async ten apis in goroutines other @@ -301,6 +310,14 @@ func (p *tenEnv) SendAudioFrame( func (p *tenEnv) OnConfigureDone() error { p.LogDebug("OnConfigureDone") + + if p.attachToType == tenAttachToApp { + if err := RegisterAllAddons(nil); err != nil { + p.LogFatal("Failed to register all GO addons: " + err.Error()) + return nil + } + } + C.ten_go_ten_env_on_configure_done(p.cPtr) return nil diff --git a/core/src/ten_runtime/binding/go/native/addon/addon.c b/core/src/ten_runtime/binding/go/native/addon/addon.c index 82801d57b..05b8f81d9 100644 --- a/core/src/ten_runtime/binding/go/native/addon/addon.c +++ b/core/src/ten_runtime/binding/go/native/addon/addon.c @@ -214,7 +214,8 @@ static void ten_go_addon_destroy_instance_helper(ten_addon_t *addon, static ten_go_addon_t *ten_go_addon_register( const void *addon_name, int addon_name_len, const void *base_dir, - int base_dir_len, uintptr_t go_addon, TEN_ADDON_TYPE addon_type) { + int base_dir_len, uintptr_t go_addon, TEN_ADDON_TYPE addon_type, + void *register_ctx) { TEN_ASSERT(addon_name && addon_name_len > 0, "Invalid argument."); ten_go_addon_t *addon_bridge = @@ -239,14 +240,14 @@ static ten_go_addon_t *ten_go_addon_register( ten_addon_init(&addon_bridge->c_addon, ten_go_addon_on_init_helper, ten_go_addon_on_deinit_helper, ten_go_addon_create_extension_async_helper, - ten_go_addon_destroy_instance_helper); + ten_go_addon_destroy_instance_helper, NULL); break; case TEN_ADDON_TYPE_EXTENSION_GROUP: ten_addon_init(&addon_bridge->c_addon, ten_go_addon_on_init_helper, ten_go_addon_on_deinit_helper, ten_go_addon_create_extension_group_async_helper, - ten_go_addon_destroy_instance_helper); + ten_go_addon_destroy_instance_helper, NULL); break; default: @@ -264,7 +265,8 @@ static ten_go_addon_t *ten_go_addon_register( case TEN_ADDON_TYPE_EXTENSION: ten_addon_register_extension( ten_string_get_raw_str(&addon_bridge->addon_name), - ten_string_get_raw_str(&base_dir_str), &addon_bridge->c_addon); + ten_string_get_raw_str(&base_dir_str), &addon_bridge->c_addon, + register_ctx); break; default: @@ -278,24 +280,6 @@ static ten_go_addon_t *ten_go_addon_register( } ten_go_error_t ten_go_addon_register_extension( - const void *addon_name, int addon_name_len, const void *base_dir, - int base_dir_len, uintptr_t go_addon, uintptr_t *bridge_addr) { - TEN_ASSERT(addon_name && addon_name_len > 0 && go_addon && bridge_addr, - "Invalid argument."); - - ten_go_error_t cgo_error; - ten_go_error_init_with_errno(&cgo_error, TEN_ERRNO_OK); - - ten_go_addon_t *addon_bridge = - ten_go_addon_register(addon_name, addon_name_len, base_dir, base_dir_len, - go_addon, TEN_ADDON_TYPE_EXTENSION); - - *bridge_addr = (uintptr_t)addon_bridge; - - return cgo_error; -} - -ten_go_error_t ten_go_addon_register_extension_v2( const void *addon_name, int addon_name_len, const void *base_dir, int base_dir_len, uintptr_t go_addon, uintptr_t *register_ctx, uintptr_t *bridge_addr) { @@ -307,7 +291,7 @@ ten_go_error_t ten_go_addon_register_extension_v2( ten_go_addon_t *addon_bridge = ten_go_addon_register(addon_name, addon_name_len, base_dir, base_dir_len, - go_addon, TEN_ADDON_TYPE_EXTENSION); + go_addon, TEN_ADDON_TYPE_EXTENSION, register_ctx); *bridge_addr = (uintptr_t)addon_bridge; diff --git a/core/src/ten_runtime/binding/go/native/extension/extension.c b/core/src/ten_runtime/binding/go/native/extension/extension.c index 3725e40ac..3c463bcf7 100644 --- a/core/src/ten_runtime/binding/go/native/extension/extension.c +++ b/core/src/ten_runtime/binding/go/native/extension/extension.c @@ -288,7 +288,7 @@ static void proxy_on_audio_frame(ten_extension_t *self, ten_env_t *ten_env, msg_bridge_addr); } -ten_go_extension_t *ten_go_extension_create_internal( +static ten_go_extension_t *ten_go_extension_create_internal( ten_go_handle_t go_extension, const char *name) { TEN_ASSERT(name, "Invalid argument."); @@ -352,13 +352,3 @@ void ten_go_extension_finalize(uintptr_t bridge_addr) { ten_go_bridge_destroy_go_part(&self->bridge); } - -void ten_go_extension_set_go_handle(ten_go_extension_t *self, - ten_go_handle_t go_handle) { - TEN_ASSERT(self && ten_go_extension_check_integrity(self), - "Invalid argument."); - TEN_ASSERT(go_handle > 0, "Invalid argument."); - TEN_ASSERT(self->bridge.go_instance == 0, "Invalid argument."); - - self->bridge.go_instance = go_handle; -} diff --git a/core/src/ten_runtime/binding/python/interface/ten/__init__.py b/core/src/ten_runtime/binding/python/interface/ten/__init__.py index 973629f18..95e3d17f8 100644 --- a/core/src/ten_runtime/binding/python/interface/ten/__init__.py +++ b/core/src/ten_runtime/binding/python/interface/ten/__init__.py @@ -9,10 +9,7 @@ from .async_extension import AsyncExtension from .async_ten_env import AsyncTenEnv from .addon import Addon -from .addon_manager import ( - register_addon_as_extension, - register_addon_as_extension_v2, -) +from .addon_manager import register_addon_as_extension, _AddonManager from .ten_env import TenEnv from .cmd import Cmd from .cmd_result import CmdResult, StatusCode @@ -26,8 +23,8 @@ # ten_runtime_python package. __all__ = [ "Addon", + "_AddonManager", "register_addon_as_extension", - "register_addon_as_extension_v2", "App", "Extension", "AsyncExtension", diff --git a/core/src/ten_runtime/binding/python/interface/ten/addon_manager.py b/core/src/ten_runtime/binding/python/interface/ten/addon_manager.py index 6c00b0a52..98c626626 100644 --- a/core/src/ten_runtime/binding/python/interface/ten/addon_manager.py +++ b/core/src/ten_runtime/binding/python/interface/ten/addon_manager.py @@ -9,12 +9,9 @@ import sys import importlib.util from glob import glob -from typing import Callable, Any, Dict, Type +from typing import Callable, Dict, Type from .addon import Addon -from libten_runtime_python import ( - _register_addon_as_extension, - _register_addon_as_extension_v2, -) +from libten_runtime_python import _register_addon_as_extension class _AddonManager: @@ -23,10 +20,10 @@ class _AddonManager: # TEN runtime. This avoids using `setattr` on the module, which may not be # supported in advanced environments like Cython. The global array method # is simple enough that it should work in all environments. - _registration_registry: Dict[str, Callable[[Any], None]] = {} + _registry: Dict[str, Callable[[object], None]] = {} @classmethod - def load_all_addons(cls, register_ctx: object): + def load_all_addons(cls): base_dir = cls._find_app_base_dir() # Read manifest.json under base_dir. @@ -64,7 +61,6 @@ def load_all_addons(cls, register_ctx: object): f"ten_packages.extension.{module_name}" ), module_name=module_name, - register_ctx=register_ctx, ) else: print(f"Skipping module: {module_name}") @@ -74,12 +70,7 @@ def _load_module( cls, module_full_name: str, module_name: str, - register_ctx: object, ): - """ - Helper method to load a module, check for the special function, - invoke it, and unload the module if the special function is missing. - """ try: spec = importlib.util.find_spec(module_full_name) if spec is None: @@ -88,76 +79,36 @@ def _load_module( _ = importlib.import_module(module_full_name) print(f"Imported module: {module_name}") - # Retrieve the registration function from the global registry - registration_func_name = _AddonManager._get_registration_func_name( - module_name - ) + except ImportError as e: + print(f"Error importing module {module_name}: {e}") - registration_func = _AddonManager._get_registration_func( - module_name - ) + @classmethod + def register_all_addons(cls, register_ctx: object): + registry_keys = list(cls._registry.keys()) - if registration_func: + for register_key in registry_keys: + register_handler = cls._registry.get(register_key) + if register_handler: try: - registration_func(register_ctx) - print(f"Successfully registered addon '{module_name}'") + register_handler(register_ctx) + + print(f"Successfully registered addon '{register_key}'") except Exception as e: print( ( "Error during registration of addon " - f"'{module_name}': {e}" + f"'{register_key}': {e}" ) ) - finally: - # Remove the registration function from the global registry. - if ( - registration_func_name - in _AddonManager._registration_registry - ): - del _AddonManager._registration_registry[ - registration_func_name - ] - print( - ( - "Removed registration function for addon " - f"'{registration_func_name}'" - ) - ) - else: - print(f"No {registration_func_name} found in {module_name}") - - except ImportError as e: - print(f"Error importing module {module_name}: {e}") - @staticmethod - def _get_registration_func_name(addon_name: str) -> str: - return f"____ten_addon_{addon_name}_register____" + cls._registry.clear() @staticmethod - def _get_registration_func(addon_name: str) -> Callable[[Any], None] | None: - return _AddonManager._registration_registry.get( - _AddonManager._get_registration_func_name(addon_name) - ) - - @staticmethod - def _set_registration_func( + def _set_register_handler( addon_name: str, - registration_func: Callable[[Any], None], + register_handler: Callable[[object], None], ) -> None: - registration_func_name = _AddonManager._get_registration_func_name( - addon_name - ) - - print( - ( - f"Injected registration function '{registration_func_name}' " - "into module '{module.__name__}'" - ) - ) - - _AddonManager._registration_registry[registration_func_name] = ( - registration_func - ) + _AddonManager._registry[addon_name] = register_handler @staticmethod def _find_app_base_dir(): @@ -183,37 +134,6 @@ def _find_app_base_dir(): def register_addon_as_extension(name: str, base_dir: str | None = None): - if base_dir is None: - try: - # Attempt to get the caller's file path using sys._getframe() - caller_frame = sys._getframe(1) - base_dir = os.path.dirname(caller_frame.f_code.co_filename) - except (AttributeError, ValueError): - # Fallback in case sys._getframe() is not available or fails. - # Ex: in cython. - base_dir = None - - # If base_dir is not None, convert it to its directory name. - if base_dir is not None: - base_dir = os.path.dirname(base_dir) - - return _register_addon_as_extension(name, base_dir) - - -def register_addon_as_extension_v2(name: str, base_dir: str | None = None): - """ - Decorator to register a class as an addon extension and create a special - registration function required by the Addon loader. - - Args: - name (str): The name of the addon extension. - base_dir (str, optional): The base directory of the addon. Defaults to - None. - - Returns: - Callable: The decorator function. - """ - def decorator(cls: Type[Addon]) -> Type[Addon]: # Resolve base_dir. if base_dir is None: @@ -231,31 +151,20 @@ def decorator(cls: Type[Addon]) -> Type[Addon]: # If base_dir is provided, ensure it's the directory name resolved_base_dir = os.path.dirname(base_dir) - # Define the registration function that will be called by the Addon - # loader. - def registration_func(register_ctx): - """ - Registration function injected into the module to handle addon - registration. - - Args: - register_ctx: An opaque parameter provided by the Addon loader. - """ + # Define the register_handler that will be called by the Addon manager. + def register_handler(register_ctx): # Instantiate the addon class. - instance = cls() + addon_instance = cls() try: - _register_addon_as_extension_v2( - name, resolved_base_dir, instance, register_ctx - ) - print( - f"Called '_register_addon_as_extension' for addon '{name}'" + _register_addon_as_extension( + name, resolved_base_dir, addon_instance, register_ctx ) except Exception as e: print(f"Failed to register addon '{name}': {e}") # Define the registration function name based on the addon name. - _AddonManager._set_registration_func(name, registration_func) + _AddonManager._set_register_handler(name, register_handler) # Return the original class without modification. return cls diff --git a/core/src/ten_runtime/binding/python/interface/ten/async_extension.py b/core/src/ten_runtime/binding/python/interface/ten/async_extension.py index cebbc88c7..7a9cb96aa 100644 --- a/core/src/ten_runtime/binding/python/interface/ten/async_extension.py +++ b/core/src/ten_runtime/binding/python/interface/ten/async_extension.py @@ -19,6 +19,10 @@ class AsyncExtension(_Extension): + def __new__(cls, name: str): + instance = super().__new__(cls, name) + return instance + def __init__(self, name: str) -> None: self._ten_stop_event = asyncio.Event() diff --git a/core/src/ten_runtime/binding/python/interface/ten/extension.py b/core/src/ten_runtime/binding/python/interface/ten/extension.py index 2a6fbe3ed..4cf0afaf0 100644 --- a/core/src/ten_runtime/binding/python/interface/ten/extension.py +++ b/core/src/ten_runtime/binding/python/interface/ten/extension.py @@ -15,6 +15,10 @@ class Extension(_Extension): + def __new__(cls, name: str): + instance = super().__new__(cls, name) + return instance + def __init__(self, name: str) -> None: pass diff --git a/core/src/ten_runtime/binding/python/interface/ten/libten_runtime_python.pyi b/core/src/ten_runtime/binding/python/interface/ten/libten_runtime_python.pyi index 5cfe2ba1c..2398834ee 100644 --- a/core/src/ten_runtime/binding/python/interface/ten/libten_runtime_python.pyi +++ b/core/src/ten_runtime/binding/python/interface/ten/libten_runtime_python.pyi @@ -140,7 +140,8 @@ class _App: ) -> None: ... class _Extension: - def __init__(self, name: str): ... + def __new__(cls, name: str): ... + def __init__(self, name: str) -> None: ... def on_init( self, ten_env: _TenEnv, @@ -179,7 +180,6 @@ class _ExtensionTester: def set_test_mode_single(self, addon_name: str) -> None: ... def run(self) -> None: ... -def _register_addon_as_extension(name: str, base_dir: str | None): ... -def _register_addon_as_extension_v2( +def _register_addon_as_extension( name: str, base_dir: str | None, instance: Addon, register_ctx: object ): ... diff --git a/core/src/ten_runtime/binding/python/interface/ten/ten_env.py b/core/src/ten_runtime/binding/python/interface/ten/ten_env.py index b80a65687..93a943696 100644 --- a/core/src/ten_runtime/binding/python/interface/ten/ten_env.py +++ b/core/src/ten_runtime/binding/python/interface/ten/ten_env.py @@ -42,14 +42,15 @@ def on_configure_done(self) -> None: if self._internal._attach_to == _TenEnvAttachTo.APP: # Load all python addons when app on_configure_done. - # + _AddonManager.load_all_addons() + # In the current use of the TEN framework's Python environment, # there is no need to pass any `register_ctx` object into the - # registration function of the Python addon. Therefore, for now, - # simply passing `None` is sufficient. If needed in the future, we - # can consider what information should be passed to the registration - # function of the Python addon. - _AddonManager.load_all_addons(None) + # register handler of the Python addon. Therefore, for now, simply + # passing `None` is sufficient. If needed in the future, we can + # consider what information should be passed to the register + # handler of the Python addon. + _AddonManager.register_all_addons(None) return self._internal.on_configure_done() def on_init_done(self) -> None: diff --git a/core/src/ten_runtime/binding/python/interface/ten/test.py b/core/src/ten_runtime/binding/python/interface/ten/test.py index 8e1d20b67..79191354c 100644 --- a/core/src/ten_runtime/binding/python/interface/ten/test.py +++ b/core/src/ten_runtime/binding/python/interface/ten/test.py @@ -14,6 +14,7 @@ from .audio_frame import AudioFrame from .video_frame import VideoFrame from .cmd_result import CmdResult +from .addon_manager import _AddonManager class TenEnvTester: ... # type: ignore @@ -53,6 +54,10 @@ class ExtensionTester(_ExtensionTester): def __init__(self): self.addon_base_dirs = [] + @final + def _on_test_app_configure(self, ten_env_tester: TenEnvTester) -> None: + self.on_start(ten_env_tester) + @final def _import_package_from_path(self, addon_base_dir_str: str) -> None: addon_base_dir = Path(addon_base_dir_str).resolve() @@ -60,6 +65,9 @@ def _import_package_from_path(self, addon_base_dir_str: str) -> None: sys.path.insert(0, str(addon_base_dir.parent)) importlib.import_module(addon_base_dir.name) + # =-=-= + _AddonManager.register_all_addons(None) + @final def add_addon_base_dir(self, base_dir: str) -> None: self.addon_base_dirs.append(base_dir) diff --git a/core/src/ten_runtime/binding/python/native/addon/addon.c b/core/src/ten_runtime/binding/python/native/addon/addon.c index b24eb68fe..cbaaf9ee4 100644 --- a/core/src/ten_runtime/binding/python/native/addon/addon.c +++ b/core/src/ten_runtime/binding/python/native/addon/addon.c @@ -95,7 +95,13 @@ static void proxy_on_init(ten_addon_t *addon, ten_env_t *ten_env) { static void proxy_on_deinit(ten_addon_t *addon, ten_env_t *ten_env) { TEN_ASSERT(addon, "Invalid argument."); - TEN_ASSERT(ten_env && ten_env_check_integrity(ten_env, true), + // TODO(Wei): In the context of Python standalone tests, the Python addon is + // registered into the TEN world within the extension tester thread (i.e., the + // Python thread) but is unregistered in the test app thread. It should be + // modified to also perform the Python addon registration within the test + // app's `on_configure_done`. This change will allow the underlying thread + // check to be set to `true`. + TEN_ASSERT(ten_env && ten_env_check_integrity(ten_env, false), "Invalid argument."); // About to call the Python function, so it's necessary to ensure that the GIL @@ -236,7 +242,7 @@ static PyObject *ten_py_addon_create(PyTypeObject *type, py_addon->type = TEN_ADDON_TYPE_EXTENSION; // Now we only support extension. py_addon->c_addon_host = NULL; - ten_addon_init(&py_addon->c_addon, proxy_on_init, proxy_on_deinit, NULL, + ten_addon_init(&py_addon->c_addon, proxy_on_init, proxy_on_deinit, NULL, NULL, NULL); py_addon->c_addon.on_create_instance = proxy_on_create_instance_async; diff --git a/core/src/ten_runtime/binding/python/native/addon/addon_manager.c b/core/src/ten_runtime/binding/python/native/addon/addon_manager.c index 360f4e2dd..b861e9952 100644 --- a/core/src/ten_runtime/binding/python/native/addon/addon_manager.c +++ b/core/src/ten_runtime/binding/python/native/addon/addon_manager.c @@ -9,261 +9,51 @@ #include "include_internal/ten_runtime/binding/python/addon/addon.h" #include "include_internal/ten_runtime/binding/python/common/error.h" #include "ten_runtime/addon/extension/extension.h" -#include "ten_utils/lib/string.h" -#include "ten_utils/macro/mark.h" -static PyObject *ten_py_addon_manager_register_addon_decorator_create( - PyTypeObject *ty, PyObject *args, TEN_UNUSED PyObject *kwds) { - ten_py_addon_manager_register_addon_decorator_t *py_decorator = - (ten_py_addon_manager_register_addon_decorator_t *)ty->tp_alloc(ty, 0); - if (!py_decorator) { - PyObject *result = ten_py_raise_py_memory_error_exception( - "Failed to allocate memory for addon decorator."); - TEN_ASSERT(0, "Failed to allocate memory."); - return result; - } - - ten_string_init(&py_decorator->addon_name); - ten_string_init(&py_decorator->base_dir); - - return (PyObject *)py_decorator; -} - -static PyObject *ten_py_addon_manager_register_addon_decorator_create_v2( - PyTypeObject *ty, PyObject *args, TEN_UNUSED PyObject *kwds) { - ten_py_addon_manager_register_addon_decorator_v2_t *py_decorator = - (ten_py_addon_manager_register_addon_decorator_v2_t *)ty->tp_alloc(ty, 0); - if (!py_decorator) { - PyObject *result = ten_py_raise_py_memory_error_exception( - "Failed to allocate memory for addon decorator."); - TEN_ASSERT(0, "Failed to allocate memory."); - return result; - } - - return (PyObject *)py_decorator; -} - -static int ten_py_addon_manager_register_addon_decorator_init( - PyObject *self, PyObject *args, TEN_UNUSED PyObject *kwds) { - ten_py_addon_manager_register_addon_decorator_t *py_decorator = - (ten_py_addon_manager_register_addon_decorator_t *)self; - - const char *name = NULL; - const char *base_dir = NULL; - - if (!PyArg_ParseTuple(args, "s|z", &name, &base_dir)) { - return -1; - } - - ten_string_set_formatted(&py_decorator->addon_name, "%s", name); - - if (base_dir) { - ten_string_set_formatted(&py_decorator->base_dir, "%s", base_dir); - } - - return 0; -} - -static int ten_py_addon_manager_register_addon_decorator_init_v2( - PyObject *self, PyObject *args, TEN_UNUSED PyObject *kwds) { - return 0; -} - -static void ten_py_addon_manager_register_addon_decorator_destroy( - PyObject *self) { - ten_py_addon_manager_register_addon_decorator_t *py_decorator = - (ten_py_addon_manager_register_addon_decorator_t *)self; - - TEN_ASSERT(py_decorator, "Invalid argument."); - - ten_string_deinit(&py_decorator->addon_name); - ten_string_deinit(&py_decorator->base_dir); - - Py_TYPE(self)->tp_free(self); -} - -static void ten_py_addon_manager_register_addon_decorator_destroy_v2( - PyObject *self) { - ten_py_addon_manager_register_addon_decorator_v2_t *py_decorator = - (ten_py_addon_manager_register_addon_decorator_v2_t *)self; - TEN_ASSERT(py_decorator, "Invalid argument."); - - Py_TYPE(self)->tp_free(self); -} - -static PyObject *ten_py_addon_manager_register_addon_decorator_call( - ten_py_addon_manager_register_addon_decorator_t *self, PyObject *args, - ten_addon_register_extension_func_t register_addon_func) { - PyTypeObject *py_addon_type_object = NULL; - - if (!PyArg_ParseTuple(args, "O", &py_addon_type_object)) { - return ten_py_raise_py_value_error_exception( - "Failed to parse argument when registering addon."); - } - - PyObject *py_addon_object = - PyObject_CallObject((PyObject *)py_addon_type_object, NULL); - if (!py_addon_object || ten_py_check_and_clear_py_error()) { - Py_XDECREF(py_addon_object); // Ensure cleanup if an error occurred. - return ten_py_raise_py_value_error_exception( - "Failed to create Python Addon object."); - } - - // Validate the returned object is an instance of the expected type. - if (!PyObject_TypeCheck(py_addon_object, ten_py_addon_py_type())) { - Py_DECREF(py_addon_object); - return ten_py_raise_py_type_error_exception( - "Object is not an instance of Python Addon."); - } - - // The memory of this c_addon will persist until the Python VM terminates. - // Since the main of the TEN Python APP is Python, and the TEN world is just a - // C FFI extension of the Python world, structurally, the Python VM will not - // terminate until the entire TEN world has concluded. Therefore, this c_addon - // existing within the Python VM memory space can be safely used within the - // TEN world. - ten_py_addon_t *py_addon = (ten_py_addon_t *)py_addon_object; - ten_addon_host_t *c_addon_host = register_addon_func( - ten_string_get_raw_str(&self->addon_name), - ten_string_get_raw_str(&self->base_dir), &py_addon->c_addon); - TEN_ASSERT(c_addon_host, "Should not happen."); - - py_addon->c_addon_host = c_addon_host; - - return py_addon_object; -} - -static PyObject * -ten_py_addon_manager_register_addon_as_extension_decorator_call( - PyObject *self, PyObject *args, TEN_UNUSED PyObject *kwds) { - return ten_py_addon_manager_register_addon_decorator_call( - (ten_py_addon_manager_register_addon_decorator_t *)self, args, - ten_addon_register_extension); -} - -static PyObject *ten_py_addon_manager_register_addon_decorator_call_v2( - ten_py_addon_manager_register_addon_decorator_v2_t *self, PyObject *args, - ten_addon_register_extension_v2_func_t register_addon_func) { +PyObject *ten_py_addon_manager_register_addon_as_extension(PyObject *self, + PyObject *args) { const char *name = NULL; - const char *base_dir = NULL; + PyObject *base_dir = NULL; PyObject *py_addon_object = NULL; PyObject *py_register_ctx = NULL; - if (!PyArg_ParseTuple(args, "ssOO", &name, &base_dir, &py_addon_object, + if (!PyArg_ParseTuple(args, "sOOO", &name, &base_dir, &py_addon_object, &py_register_ctx)) { return ten_py_raise_py_value_error_exception( "Failed to parse arguments when registering addon."); } + if (base_dir != Py_None && !PyUnicode_Check(base_dir)) { + return ten_py_raise_py_type_error_exception( + "base_dir must be a string or None."); + } + if (!PyObject_TypeCheck(py_addon_object, ten_py_addon_py_type())) { return ten_py_raise_py_type_error_exception( "Object is not an instance of Python Addon."); } + const char *base_dir_str = NULL; + if (base_dir != Py_None) { + base_dir_str = PyUnicode_AsUTF8(base_dir); + if (!base_dir_str) { + return ten_py_raise_py_value_error_exception( + "Failed to convert base_dir to UTF-8 string."); + } + } + ten_py_addon_t *py_addon = (ten_py_addon_t *)py_addon_object; - ten_addon_host_t *c_addon_host = - register_addon_func(name, base_dir, &py_addon->c_addon, NULL); + ten_addon_host_t *c_addon_host = ten_addon_register_extension( + name, base_dir_str, &py_addon->c_addon, /* register_ctx= */ NULL); if (!c_addon_host) { return ten_py_raise_py_value_error_exception( - "Failed to register addon in register_addon_func."); + "Failed to register addon in ten_addon_register_extension."); } py_addon->c_addon_host = c_addon_host; Py_INCREF(py_addon_object); // Ensure the object is kept alive. - return py_addon_object; -} - -static PyObject * -ten_py_addon_manager_register_addon_as_extension_decorator_call_v2( - PyObject *self, PyObject *args, TEN_UNUSED PyObject *kwds) { - return ten_py_addon_manager_register_addon_decorator_call_v2( - (ten_py_addon_manager_register_addon_decorator_v2_t *)self, args, - ten_addon_register_extension_v2); -} - -static PyTypeObject * -ten_py_addon_manager_register_addon_as_extension_decorator_py_type(void) { - static PyMethodDef decorator_methods[] = { - {NULL, NULL, 0, NULL}, - }; - - static PyTypeObject py_type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = - "libten_runtime_python.register_addon_as_extension", - .tp_doc = PyDoc_STR("register_addon_as_extension"), - .tp_basicsize = sizeof(ten_py_addon_manager_register_addon_decorator_t), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_new = ten_py_addon_manager_register_addon_decorator_create, - .tp_init = ten_py_addon_manager_register_addon_decorator_init, - .tp_dealloc = ten_py_addon_manager_register_addon_decorator_destroy, - .tp_call = - ten_py_addon_manager_register_addon_as_extension_decorator_call, - .tp_getset = NULL, - .tp_methods = decorator_methods, - }; - - return &py_type; -} - -static PyTypeObject * -ten_py_addon_manager_register_addon_as_extension_decorator_py_type_v2(void) { - static PyMethodDef decorator_methods[] = { - {NULL, NULL, 0, NULL}, - }; - - static PyTypeObject py_type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = - "libten_runtime_python.register_addon_as_extension_v2", - .tp_doc = PyDoc_STR("register_addon_as_extension_v2"), - .tp_basicsize = sizeof(ten_py_addon_manager_register_addon_decorator_t), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_new = ten_py_addon_manager_register_addon_decorator_create_v2, - .tp_init = ten_py_addon_manager_register_addon_decorator_init_v2, - .tp_dealloc = ten_py_addon_manager_register_addon_decorator_destroy_v2, - .tp_call = - ten_py_addon_manager_register_addon_as_extension_decorator_call_v2, - .tp_getset = NULL, - .tp_methods = decorator_methods, - }; - - return &py_type; -} - -static bool ten_py_addon_manager_register_addon_decorator_module_init( - PyObject *module, PyTypeObject *py_type, const char *name) { - if (PyType_Ready(py_type) < 0) { - ten_py_raise_py_system_error_exception( - "Failed to ready Python type for decorator."); - TEN_ASSERT(0, "Should not happen."); - return false; - } - - if (PyModule_AddObjectRef(module, name, (PyObject *)py_type) < 0) { - ten_py_raise_py_import_error_exception( - "Failed to add Python decorator type to module."); - return false; - } - - return true; -} - -bool ten_py_addon_manager_register_addon_as_extension_decorator_init_for_module( - PyObject *module) { - return ten_py_addon_manager_register_addon_decorator_module_init( - module, - ten_py_addon_manager_register_addon_as_extension_decorator_py_type(), - "_register_addon_as_extension"); -} - -bool ten_py_addon_manager_register_addon_as_extension_decorator_init_for_module_v2( - PyObject *module) { - return ten_py_addon_manager_register_addon_decorator_module_init( - module, - ten_py_addon_manager_register_addon_as_extension_decorator_py_type_v2(), - "_register_addon_as_extension_v2"); + Py_RETURN_NONE; } diff --git a/core/src/ten_runtime/binding/python/native/extension/extension.c b/core/src/ten_runtime/binding/python/native/extension/extension.c index 62f28e4a5..794dcd215 100644 --- a/core/src/ten_runtime/binding/python/native/extension/extension.c +++ b/core/src/ten_runtime/binding/python/native/extension/extension.c @@ -429,7 +429,7 @@ PyTypeObject *ten_py_extension_py_type(void) { static PyTypeObject py_extension_type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = - "libten_runtime_python.Extension", + "libten_runtime_python._Extension", .tp_doc = PyDoc_STR("Extension"), .tp_basicsize = sizeof(ten_py_extension_t), .tp_itemsize = 0, diff --git a/core/src/ten_runtime/binding/python/native/init.c b/core/src/ten_runtime/binding/python/native/init.c index edf64ff96..a9d2fa2c8 100644 --- a/core/src/ten_runtime/binding/python/native/init.c +++ b/core/src/ten_runtime/binding/python/native/init.c @@ -36,21 +36,25 @@ // the TEN Memory Sanitizer. static PyModuleDef *ten_py_runtime_module(void) { - static struct PyMethodDef empty_methods[] = {{NULL, NULL, 0, NULL}}; + static struct PyMethodDef module_methods[] = { + {"_register_addon_as_extension", + ten_py_addon_manager_register_addon_as_extension, METH_VARARGS, + "Register an addon as an extension"}, + {NULL, NULL, 0, NULL}}; - static struct PyModuleDef ten_module_def = { + static struct PyModuleDef module_def = { PyModuleDef_HEAD_INIT, "libten_runtime_python", NULL, -1, - empty_methods, + module_methods, NULL, 0, 0, 0, }; - return &ten_module_def; + return &module_def; } PyMODINIT_FUNC PyInit_libten_runtime_python(void) { @@ -65,18 +69,6 @@ PyMODINIT_FUNC PyInit_libten_runtime_python(void) { return NULL; } - if (!ten_py_addon_manager_register_addon_as_extension_decorator_init_for_module( - module)) { - Py_DECREF(module); - return NULL; - } - - if (!ten_py_addon_manager_register_addon_as_extension_decorator_init_for_module_v2( - module)) { - Py_DECREF(module); - return NULL; - } - if (!ten_py_app_init_for_module(module)) { Py_DECREF(module); return NULL; diff --git a/core/src/ten_runtime/engine/on_xxx.c b/core/src/ten_runtime/engine/on_xxx.c index 77fc0cc7a..68c4bf125 100644 --- a/core/src/ten_runtime/engine/on_xxx.c +++ b/core/src/ten_runtime/engine/on_xxx.c @@ -258,10 +258,9 @@ void ten_engine_thread_on_addon_create_protocol_done(void *self, void *arg) { ten_addon_context_t *addon_context = info->addon_context; TEN_ASSERT(addon_context, "Should not happen."); - if (addon_context->addon_on_create_instance_async_cb) { - addon_context->addon_on_create_instance_async_cb( - engine->ten_env, protocol, - addon_context->addon_on_create_instance_async_cb_data); + if (addon_context->create_instance_done_cb) { + addon_context->create_instance_done_cb( + engine->ten_env, protocol, addon_context->create_instance_done_cb_data); } ten_addon_context_destroy(addon_context); diff --git a/core/src/ten_runtime/extension_context/extension_context.c b/core/src/ten_runtime/extension_context/extension_context.c index ee4a79d00..9aabc7acd 100644 --- a/core/src/ten_runtime/extension_context/extension_context.c +++ b/core/src/ten_runtime/extension_context/extension_context.c @@ -572,7 +572,7 @@ bool ten_extension_context_start_extension_group( &extension_group_info->extension_group_addon_name), ten_string_get_raw_str( &extension_group_info->loc.extension_group_name), - (ten_env_addon_on_create_instance_async_cb_t) + (ten_env_addon_create_instance_done_cb_t) ten_extension_context_create_extension_group_done, NULL); diff --git a/core/src/ten_runtime/extension_context/ten_env/on_xxx.c b/core/src/ten_runtime/extension_context/ten_env/on_xxx.c index 0015d1d08..f710d1809 100644 --- a/core/src/ten_runtime/extension_context/ten_env/on_xxx.c +++ b/core/src/ten_runtime/extension_context/ten_env/on_xxx.c @@ -10,8 +10,8 @@ #include "include_internal/ten_runtime/engine/engine.h" #include "include_internal/ten_runtime/extension_group/extension_group.h" #include "include_internal/ten_runtime/ten_env/ten_env.h" -#include "ten_utils/macro/check.h" #include "ten_runtime/ten_env/ten_env.h" +#include "ten_utils/macro/check.h" #include "ten_utils/macro/mark.h" #include "ten_utils/macro/memory.h" @@ -45,9 +45,9 @@ void ten_extension_context_on_addon_create_extension_group_done( // This happens on the engine thread, so it's thread safe. - if (addon_context->addon_on_create_instance_async_cb) { - addon_context->addon_on_create_instance_async_cb( - self, instance, addon_context->addon_on_create_instance_async_cb_data); + if (addon_context->create_instance_done_cb) { + addon_context->create_instance_done_cb( + self, instance, addon_context->create_instance_done_cb_data); } if (addon_context) { @@ -67,9 +67,9 @@ void ten_extension_context_on_addon_destroy_extension_group_done( TEN_ASSERT(engine && ten_engine_check_integrity(engine, true), "Should not happen."); - if (addon_context->addon_on_destroy_instance_async_cb) { - addon_context->addon_on_destroy_instance_async_cb( - self, addon_context->addon_on_destroy_instance_async_cb_data); + if (addon_context->destroy_instance_done_cb) { + addon_context->destroy_instance_done_cb( + self, addon_context->destroy_instance_done_cb_data); } ten_addon_context_destroy(addon_context); diff --git a/core/src/ten_runtime/extension_group/builtin/builtin_extension_group.c b/core/src/ten_runtime/extension_group/builtin/builtin_extension_group.c index 86b696993..52c9abf6b 100644 --- a/core/src/ten_runtime/extension_group/builtin/builtin_extension_group.c +++ b/core/src/ten_runtime/extension_group/builtin/builtin_extension_group.c @@ -124,8 +124,7 @@ static void ten_builtin_extension_group_on_create_extensions( bool res = ten_addon_create_extension( ten_env, ten_string_get_raw_str(extension_addon_name), ten_string_get_raw_str(extension_instance_name), - (ten_env_addon_on_create_instance_async_cb_t) - on_addon_create_instance_done, + (ten_env_addon_create_instance_done_cb_t)on_addon_create_instance_done, result, NULL); if (!res) { @@ -212,11 +211,12 @@ static ten_addon_t builtin_extension_group_addon = { ten_builtin_extension_group_addon_create_instance, ten_builtin_extension_group_addon_destroy_instance, NULL, + NULL, }; void ten_builtin_extension_group_addon_register(void) { ten_addon_register_extension_group(TEN_STR_DEFAULT_EXTENSION_GROUP, NULL, - &builtin_extension_group_addon); + &builtin_extension_group_addon, NULL); } void ten_builtin_extension_group_addon_unregister(void) { diff --git a/core/src/ten_runtime/extension_group/ten_env/on_xxx.c b/core/src/ten_runtime/extension_group/ten_env/on_xxx.c index 9127295f1..507c46b26 100644 --- a/core/src/ten_runtime/extension_group/ten_env/on_xxx.c +++ b/core/src/ten_runtime/extension_group/ten_env/on_xxx.c @@ -201,9 +201,9 @@ void ten_extension_group_on_addon_create_extension_done( // This happens on the extension thread, so it's thread safe. - if (addon_context->addon_on_create_instance_async_cb) { - addon_context->addon_on_create_instance_async_cb( - self, instance, addon_context->addon_on_create_instance_async_cb_data); + if (addon_context->create_instance_done_cb) { + addon_context->create_instance_done_cb( + self, instance, addon_context->create_instance_done_cb_data); } if (addon_context) { @@ -226,9 +226,9 @@ void ten_extension_group_on_addon_destroy_extension_done( ten_extension_group_check_integrity(extension_group, true), "Should not happen."); - if (addon_context->addon_on_destroy_instance_async_cb) { - addon_context->addon_on_destroy_instance_async_cb( - self, addon_context->addon_on_destroy_instance_async_cb_data); + if (addon_context->destroy_instance_done_cb) { + addon_context->destroy_instance_done_cb( + self, addon_context->destroy_instance_done_cb_data); } ten_addon_context_destroy(addon_context); diff --git a/core/src/ten_runtime/test/test_extension.c b/core/src/ten_runtime/test/test_extension.c index 48afac418..96cd8f25d 100644 --- a/core/src/ten_runtime/test/test_extension.c +++ b/core/src/ten_runtime/test/test_extension.c @@ -282,11 +282,12 @@ static ten_addon_t ten_builtin_test_extension_addon = { test_extension_addon_create_instance, test_extension_addon_destroy_instance, NULL, + NULL, }; void ten_builtin_test_extension_addon_register(void) { ten_addon_register_extension(TEN_STR_TEN_TEST_EXTENSION, NULL, - &ten_builtin_test_extension_addon); + &ten_builtin_test_extension_addon, NULL); } void ten_builtin_test_extension_addon_unregister(void) { diff --git a/core/src/ten_utils/lib/sys/general/string.c b/core/src/ten_utils/lib/sys/general/string.c index 64245b5e1..bc3d70990 100644 --- a/core/src/ten_utils/lib/sys/general/string.c +++ b/core/src/ten_utils/lib/sys/general/string.c @@ -258,8 +258,6 @@ void ten_string_clear(ten_string_t *self) { self->buf[0] = 0; } -#define MAX_BUFFER_SIZE (10 * 1024 * 1024) // 10 M - void ten_string_reserve(ten_string_t *self, size_t extra) { TEN_ASSERT(self && ten_string_check_integrity(self), "Invalid argument."); @@ -275,7 +273,7 @@ void ten_string_reserve(ten_string_t *self, size_t extra) { } if (self->buf_size < required_size) { - size_t new_size = self->buf_size * 2; + size_t new_size = self->buf_size * BUFFER_ENLARGE_RATIO; if (new_size < required_size) { new_size = required_size; } diff --git a/core/src/ten_utils/lib/sys/posix/env.c b/core/src/ten_utils/lib/sys/posix/env.c new file mode 100644 index 000000000..5cfc2f4d4 --- /dev/null +++ b/core/src/ten_utils/lib/sys/posix/env.c @@ -0,0 +1,17 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "include_internal/ten_utils/lib/env.h" + +#include + +bool ten_env_set(const char *name, const char *value) { + if (setenv(name, value, 1) != 0) { + return false; + } + + return true; +} diff --git a/core/src/ten_utils/lib/sys/win/env.c b/core/src/ten_utils/lib/sys/win/env.c new file mode 100644 index 000000000..79ee3b106 --- /dev/null +++ b/core/src/ten_utils/lib/sys/win/env.c @@ -0,0 +1,17 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "include_internal/ten_utils/lib/env.h" + +#include + +bool ten_env_set(const char *name, const char *value) { + if (_putenv_s(name, value) != 0) { + return false; + } + + return true; +} diff --git a/core/src/ten_utils/sanitizer/memory_check.c b/core/src/ten_utils/sanitizer/memory_check.c index 139423689..b6e03ff68 100644 --- a/core/src/ten_utils/sanitizer/memory_check.c +++ b/core/src/ten_utils/sanitizer/memory_check.c @@ -260,7 +260,7 @@ void ten_sanitizer_memory_record_dump(void) { TEN_ASSERT(!rc, "Failed to lock."); if (g_memory_records.total_size) { - (void)fprintf(stderr, "Memory allocation summary(%zu bytes):", + (void)fprintf(stderr, "Memory allocation summary(%zu bytes):\n", g_memory_records.total_size); } @@ -280,7 +280,7 @@ void ten_sanitizer_memory_record_dump(void) { ten_sanitizer_memory_record_t *info = ten_ptr_listnode_get(iter.node); - (void)fprintf(stderr, "\t#%zu %p(%zu bytes) in %s %s:%d", idx, info->addr, + (void)fprintf(stderr, "\t#%zu %p(%zu bytes) in %s %s:%d\n", idx, info->addr, info->size, info->func_name, info->file_name, info->lineno); idx++; @@ -304,7 +304,7 @@ void ten_sanitizer_memory_record_dump(void) { TEN_ASSERT(!rc, "Failed to unlock."); if (total_size) { - (void)fprintf(stderr, "Memory leak with %zu bytes.", total_size); + (void)fprintf(stderr, "Memory leak with %zu bytes.\n", total_size); #if defined(TEN_USE_ASAN) __lsan_enable(); diff --git a/packages/core_extensions/py_init_extension_cpp/src/main.cc b/packages/core_extensions/py_init_extension_cpp/src/main.cc index 2d06d8dc6..07d92f5ca 100644 --- a/packages/core_extensions/py_init_extension_cpp/src/main.cc +++ b/packages/core_extensions/py_init_extension_cpp/src/main.cc @@ -6,7 +6,6 @@ #include #include -#include "include_internal/ten_runtime/addon/extension/extension.h" #include "include_internal/ten_runtime/app/metadata.h" #include "include_internal/ten_runtime/binding/cpp/detail/ten_env_internal_accessor.h" #include "include_internal/ten_runtime/binding/python/common.h" @@ -14,6 +13,7 @@ #include "include_internal/ten_runtime/common/constant_str.h" #include "include_internal/ten_runtime/metadata/manifest.h" #include "include_internal/ten_runtime/ten_env/ten_env.h" +#include "ten_runtime/addon/addon_manager.h" #include "ten_runtime/binding/cpp/detail/ten_env.h" #include "ten_runtime/binding/cpp/ten.h" #include "ten_utils/container/list_str.h" @@ -277,6 +277,8 @@ class py_init_addon_t : public ten::addon_t { load_all_python_modules(ten_env, addon_extensions_path, &extension_dependencies); + register_all_addons(); + ten_list_clear(&extension_dependencies); ten_string_destroy(addon_extensions_path); @@ -404,6 +406,12 @@ class py_init_addon_t : public ten::addon_t { } } + static void register_all_addons() { + ten_py_run_simple_string( + "from ten import _AddonManager\n" + "_AddonManager.register_all_addons(None)\n"); + } + static void load_python_lib() { ten_string_t *python_lib_path = ten_string_create_formatted("libten_runtime_python.so"); @@ -420,21 +428,24 @@ class py_init_addon_t : public ten::addon_t { } }; -static ten::addon_t *g_py_init_default_extension_addon = nullptr; - -extern "C" void ____ten_addon_py_init_extension_cpp_register____( +static void ____ten_addon_py_init_extension_cpp_register_handler____( void *register_ctx) { - g_py_init_default_extension_addon = new py_init_addon_t(); - ten_addon_register_extension_v2( - "py_init_extension_cpp", nullptr, - g_py_init_default_extension_addon->get_c_addon(), register_ctx); + auto *addon_instance = new py_init_addon_t(); + ten_string_t *base_dir = + ten_path_get_module_path(/* NOLINTNEXTLINE */ + (void *) + ____ten_addon_py_init_extension_cpp_register_handler____); + ten_addon_register_extension("py_init_extension_cpp", + ten_string_get_raw_str(base_dir), + addon_instance->get_c_addon(), register_ctx); + ten_string_destroy(base_dir); } -TEN_DESTRUCTOR(____dtor_ten_declare_py_init_extension_addon____) { - if (g_py_init_default_extension_addon != nullptr) { - ten_addon_unregister_extension("py_init_extension_cpp"); - delete g_py_init_default_extension_addon; - } +TEN_CONSTRUCTOR(____ten_addon_py_init_extension_cpp_registrar____) { + ten_addon_manager_t *manager = ten_addon_manager_get_instance(); + ten_addon_manager_add_addon( + manager, "py_init_extension_cpp", + ____ten_addon_py_init_extension_cpp_register_handler____); } } // namespace default_extension diff --git a/packages/core_protocols/msgpack/protocol.c b/packages/core_protocols/msgpack/protocol.c index ba1d17092..f43f79e53 100644 --- a/packages/core_protocols/msgpack/protocol.c +++ b/packages/core_protocols/msgpack/protocol.c @@ -115,6 +115,7 @@ static ten_addon_t msgpack_protocol_factory = { ten_protocol_msgpack_on_create_instance, ten_protocol_msgpack_on_destroy_instance, NULL, + NULL, }; TEN_REGISTER_ADDON_AS_PROTOCOL(msgpack, &msgpack_protocol_factory); diff --git a/packages/example_extensions/simple_http_server_go/endpoint/endpoint.go b/packages/example_extensions/simple_http_server_go/endpoint/endpoint.go index 15423274e..add044e21 100644 --- a/packages/example_extensions/simple_http_server_go/endpoint/endpoint.go +++ b/packages/example_extensions/simple_http_server_go/endpoint/endpoint.go @@ -34,21 +34,21 @@ func (s *Endpoint) defaultHandler( case "/health": writer.WriteHeader(http.StatusOK) default: - statusChan := make(chan ten.CmdResult, 1) + cmdResultChan := make(chan ten.CmdResult, 1) cmd, _ := ten.NewCmd("demo") s.tenEnv.SendCmd( cmd, func(tenEnv ten.TenEnv, cmdResult ten.CmdResult, e error) { - statusChan <- cmdResult + cmdResultChan <- cmdResult }, ) select { - case status := <-statusChan: + case cmdResult := <-cmdResultChan: writer.WriteHeader(http.StatusOK) - detail, _ := status.GetPropertyString("detail") + detail, _ := cmdResult.GetPropertyString("detail") writer.Write([]byte(detail)) } } diff --git a/tests/common/client/tcp.c b/tests/common/client/tcp.c index 96cf48bce..fb11b0541 100644 --- a/tests/common/client/tcp.c +++ b/tests/common/client/tcp.c @@ -135,8 +135,8 @@ bool ten_test_tcp_client_init( ten_socket_destroy(self->socket); self->socket = NULL; - // Wait 10 ms between retry. - ten_sleep(10); + // Wait 100 ms between retry. + ten_sleep(100); } if (!self->socket) { diff --git a/tests/common/client/tcp.h b/tests/common/client/tcp.h index aef90ca4d..86865dd0a 100644 --- a/tests/common/client/tcp.h +++ b/tests/common/client/tcp.h @@ -9,11 +9,9 @@ #include "ten_runtime/ten_config.h" #include "ten_utils/io/socket.h" -#include "ten_utils/lib/error.h" -#include "ten_utils/lib/json.h" #include "ten_utils/lib/smart_ptr.h" -#define TCP_CLIENT_CONNECT_RETRY_TIMES 100 +#define TCP_CLIENT_CONNECT_RETRY_TIMES 200 typedef struct ten_test_tcp_client_t ten_test_tcp_client_t; diff --git a/tests/ten_runtime/integration/go/access_property_go/access_property_go_app/ten_packages/extension/extension_a/extension.go b/tests/ten_runtime/integration/go/access_property_go/access_property_go_app/ten_packages/extension/extension_a/extension.go index 8d6a44eba..ec317a82e 100644 --- a/tests/ten_runtime/integration/go/access_property_go/access_property_go_app/ten_packages/extension/extension_a/extension.go +++ b/tests/ten_runtime/integration/go/access_property_go/access_property_go_app/ten_packages/extension/extension_a/extension.go @@ -217,7 +217,7 @@ func (p *aExtension) OnCmd( func init() { // Register addon - err := ten.RegisterAddonAsExtensionV2( + err := ten.RegisterAddonAsExtension( "extension_a", ten.NewDefaultExtensionAddon(newAExtension), ) diff --git a/tests/ten_runtime/integration/go/prepare_to_stop_go/prepare_to_stop_go_app/ten_packages/extension/extension_c/extension.go b/tests/ten_runtime/integration/go/prepare_to_stop_go/prepare_to_stop_go_app/ten_packages/extension/extension_c/extension.go index 2e665d0b1..3545a6c4c 100644 --- a/tests/ten_runtime/integration/go/prepare_to_stop_go/prepare_to_stop_go_app/ten_packages/extension/extension_c/extension.go +++ b/tests/ten_runtime/integration/go/prepare_to_stop_go/prepare_to_stop_go_app/ten_packages/extension/extension_c/extension.go @@ -76,7 +76,10 @@ func init() { fmt.Println("call init") // Register addon - err := ten.RegisterAddonAsExtension("extension_c", ten.NewDefaultExtensionAddon(NewCExtension)) + err := ten.RegisterAddonAsExtension( + "extension_c", + ten.NewDefaultExtensionAddon(NewCExtension), + ) if err != nil { fmt.Println("register addon failed", err) } diff --git a/tests/ten_runtime/integration/go/three_extension_cmd_go/three_extension_cmd_go_app/ten_packages/extension/extension_a/extension.go b/tests/ten_runtime/integration/go/three_extension_cmd_go/three_extension_cmd_go_app/ten_packages/extension/extension_a/extension.go index d7dd6a098..c2b99d0d7 100644 --- a/tests/ten_runtime/integration/go/three_extension_cmd_go/three_extension_cmd_go_app/ten_packages/extension/extension_a/extension.go +++ b/tests/ten_runtime/integration/go/three_extension_cmd_go/three_extension_cmd_go_app/ten_packages/extension/extension_a/extension.go @@ -30,12 +30,11 @@ func (p *aExtension) OnCmd( ) { go func() { cmdName, _ := cmd.GetName() - fmt.Println( - "aExtension receive command: ", - cmdName, + tenEnv.LogInfo( + "aExtension receive command: " + cmdName, ) if cmd.GetType() != ten.MsgTypeCmdResult { - fmt.Println(p.name, "onCmd: ", cmdName) + tenEnv.LogInfo("onCmd: " + cmdName) } if cmdName == "A" { @@ -52,11 +51,11 @@ func (p *aExtension) OnCmd( panic("Should not happen.") } statusCode, _ := cmdResult.GetStatusCode() - fmt.Println( - "statusCode:", - statusCode, - " detail: ", - detail, + tenEnv.LogInfo( + "statusCode:" + fmt.Sprintf( + "%d", + statusCode, + ) + " detail: " + detail, ) cmdResult2, _ := ten.NewCmdResult(ten.StatusCodeOk) diff --git a/tests/ten_runtime/integration/go/three_extension_cmd_go/three_extension_cmd_go_app/ten_packages/extension/extension_b/extension.go b/tests/ten_runtime/integration/go/three_extension_cmd_go/three_extension_cmd_go_app/ten_packages/extension/extension_b/extension.go index 7ae875f11..69d0a4592 100644 --- a/tests/ten_runtime/integration/go/three_extension_cmd_go/three_extension_cmd_go_app/ten_packages/extension/extension_b/extension.go +++ b/tests/ten_runtime/integration/go/three_extension_cmd_go/three_extension_cmd_go_app/ten_packages/extension/extension_b/extension.go @@ -54,11 +54,11 @@ func (p *bExtension) OnCmd( panic("Should not happen.") } statusCode, _ := cmdResult.GetStatusCode() - fmt.Println( - "statusCode:", - statusCode, - " detail: ", - detail, + tenEnv.LogInfo( + "statusCode:" + fmt.Sprintf( + "%d", + statusCode, + ) + " detail: " + detail, ) cmdResult2, _ := ten.NewCmdResult(ten.StatusCodeOk) diff --git a/tests/ten_runtime/integration/python/async_extension_basic_python/async_extension_basic_python_app/ten_packages/extension/default_async_extension_python/extension.py b/tests/ten_runtime/integration/python/async_extension_basic_python/async_extension_basic_python_app/ten_packages/extension/default_async_extension_python/extension.py index d6741075d..39c07d975 100644 --- a/tests/ten_runtime/integration/python/async_extension_basic_python/async_extension_basic_python_app/ten_packages/extension/default_async_extension_python/extension.py +++ b/tests/ten_runtime/integration/python/async_extension_basic_python/async_extension_basic_python_app/ten_packages/extension/default_async_extension_python/extension.py @@ -13,10 +13,6 @@ class DefaultAsyncExtension(AsyncExtension): - def __init__(self, name: str) -> None: - super().__init__(name) - self.name = name - async def on_configure(self, ten_env: AsyncTenEnv) -> None: await asyncio.sleep(0.5) diff --git a/tests/ten_runtime/integration/python/cpp_app_multi_process_python/cpp_app_multi_process_python_app_source/ten_packages/extension/default_extension_python/extension.py b/tests/ten_runtime/integration/python/cpp_app_multi_process_python/cpp_app_multi_process_python_app_source/ten_packages/extension/default_extension_python/extension.py index 3fa2407e0..1de457a9f 100644 --- a/tests/ten_runtime/integration/python/cpp_app_multi_process_python/cpp_app_multi_process_python_app_source/ten_packages/extension/default_extension_python/extension.py +++ b/tests/ten_runtime/integration/python/cpp_app_multi_process_python/cpp_app_multi_process_python_app_source/ten_packages/extension/default_extension_python/extension.py @@ -20,6 +20,7 @@ class DefaultExtension(Extension): def __init__(self, name: str) -> None: super().__init__(name) self.name = name + mp.set_start_method("spawn", force=True) print("start method", mp.get_start_method()) self.ready = mp.Value("b", False) @@ -29,7 +30,6 @@ def on_configure(self, ten_env: TenEnv) -> None: assert self.name == "default_extension_python" ten_env.init_property_from_json('{"testKey": "testValue"}') - ten_env.on_configure_done() def on_start(self, ten_env: TenEnv) -> None: diff --git a/tests/ten_runtime/integration/python/large_json_python/large_json_python_app/ten_packages/extension/default_extension_python/extension.py b/tests/ten_runtime/integration/python/large_json_python/large_json_python_app/ten_packages/extension/default_extension_python/extension.py index fc9c70250..d809a62ab 100644 --- a/tests/ten_runtime/integration/python/large_json_python/large_json_python_app/ten_packages/extension/default_extension_python/extension.py +++ b/tests/ten_runtime/integration/python/large_json_python/large_json_python_app/ten_packages/extension/default_extension_python/extension.py @@ -22,14 +22,14 @@ def __init__(self, name: str) -> None: self.name = name def on_configure(self, ten_env: TenEnv) -> None: - print("DefaultExtension on_init, name", self.name) + ten_env.log_info("on_init") assert self.name == "default_extension_python" ten_env.init_property_from_json('{"testKey": "testValue"}') ten_env.on_configure_done() def __routine(self, ten_env: TenEnv): - start = self.queue.get() + self.queue.get() i = 0 for _ in range(0, 10000): @@ -42,7 +42,7 @@ def __routine(self, ten_env: TenEnv): assert throw_exception == True - stop = self.queue.get() + self.queue.get() print("DefaultExtension __test_thread_routine done") diff --git a/tests/ten_runtime/integration/python/multi_process_python/multi_process_python_app/ten_packages/extension/default_extension_python/extension.py b/tests/ten_runtime/integration/python/multi_process_python/multi_process_python_app/ten_packages/extension/default_extension_python/extension.py index ce435b9b4..bb7e21b08 100644 --- a/tests/ten_runtime/integration/python/multi_process_python/multi_process_python_app/ten_packages/extension/default_extension_python/extension.py +++ b/tests/ten_runtime/integration/python/multi_process_python/multi_process_python_app/ten_packages/extension/default_extension_python/extension.py @@ -16,58 +16,53 @@ class DefaultExtension(Extension): - def __init__(self, name: str) -> None: - super().__init__(name) - self.name = name - def on_configure(self, ten_env: TenEnv) -> None: - print("DefaultExtension on_init, name", self.name) - assert self.name == "default_extension_python" + ten_env.log_info("on_init") ten_env.init_property_from_json('{"testKey": "testValue"}') ten_env.on_configure_done() def on_start(self, ten_env: TenEnv) -> None: ten_env.log_debug("on_start") + ten_env.set_property_from_json("testKey2", '"testValue2"') testValue = ten_env.get_property_to_json("testKey") testValue2 = ten_env.get_property_to_json("testKey2") - print("testValue: ", testValue, " testValue2: ", testValue2) + ten_env.log_info(f"testValue: {testValue}, testValue2: {testValue2}") + ten_env.on_start_done() def on_stop(self, ten_env: TenEnv) -> None: - print("DefaultExtension on_stop") + ten_env.log_info("on_stop") ten_env.on_stop_done() def on_deinit(self, ten_env: TenEnv) -> None: - print("DefaultExtension on_deinit") + ten_env.log_info("on_deinit") ten_env.on_deinit_done() def check_hello(self, ten_env: TenEnv, result: CmdResult, receivedCmd: Cmd): statusCode = result.get_status_code() detail = result.get_property_string("detail") - print( - "DefaultExtension check_hello: status:" - + str(statusCode) - + " detail:" - + detail + ten_env.log_info( + "check_hello: status:" + str(statusCode) + " detail:" + detail ) respCmd = CmdResult.create(StatusCode.OK) respCmd.set_property_string("detail", detail + " nbnb") - print("DefaultExtension create respCmd") + ten_env.log_info("create respCmd") ten_env.return_result(respCmd, receivedCmd) def on_cmd(self, ten_env: TenEnv, cmd: Cmd) -> None: - print("DefaultExtension on_cmd") + ten_env.log_info("on_cmd") + cmd_json = cmd.to_json() - print("DefaultExtension on_cmd json: " + cmd_json) + ten_env.log_info("on_cmd json: " + cmd_json) new_cmd = Cmd.create("hello") new_cmd.set_property_from_json("test", '"testValue2"') test_value = new_cmd.get_property_to_json("test") - print("DefaultExtension on_cmd test_value: " + test_value) + ten_env.log_info("on_cmd test_value: " + test_value) p = Process(target=f, args=("bob",)) p.start() diff --git a/tests/ten_runtime/integration/python/multiple_results_python_1/multiple_results_python_1_app/ten_packages/extension/default_extension_python/extension.py b/tests/ten_runtime/integration/python/multiple_results_python_1/multiple_results_python_1_app/ten_packages/extension/default_extension_python/extension.py index a34adeebc..447ae8e71 100644 --- a/tests/ten_runtime/integration/python/multiple_results_python_1/multiple_results_python_1_app/ten_packages/extension/default_extension_python/extension.py +++ b/tests/ten_runtime/integration/python/multiple_results_python_1/multiple_results_python_1_app/ten_packages/extension/default_extension_python/extension.py @@ -17,7 +17,6 @@ class DefaultExtension(Extension): def __init__(self, name: str) -> None: super().__init__(name) self.name = name - self.__counter = 0 def on_init(self, ten_env: TenEnv) -> None: diff --git a/tests/ten_runtime/integration/python/send_cmd_python/send_cmd_python_app/ten_packages/extension/default_extension_python/addon.py b/tests/ten_runtime/integration/python/send_cmd_python/send_cmd_python_app/ten_packages/extension/default_extension_python/addon.py index cbb565e8f..0916edd0f 100644 --- a/tests/ten_runtime/integration/python/send_cmd_python/send_cmd_python_app/ten_packages/extension/default_extension_python/addon.py +++ b/tests/ten_runtime/integration/python/send_cmd_python/send_cmd_python_app/ten_packages/extension/default_extension_python/addon.py @@ -5,15 +5,15 @@ # from ten import ( Addon, - register_addon_as_extension_v2, + register_addon_as_extension, TenEnv, ) from .extension import DefaultExtension -@register_addon_as_extension_v2("default_extension_python") +@register_addon_as_extension("default_extension_python") class DefaultExtensionAddon(Addon): def on_create_instance(self, ten_env: TenEnv, name: str, context) -> None: - ten_env.log_info("DefaultExtensionAddon on_create_instance") + ten_env.log_info("on_create_instance") ten_env.on_create_instance_done(DefaultExtension(name), context) diff --git a/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/tests/test_basic.py b/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/tests/test_basic.py index 019740a3d..7217ca166 100644 --- a/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/tests/test_basic.py +++ b/tests/ten_runtime/integration/python/standalone_test_python/default_extension_python/tests/test_basic.py @@ -34,3 +34,7 @@ def test_basic(): tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) tester.set_test_mode_single("default_extension_python") tester.run() + + +if __name__ == "__main__": + test_basic() diff --git a/tests/ten_runtime/smoke/BUILD.gn b/tests/ten_runtime/smoke/BUILD.gn index 2c208a4d0..2212c66d6 100644 --- a/tests/ten_runtime/smoke/BUILD.gn +++ b/tests/ten_runtime/smoke/BUILD.gn @@ -74,7 +74,6 @@ ten_executable("ten_runtime_smoke_test") { public_deps = [ "//third_party/googlemock", "//third_party/googletest", - "//third_party/googletest:gtest_main", ] } diff --git a/tests/ten_runtime/smoke/gtest_main.cc b/tests/ten_runtime/smoke/gtest_main.cc new file mode 100644 index 000000000..bcf3ddee7 --- /dev/null +++ b/tests/ten_runtime/smoke/gtest_main.cc @@ -0,0 +1,42 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include + +#include "gtest/gtest.h" +#include "include_internal/ten_runtime/addon/addon_manager.h" +#include "include_internal/ten_runtime/addon/extension/extension.h" +#include "include_internal/ten_utils/lib/env.h" + +class GlobalTestEnvironment : public ::testing::Environment { + public: + // This method is run before any test cases. + void SetUp() override { + if (!ten_env_set("TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE", "true")) { + perror("Failed to set TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"); + exit(-1); + } + + ten_addon_manager_t *manager = ten_addon_manager_get_instance(); + + // In the context of smoke testing, there is no need to register + // `register_ctx`. + ten_addon_manager_register_all_addons(manager, nullptr); + } + + // This method is run after all test cases. + void TearDown() override { ten_addon_unregister_all_extension(); } +}; + +GTEST_API_ int main(int argc, char **argv) { + printf("Running main() from %s\n", __FILE__); + testing::InitGoogleTest(&argc, argv); + + // Add the environment to Google Test. + ::testing::AddGlobalTestEnvironment(new GlobalTestEnvironment); + + return RUN_ALL_TESTS(); +}