Skip to content

File main.cpp

File List > src > main.cpp

Go to the documentation of this file

#ifndef ENABLE_MONADO

#    include "illixr.hpp"
#    ifdef __ANDROID__
#        include 
#        include 
#        include 
#        include 
#        include 
#    else
#        include 
#    endif
#    include 

#    ifndef NDEBUG
static void sigill_handler(int sig) {
    assert(sig == SIGILL && "sigill_handler is for SIGILL");
    std::raise(SIGSEGV);
}

static void sigabrt_handler(int sig) {
    assert(sig == SIGABRT && "sigabrt_handler is for SIGABRT");
    std::raise(SIGSEGV);
}
#    endif 

static void sigint_handler([[maybe_unused]] int sig) {
    assert(sig == SIGINT && "sigint_handler is for SIGINT");
    if (runtime_) {
        runtime_->stop();
    }
}

using namespace ILLIXR;

#    ifdef __ANDROID__
#        if defined(ILLIXR_ENABLE_BOBA) && defined(ILLIXR_ENABLE_QUEST_CONTROLLERS)
namespace {
std::mutex              quest_config_mutex;
std::condition_variable quest_config_cv;
bool                    quest_config_ready        = false;
bool                    android_destroy_requested = false;
} // namespace

#        endif

extern "C" {
// called from Java after permission is granted
JNIEXPORT void JNICALL Java_com_example_ILLIXR_ILLIXRNativeActivity_nativeOnPermissionGranted(JNIEnv* env, jobject activity) { }

// Keep the Java entry point in sync with the native build selection.
JNIEXPORT jboolean JNICALL Java_com_example_ILLIXR_ILLIXRNativeActivity_nativeIsBobaEnabled(JNIEnv*, jobject) {
#        if defined(ILLIXR_ENABLE_BOBA) && defined(ILLIXR_ENABLE_QUEST_CONTROLLERS)
    return JNI_TRUE;
#        else
    return JNI_FALSE;
#        endif
}

JNIEXPORT void JNICALL Java_com_example_ILLIXR_ILLIXRNativeActivity_nativeConfigure(JNIEnv* env, jobject activity,
                                                                                    jstring server_ip) {
#        if defined(ILLIXR_ENABLE_BOBA) && defined(ILLIXR_ENABLE_QUEST_CONTROLLERS)
    (void) activity;
    if (server_ip == nullptr) {
        return;
    }
    const char* value = env->GetStringUTFChars(server_ip, nullptr);
    if (value != nullptr) {
        if (value[0] != '\0') {
            setenv("ILLIXR_SERVER_IP", value, true);
            {
                const std::lock_guard<std::mutex> lock{quest_config_mutex};
                quest_config_ready = true;
            }
            quest_config_cv.notify_all();
        }
        env->ReleaseStringUTFChars(server_ip, value);
    }

#        endif
}
}

static std::thread runtime_thread_;

static void handle_cmd(struct android_app* app, int32_t cmd) {
#    else
int main(int argc, const char* argv[]) {
#    endif

#    ifdef __ANDROID__
    if (cmd == APP_CMD_INIT_WINDOW && !runtime_thread_.joinable()) {
        const std::vector<std::string> plugins = {"tcp_network_backend", "udp_network_backend", "network_latency.tx",
                                                  "offload_rendering_client", "openxr_interface"};

        // EuRoC
        setenv("ILLIXR_DATA", "/sdcard/Android/data/com.example.native_activity/mav0", true);
        setenv("ILLIXR_LOG", "/sdcard/Android/data/com.example.native_activity/log.txt", true);

        setenv("ILLIXR_DEMO_DATA", "/sdcard/Android/data/com.example.native_activity/demo_data", true);
        setenv("ILLIXR_OFFLOAD_ENABLE", "False", true);
        setenv("ILLIXR_ALIGNMENT_ENABLE", "False", true);
        setenv("ILLIXR_ENABLE_VERBOSE_ERRORS", "False", true);
        setenv("ILLIXR_RUN_DURATION", "1000000", true);
        setenv("ILLIXR_ENABLE_PRE_SLEEP", "False", true);
        setenv("ILLIXR_ENABLE_PRE_SLEEP", "False", true);
#        ifndef ILLIXR_ENABLE_BOBA
        setenv("ILLIXR_TCP_CLIENT_IP", "192.168.8.140", true);
        setenv("ILLIXR_TCP_SERVER_IP", "192.168.8.158", true);
        setenv("ILLIXR_TCP_CLIENT_PORT", "9000", true);
#        endif
        setenv("ILLIXR_UDP_CLIENT_PORT", "9002", true);
        setenv("ILLIXR_TCP_SERVER_PORT", "9001", true);
        setenv("ILLIXR_UDP_SERVER_PORT", "9003", true);
        setenv("ILLIXR_IS_CLIENT", "1", true);
        setenv("ILLIXR_USE_DEPTH_IMAGES", "0", true);
        setenv("ILLIXR_USE_MOTION_VECTOR_IMAGES", "0", true);
#        ifndef ILLIXR_ENABLE_BOBA
        setenv("ILLIXR_OVERSCAN", "1.1", true); // overscanning
#        endif
#    else
    cxxopts::Options options("ILLIXR", "Main program");
    options.show_positional_help();
    options.allow_unrecognised_options();
    // std::string illixr_data, illixr_demo_data, realsense_cam;
    // illixr_data = illixr_demo_data = realsense_cam = "";
    // bool offload_enable, alignment_enable, enable_verbose_errors, enable_pre_sleep;
    // offload_enable = alignment_enable = enable_verbose_errors = enable_pre_sleep = false;
    // long run_dur = 0;
    options.add_options()("d,duration", "The duration to run for", cxxopts::value<long>())(
        "data", "The data", cxxopts::value<std::string>())("demo_data", "The demo data", cxxopts::value<std::string>())(
        "enable_offload", "")("enable_alignment", "")("enable_verbose_errors", "")("enable_pre_sleep", "")(
        "h,help", "Produce help message")("realsense_cam", "", cxxopts::value<std::string>()->default_value("auto"))(
        "p,plugins", "The plugins to use",
        cxxopts::value<std::vector<std::string>>())("y,yaml", "Yaml config file", cxxopts::value<std::string>())("openxr", "");
#        if defined(ILLIXR_ENABLE_BOBA) && defined(ILLIXR_ENABLE_QUEST_CONTROLLERS)
    options.add_options()("quest-ip", "Quest IP address for native ILLIXR wireless setup", cxxopts::value<std::string>())(
        "quest-connect-timeout", "Seconds to wait for ILLIXRApp", cxxopts::value<int>()->default_value("120"));
#        endif
    auto result = options.parse(argc, argv);
    if (result.count("help")) {
        std::cout << options.help() << std::endl;
        return EXIT_SUCCESS;
    }
#    endif
#    ifndef NDEBUG
        std::signal(SIGILL, sigill_handler);
        std::signal(SIGABRT, sigabrt_handler);
#    endif 

        std::signal(SIGINT, sigint_handler);
#    ifdef __ANDROID__
#        if defined(ILLIXR_ENABLE_BOBA) && defined(ILLIXR_ENABLE_QUEST_CONTROLLERS)
        runtime_thread_ = std::thread([plugins, app]() {
            {
                std::unique_lock<std::mutex> lock{quest_config_mutex};
                // An existing configuration must not wait for a discovery packet.
                const char* server        = std::getenv("ILLIXR_SERVER_IP");
                const char* legacy_server = std::getenv("ILLIXR_TCP_SERVER_IP");
                quest_config_ready        = quest_config_ready || (server && *server) || (legacy_server && *legacy_server);
                quest_config_cv.wait(lock, []() {
                    return quest_config_ready || android_destroy_requested;
                });
                if (android_destroy_requested) {
                    return;
                }
            }
            ILLIXR::run(plugins, app);
        });
#        else
        runtime_thread_ = std::thread(ILLIXR::run, plugins, app);
#        endif
    } else if (cmd == APP_CMD_DESTROY) {
#        if defined(ILLIXR_ENABLE_BOBA) && defined(ILLIXR_ENABLE_QUEST_CONTROLLERS)
        {
            const std::lock_guard<std::mutex> lock{quest_config_mutex};
            android_destroy_requested = true;
        }
        quest_config_cv.notify_all();
#        endif
        if (runtime_) {
            runtime_->stop();
        }
    }
#    else
    return ILLIXR::run(result);
#    endif
}

#    ifdef __ANDROID__
void android_main(struct android_app* state) {
    state->onAppCmd = handle_cmd;
    while (!state->destroyRequested) {
        int                         ident;
        int                         events;
        struct android_poll_source* source;

        // This loop performs no per-frame work of its own -- rendering happens on
        // runtime_thread_ via OpenXR/Vulkan -- so it blocks indefinitely and only wakes to
        // dispatch the next lifecycle command or input event.
        do {
            ident = ALooper_pollOnce(-1, nullptr, &events, (void**) &source);
            if (ident >= 0) {
                // Process this event.
                if (source != nullptr) {
                    source->process(state, source);
                }
            }
        } while (ident >= 0 && !state->destroyRequested);
    }

    if (runtime_thread_.joinable()) {
        runtime_thread_.join();
    }
}
#    endif

#endif