Skip to content

Commit

Permalink
feat: expand the implementation of extension tester to allow it to be…
Browse files Browse the repository at this point in the history
… used for testing the graph (#296)

Co-authored-by: Hu Yueh-Wei <[email protected]>
  • Loading branch information
sunxilin and halajohn authored Nov 26, 2024
1 parent f57aa21 commit 3055c4c
Show file tree
Hide file tree
Showing 41 changed files with 1,676 additions and 334 deletions.
253 changes: 253 additions & 0 deletions core/include/ten_runtime/binding/cpp/experimental/ten_client_proxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
//
// 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/binding/cpp/internal/test/env_tester_proxy.h"
#include "ten_runtime/binding/cpp/internal/test/extension_tester.h"
#include "ten_utils/log/log.h"

namespace ten {

using ten_client_proxy_send_cmd_result_handler_func_t =
std::function<void(std::unique_ptr<ten::cmd_result_t>)>;

class ten_client_proxy_event_handler_t {
public:
ten_client_proxy_event_handler_t() = default;
virtual ~ten_client_proxy_event_handler_t() = default;

ten_client_proxy_event_handler_t(const ten_client_proxy_event_handler_t &) =
delete;
ten_client_proxy_event_handler_t(ten_client_proxy_event_handler_t &&) =
delete;
ten_client_proxy_event_handler_t &operator=(
const ten_client_proxy_event_handler_t &) = delete;
ten_client_proxy_event_handler_t &operator=(
const ten_client_proxy_event_handler_t &&) = delete;

virtual void on_start() {}

virtual void on_cmd(std::unique_ptr<cmd_t> cmd) {}

virtual void on_data(std::unique_ptr<data_t> data) {}

virtual void on_audio_frame(std::unique_ptr<audio_frame_t> audio_frame) {}

virtual void on_video_frame(std::unique_ptr<video_frame_t> video_frame) {}
};

namespace {

class ten_client_proxy_internal_impl_t : public ten::extension_tester_t {
protected:
void on_start(ten::ten_env_tester_t &ten_env_tester) override {
ten_env_tester_proxy_ = std::unique_ptr<ten::ten_env_tester_proxy_t>(
ten::ten_env_tester_proxy_t::create(ten_env_tester));
TEN_ASSERT(ten_env_tester_proxy_, "Should not happen.");

if (event_handler_ != nullptr) {
event_handler_->on_start();
}

ten_env_tester.on_start_done();
}

void on_cmd(ten::ten_env_tester_t & /*ten_env_tester*/,
std::unique_ptr<ten::cmd_t> cmd) override {
if (event_handler_ != nullptr) {
event_handler_->on_cmd(std::move(cmd));
}
}

void on_data(ten::ten_env_tester_t & /*ten_env_tester*/,
std::unique_ptr<ten::data_t> data) override {
if (event_handler_ != nullptr) {
event_handler_->on_data(std::move(data));
}
}

void on_audio_frame(
ten::ten_env_tester_t & /*ten_env_tester*/,
std::unique_ptr<ten::audio_frame_t> audio_frame) override {
if (event_handler_ != nullptr) {
event_handler_->on_audio_frame(std::move(audio_frame));
}
}

void on_video_frame(
ten::ten_env_tester_t & /*ten_env_tester*/,
std::unique_ptr<ten::video_frame_t> video_frame) override {
if (event_handler_ != nullptr) {
event_handler_->on_video_frame(std::move(video_frame));
}
}

static void proxy_on_cmd_response(
std::unique_ptr<ten::cmd_result_t> cmd_result,
const ten::ten_client_proxy_send_cmd_result_handler_func_t
&result_handler) {
if (result_handler) {
result_handler(std::move(cmd_result));
}
}

public:
void register_callback(ten::ten_client_proxy_event_handler_t *event_handler) {
event_handler_ = event_handler;
}

bool send_cmd(
std::unique_ptr<ten::cmd_t> cmd,
ten::ten_client_proxy_send_cmd_result_handler_func_t &&result_handler) {
TEN_ASSERT(ten_env_tester_proxy_, "Invalid state.");

if (ten_env_tester_proxy_ == nullptr) {
TEN_LOGE("Failed to send_cmd: %s before started.", cmd->get_name());
return false;
}

auto cmd_shared =
std::make_shared<std::unique_ptr<ten::cmd_t>>(std::move(cmd));

return ten_env_tester_proxy_->notify(
[cmd_shared, result_handler](ten::ten_env_tester_t &ten_env_tester) {
ten_env_tester.send_cmd(
std::move(*cmd_shared),
[result_handler](ten::ten_env_tester_t & /*ten_env_tester*/,
std::unique_ptr<ten::cmd_result_t> cmd_result) {
proxy_on_cmd_response(std::move(cmd_result), result_handler);
});
},
nullptr);
}

bool send_data(std::unique_ptr<ten::data_t> data) {
TEN_ASSERT(ten_env_tester_proxy_, "Invalid state.");

if (ten_env_tester_proxy_ == nullptr) {
TEN_LOGE("Failed to send_data before started.");
return false;
}

auto data_shared =
std::make_shared<std::unique_ptr<ten::data_t>>(std::move(data));

return ten_env_tester_proxy_->notify(
[data_shared](ten::ten_env_tester_t &env_tester) {
env_tester.send_data(std::move(*data_shared));
},
nullptr);
}

bool send_audio_frame(std::unique_ptr<ten::audio_frame_t> audio_frame) {
TEN_ASSERT(ten_env_tester_proxy_, "Invalid state.");

if (ten_env_tester_proxy_ == nullptr) {
TEN_LOGE("Failed to send_audio_frame before started.");
return false;
}

auto audio_frame_shared =
std::make_shared<std::unique_ptr<ten::audio_frame_t>>(
std::move(audio_frame));

return ten_env_tester_proxy_->notify(
[audio_frame_shared](ten::ten_env_tester_t &env_tester) {
env_tester.send_audio_frame(std::move(*audio_frame_shared));
},
nullptr);
}

bool send_video_frame(std::unique_ptr<ten::video_frame_t> video_frame) {
TEN_ASSERT(ten_env_tester_proxy_, "Invalid state.");

if (ten_env_tester_proxy_ == nullptr) {
TEN_LOGE("Failed to send_video_frame before started.");
return false;
}

auto video_frame_shared =
std::make_shared<std::unique_ptr<ten::video_frame_t>>(
std::move(video_frame));

return ten_env_tester_proxy_->notify(
[video_frame_shared](ten::ten_env_tester_t &env_tester) {
env_tester.send_video_frame(std::move(*video_frame_shared));
},
nullptr);
}

bool stop() {
if (ten_env_tester_proxy_ == nullptr) {
TEN_LOGE("Failed to stop before started.");
return false;
}

return ten_env_tester_proxy_->notify(
[](ten::ten_env_tester_t &env_tester) { env_tester.stop_test(); },
nullptr);
}

private:
ten::ten_client_proxy_event_handler_t *event_handler_;

// The thread-safety should be guaranteed by the caller.
std::unique_ptr<ten::ten_env_tester_proxy_t> ten_env_tester_proxy_;
};

} // namespace

class ten_client_proxy_t {
public:
ten_client_proxy_t() = default;
virtual ~ten_client_proxy_t() = default;

ten_client_proxy_t(const ten_client_proxy_t &) = delete;
ten_client_proxy_t(ten_client_proxy_t &&) = delete;
ten_client_proxy_t &operator=(const ten_client_proxy_t &) = delete;
ten_client_proxy_t &operator=(const ten_client_proxy_t &&) = delete;

void add_addon_base_dir(const char *addon_path) {
TEN_ASSERT(addon_path, "Invalid argument.");
impl_.add_addon_base_dir(addon_path);
}

void start_graph(const char *graph_json) {
TEN_ASSERT(graph_json, "Invalid argument.");
impl_.set_test_mode_graph(graph_json);
impl_.run();
}

// These functions should be called after the on_start callback is received.

void send_cmd(
std::unique_ptr<cmd_t> cmd,
ten_client_proxy_send_cmd_result_handler_func_t &&result_handler) {
impl_.send_cmd(std::move(cmd), std::move(result_handler));
}

void send_data(std::unique_ptr<data_t> data) {
impl_.send_data(std::move(data));
}

void send_audio_frame(std::unique_ptr<audio_frame_t> audio_frame) {
impl_.send_audio_frame(std::move(audio_frame));
}

void send_video_frame(std::unique_ptr<video_frame_t> video_frame) {
impl_.send_video_frame(std::move(video_frame));
}

void register_event_handler(ten_client_proxy_event_handler_t *event_handler) {
impl_.register_callback(event_handler);
}

private:
ten_client_proxy_internal_impl_t impl_;
};

} // namespace ten
Loading

0 comments on commit 3055c4c

Please sign in to comment.