Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ sudo cmake --install build
| `OpenSSL` | Yes | TLS |
| `libmosquitto` + `nlohmann_json` + `spdlog` | For MQTT | Real-time pub/sub |
| `OpenCV` | Optional | `camera_stream_opencv` example (`./install.sh --with-opencv`) |
| `libdatachannel` | Optional | WebRTC in CameraStreamer and EncodedH264CameraStreamer |
| FFmpeg (`libavcodec`, `libavutil`, `libswscale`) | Optional | H264 encoding in CameraStreamer (not required for EncodedH264CameraStreamer passthrough) |
| `libdatachannel` | Optional | WebRTC camera streaming |
| FFmpeg (`libavcodec`, `libavutil`, `libswscale`) | Optional | H264 encoding in CameraStreamer |

## Using the SDK in Your Project

Expand Down
75 changes: 1 addition & 74 deletions include/cyberwave/camera_streaming.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class CameraStreamer

private:
void stream_loop();
void publish_edge_health(double now_seconds);

std::shared_ptr<IMqttClient> mqtt_;
std::string twin_uuid_;
Expand All @@ -117,7 +118,6 @@ class CameraStreamer
std::string webrtc_stun_url_;
std::vector<std::string> webrtc_turn_servers_;
std::unique_ptr<WebRTCAdapter> webrtc_adapter_;
std::unique_ptr<MqttSubscriptionHandle> webrtc_mqtt_subscription_;

// Optional: JPEG -> Annex-B H264 conversion when WebRTC is enabled.
std::unique_ptr<JpegToH264EncoderImpl> h264_encoder_;
Expand All @@ -137,79 +137,6 @@ class CameraStreamer
std::function<void(const std::string&)> log_fn_;
};

/**
* @brief Streamer for pre-encoded Annex-B H264 video.
*
* Bypasses raw-frame conversion and software H264 encoding for devices that
* already produce browser-compatible Annex-B access units. WebRTC carries video;
* MQTT carries signaling and edge_health telemetry (same contract as
* CameraStreamer).
*
* send_frame() forwards every access unit as-is: incoming frames are already
* inter-predicted by the source encoder, so dropping a non-key frame here would
* corrupt the decode chain for every subsequent frame until the next IDR. Rate
* limiting (if ever needed) must happen at GOP granularity upstream, not here.
*
* Threading: do not call send_frame() concurrently with stop() or from multiple
* threads without external synchronization.
*/
class EncodedH264CameraStreamer
{
public:
/**
* @param mqtt Must outlive the streamer; can be nullptr (start() no-op).
* @param twin_uuid Twin to stream to.
*/
EncodedH264CameraStreamer(std::shared_ptr<IMqttClient> mqtt, const std::string& twin_uuid,
std::string sensor_name = "",
std::string webrtc_stun_url = "stun:stun.l.google.com:19302",
std::vector<std::string> webrtc_turn_servers = {});
~EncodedH264CameraStreamer();

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

void start();
void stop();
bool running() const noexcept { return running_.load(); }

/**
* @brief Inject a log callback so WebRTC state messages use the caller's logger.
*
* Call before start().
*/
void set_log_callback(std::function<void(const std::string&)> fn);

/**
* @brief Enable or disable recording in the WebRTC offer sent to the media service.
*
* Call before start(). Default is false.
*/
void set_recording(bool recording) { recording_ = recording; }

/** Push one Annex-B access unit. Returns false when not running, throttled, or send failed. */
bool send_frame(const std::vector<std::uint8_t>& annexb_h264, std::uint64_t timestamp_us);

private:
std::shared_ptr<IMqttClient> mqtt_;
std::string twin_uuid_;
std::atomic<bool> running_{false};

std::string sensor_name_{};
bool recording_{false};
std::string webrtc_stun_url_;
std::vector<std::string> webrtc_turn_servers_;
std::unique_ptr<WebRTCAdapter> webrtc_adapter_;
std::unique_ptr<MqttSubscriptionHandle> webrtc_mqtt_subscription_;

double edge_health_stream_started_at_seconds_{0.0};
double edge_health_last_publish_ts_seconds_{0.0};
double edge_health_last_frame_ts_seconds_{0.0};
std::uint64_t edge_health_frames_sent_{0};

std::function<void(const std::string&)> log_fn_;
};

/**
* @brief Synthetic frame source for tests and placeholder streaming.
*/
Expand Down
7 changes: 0 additions & 7 deletions include/cyberwave/cyberwave_mqtt_adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,6 @@ class CyberwaveMqttAdapter : public IMqttClient
inner_->subscribe_pointcloud_stream(twin_uuid, wrap(handler));
}

std::unique_ptr<MqttSubscriptionHandle> subscribe_webrtc_messages_scoped(const std::string& twin_uuid,
MqttMessageHandler handler) override
{
inner_->publish_telemetry_start(twin_uuid);
return IMqttClient::subscribe_webrtc_messages_scoped(twin_uuid, std::move(handler));
}

void subscribe_environment(const std::string& env_uuid, MqttMessageHandler handler) override
{
inner_->subscribe_environment(env_uuid, wrap(handler));
Expand Down
21 changes: 0 additions & 21 deletions include/cyberwave/mqtt_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <optional>
#include <sstream>
#include <string>
#include <vector>

namespace cyberwave
{
Expand Down Expand Up @@ -403,26 +402,6 @@ struct IMqttClient
subscribe(get_topic_prefix() + "cyberwave/twin/" + twin_uuid + "/webrtc-candidate", std::move(handler));
}

/**
* Subscribe to WebRTC signaling with RAII unsubscribe when the handle is destroyed.
* Prefer this over subscribe_webrtc_messages() for stream lifecycles tied to start()/stop().
*/
virtual std::unique_ptr<MqttSubscriptionHandle> subscribe_webrtc_messages_scoped(const std::string& twin_uuid,
MqttMessageHandler handler)
{
struct WebRtcMessageSubscriptions final : MqttSubscriptionHandle
{
std::vector<std::unique_ptr<MqttSubscriptionHandle>> subscriptions;
};

auto handle = std::make_unique<WebRtcMessageSubscriptions>();
const std::string base = get_topic_prefix() + "cyberwave/twin/" + twin_uuid + "/webrtc-";
handle->subscriptions.push_back(subscribe_scoped(base + "offer", handler));
handle->subscriptions.push_back(subscribe_scoped(base + "answer", handler));
handle->subscriptions.push_back(subscribe_scoped(base + "candidate", std::move(handler)));
return handle;
}

/**
* Publish an edge command response message for a twin.
* Topic: {prefix}cyberwave/twin/{uuid}/command
Expand Down
55 changes: 0 additions & 55 deletions rest/include/CppRestOpenAPIClient/api/CatalogApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,9 @@
#include "CppRestOpenAPIClient/ApiClient.h"

#include "CppRestOpenAPIClient/AnyType.h"
#include "CppRestOpenAPIClient/model/CatalogSeedDetailSchema.h"
#include "CppRestOpenAPIClient/model/CatalogSeedOptionsResponseSchema.h"
#include "CppRestOpenAPIClient/model/CatalogSeedRequestSchema.h"
#include "CppRestOpenAPIClient/model/CatalogSeedResponseSchema.h"
#include "CppRestOpenAPIClient/model/DriverControllerAssetsResponseSchema.h"
#include "CppRestOpenAPIClient/model/DriverControllerSeedRequestSchema.h"
#include "CppRestOpenAPIClient/model/DriverControllerSeedResponseSchema.h"
#include "CppRestOpenAPIClient/model/SeedAutogenControllersRequestSchema.h"
#include "CppRestOpenAPIClient/model/SeedAutogenControllersResponseSchema.h"
#include "CppRestOpenAPIClient/model/TriggerAutogenControllersResponseSchema.h"
#include <map>
#include <cpprest/details/basic_types.h>
#include <boost/optional.hpp>
Expand All @@ -54,14 +47,6 @@ class CatalogApi

virtual ~CatalogApi();

/// <summary>
/// List Driver Controller Assets
/// </summary>
/// <remarks>
///
/// </remarks>
pplx::task<std::shared_ptr<DriverControllerAssetsResponseSchema>> srcAppApiCatalogSeedListDriverControllerAssets(
) const;
/// <summary>
/// Search Catalog
/// </summary>
Expand All @@ -77,16 +62,6 @@ class CatalogApi
boost::optional<int32_t> offset
) const;
/// <summary>
/// Seed Autogen Controllers
/// </summary>
/// <remarks>
/// Seed (create or update) all autogenerated controllers into a workspace. Autogenerated controllers are derived from asset capabilities and stored in AUTOGENERATED_CONTROLLERS inside seed_controllers.py. This endpoint mirrors what the CLI does without the --autogen-controllers-from-prod file-write step. If the list is empty (no autogen run has happened yet), returns a zero-count result.
/// </remarks>
/// <param name="seedAutogenControllersRequestSchema"></param>
pplx::task<std::shared_ptr<SeedAutogenControllersResponseSchema>> srcAppApiCatalogSeedSeedAutogenControllers(
std::shared_ptr<SeedAutogenControllersRequestSchema> seedAutogenControllersRequestSchema
) const;
/// <summary>
/// Seed Catalog
/// </summary>
/// <remarks>
Expand All @@ -97,43 +72,13 @@ class CatalogApi
std::shared_ptr<CatalogSeedRequestSchema> catalogSeedRequestSchema
) const;
/// <summary>
/// Seed Detail
/// </summary>
/// <remarks>
/// Inspectable detail for a single catalog item (admin \&quot;info\&quot; button). &#x60;&#x60;group&#x60;&#x60; is one of &#x60;&#x60;controllers&#x60;&#x60;, &#x60;&#x60;mlmodels&#x60;&#x60;, &#x60;&#x60;workflow_templates&#x60;&#x60;, &#x60;&#x60;asset_patches&#x60;&#x60;, or &#x60;&#x60;simplified_meshes&#x60;&#x60;; &#x60;&#x60;key&#x60;&#x60; is the item&#39;s catalog key (or registry_id for asset patches and simplified meshes).
/// </remarks>
/// <param name="group"></param>
/// <param name="key"></param>
pplx::task<std::shared_ptr<CatalogSeedDetailSchema>> srcAppApiCatalogSeedSeedDetail(
utility::string_t group,
utility::string_t key
) const;
/// <summary>
/// Seed Driver Controllers
/// </summary>
/// <remarks>
///
/// </remarks>
/// <param name="driverControllerSeedRequestSchema"></param>
pplx::task<std::shared_ptr<DriverControllerSeedResponseSchema>> srcAppApiCatalogSeedSeedDriverControllers(
std::shared_ptr<DriverControllerSeedRequestSchema> driverControllerSeedRequestSchema
) const;
/// <summary>
/// Seed Options
/// </summary>
/// <remarks>
///
/// </remarks>
pplx::task<std::shared_ptr<CatalogSeedOptionsResponseSchema>> srcAppApiCatalogSeedSeedOptions(
) const;
/// <summary>
/// Trigger Autogen Controllers
/// </summary>
/// <remarks>
/// Fetch assets from production, regenerate AUTOGENERATED_CONTROLLERS in seed_controllers.py. Equivalent to running: python manage.py seed_controllers --env {env} --autogen-controllers-from-prod After the file is written, the module is reloaded so subsequent calls to /seed-options and /seed-autogen-controllers see the updated list immediately.
/// </remarks>
pplx::task<std::shared_ptr<TriggerAutogenControllersResponseSchema>> srcAppApiCatalogSeedTriggerAutogenControllers(
) const;

protected:
std::shared_ptr<const ApiClient> m_ApiClient;
Expand Down
Loading