487 lines
19 KiB
C
487 lines
19 KiB
C
/*
|
|
* joc_core.h -- JustOneCacophony C++ Core, public ABI. Pure C.
|
|
*
|
|
* This header is the single authoritative definition of the Core's public
|
|
* parameter/error surface. Frontends (thin Python CLI, joc_dump, foobar2000,
|
|
* MPV, FFmpeg) only ever fill these POD structs and read these POD results;
|
|
* no audio data, no internal DSP concept, and no Python type crosses this
|
|
* boundary.
|
|
*
|
|
* Stability tiers
|
|
* ---------------
|
|
* [T1] host tier
|
|
* joc_abi_version / joc_version_string / joc_build_info, joc_error,
|
|
* joc_error_name / joc_error_stage, joc_last_error_detail.
|
|
* Stable, versioned, safe for media hosts.
|
|
*
|
|
* [T2] bitstream / verification tier
|
|
* joc_parse_eac3_frame, joc_parse_id14, joc_frame_params, joc_emdf_info.
|
|
* These deliberately expose the dequantized JOC matrix coefficients so the
|
|
* bitstream front-end can be validated bit-exactly and driven by tooling
|
|
* (joc_dump) and A/B harnesses. Media hosts must NOT use this tier; they
|
|
* use the task/stream API (added in later milestones).
|
|
*
|
|
* Conventions
|
|
* -----------
|
|
* * every struct's first two fields are struct_size / struct_version;
|
|
* * all arrays are fixed size and POD, no pointers, no allocation;
|
|
* * every function returns joc_error (JOC_OK == 0);
|
|
* * joc_last_error_detail() returns a thread-local message that stays valid
|
|
* until the next Core call on the same thread.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
#define JOC_ABI_VERSION 3u
|
|
#define JOC_FRAME_PARAMS_VERSION 1u
|
|
#define JOC_EMDF_INFO_VERSION 1u
|
|
#define JOC_TASK_CONFIG_VERSION 3u
|
|
#define JOC_TASK_RESULT_VERSION 2u
|
|
#define JOC_EVENT_VERSION 1u
|
|
|
|
#if defined(_WIN32)
|
|
#if defined(JOC_BUILD_DLL)
|
|
#define JOC_API __declspec(dllexport)
|
|
#else
|
|
#define JOC_API __declspec(dllimport)
|
|
#endif
|
|
#define JOC_CALL __cdecl
|
|
#else
|
|
#define JOC_API __attribute__((visibility("default")))
|
|
#define JOC_CALL
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Fixed layout constants (single source of truth for every frontend) */
|
|
/* ------------------------------------------------------------------ */
|
|
enum {
|
|
JOC_FRAME_SAMPLES = 1536, /* E-AC-3 frame = 24 * 64 */
|
|
JOC_TIMESLOTS = 24,
|
|
JOC_SUBBANDS = 64,
|
|
JOC_CORE_CHANNELS = 5, /* L R C Ls Rs (JOC order) */
|
|
JOC_MAX_CORE_CHANNELS = 7, /* dmx_config_idx 1/2/4 declare 7 */
|
|
JOC_OUTPUT_CHANNELS = 16, /* ch0 = LFE, ch1..15 = objects */
|
|
JOC_MAX_OBJECTS = 15,
|
|
JOC_MAX_DPOINTS = 2,
|
|
JOC_MAX_PARAMETER_BANDS = 23,
|
|
JOC_MAX_EMDF_PAYLOADS = 16,
|
|
JOC_SPEAKER_BLOCK_SAMPLES = 32,
|
|
JOC_BINAURAL_BLOCK_SAMPLES = 512,
|
|
JOC_BINAURAL_QMF_BANDS = 64,
|
|
JOC_BINAURAL_HYBRID_BANDS = 77,
|
|
JOC_QMF_HOP_SAMPLES = 64,
|
|
JOC_BINAURAL_LATENCY_SAMPLES = 961,
|
|
JOC_LFE_DELAY_SAMPLES = 1217
|
|
};
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* [T1] library / error surface */
|
|
/* ------------------------------------------------------------------ */
|
|
typedef enum joc_error {
|
|
JOC_OK = 0,
|
|
JOC_ERR_INVALID_ARGUMENT,
|
|
JOC_ERR_INVALID_CONFIG,
|
|
JOC_ERR_OUT_OF_MEMORY,
|
|
JOC_ERR_IO,
|
|
JOC_ERR_UNSUPPORTED_PLATFORM,
|
|
JOC_ERR_LIBRARY_MISSING,
|
|
/* input / bitstream */
|
|
JOC_ERR_INPUT_NOT_FOUND,
|
|
JOC_ERR_INPUT_FORMAT,
|
|
JOC_ERR_EAC3_SYNCFRAME,
|
|
JOC_ERR_EMDF_TRANSPORT,
|
|
JOC_ERR_EMDF_SYNTAX,
|
|
JOC_ERR_JOC_SYNTAX,
|
|
JOC_ERR_JOC_UNSUPPORTED_VARIANT,
|
|
JOC_ERR_OAMD_SYNTAX,
|
|
JOC_ERR_OAMD_UNSUPPORTED_VARIANT,
|
|
JOC_ERR_BITSTREAM_TRUNCATED,
|
|
JOC_ERR_BITSTREAM_PADDING,
|
|
/* resources */
|
|
JOC_ERR_HRTF_NOT_FOUND,
|
|
JOC_ERR_HRTF_FORMAT,
|
|
JOC_ERR_HRTF_VERSION,
|
|
JOC_ERR_HRTF_HASH,
|
|
JOC_ERR_HRTF_UNSUPPORTED_CONVENTION,
|
|
/* rendering / output */
|
|
JOC_ERR_LAYOUT_UNSUPPORTED,
|
|
JOC_ERR_RENDER_FAILED,
|
|
JOC_ERR_OUTPUT_OPEN,
|
|
JOC_ERR_OUTPUT_WRITE,
|
|
JOC_ERR_OUTPUT_CLIP_ABORT,
|
|
JOC_ERR_ADM_VALIDATION,
|
|
/* task / stream */
|
|
JOC_ERR_CANCELLED,
|
|
JOC_ERR_STATE,
|
|
JOC_ERR_NOT_SUPPORTED,
|
|
JOC_ERR_INTERNAL
|
|
} joc_error;
|
|
|
|
JOC_API uint32_t JOC_CALL joc_abi_version(void);
|
|
JOC_API const char* JOC_CALL joc_version_string(void);
|
|
JOC_API const char* JOC_CALL joc_build_info(void);
|
|
/* Struct sizes, so a binding can assert its layout matches the library instead of
|
|
* assuming (mismatches are otherwise silent memory corruption). */
|
|
JOC_API uint32_t JOC_CALL joc_event_size(void);
|
|
JOC_API uint32_t JOC_CALL joc_task_config_size(void);
|
|
JOC_API uint32_t JOC_CALL joc_task_result_size(void);
|
|
JOC_API const char* JOC_CALL joc_error_name(joc_error code);
|
|
JOC_API const char* JOC_CALL joc_error_stage(joc_error code);
|
|
/* Thread-local structured detail for the most recent failing call. */
|
|
JOC_API const char* JOC_CALL joc_last_error_detail(void);
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* [T2] bitstream / verification tier */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* One EMDF payload directory entry. bit_offset is the MSB-first bit
|
|
* position of the payload's first byte inside the syncframe, exactly as the
|
|
* EMDF container syntax defines it (payloads are not byte aligned in general). */
|
|
typedef struct joc_emdf_payload_info {
|
|
uint8_t id;
|
|
uint8_t reserved[3];
|
|
uint16_t sample_offset; /* EMDF outer smpoffst, 11 bits */
|
|
uint16_t reserved2;
|
|
uint32_t bit_offset;
|
|
uint32_t size; /* payload bytes */
|
|
} joc_emdf_payload_info;
|
|
|
|
typedef struct joc_emdf_info {
|
|
uint32_t struct_size;
|
|
uint32_t struct_version;
|
|
uint32_t start_bit; /* container syncword bit position */
|
|
uint32_t container_bytes; /* 4 + declared length */
|
|
uint32_t payload_count;
|
|
uint32_t reserved;
|
|
joc_emdf_payload_info payloads[JOC_MAX_EMDF_PAYLOADS];
|
|
} joc_emdf_info;
|
|
|
|
/* Per-object ID14/JOC descriptor plus its dequantized matrix.
|
|
* dq[dp][ch][pb] is zero filled outside [0,n_dpoints) x [0,n_channels) x
|
|
* [0,n_bands). Absent objects are entirely zero. */
|
|
typedef struct joc_object_params {
|
|
uint8_t present;
|
|
uint8_t num_bands_idx;
|
|
uint8_t n_bands;
|
|
uint8_t sparse; /* 0 = dense (MTX), 1 = sparse (IDX+VEC) */
|
|
uint8_t quant_idx; /* 0 = 96 levels, 1 = 192 levels */
|
|
uint8_t slope_idx; /* 0 = interpolate, 1 = step at offset_ts */
|
|
uint8_t num_dpoints_bits;
|
|
uint8_t n_dpoints;
|
|
uint8_t offset_ts[JOC_MAX_DPOINTS];
|
|
uint8_t reserved[2];
|
|
double dq[JOC_MAX_DPOINTS][JOC_MAX_CORE_CHANNELS][JOC_MAX_PARAMETER_BANDS];
|
|
} joc_object_params;
|
|
|
|
typedef struct joc_frame_params {
|
|
uint32_t struct_size;
|
|
uint32_t struct_version;
|
|
uint8_t dmx_config_idx;
|
|
uint8_t num_objects_bits;
|
|
uint8_t ext_config_idx;
|
|
uint8_t n_objects;
|
|
uint8_t n_channels; /* 5 or 7 */
|
|
uint8_t clipgain_x_bits;
|
|
uint8_t clipgain_y_bits;
|
|
uint8_t reserved;
|
|
uint32_t seq_count; /* 10-bit JOC sequence counter, parsed only */
|
|
uint32_t present_mask; /* bit i == object i present */
|
|
uint32_t data_end_bits; /* bit position just after joc_data */
|
|
uint32_t trailing_bits; /* bits left after joc_data (padding/ext) */
|
|
uint8_t tail_bytes[8]; /* first up to 8 trailing bytes, for A/B */
|
|
double clipgain; /* 1 + (y/32) * 2^(x-4), bit-exact */
|
|
joc_object_params objects[JOC_MAX_OBJECTS];
|
|
} joc_frame_params;
|
|
|
|
/* Parse an EMDF ID14 (JOC) payload. */
|
|
JOC_API joc_error JOC_CALL joc_parse_id14(const uint8_t* payload, size_t payload_size,
|
|
joc_frame_params* out_params);
|
|
|
|
/* Locate the contiguous JOC EMDF container inside one E-AC-3 syncframe and
|
|
* parse its ID14 payload. out_emdf may be NULL. */
|
|
JOC_API joc_error JOC_CALL joc_parse_eac3_frame(const uint8_t* frame, size_t frame_size,
|
|
joc_frame_params* out_params,
|
|
joc_emdf_info* out_emdf);
|
|
|
|
/* Copy one payload's bytes out of a syncframe (MSB-first bit extraction, which
|
|
* equals a memcpy for byte-aligned containers). out_size receives the payload
|
|
* byte count; pass out == NULL to query only the size. */
|
|
JOC_API joc_error JOC_CALL joc_extract_payload(const uint8_t* frame, size_t frame_size,
|
|
const joc_emdf_payload_info* payload,
|
|
uint8_t* out, size_t out_capacity,
|
|
size_t* out_size);
|
|
|
|
/* E-AC-3 syncframe traversal: given the offset of a frame start, report its
|
|
* byte length so a host can walk a bare E-AC-3 stream without duplicating
|
|
* frmsiz logic. Rejects resynchronisation (no silent recovery). */
|
|
JOC_API joc_error JOC_CALL joc_eac3_frame_bytes(const uint8_t* data, size_t size,
|
|
size_t offset, size_t* out_frame_bytes);
|
|
|
|
/* Strict trailing-bit check for the JOC payload (A/B robustness corpus).
|
|
* Returns JOC_ERR_BITSTREAM_PADDING when more than 7 bits are left over or the
|
|
* leftover bits are not zero. */
|
|
JOC_API joc_error JOC_CALL joc_check_id14_padding(const uint8_t* payload, size_t payload_size,
|
|
uint32_t* out_trailing_bits);
|
|
|
|
/* ================================================================== */
|
|
/* [T1] host tier: task, telemetry and control */
|
|
/* ================================================================== */
|
|
|
|
/* ---- 1. events ---------------------------------------------------- */
|
|
/*
|
|
* Events carry state only: frame/sample counters, stage, progress, statistics,
|
|
* warnings, errors and paths. Audio never travels through an event; a fixed
|
|
* size POD with no pointers keeps that enforceable (see the static assertion in
|
|
* the implementation).
|
|
*/
|
|
typedef enum joc_event_type {
|
|
JOC_EV_TASK_STARTED = 0x0001,
|
|
JOC_EV_TASK_STATE_CHANGED = 0x0002,
|
|
JOC_EV_TASK_COMPLETED = 0x0003,
|
|
JOC_EV_TASK_FAILED = 0x0004,
|
|
JOC_EV_TASK_CANCELLED = 0x0005,
|
|
JOC_EV_INPUT_OPENED = 0x0101,
|
|
JOC_EV_METADATA_INDEXED = 0x0103,
|
|
JOC_EV_HRTF_LOADED = 0x0110,
|
|
JOC_EV_RENDERER_INITIALIZED = 0x0120,
|
|
JOC_EV_PROGRESS = 0x0201,
|
|
JOC_EV_STAGE_CHANGED = 0x0202,
|
|
JOC_EV_JOC_FRAME_STATS = 0x0301,
|
|
JOC_EV_OAMD_STATS = 0x0302,
|
|
JOC_EV_OUTPUT_STATS = 0x0303,
|
|
JOC_EV_OUTPUT_OPENED = 0x0401,
|
|
JOC_EV_OUTPUT_FORMAT_DECIDED = 0x0402,
|
|
JOC_EV_OUTPUT_FINALIZED = 0x0403,
|
|
JOC_EV_LOG = 0x0501,
|
|
JOC_EV_WARNING = 0x0502,
|
|
JOC_EV_ERROR = 0x0503
|
|
} joc_event_type;
|
|
|
|
typedef enum joc_stage {
|
|
JOC_STAGE_IDLE = 0,
|
|
JOC_STAGE_INPUT = 1,
|
|
JOC_STAGE_METADATA = 2,
|
|
JOC_STAGE_DECODE = 3,
|
|
JOC_STAGE_JOC = 4,
|
|
JOC_STAGE_RENDER = 5,
|
|
JOC_STAGE_OUTPUT = 6,
|
|
JOC_STAGE_DONE = 7
|
|
} joc_stage;
|
|
|
|
enum { JOC_LOG_TRACE = 0, JOC_LOG_DEBUG = 1, JOC_LOG_INFO = 2, JOC_LOG_NOTICE = 3,
|
|
JOC_LOG_WARNING = 4, JOC_LOG_ERROR = 5, JOC_LOG_FATAL = 6 };
|
|
|
|
typedef struct joc_event {
|
|
uint32_t struct_size;
|
|
uint32_t type;
|
|
uint64_t sequence;
|
|
uint64_t timestamp_us;
|
|
uint64_t current_frame;
|
|
uint64_t total_frames;
|
|
uint64_t current_sample;
|
|
uint64_t total_samples;
|
|
uint32_t stage;
|
|
uint32_t backend;
|
|
double progress; /* 0..1, -1 = unknown */
|
|
double elapsed_seconds;
|
|
double realtime_factor;
|
|
uint64_t output_samples;
|
|
uint64_t output_bytes;
|
|
double output_duration_seconds;
|
|
joc_error error_code;
|
|
uint32_t log_level;
|
|
char stage_name[32];
|
|
char message[256];
|
|
} joc_event;
|
|
|
|
typedef void (JOC_CALL *joc_event_fn)(void* user, const joc_event* event);
|
|
|
|
typedef struct joc_event_sink {
|
|
uint32_t struct_size;
|
|
joc_event_fn callback;
|
|
void* user;
|
|
uint32_t min_type; /* 0 = no filter */
|
|
uint32_t max_type; /* 0 = no filter */
|
|
} joc_event_sink;
|
|
|
|
/* ---- 2. cancellation ---------------------------------------------- */
|
|
typedef struct joc_cancel_token joc_cancel_token;
|
|
|
|
JOC_API joc_cancel_token* JOC_CALL joc_cancel_token_create(void);
|
|
JOC_API void JOC_CALL joc_cancel_token_request(joc_cancel_token* token);
|
|
JOC_API int32_t JOC_CALL joc_cancel_token_is_requested(const joc_cancel_token* token);
|
|
JOC_API void JOC_CALL joc_cancel_token_destroy(joc_cancel_token* token);
|
|
|
|
/* ---- 3. task configuration and results ---------------------------- */
|
|
typedef enum joc_operation {
|
|
JOC_OP_ADM_BWF = 0,
|
|
JOC_OP_SPEAKER = 1,
|
|
JOC_OP_BINAURAL = 2
|
|
} joc_operation;
|
|
|
|
typedef enum joc_output_format {
|
|
JOC_FORMAT_FLOAT32 = 0,
|
|
JOC_FORMAT_PCM24 = 1
|
|
} joc_output_format;
|
|
|
|
typedef enum joc_binaural_mode {
|
|
JOC_BINAURAL_OFF = 0,
|
|
JOC_BINAURAL_NEAR = 1,
|
|
JOC_BINAURAL_FAR = 2,
|
|
JOC_BINAURAL_MID = 3
|
|
} joc_binaural_mode;
|
|
|
|
typedef enum joc_trajectory_mode {
|
|
JOC_TRAJECTORY_COMPACT = 0,
|
|
JOC_TRAJECTORY_DENSE64 = 1
|
|
} joc_trajectory_mode;
|
|
|
|
/* What to do when an int24 WAV would clip (peak outside [-1, 1]). Mirrors the
|
|
* reference CLI's --clip-action; ADM BWF output is always int24 and does not
|
|
* consult this because no alternative format exists there. */
|
|
typedef enum joc_clip_action {
|
|
JOC_CLIP_ASK = 0, /* prompt on stdin; an error when stdin is not a terminal */
|
|
JOC_CLIP_CONTINUE = 1, /* write int24, truncating out-of-range values */
|
|
JOC_CLIP_FLOAT32 = 2, /* switch the output to float32 */
|
|
JOC_CLIP_ABORT = 3 /* fail the task */
|
|
} joc_clip_action;
|
|
|
|
/* Compiled-HRTF cache policy for a SOFA input; the .jochrtf itself is an
|
|
* internal artifact of the compile step. */
|
|
typedef enum joc_hrtf_cache_policy {
|
|
JOC_HRTF_CACHE_NONE = 0, /* compile and discard */
|
|
JOC_HRTF_CACHE_MEMORY = 1, /* compile and keep in this process (default) */
|
|
JOC_HRTF_CACHE_DISK = 2 /* compile, reuse and write <cache_dir>/<name>.jochrtf */
|
|
} joc_hrtf_cache_policy;
|
|
|
|
enum { JOC_TASK_F_SKIP_SHA256 = 1u, JOC_TASK_F_KEEP_INTERMEDIATE = 2u,
|
|
JOC_TASK_F_QUIET = 4u, JOC_TASK_F_METADATA_ONLY = 8u };
|
|
|
|
typedef struct joc_task_config {
|
|
uint32_t struct_size;
|
|
uint32_t struct_version;
|
|
|
|
/* input */
|
|
const char* input_path; /* .eac3/.ec3/.m4a/... */
|
|
const char* ffmpeg_path; /* NULL = "ffmpeg" from PATH */
|
|
const char* bed_path; /* NULL = decode the core PCM with ffmpeg */
|
|
const char* work_dir; /* NULL = a temporary directory */
|
|
double eac3_drc_scale; /* 0 = DRC off (reference default) */
|
|
int32_t eac3_target_level; /* -31..0, 0 = not applied */
|
|
|
|
/* output */
|
|
uint32_t operation;
|
|
const char* output_path;
|
|
uint32_t output_format; /* requested format for speaker/binaural */
|
|
uint32_t flags;
|
|
uint32_t clip_action; /* joc_clip_action; JOC_CLIP_ASK by default */
|
|
|
|
/* rendering */
|
|
const char* speaker_layout_name;
|
|
uint32_t speaker_metadata_offset; /* default 1473 */
|
|
uint32_t binaural_mode;
|
|
const char* hrtf_path; /* .jochrtf */
|
|
const char* kernels_path; /* rosella_kernels.npz */
|
|
double binaural_tail_seconds; /* default 5.0 */
|
|
double binaural_tail_threshold; /* binaural only; 0 disables trimming */
|
|
uint32_t binaural_chunk_frames; /* accepted for CLI parity; no effect */
|
|
|
|
/* ADM */
|
|
uint32_t adm_binaural_mode; /* DBMD segment 10 encoding */
|
|
uint32_t trajectory_mode;
|
|
|
|
/* generic */
|
|
uint32_t object_delay_samples; /* default 1473 */
|
|
double gain_db; /* default 0 */
|
|
uint64_t duration_frames; /* 0 = the whole stream */
|
|
uint32_t progress_interval_frames; /* default 1000 */
|
|
uint32_t native_threads; /* 0 = automatic */
|
|
|
|
/* diagnostics */
|
|
uint32_t print_metadata; /* 0 none, 1 summary, 2 per frame */
|
|
const char* metadata_json_path; /* NULL = no JSON summary */
|
|
|
|
joc_cancel_token* cancel; /* optional */
|
|
|
|
/* Binaural HRTF input (config version 2): when hrtf_sofa_path is set the
|
|
* library compiles it with hrtf_cache_policy / hrtf_cache_dir / hrtf_radius_m
|
|
* and hrtf_path is unused. hrtf_path stays the advanced override that reads
|
|
* a .jochrtf directly. */
|
|
const char* hrtf_sofa_path; /* SOFA SimpleFreeFieldHRIR input */
|
|
const char* personalized_headphone_path; /* Rosella .personalized_headphone input */
|
|
const char* hrtf_cache_dir; /* disk policy directory */
|
|
uint32_t hrtf_cache_policy; /* joc_hrtf_cache_policy */
|
|
uint32_t reserved0;
|
|
double hrtf_radius_m; /* SOFA measurement-radius shell */
|
|
} joc_task_config;
|
|
|
|
typedef enum joc_task_status {
|
|
JOC_TASK_OK = 0,
|
|
JOC_TASK_FAILED = 1,
|
|
JOC_TASK_CANCELLED = 2
|
|
} joc_task_status;
|
|
|
|
typedef struct joc_task_result {
|
|
uint32_t struct_size;
|
|
uint32_t struct_version;
|
|
uint32_t status;
|
|
uint32_t error_code;
|
|
char error_message[512];
|
|
char error_stage[32];
|
|
uint64_t input_frames;
|
|
uint64_t output_samples;
|
|
double duration_sec;
|
|
uint32_t output_format_actual;
|
|
double output_peak;
|
|
uint64_t output_over_unity_values;
|
|
uint64_t output_file_bytes;
|
|
char output_sha256[65]; /* empty when skipped */
|
|
uint64_t oamd_payloads;
|
|
uint64_t oamd_transitions;
|
|
double t_decode_bed;
|
|
double t_render;
|
|
double t_write;
|
|
double t_total;
|
|
double t_render_dsp; /* speaker/binaural DSP calls only; 0 for ADM */
|
|
double t_write_file; /* disk writes including the finalize; >= t_write */
|
|
} joc_task_result;
|
|
|
|
typedef struct joc_validation_issue {
|
|
joc_error code;
|
|
uint32_t severity; /* 0 = info, 1 = warning, 2 = error */
|
|
char field[48];
|
|
char message[256];
|
|
} joc_validation_issue;
|
|
|
|
/* ---- 4. entry points ---------------------------------------------- */
|
|
/* Fills `issues` (up to `capacity`) and reports how many were produced.
|
|
* Returns JOC_OK when no *error*-severity issue was found. */
|
|
JOC_API joc_error JOC_CALL joc_task_validate(const joc_task_config* config,
|
|
joc_validation_issue* issues, uint32_t capacity,
|
|
uint32_t* count);
|
|
|
|
/* Runs the whole task on the calling thread. `sink` may be NULL; `out` may be
|
|
* NULL. On cancellation the partial output is removed and JOC_ERR_CANCELLED is
|
|
* returned with out->status = JOC_TASK_CANCELLED. */
|
|
JOC_API joc_error JOC_CALL joc_task_execute(const joc_task_config* config,
|
|
const joc_event_sink* sink, joc_task_result* out);
|
|
|
|
/* Serialises the stable subset of the result as JSON (no environment fields -
|
|
* those belong to the frontend). `needed` receives the required size including
|
|
* the terminator; a NULL buffer queries only the size. */
|
|
JOC_API joc_error JOC_CALL joc_task_result_to_json(const joc_task_result* result, char* buffer,
|
|
size_t capacity, size_t* needed);
|
|
|
|
/* The streaming (push/pull) tier lives in "joc_stream.h" so an embedder can
|
|
* include the narrow surface without the bitstream/verification tier. */
|
|
|
|
#ifdef __cplusplus
|
|
} /* extern "C" */
|
|
#endif
|