Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ enum MemberFuncType {
ADD_CONTEXT,
LIST_COMPATIBLE_LLMS,
GET_HARDWARE_INFO,
#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
Comment thread
nrjpoddar marked this conversation as resolved.
CONVERT_TEXT_TO_PHONEMES,
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)
LASTTYPE, // should be last
};
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ def zeros(shape: list[int], dtype: str) -> Tensor:

OpReturnType set_threads(const std::vector<OpReturnType>& arguments);

#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
OpReturnType convert_text_to_phonemes(const std::vector<OpReturnType>& arguments);
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)

OpReturnType call_function(int memberFuncIndex, const std::vector<OpReturnType>& arguments,
CallStack& stack) override;
Expand Down
8 changes: 4 additions & 4 deletions coreruntime/nimblenet/data_variable/src/data_variable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ std::map<std::string, int> DataVariable::_memberFuncMap = {
{"add_context", MemberFuncType::ADD_CONTEXT},
{"list_compatible_llms", MemberFuncType::LIST_COMPATIBLE_LLMS},
{"get_hardware_info", MemberFuncType::GET_HARDWARE_INFO},
#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
{"convert_text_to_phonemes", MemberFuncType::CONVERT_TEXT_TO_PHONEMES},
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)
};

std::map<int, std::string> DataVariable::_inverseMemberFuncMap = {
Expand Down Expand Up @@ -198,9 +198,9 @@ std::map<int, std::string> DataVariable::_inverseMemberFuncMap = {
{MemberFuncType::ADD_CONTEXT, "add_context"},
{MemberFuncType::LIST_COMPATIBLE_LLMS, "list_compatible_llms"},
{MemberFuncType::GET_HARDWARE_INFO, "get_hardware_info"},
#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
{MemberFuncType::CONVERT_TEXT_TO_PHONEMES, "convert_text_to_phonemes"},
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)
};

int DataVariable::add_and_get_member_func_index(const std::string& memberFuncString) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include "retriever.hpp"
#endif // GENAI

#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
// TODO (jpuneet): move this chunk to a separate file
namespace {
// UTF-8 helper function to determine if byte is a continuation byte
Expand Down Expand Up @@ -229,7 +229,7 @@ std::string process_phonemes(const char* phonemes) {
return transform_phonemes(without_stress);
}
} // anonymous namespace
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)

OpReturnType NimbleNetDataVariable::create_tensor(const std::vector<OpReturnType>& arguments) {
THROW_ARGUMENTS_NOT_MATCH(arguments.size(), 2, MemberFuncType::CREATETENSOR);
Expand Down Expand Up @@ -522,7 +522,7 @@ OpReturnType NimbleNetDataVariable::set_threads(const std::vector<OpReturnType>&
#endif // MINIMAL_BUILD
}

#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
OpReturnType NimbleNetDataVariable::convert_text_to_phonemes(
const std::vector<OpReturnType>& arguments) {
THROW_ARGUMENTS_NOT_MATCH(arguments.size(), 1, MemberFuncType::CONVERT_TEXT_TO_PHONEMES);
Expand All @@ -536,7 +536,7 @@ OpReturnType NimbleNetDataVariable::convert_text_to_phonemes(
}
return std::make_shared<SingleVariable<std::string>>(phonemes);
}
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)

OpReturnType NimbleNetDataVariable::call_function(int memberFuncIndex,
const std::vector<OpReturnType>& arguments,
Expand Down Expand Up @@ -594,11 +594,11 @@ OpReturnType NimbleNetDataVariable::call_function(int memberFuncIndex,
return list_compatible_llms(arguments);
case MemberFuncType::GET_HARDWARE_INFO:
return get_hardware_info(arguments, stack);
#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
case MemberFuncType::CONVERT_TEXT_TO_PHONEMES:
// TODO (jpuneet): Should this be a part of another DelitePy module?
return convert_text_to_phonemes(arguments);
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)
}
THROW("%s not implemented for nimblenet", DataVariable::get_member_func_string(memberFuncIndex));
}
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ bool schedule_logs_upload(long repeatIntervalInMinutes, long retryIntervalInMinu
*/
nlohmann::json get_hardware_info();

#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
const char* get_phonemes(const char* text);
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)

} // namespace nativeinterface
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,8 @@ nlohmann::json get_hardware_info() {
return hardware_info_json;
}

#ifdef IOS
#if defined(__ANDROID__) || defined(IOS)
const char* get_phonemes(const char* text) { return ::get_phonemes(text); }
#endif // IOS
#endif // defined(__ANDROID__) || defined(IOS)

} // namespace nativeinterface
1 change: 1 addition & 0 deletions coreruntime/platform/android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ target_sources(nimblenet ${VISIBILITY}
src/frontend_data_variable.cpp
src/hardware_info_shadow.cpp
src/logs_upload_scheduler_shadow.cpp
src/native_request_receiver_shadow.cpp
src/networking_shadow.cpp
)

Expand Down
7 changes: 7 additions & 0 deletions coreruntime/platform/android/include/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,11 @@ bool deallocate_frontend_tensors(CTensors cTensors);
*/
bool free_frontend_function_context(void* context);

/**
* @brief Return phonemes of the given string.
*
* @return char* Pointer to phoneme string.
*/
char* get_phonemes(const char* text);

#pragma GCC visibility pop
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,22 @@ class DependencyContainerShadow {
*/
static jobject getLogsUploadSchedulerInstance(JNIEnv *env);

/**
* @brief Retrieves the NativeRequestReceiver instance from the DependencyContainer via JNI.
*
* @param env JNI environment pointer.
* @return jobject Java NativeRequestReceiver instance.
*/
static jobject getNativeRequestReceiverInstance(JNIEnv *env);

private:
inline static jobject dependencyContainerInstance = nullptr; /**< Global reference to DependencyContainer instance. */
inline static jmethodID getInstanceMethodId = nullptr; /**< Method ID for getInstance. */
inline static jclass dependencyContainerClass = nullptr; /**< Global reference to DependencyContainer Kotlin class. */
inline static jmethodID getNetworkingMethodId = nullptr; /**< Method ID for getNetworking. */
inline static jmethodID getHardwareInfoMethodId = nullptr; /**< Method ID for getHardwareInfo. */
inline static jmethodID getLogsUploadSchedulerMethodId = nullptr; /**< Method ID for getLogsUploadScheduler. */
inline static jmethodID getNativeRequestReceiverMethodId = nullptr; /**< Method ID for getNativeRequestReceiver. */

/**
* @brief Sets the global DependencyContainer instance via JNI.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: (C) 2025 DeliteAI Authors
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <jni.h>

#include <string>

class NativeRequestReceiverShadow {
public:
static void init(JNIEnv* env);
static jobject dispatch(JNIEnv* env, const std::string& functionName, int argCount, ...);

private:
inline static jclass nativeRequestReceiverClass = nullptr;
inline static jmethodID dispatchMethodId = nullptr;
inline static jobject nativeRequestReceiverKotlinInstance = nullptr;
};
70 changes: 70 additions & 0 deletions coreruntime/platform/android/src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "file_download_state_transition_shadow.h"
#include "hardware_info_shadow.hpp"
#include "logs_upload_scheduler_shadow.hpp"
#include "native_request_receiver_shadow.hpp"
#include "nimble_net_util.hpp"

JavaVM *globalJvm;
Expand Down Expand Up @@ -310,3 +311,72 @@ bool schedule_logs_upload(long repeatIntervalInMinutes, long retryIntervalInMinu
bool deallocate_frontend_tensors(CTensors cTensors) { return true; }

bool free_frontend_function_context(void *context) { return true; }

namespace {

/**
* @brief Private helper function to convert jstring to persistent C string.
*
* @param env JNI environment pointer.
* @param jStr Java string to convert.
* @return char* Persistent C string (caller must free), or nullptr on failure.
*/
char* jstring_to_cstring(JNIEnv* env, jstring jStr) {
if (!jStr) return nullptr;

const char* chars = env->GetStringUTFChars(jStr, nullptr);
if (!chars) return nullptr;

char* result = strdup(chars);
env->ReleaseStringUTFChars(jStr, chars);

return result;
}

} // namespace

char* get_phonemes(const char* text) {
if (!text) {
return nullptr;
}

JNIEnv* env;
bool attached = false;
int getEnvStatus = globalJvm->GetEnv((void **)&env, JNI_VERSION_1_6);

if (getEnvStatus == JNI_EDETACHED) {
attached = true;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6;
args.name = NULL;
args.group = NULL;

if (globalJvm->AttachCurrentThread(&env, NULL) != 0) {
return nullptr;
}
}

jstring jText = env->NewStringUTF(text);
if (!jText) {
if (attached) {
globalJvm->DetachCurrentThread();
}
return nullptr;
}

jobject result = NativeRequestReceiverShadow::dispatch(env, "getPhonemes", 1, jText);

env->DeleteLocalRef(jText);

char* phonemes = nullptr;
if (result) {
phonemes = jstring_to_cstring(env, (jstring)result);
env->DeleteLocalRef(result);
}

if (attached) {
globalJvm->DetachCurrentThread();
}

return phonemes;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ void DependencyContainerShadow::setMethodIds(JNIEnv *env) {
"()Ldev/deliteai/impl/common/HardwareInfo;");
getLogsUploadSchedulerMethodId = env->GetMethodID(dependencyContainerClass, "getLogsUploadScheduler",
"()Ldev/deliteai/impl/loggers/workManager/LogsUploadScheduler;");
getNativeRequestReceiverMethodId = env->GetMethodID(dependencyContainerClass, "getNativeRequestReceiver",
"()Ldev/deliteai/impl/nativeBridge/NativeRequestReceiver;");
}

void DependencyContainerShadow::setDependencyContainerInstance(JNIEnv *env) {
Expand Down Expand Up @@ -81,3 +83,14 @@ jobject DependencyContainerShadow::getLogsUploadSchedulerInstance(JNIEnv *env) {

return env->CallObjectMethod(dependencyContainerInstance, getLogsUploadSchedulerMethodId);
}

jobject DependencyContainerShadow::getNativeRequestReceiverInstance(JNIEnv *env) {
if (!getNativeRequestReceiverMethodId || !dependencyContainerClass) {
throw std::runtime_error("encountered nullptr in getNativeRequestReceiverInstance()");
}
if (!dependencyContainerInstance) {
throw std::runtime_error("dependencyContainerClass is not initialized");
}

return env->CallObjectMethod(dependencyContainerInstance, getNativeRequestReceiverMethodId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* SPDX-FileCopyrightText: (C) 2025 DeliteAI Authors
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "native_request_receiver_shadow.hpp"

#include <cstdarg>
#include <string>

#include "../../jni/utils/jni_logger.h"
#include "client.h"
#include "dependency_container_shadow.hpp"

void NativeRequestReceiverShadow::init(JNIEnv* env) {
if (!env) return;

jclass localClass = env->FindClass("dev/deliteai/impl/nativeBridge/NativeRequestReceiver");
if (!localClass) {
LOGE("Class dev.deliteai.impl.nativeBridge.NativeRequestReceiver not found.\n");
return;
}

nativeRequestReceiverClass = static_cast<jclass>(env->NewGlobalRef(localClass));
env->DeleteLocalRef(localClass);

if (!nativeRequestReceiverClass) {
LOGE("Failed to create global reference for NativeRequestReceiver class.\n");
return;
}

dispatchMethodId =
env->GetMethodID(nativeRequestReceiverClass, "dispatch",
"(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;");
if (!dispatchMethodId) {
LOGE("Method dispatch not found.\n");
}

auto nativeRequestReceiverKotlinInstanceLocal = DependencyContainerShadow::getNativeRequestReceiverInstance(env);
nativeRequestReceiverKotlinInstance = env->NewGlobalRef(nativeRequestReceiverKotlinInstanceLocal);
env->DeleteLocalRef(nativeRequestReceiverKotlinInstanceLocal);
}

jobject NativeRequestReceiverShadow::dispatch(JNIEnv* env, const std::string& functionName, int argCount, ...) {
if (!nativeRequestReceiverKotlinInstance) {
LOGE("nativeRequestReceiverKotlinInstance is null in dispatch.\n");
return nullptr;
}

jstring jFunctionName = env->NewStringUTF(functionName.c_str());

// Create an array with the specified number of arguments
jclass objectClass = env->FindClass("java/lang/Object");
jobjectArray argsArray = env->NewObjectArray(argCount, objectClass, nullptr);
env->DeleteLocalRef(objectClass);

// Process variable arguments
va_list args;
va_start(args, argCount);
for (int i = 0; i < argCount; i++) {
jobject arg = va_arg(args, jobject);
env->SetObjectArrayElement(argsArray, i, arg);
}
va_end(args);

jobject result =
env->CallObjectMethod(nativeRequestReceiverKotlinInstance, dispatchMethodId, jFunctionName, argsArray);

env->DeleteLocalRef(jFunctionName);
env->DeleteLocalRef(argsArray);

return result;
}
Loading