@@ -0,0 +1,249 @@
|
||||
|
||||
#include "joc_core.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "eac3_transport/eac3_reader.h"
|
||||
#include "emdf/emdf_parser.h"
|
||||
#include "foundation/status.h"
|
||||
#include "joc_bitstream/joc_parser.h"
|
||||
|
||||
namespace {
|
||||
|
||||
thread_local std::string g_detail;
|
||||
|
||||
joc_error finish(const joc::Status& status) {
|
||||
if (status.ok()) {
|
||||
g_detail.clear();
|
||||
return JOC_OK;
|
||||
}
|
||||
g_detail.assign(status.stage());
|
||||
g_detail.append(": ");
|
||||
g_detail.append(status.message());
|
||||
return status.code();
|
||||
}
|
||||
|
||||
joc_error arg_fail(const char* message) {
|
||||
return finish(joc::Status::fail(JOC_ERR_INVALID_ARGUMENT, "core", message));
|
||||
}
|
||||
|
||||
void fill_emdf_info(const joc::emdf::Container& container, joc_emdf_info* out) {
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
out->struct_size = sizeof(joc_emdf_info);
|
||||
out->struct_version = JOC_EMDF_INFO_VERSION;
|
||||
out->start_bit = static_cast<std::uint32_t>(container.start_bit);
|
||||
out->container_bytes = static_cast<std::uint32_t>(container.raw_size);
|
||||
out->payload_count = static_cast<std::uint32_t>(container.payload_count);
|
||||
for (std::size_t i = 0; i < container.payload_count; ++i) {
|
||||
out->payloads[i].id = container.payloads[i].id;
|
||||
out->payloads[i].sample_offset = container.payloads[i].sample_offset;
|
||||
out->payloads[i].bit_offset = static_cast<std::uint32_t>(container.payloads[i].bit_offset);
|
||||
out->payloads[i].size = static_cast<std::uint32_t>(container.payloads[i].size);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
std::uint32_t JOC_CALL joc_abi_version(void) { return JOC_ABI_VERSION; }
|
||||
|
||||
const char* JOC_CALL joc_version_string(void) { return "0.1.0-m1"; }
|
||||
|
||||
std::uint32_t JOC_CALL joc_event_size(void) { return static_cast<std::uint32_t>(sizeof(joc_event)); }
|
||||
std::uint32_t JOC_CALL joc_task_config_size(void) {
|
||||
return static_cast<std::uint32_t>(sizeof(joc_task_config));
|
||||
}
|
||||
std::uint32_t JOC_CALL joc_task_result_size(void) {
|
||||
return static_cast<std::uint32_t>(sizeof(joc_task_result));
|
||||
}
|
||||
|
||||
const char* JOC_CALL joc_build_info(void) {
|
||||
static const std::string info = [] {
|
||||
std::string text = "joc_core 0.1.0-m1 (";
|
||||
#if defined(_MSC_VER)
|
||||
text += "msvc " + std::to_string(_MSC_VER);
|
||||
#elif defined(__clang__)
|
||||
text += std::string("clang ") + __clang_version__;
|
||||
#elif defined(__GNUC__)
|
||||
text += "gcc " + std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__);
|
||||
#else
|
||||
text += "unknown-compiler";
|
||||
#endif
|
||||
#if defined(_M_AMD64) || defined(__x86_64__)
|
||||
text += ", x64";
|
||||
#elif defined(_M_ARM64) || defined(__aarch64__)
|
||||
text += ", arm64";
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
text += ", x86";
|
||||
#endif
|
||||
text += ", c++";
|
||||
text += std::to_string(static_cast<long long>(__cplusplus / 100 % 100));
|
||||
text += ")";
|
||||
return text;
|
||||
}();
|
||||
return info.c_str();
|
||||
}
|
||||
|
||||
const char* JOC_CALL joc_error_name(joc_error code) {
|
||||
switch (code) {
|
||||
case JOC_OK: return "JOC_OK";
|
||||
case JOC_ERR_INVALID_ARGUMENT: return "JOC_ERR_INVALID_ARGUMENT";
|
||||
case JOC_ERR_INVALID_CONFIG: return "JOC_ERR_INVALID_CONFIG";
|
||||
case JOC_ERR_OUT_OF_MEMORY: return "JOC_ERR_OUT_OF_MEMORY";
|
||||
case JOC_ERR_IO: return "JOC_ERR_IO";
|
||||
case JOC_ERR_UNSUPPORTED_PLATFORM: return "JOC_ERR_UNSUPPORTED_PLATFORM";
|
||||
case JOC_ERR_LIBRARY_MISSING: return "JOC_ERR_LIBRARY_MISSING";
|
||||
case JOC_ERR_INPUT_NOT_FOUND: return "JOC_ERR_INPUT_NOT_FOUND";
|
||||
case JOC_ERR_INPUT_FORMAT: return "JOC_ERR_INPUT_FORMAT";
|
||||
case JOC_ERR_EAC3_SYNCFRAME: return "JOC_ERR_EAC3_SYNCFRAME";
|
||||
case JOC_ERR_EMDF_TRANSPORT: return "JOC_ERR_EMDF_TRANSPORT";
|
||||
case JOC_ERR_EMDF_SYNTAX: return "JOC_ERR_EMDF_SYNTAX";
|
||||
case JOC_ERR_JOC_SYNTAX: return "JOC_ERR_JOC_SYNTAX";
|
||||
case JOC_ERR_JOC_UNSUPPORTED_VARIANT: return "JOC_ERR_JOC_UNSUPPORTED_VARIANT";
|
||||
case JOC_ERR_OAMD_SYNTAX: return "JOC_ERR_OAMD_SYNTAX";
|
||||
case JOC_ERR_OAMD_UNSUPPORTED_VARIANT: return "JOC_ERR_OAMD_UNSUPPORTED_VARIANT";
|
||||
case JOC_ERR_BITSTREAM_TRUNCATED: return "JOC_ERR_BITSTREAM_TRUNCATED";
|
||||
case JOC_ERR_BITSTREAM_PADDING: return "JOC_ERR_BITSTREAM_PADDING";
|
||||
case JOC_ERR_HRTF_NOT_FOUND: return "JOC_ERR_HRTF_NOT_FOUND";
|
||||
case JOC_ERR_HRTF_FORMAT: return "JOC_ERR_HRTF_FORMAT";
|
||||
case JOC_ERR_HRTF_VERSION: return "JOC_ERR_HRTF_VERSION";
|
||||
case JOC_ERR_HRTF_HASH: return "JOC_ERR_HRTF_HASH";
|
||||
case JOC_ERR_HRTF_UNSUPPORTED_CONVENTION: return "JOC_ERR_HRTF_UNSUPPORTED_CONVENTION";
|
||||
case JOC_ERR_LAYOUT_UNSUPPORTED: return "JOC_ERR_LAYOUT_UNSUPPORTED";
|
||||
case JOC_ERR_RENDER_FAILED: return "JOC_ERR_RENDER_FAILED";
|
||||
case JOC_ERR_OUTPUT_OPEN: return "JOC_ERR_OUTPUT_OPEN";
|
||||
case JOC_ERR_OUTPUT_WRITE: return "JOC_ERR_OUTPUT_WRITE";
|
||||
case JOC_ERR_OUTPUT_CLIP_ABORT: return "JOC_ERR_OUTPUT_CLIP_ABORT";
|
||||
case JOC_ERR_ADM_VALIDATION: return "JOC_ERR_ADM_VALIDATION";
|
||||
case JOC_ERR_CANCELLED: return "JOC_ERR_CANCELLED";
|
||||
case JOC_ERR_STATE: return "JOC_ERR_STATE";
|
||||
case JOC_ERR_NOT_SUPPORTED: return "JOC_ERR_NOT_SUPPORTED";
|
||||
case JOC_ERR_INTERNAL: return "JOC_ERR_INTERNAL";
|
||||
default: return "JOC_ERR_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char* JOC_CALL joc_error_stage(joc_error code) {
|
||||
switch (code) {
|
||||
case JOC_ERR_EAC3_SYNCFRAME:
|
||||
case JOC_ERR_INPUT_NOT_FOUND:
|
||||
case JOC_ERR_INPUT_FORMAT:
|
||||
return "eac3_transport";
|
||||
case JOC_ERR_EMDF_TRANSPORT:
|
||||
case JOC_ERR_EMDF_SYNTAX:
|
||||
return "emdf";
|
||||
case JOC_ERR_JOC_SYNTAX:
|
||||
case JOC_ERR_JOC_UNSUPPORTED_VARIANT:
|
||||
return "joc";
|
||||
case JOC_ERR_OAMD_SYNTAX:
|
||||
case JOC_ERR_OAMD_UNSUPPORTED_VARIANT:
|
||||
return "oamd";
|
||||
case JOC_ERR_BITSTREAM_TRUNCATED:
|
||||
case JOC_ERR_BITSTREAM_PADDING:
|
||||
return "bitstream";
|
||||
case JOC_ERR_HRTF_NOT_FOUND:
|
||||
case JOC_ERR_HRTF_FORMAT:
|
||||
case JOC_ERR_HRTF_VERSION:
|
||||
case JOC_ERR_HRTF_HASH:
|
||||
case JOC_ERR_HRTF_UNSUPPORTED_CONVENTION:
|
||||
return "hrtf";
|
||||
case JOC_ERR_LAYOUT_UNSUPPORTED:
|
||||
case JOC_ERR_RENDER_FAILED:
|
||||
return "render";
|
||||
case JOC_ERR_OUTPUT_OPEN:
|
||||
case JOC_ERR_OUTPUT_WRITE:
|
||||
case JOC_ERR_OUTPUT_CLIP_ABORT:
|
||||
case JOC_ERR_ADM_VALIDATION:
|
||||
return "output";
|
||||
case JOC_ERR_CANCELLED:
|
||||
case JOC_ERR_STATE:
|
||||
case JOC_ERR_NOT_SUPPORTED:
|
||||
case JOC_ERR_INTERNAL:
|
||||
return "task";
|
||||
default:
|
||||
return "core";
|
||||
}
|
||||
}
|
||||
|
||||
const char* JOC_CALL joc_last_error_detail(void) { return g_detail.c_str(); }
|
||||
|
||||
joc_error JOC_CALL joc_parse_id14(const std::uint8_t* payload, std::size_t payload_size,
|
||||
joc_frame_params* out_params) {
|
||||
if (payload == nullptr || out_params == nullptr || payload_size == 0) {
|
||||
return arg_fail("joc_parse_id14 requires a non-empty payload and an output struct");
|
||||
}
|
||||
return finish(joc::joc::parse_id14(payload, payload_size, out_params, nullptr));
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_parse_eac3_frame(const std::uint8_t* frame, std::size_t frame_size,
|
||||
joc_frame_params* out_params, joc_emdf_info* out_emdf) {
|
||||
if (frame == nullptr || out_params == nullptr || frame_size == 0) {
|
||||
return arg_fail("joc_parse_eac3_frame requires a frame and an output struct");
|
||||
}
|
||||
joc::emdf::Container container;
|
||||
const joc::Status status =
|
||||
joc::joc::parse_eac3_frame(frame, frame_size, out_params, &container, nullptr);
|
||||
if (!status.ok()) {
|
||||
return finish(status);
|
||||
}
|
||||
if (out_emdf != nullptr) {
|
||||
fill_emdf_info(container, out_emdf);
|
||||
}
|
||||
return JOC_OK;
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_extract_payload(const std::uint8_t* frame, std::size_t frame_size,
|
||||
const joc_emdf_payload_info* payload, std::uint8_t* out,
|
||||
std::size_t out_capacity, std::size_t* out_size) {
|
||||
if (frame == nullptr || payload == nullptr || out_size == nullptr) {
|
||||
return arg_fail("joc_extract_payload requires frame, payload and out_size");
|
||||
}
|
||||
*out_size = payload->size;
|
||||
if (out == nullptr) {
|
||||
return JOC_OK;
|
||||
}
|
||||
if (out_capacity < payload->size) {
|
||||
return arg_fail("joc_extract_payload output buffer too small");
|
||||
}
|
||||
joc::emdf::Payload entry;
|
||||
entry.id = payload->id;
|
||||
entry.sample_offset = payload->sample_offset;
|
||||
entry.bit_offset = payload->bit_offset;
|
||||
entry.size = payload->size;
|
||||
std::vector<std::uint8_t> bytes;
|
||||
const joc::Status status = joc::emdf::extract_payload_bytes(frame, frame_size, entry, &bytes);
|
||||
if (!status.ok()) {
|
||||
return finish(status);
|
||||
}
|
||||
if (!bytes.empty()) {
|
||||
std::memcpy(out, bytes.data(), bytes.size());
|
||||
}
|
||||
*out_size = bytes.size();
|
||||
return JOC_OK;
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_eac3_frame_bytes(const std::uint8_t* data, std::size_t size, std::size_t offset,
|
||||
std::size_t* out_frame_bytes) {
|
||||
if (data == nullptr || out_frame_bytes == nullptr) {
|
||||
return arg_fail("joc_eac3_frame_bytes requires data and out_frame_bytes");
|
||||
}
|
||||
const joc_error code = joc::eac3::FrameReader::frame_bytes(data, size, offset, out_frame_bytes);
|
||||
if (code != JOC_OK) {
|
||||
return finish(joc::Status::fail(code, joc::stage::kEac3,
|
||||
"invalid or truncated E-AC-3 syncframe at byte " +
|
||||
std::to_string(offset)));
|
||||
}
|
||||
return JOC_OK;
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_check_id14_padding(const std::uint8_t* payload, std::size_t payload_size,
|
||||
std::uint32_t* out_trailing_bits) {
|
||||
if (payload == nullptr || payload_size == 0) {
|
||||
return arg_fail("joc_check_id14_padding requires a payload");
|
||||
}
|
||||
return finish(joc::joc::check_id14_padding(payload, payload_size, out_trailing_bits));
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,162 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "foundation/status.h"
|
||||
#include "joc_core.h"
|
||||
#include "joc_stream.h"
|
||||
#include "stream/stream.h"
|
||||
|
||||
struct joc_stream {
|
||||
joc::stream::Stream instance;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
joc_error finish_stream(const joc::Status& status) {
|
||||
return status.code();
|
||||
}
|
||||
|
||||
joc::stream::Config to_config(const joc_stream_config& config) {
|
||||
joc::stream::Config out;
|
||||
out.input = config.input;
|
||||
out.output = config.output;
|
||||
if (config.speaker_layout_name != nullptr) { out.layout = config.speaker_layout_name; }
|
||||
if (config.speaker_metadata_offset != 0u) {
|
||||
out.metadata_offset = config.speaker_metadata_offset;
|
||||
}
|
||||
out.binaural_mode = config.binaural_mode != 0u ? config.binaural_mode : JOC_BINAURAL_MID;
|
||||
if (config.hrtf_path != nullptr) { out.hrtf_path = config.hrtf_path; }
|
||||
if (config.kernels_path != nullptr) { out.kernels_path = config.kernels_path; }
|
||||
if (config.binaural_tail_seconds > 0.0) { out.tail_seconds = config.binaural_tail_seconds; }
|
||||
if (config.object_delay_samples != 0u) {
|
||||
out.object_delay_samples = config.object_delay_samples;
|
||||
}
|
||||
out.gain_db = config.gain_db;
|
||||
out.native_threads = config.native_threads;
|
||||
// The binaural HRTF inputs of joc_task_config, copied with the same defaults:
|
||||
// the policy is taken verbatim (0 is "none", a real choice, not "unset") and
|
||||
// the radius keeps its documented default of 1.0 when the field is not set.
|
||||
if (config.hrtf_sofa_path != nullptr) { out.hrtf_sofa_path = config.hrtf_sofa_path; }
|
||||
if (config.personalized_headphone_path != nullptr) {
|
||||
out.personalized_headphone_path = config.personalized_headphone_path;
|
||||
}
|
||||
if (config.hrtf_cache_dir != nullptr) { out.hrtf_cache_dir = config.hrtf_cache_dir; }
|
||||
out.hrtf_cache_policy = config.hrtf_cache_policy;
|
||||
if (config.hrtf_radius_m > 0.0) { out.hrtf_radius_m = config.hrtf_radius_m; }
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
joc_error JOC_CALL joc_stream_create(const joc_stream_config* config, joc_stream** out) {
|
||||
if (config == nullptr || out == nullptr || config->struct_size != sizeof(joc_stream_config)) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
auto* stream = new (std::nothrow) joc_stream();
|
||||
if (stream == nullptr) {
|
||||
return JOC_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
const joc::Status status = stream->instance.create(to_config(*config));
|
||||
if (!status.ok()) {
|
||||
delete stream;
|
||||
return finish_stream(status);
|
||||
}
|
||||
*out = stream;
|
||||
return JOC_OK;
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_stream_push(joc_stream* stream, const joc_stream_buffer* input,
|
||||
std::uint32_t* consumed_samples, std::uint32_t* consumed_bytes) {
|
||||
if (stream == nullptr || input == nullptr ||
|
||||
input->struct_size != sizeof(joc_stream_buffer)) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
const joc::Status status = [&] {
|
||||
if (input->kind == JOC_STREAM_IN_EAC3) {
|
||||
std::size_t consumed = 0;
|
||||
const joc::Status pushed =
|
||||
stream->instance.push_eac3(input->bytes, input->byte_count, &consumed);
|
||||
if (consumed_bytes != nullptr) {
|
||||
*consumed_bytes = static_cast<std::uint32_t>(consumed);
|
||||
}
|
||||
return pushed;
|
||||
}
|
||||
if (input->kind == JOC_STREAM_IN_PCM_OBJECTS16) {
|
||||
std::size_t consumed = 0;
|
||||
const joc::Status pushed =
|
||||
stream->instance.push_objects16(input->pcm, input->sample_count, &consumed);
|
||||
if (consumed_samples != nullptr) {
|
||||
*consumed_samples = static_cast<std::uint32_t>(consumed);
|
||||
}
|
||||
return pushed;
|
||||
}
|
||||
std::size_t consumed = 0;
|
||||
const joc::Status pushed =
|
||||
stream->instance.push_bed(input->pcm, input->sample_count, &consumed);
|
||||
if (consumed_samples != nullptr) {
|
||||
*consumed_samples = static_cast<std::uint32_t>(consumed);
|
||||
}
|
||||
return pushed; }();
|
||||
return finish_stream(status);
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_stream_pull(joc_stream* stream, joc_stream_buffer* output,
|
||||
std::uint32_t* produced_samples) {
|
||||
if (stream == nullptr || output == nullptr || output->out_pcm == nullptr ||
|
||||
output->struct_size != sizeof(joc_stream_buffer)) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
std::size_t produced = 0;
|
||||
const joc::Status status =
|
||||
stream->instance.pull(output->out_pcm, output->sample_count, &produced);
|
||||
if (!status.ok()) {
|
||||
return finish_stream(status);
|
||||
}
|
||||
if (produced_samples != nullptr) {
|
||||
*produced_samples = static_cast<std::uint32_t>(produced);
|
||||
}
|
||||
output->sample_count = static_cast<std::uint32_t>(produced);
|
||||
return JOC_OK;
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_stream_flush(joc_stream* stream) {
|
||||
if (stream == nullptr) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
return finish_stream(stream->instance.flush());
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_stream_reset(joc_stream* stream) {
|
||||
if (stream == nullptr) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
return finish_stream(stream->instance.reset());
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_stream_status(const joc_stream* stream, joc_stream_status_info* out) {
|
||||
if (stream == nullptr || out == nullptr ||
|
||||
out->struct_size != sizeof(joc_stream_status_info)) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
const joc::stream::Info& info = stream->instance.info();
|
||||
out->frames_in = info.frames_in;
|
||||
out->frames_out = info.frames_out;
|
||||
out->samples_in = info.samples_in;
|
||||
out->samples_out = info.samples_out;
|
||||
out->bytes_in = info.bytes_in;
|
||||
out->buffered_samples = stream->instance.buffered_samples();
|
||||
out->oamd_payloads = info.oamd_payloads;
|
||||
out->oamd_transitions = info.oamd_transitions;
|
||||
out->output_channels = info.output_channels;
|
||||
out->ended = info.ended;
|
||||
return JOC_OK;
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_stream_destroy(joc_stream* stream) {
|
||||
delete stream;
|
||||
return JOC_OK;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,120 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "foundation/status.h"
|
||||
#include "joc_core.h"
|
||||
#include "task/task.h"
|
||||
|
||||
// task and whichever frontend wants to stop it (plan 29.1/29.2).
|
||||
struct joc_cancel_token {
|
||||
std::atomic<std::uint32_t> requested{0u};
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
thread_local std::string g_task_detail;
|
||||
|
||||
joc_error finish_task(const joc::Status& status) {
|
||||
if (status.ok()) {
|
||||
g_task_detail.clear();
|
||||
return JOC_OK;
|
||||
}
|
||||
g_task_detail.assign(status.stage());
|
||||
g_task_detail.append(": ");
|
||||
g_task_detail.append(status.message());
|
||||
return status.code();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
joc_cancel_token* JOC_CALL joc_cancel_token_create(void) {
|
||||
return new (std::nothrow) joc_cancel_token();
|
||||
}
|
||||
|
||||
void JOC_CALL joc_cancel_token_request(joc_cancel_token* token) {
|
||||
if (token != nullptr) {
|
||||
token->requested.store(1u, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
std::int32_t JOC_CALL joc_cancel_token_is_requested(const joc_cancel_token* token) {
|
||||
return (token != nullptr && token->requested.load(std::memory_order_relaxed) != 0u) ? 1 : 0;
|
||||
}
|
||||
|
||||
void JOC_CALL joc_cancel_token_destroy(joc_cancel_token* token) { delete token; }
|
||||
|
||||
joc_error JOC_CALL joc_task_validate(const joc_task_config* config,
|
||||
joc_validation_issue* issues, std::uint32_t capacity,
|
||||
std::uint32_t* count) {
|
||||
if (config == nullptr) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (config->struct_size != sizeof(joc_task_config)) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
std::vector<joc_validation_issue> found;
|
||||
std::uint32_t errors = 0;
|
||||
const joc::Status status = joc::task::validate(*config, &found, &errors);
|
||||
if (count != nullptr) {
|
||||
*count = static_cast<std::uint32_t>(found.size());
|
||||
}
|
||||
if (issues != nullptr) {
|
||||
for (std::uint32_t i = 0; i < capacity && i < found.size(); ++i) {
|
||||
issues[i] = found[i];
|
||||
}
|
||||
}
|
||||
return status.ok() ? JOC_OK : JOC_ERR_INVALID_CONFIG;
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_task_execute(const joc_task_config* config, const joc_event_sink* sink,
|
||||
joc_task_result* out) {
|
||||
if (config == nullptr || config->struct_size != sizeof(joc_task_config)) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (out != nullptr) {
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
out->struct_size = sizeof(joc_task_result);
|
||||
out->struct_version = JOC_TASK_RESULT_VERSION;
|
||||
}
|
||||
const joc::Status status = joc::task::run(*config, sink, out);
|
||||
if (!status.ok() && out != nullptr && out->status == 0u) {
|
||||
out->status = JOC_TASK_FAILED;
|
||||
out->error_code = static_cast<std::uint32_t>(status.code());
|
||||
std::snprintf(out->error_stage, sizeof(out->error_stage), "%s", status.stage().c_str());
|
||||
std::snprintf(out->error_message, sizeof(out->error_message), "%s",
|
||||
status.message().c_str());
|
||||
}
|
||||
g_task_detail = status.ok() ? std::string() : status.message();
|
||||
return status.code();
|
||||
}
|
||||
|
||||
joc_error JOC_CALL joc_task_result_to_json(const joc_task_result* result, char* buffer,
|
||||
std::size_t capacity, std::size_t* needed) {
|
||||
if (result == nullptr) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
std::string json;
|
||||
const joc::Status status = joc::task::result_to_json(*result, &json);
|
||||
if (!status.ok()) {
|
||||
return status.code();
|
||||
}
|
||||
if (needed != nullptr) {
|
||||
*needed = json.size() + 1u;
|
||||
}
|
||||
if (buffer == nullptr) {
|
||||
return JOC_OK;
|
||||
}
|
||||
if (capacity < json.size() + 1u) {
|
||||
return JOC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
std::memcpy(buffer, json.c_str(), json.size() + 1u);
|
||||
return JOC_OK;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
Reference in New Issue
Block a user