C API
The C API provides a stable ABI for plugin and host integration. All types use the Nozzle prefix. Include:
#include <nozzle/nozzle_c.h>
Error Handling
All functions return NozzleErrorCode. NOZZLE_OK (0) indicates success.
typedef enum NozzleErrorCode {
NOZZLE_OK = 0,
NOZZLE_ERROR_UNKNOWN,
NOZZLE_ERROR_INVALID_ARGUMENT,
NOZZLE_ERROR_UNSUPPORTED_BACKEND,
NOZZLE_ERROR_UNSUPPORTED_FORMAT,
NOZZLE_ERROR_DEVICE_MISMATCH,
NOZZLE_ERROR_RESOURCE_CREATION_FAILED,
NOZZLE_ERROR_SHARED_HANDLE_FAILED,
NOZZLE_ERROR_SENDER_NOT_FOUND,
NOZZLE_ERROR_SENDER_CLOSED,
NOZZLE_ERROR_TIMEOUT,
NOZZLE_ERROR_BACKEND_ERROR,
} NozzleErrorCode;
Opaque Types
typedef struct NozzleSender NozzleSender;
typedef struct NozzleReceiver NozzleReceiver;
typedef struct NozzleFrame NozzleFrame;
typedef struct NozzleTexture NozzleTexture;
typedef struct NozzleDevice NozzleDevice;
Enums
NozzleBackendType
typedef enum NozzleBackendType {
NOZZLE_BACKEND_UNKNOWN = 0,
NOZZLE_BACKEND_D3D11,
NOZZLE_BACKEND_METAL,
NOZZLE_BACKEND_OPENGL,
} NozzleBackendType;
NozzleTextureFormat
typedef enum NozzleTextureFormat {
NOZZLE_FORMAT_UNKNOWN = 0,
NOZZLE_FORMAT_R8_UNORM,
NOZZLE_FORMAT_RG8_UNORM,
NOZZLE_FORMAT_RGBA8_UNORM,
NOZZLE_FORMAT_BGRA8_UNORM,
NOZZLE_FORMAT_RGBA8_SRGB,
NOZZLE_FORMAT_BGRA8_SRGB,
NOZZLE_FORMAT_R16_UNORM,
NOZZLE_FORMAT_RG16_UNORM,
NOZZLE_FORMAT_RGBA16_UNORM,
NOZZLE_FORMAT_R16_FLOAT,
NOZZLE_FORMAT_RG16_FLOAT,
NOZZLE_FORMAT_RGBA16_FLOAT,
NOZZLE_FORMAT_R32_FLOAT,
NOZZLE_FORMAT_RG32_FLOAT,
NOZZLE_FORMAT_RGBA32_FLOAT,
NOZZLE_FORMAT_R32_UINT,
NOZZLE_FORMAT_RGBA32_UINT,
NOZZLE_FORMAT_DEPTH32_FLOAT,
} NozzleTextureFormat;
NozzleReceiveMode
typedef enum NozzleReceiveMode {
NOZZLE_RECEIVE_LATEST_ONLY = 0,
NOZZLE_RECEIVE_SEQUENTIAL_BEST_EFFORT,
} NozzleReceiveMode;
NozzleFrameStatus
typedef enum NozzleFrameStatus {
NOZZLE_FRAME_NEW = 0,
NOZZLE_FRAME_NO_NEW,
NOZZLE_FRAME_DROPPED,
NOZZLE_FRAME_SENDER_CLOSED,
NOZZLE_FRAME_ERROR,
} NozzleFrameStatus;
Descriptor Structs
NozzleSenderDesc
typedef struct NozzleSenderDesc {
const char *name;
const char *application_name;
uint32_t ring_buffer_size;
int allow_format_fallback;
} NozzleSenderDesc;
| Field | Type | Description |
|---|---|---|
name |
const char * |
Sender name for discovery |
application_name |
const char * |
Application name metadata |
ring_buffer_size |
uint32_t |
Number of frames in ring buffer (default: 3) |
allow_format_fallback |
int |
Allow format fallback (nonzero = true) |
NozzleReceiverDesc
typedef struct NozzleReceiverDesc {
const char *name;
const char *application_name;
NozzleReceiveMode receive_mode;
} NozzleReceiverDesc;
NozzleAcquireDesc
typedef struct NozzleAcquireDesc {
uint64_t timeout_ms;
} NozzleAcquireDesc;
NozzleFrameInfo
typedef struct NozzleFrameInfo {
uint64_t frame_index;
uint64_t timestamp_ns;
uint32_t width;
uint32_t height;
NozzleTextureFormat format;
uint32_t dropped_frame_count;
} NozzleFrameInfo;
Sender API
nozzle_sender_create
NozzleErrorCode nozzle_sender_create(
const NozzleSenderDesc *desc,
NozzleSender **out_sender
);
| Parameter | Type | Description |
|---|---|---|
desc |
const NozzleSenderDesc * |
Sender descriptor |
out_sender |
NozzleSender ** |
Receives the created sender handle |
Returns: NOZZLE_OK on success.
nozzle_sender_destroy
void nozzle_sender_destroy(NozzleSender *sender);
nozzle_sender_publish_texture
NozzleErrorCode nozzle_sender_publish_texture(
NozzleSender *sender,
NozzleTexture *texture
);
nozzle_sender_acquire_writable_frame
NozzleErrorCode nozzle_sender_acquire_writable_frame(
NozzleSender *sender,
uint32_t width,
uint32_t height,
NozzleTextureFormat format,
NozzleFrame **out_frame
);
nozzle_sender_commit_frame
NozzleErrorCode nozzle_sender_commit_frame(
NozzleSender *sender,
NozzleFrame *frame
);
nozzle_sender_get_info
NozzleErrorCode nozzle_sender_get_info(
NozzleSender *sender,
NozzleSenderInfo *out_info
);
Receiver API
nozzle_receiver_create
NozzleErrorCode nozzle_receiver_create(
const NozzleReceiverDesc *desc,
NozzleReceiver **out_receiver
);
nozzle_receiver_destroy
void nozzle_receiver_destroy(NozzleReceiver *receiver);
nozzle_receiver_acquire_frame
NozzleErrorCode nozzle_receiver_acquire_frame(
NozzleReceiver *receiver,
const NozzleAcquireDesc *desc,
NozzleFrame **out_frame
);
Pass NULL for desc to use non-blocking (timeout_ms = 0) behavior.
nozzle_receiver_get_connected_info
NozzleErrorCode nozzle_receiver_get_connected_info(
NozzleReceiver *receiver,
NozzleConnectedSenderInfo *out_info
);
Frame API
nozzle_frame_get_info
NozzleErrorCode nozzle_frame_get_info(
NozzleFrame *frame,
NozzleFrameInfo *out_info
);
nozzle_frame_release
void nozzle_frame_release(NozzleFrame *frame);
Discovery
nozzle_enumerate_senders
typedef struct NozzleSenderInfoArray {
NozzleSenderInfo *items;
uint32_t count;
} NozzleSenderInfoArray;
NozzleErrorCode nozzle_enumerate_senders(
NozzleSenderInfoArray *out_array
);
nozzle_free_sender_info_array
void nozzle_free_sender_info_array(NozzleSenderInfoArray *array);
Must be called to free the array returned by nozzle_enumerate_senders.
NozzleSenderInfoArray arr;
if (nozzle_enumerate_senders(&arr) == NOZZLE_OK) {
for (uint32_t i = 0; i < arr.count; i++) {
printf("Sender: %s\n", arr.items[i].name);
}
nozzle_free_sender_info_array(&arr);
}
Device API
nozzle_device_get_default
NozzleErrorCode nozzle_device_get_default(
NozzleDevice **out_device
);
nozzle_device_destroy
void nozzle_device_destroy(NozzleDevice *device);
Pixel Access (CPU)
NozzleMappedPixels
typedef struct NozzleMappedPixels {
void *data;
uint32_t row_bytes;
uint32_t width;
uint32_t height;
NozzleTextureFormat format;
} NozzleMappedPixels;
nozzle_frame_lock_pixels
NozzleErrorCode nozzle_frame_lock_pixels(
NozzleFrame *frame,
NozzleMappedPixels *out_pixels
);
nozzle_frame_unlock_pixels
void nozzle_frame_unlock_pixels(NozzleFrame *frame);
nozzle_frame_lock_writable_pixels
NozzleErrorCode nozzle_frame_lock_writable_pixels(
NozzleFrame *frame,
NozzleMappedPixels *out_pixels
);
nozzle_frame_unlock_writable_pixels
void nozzle_frame_unlock_writable_pixels(NozzleFrame *frame);
GL Interop
nozzle_sender_publish_gl_texture
NozzleErrorCode nozzle_sender_publish_gl_texture(
NozzleSender *sender,
uint32_t gl_texture_name,
uint32_t gl_target,
uint32_t width,
uint32_t height,
NozzleTextureFormat format
);
Requires an active GL context on the calling thread.
nozzle_frame_copy_to_gl_texture
NozzleErrorCode nozzle_frame_copy_to_gl_texture(
NozzleFrame *frame,
uint32_t gl_texture_name,
uint32_t gl_target,
uint32_t width,
uint32_t height,
NozzleTextureFormat format
);
Full Example
#include <nozzle/nozzle_c.h>
#include <stdio.h>
#include <string.h>
int main() {
// Create sender
NozzleSender *sender;
NozzleSenderDesc desc = {0};
desc.name = "my_output";
desc.application_name = "MyApp";
desc.ring_buffer_size = 3;
if (nozzle_sender_create(&desc, &sender) != NOZZLE_OK) {
fprintf(stderr, "Failed to create sender\n");
return 1;
}
// Acquire writable frame
NozzleFrame *frame;
if (nozzle_sender_acquire_writable_frame(
sender, 1920, 1080,
NOZZLE_FORMAT_RGBA8_UNORM, &frame) != NOZZLE_OK) {
fprintf(stderr, "Failed to acquire frame\n");
nozzle_sender_destroy(sender);
return 1;
}
// Write pixels
NozzleMappedPixels pixels;
if (nozzle_frame_lock_writable_pixels(frame, &pixels) == NOZZLE_OK) {
uint8_t *buf = (uint8_t *)pixels.data;
for (uint32_t i = 0; i < pixels.width * pixels.height; i++) {
buf[i * 4 + 0] = 255;
buf[i * 4 + 1] = 128;
buf[i * 4 + 2] = 64;
buf[i * 4 + 3] = 255;
}
nozzle_frame_unlock_writable_pixels(frame);
}
// Commit
nozzle_sender_commit_frame(sender, frame);
nozzle_frame_release(frame);
// Create receiver in another process
NozzleReceiver *receiver;
NozzleReceiverDesc recv_desc = {0};
recv_desc.name = "my_output";
recv_desc.application_name = "MyViewer";
if (nozzle_receiver_create(&recv_desc, &receiver) != NOZZLE_OK) {
fprintf(stderr, "Failed to create receiver\n");
nozzle_sender_destroy(sender);
return 1;
}
// Acquire frame
NozzleAcquireDesc acq = { .timeout_ms = 1000 };
NozzleFrame *recv_frame;
if (nozzle_receiver_acquire_frame(receiver, &acq, &recv_frame) == NOZZLE_OK) {
NozzleFrameInfo info;
nozzle_frame_get_info(recv_frame, &info);
printf("Received frame: %ux%u\n", info.width, info.height);
nozzle_frame_release(recv_frame);
}
nozzle_receiver_destroy(receiver);
nozzle_sender_destroy(sender);
return 0;
}