Standalone ChannelRuntime Clients
🚧 Documentation is under development
The Holoscan SDK guide is currently under active development. Some sections may be incomplete or change without notice.
Questions? Contact RidgeRun or email to support@ridgerun.com.
-
Overview
-
Build, Run, and Validate
-
Core Concepts
-
Operators and Graphs
-
Tensor Data and Memory
-
Interprocess Communication
-
-
Application and Operator Development
- Building an HSDK Application
- Writing a Minimal Operator
- Typed Parameters and Configuration
- Reading, Writing, and Forwarding Data
- Writing Tensor Operators
- Complete Operator Patterns
- Authoring Runtime Behavior
- Runtime Parameter Updates
- Lifecycle Callbacks and Restart Control
- Performance and Debugging
- SDK Source Map
-
Operator Reference
-
Core Operators
-
Holoscan Camera
-
Holoscan RidgeRun
- Overview
- Build and Installation
- ArgusCameraOp
- V4L2SourceOp
- V4L2UserPtrSourceOp
- BgraToPlanarTensorOp
- RawBayerToBgraOp
- RawBayerToYoloTensorOp
- YuyvToBgraOp
- TensorRtInferenceOp
- DrmDisplayOp
- DrmBgraDisplayOp
- X11DisplayOp
- CudaCompositorOp
- DepthColorizerOp
- FakesinkOp
- FrameSkipperOp
- InterprocessSrcOp
- TestPatternOp
-
-
Migration from Holoscan 4.x
-
Examples
-
Core
-
Holoscan Camera
-
Holoscan RidgeRun
-
-
Benchmark and Use Cases
-
Holoscan vs GStreamer
- Overview
-
Capture and Display
-
Capture and Inference
- Compare the workloads
- Implemented Applications
- Framework Selection
- Interprocess
-
Standalone ChannelRuntime Clients
A standalone client is a separate program that publishes to a graph input or subscribes to a graph output. It uses the graph's accepted endpoint catalog to select the endpoint and payload contract, then manages its own data loop and shutdown.
Begin with External Endpoints and Endpoint Catalogs to create and save the catalog. The client examples here assume that the graph and its transport services are deployed separately.
The Channels and HoloMQ page explains the process-boundary transport choices. For Tensor or schema payloads, use the representation and ownership vocabulary from Tensor Contracts and Memory Types and Allocation Ownership and Tensor Pools.
Choose the client role
The endpoint direction determines which client role to create:
| Graph boundary | Standalone client | Typical use |
|---|---|---|
| Graph import | Publisher | Sensor service, camera process, or upstream producer. |
| Graph export | Subscriber | Recorder, display, monitoring process, or downstream consumer. |
| Descriptor-backed import or export | Tensor-schema publisher or subscriber | Image, IMU, or application schema with one or more Tensor fields. |
Load the exact catalog used by the graph. load_json() reads the catalog file, and ChannelRuntime::create() creates the client runtime. Check both results before creating an endpoint.
| Payload | Factory |
|---|---|
| Scalar, declared raw POD, or ordinary generated schema | create_publisher<T>() for an import or create_subscriber<T>() for an export.
|
| Raw Tensor | The Tensor overload, with the finite boundary and storage rules from the catalog. |
| Descriptor-backed schema | create_tensor_schema_publisher<Payload>() or create_tensor_schema_subscriber<Payload>(), with every Tensor field covered.
|
The factory checks endpoint identity, role, payload layout, capacities, capabilities, and attachment policy. A URI or familiar endpoint name alone is not enough to establish a compatible client.
Build a checked subscriber
The following complete client reads one uint32_t value from an export named measurements-out. It expects the graph to be running and the catalog to be available in the current directory:
#include <chrono>
#include <cstdint>
#include <iostream>
#include <holoscan/channel/endpoint_catalog.hpp>
#include <holoscan/channel/runtime.hpp>
int main() {
auto catalog = holoscan::ChannelEndpointCatalog::load_json(
"endpoint-catalog.json");
if (!catalog) {
return 1;
}
auto runtime = holoscan::ChannelRuntime::create();
if (!runtime) {
return 2;
}
auto subscriber = runtime->create_subscriber<std::uint32_t>(
*catalog, "measurements-out");
if (!subscriber) {
return 3;
}
const auto deadline = std::chrono::steady_clock::now()
+ std::chrono::seconds{10};
auto sample = subscriber->wait_and_receive_sample(deadline);
if (!sample) {
return 4;
}
std::cout << sample->data << '\n';
return subscriber->close() ? 0 : 5;
}
The ten-second deadline is local to this program. It does not start the graph or extend the endpoint's accepted contract. A publisher follows the same setup sequence, then emits values with metadata that matches the payload contract.
Interpret wait and publication results
A receive wait and a publication result answer different questions. Check the returned value before reading it or reporting a successful operation:
| Result | Application response |
|---|---|
| Timeout | The current wait expired. Keep the endpoint usable and retry only under an intentional application budget. |
| Interrupted or cancelled | Stop this wait and decide whether the program should continue or close the endpoint. |
| Closed or end-of-stream | Stop receiving through this endpoint generation and release its data. |
| Stale endpoint or changed producer | Rebuild the client through the catalog factory when the endpoint API requires it. |
| Other error | Report the setup, protocol, readiness, or resource problem. Do not treat it as an empty queue. |
For a publisher, a successful result counts the recipients reached by the operation. It does not mean that every recipient finished processing the value. Refreshing a connection snapshot can help an application decide whether to attempt a publication, but the publication result remains authoritative for that operation.
Keep runtime and received data alive
ChannelRuntime must outlive its ordinary endpoints, descriptor-backed received Tensors, derived views, and asynchronous device work that uses those values. Keep an owning Tensor or received bundle alive through the last read, copy, export, or stream operation.
One subscriber supports one waiting thread. Keep its facade alive and unmoved while waiting. For a descriptor-backed value with multiple Tensor fields, use the bundle receive path described in Descriptor-Tensor External Topics.
Close in the right order
For a finite publisher, check publisher.close() and interpret its outcome. Ordered end-of-stream is different from process exit, timeout, or object destruction. A subscriber close is local cleanup and does not finish the producer's stream.
Stop and join waiters before closing their endpoint. Release received samples, Tensor views, destinations, and streams before destroying the runtime. Do not retry a publication after an uncertain submission unless the API guarantees that the operation was not submitted and the application has fresh publication authority.