1 - include/AclLog.h

include/AclLog.h File Reference

Namespaces

Name
Acl
Acl::AclLog
A namespace for logging utilities.

Classes

Name
classAcl::AclLog::ThreadNameFormatterFlag
classAcl::AclLog::FileLocationFormatterFlag
A custom flag formatter which logs the source file location between a par of “[]”, in case the location is provided with the log call.

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <filesystem>
#include <string>

#include <spdlog/details/log_msg.h>
#include <spdlog/fmt/fmt.h>
#include <spdlog/formatter.h>
#include <spdlog/pattern_formatter.h>
#include <sys/prctl.h>

namespace Acl {

namespace AclLog {

enum class Level {
    kTrace,    // Detailed diagnostics (for development only)
    kDebug,    // Messages intended for debugging only
    kInfo,     // Messages about normal behavior (default log level)
    kWarning,  // Warnings (functionality intact)
    kError,    // Recoverable errors (functionality impaired)
    kCritical, // Unrecoverable errors (application must stop)
    kOff       // Turns off all logging
};

void init(const std::string& name);

void initControlMessagesLog(const std::string& name);

void setLevel(Level level);

void logControlMessage(const std::string& origin, const std::string& controlMessage);

AclLog::Level getLogLevel();

size_t getMaxFileSize();

size_t getMaxLogRotations();

std::filesystem::path getLogFileFullPath(const std::string& name);

inline std::string getThreadName() {
    static const size_t RECOMMENDED_BUFFER_SIZE = 20;
    static thread_local std::string name;

    if (name.empty()) {
        char buffer[RECOMMENDED_BUFFER_SIZE];
        int retval = prctl(PR_GET_NAME, buffer);
        if (retval == -1) {
            throw spdlog::spdlog_ex("Failed to get thread name: ", errno);
        }
        name = std::string(buffer);
    }
    return name;
}

class ThreadNameFormatterFlag : public spdlog::custom_flag_formatter {
public:
    void format(const spdlog::details::log_msg&, const std::tm&, spdlog::memory_buf_t& dest) override {
        std::string threadName = getThreadName();
        dest.append(threadName.data(), threadName.data() + threadName.size());
    }

    [[nodiscard]] std::unique_ptr<custom_flag_formatter> clone() const override {
        return spdlog::details::make_unique<ThreadNameFormatterFlag>();
    }
};

class FileLocationFormatterFlag : public spdlog::custom_flag_formatter {
public:
    void format(const spdlog::details::log_msg& msg, const std::tm&, spdlog::memory_buf_t& dest) override {
        if (!msg.source.empty()) {
            using namespace spdlog::details;

            dest.push_back('[');
            const char* filename = short_filename_formatter<null_scoped_padder>::basename(msg.source.filename);
            fmt_helper::append_string_view(filename, dest);
            dest.push_back(':');
            fmt_helper::append_int(msg.source.line, dest);
            dest.push_back(']');
        }
    }

    [[nodiscard]] std::unique_ptr<custom_flag_formatter> clone() const override {
        return spdlog::details::make_unique<FileLocationFormatterFlag>();
    }
};

} // namespace AclLog

} // namespace Acl

2 - include/AlignedFrame.h

include/AlignedFrame.h File Reference

Namespaces

Name
Acl

Classes

Name
structAcl::AlignedAudioFrame
AlignedAudioFrame is a frame of interleaved floating point audio samples with a given number of channels.
structAcl::AlignedFrame
A frame of aligned data that is passed to the rendering engine from the MediaReceiver. A DataFrame contains a time stamped frame of media, which might be video, audio and auxiliary data such as subtitles. A single DataFrame can contain one or multiple types of media. Which media types are included can be probed by nullptr-checking/size checking the data members. The struct has ownership of all data pointers included. The struct includes all logic for freeing the resources held by this struct and the user should therefore just make sure the struct itself is deallocated to ensure all resources are freed.

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <array>
#include <iostream>
#include <memory>
#include <vector>

#include <cuda_runtime_api.h>

#include "DeviceMemory.h"
#include "MediaEnumerations.h"

namespace Acl {

struct AlignedAudioFrame {
    // The samples interleaved
    std::vector<float> mSamples;
    uint8_t mNumberOfChannels = 0;
    uint32_t mNumberOfSamplesPerChannel = 0;
};

using AlignedAudioFramePtr = std::shared_ptr<AlignedAudioFrame>;
using AlignedAudioFrameConstPtr = std::shared_ptr<const AlignedAudioFrame>;

AlignedAudioFramePtr createAlignedAudioFrame(uint8_t numberOfChannels, uint32_t numberOfSamplesPerChannel);

AlignedAudioFramePtr copyAlignedAudioFrame(AlignedAudioFrameConstPtr audioFrame);

AlignedAudioFramePtr extractChannel(AlignedAudioFrameConstPtr sourceFrame, uint8_t channelIndex);

struct AlignedFrame {

    AlignedFrame() = default;

    ~AlignedFrame() = default;

    AlignedFrame(AlignedFrame const&) = delete;            // Copy construct
    AlignedFrame& operator=(AlignedFrame const&) = delete; // Copy assign

    [[nodiscard]] std::shared_ptr<AlignedFrame> makeShallowCopy() const;

    int64_t mCaptureTimestamp = 0;

    int64_t mRenderingTimestamp = 0;

    // Video
    std::shared_ptr<DeviceMemory> mVideoFrame = nullptr;
    PixelFormat mPixelFormat = PixelFormat::kUnknown;
    uint32_t mFrameRateN = 0;
    uint32_t mFrameRateD = 0;
    uint32_t mWidth = 0;
    uint32_t mHeight = 0;

    // Audio
    AlignedAudioFrameConstPtr mAudioFrame = nullptr;
    uint32_t mAudioSamplingFrequency = 0;
};

using AlignedFramePtr = std::shared_ptr<AlignedFrame>;

} // namespace Acl

3 - include/Base64.h

include/Base64.h File Reference

Namespaces

Name
Acl

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <cstdint>
#include <string>
#include <vector>

namespace Acl {

std::string encodeBase64(const uint8_t* data, size_t size);

std::string encodeBase64(const std::vector<uint8_t>& data);

std::vector<uint8_t> decodeBase64(const std::string& data);

} // namespace Acl

4 - include/ControlDataAddress.h

include/ControlDataAddress.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::ControlDataAddress
A class representing an address within the control protocol. The address consists of an internal list of UUIDs, which all represent a component that needs to be passed to reach the final address. An address might end with a wildcard, which is represented by the omni UUID (i.e. all digits set to 0xF) and will then match all addresses with the same UUID sequence in the start.
structfmt::formatter< Acl::ControlDataAddress >

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <cstdint>
#include <sstream>
#include <string>
#include <vector>

#include <fmt/format.h>

#include "UUID.h"

namespace Acl {

class ControlDataAddress final {
public:
    ControlDataAddress() = default;

    explicit ControlDataAddress(const UUID& destinationUUID);

    [[nodiscard]] size_t size() const;

    [[nodiscard]] bool empty() const;

    bool extend(const UUID& uuid);

    bool extend(const ControlDataAddress& address);

    [[nodiscard]] bool hasWildcard() const;

    [[nodiscard]] bool currentUuidIsWildcard() const;

    [[nodiscard]] bool currentUuidMatch(const UUID& uuid) const;

    [[nodiscard]] bool fullAddressMatch(const ControlDataAddress& other) const;

    [[nodiscard]] std::optional<UUID> getCurrentUuid() const;

    std::optional<UUID> moveToAndGetNextUuid();

    [[nodiscard]] std::vector<uint8_t> pack() const;

    static std::optional<ControlDataAddress> unpack(const std::vector<uint8_t>::const_iterator& packedBegin,
                                                    const std::vector<uint8_t>::const_iterator& packedEnd);

    static std::optional<ControlDataAddress> unpack(const uint8_t* packedBegin, const uint8_t* packedEnd);

    [[nodiscard]] std::string toString() const;

    bool operator==(const ControlDataAddress& other) const;

    bool operator!=(const ControlDataAddress& other) const;

    friend std::ostream& operator<<(std::ostream& stream, const ControlDataAddress& address);

private:
    std::vector<UUID> mAddress;
};

std::ostream& operator<<(std::ostream& stream, const ControlDataAddress& address);

} // namespace Acl

template <> struct fmt::formatter<Acl::ControlDataAddress> : formatter<std::string> {
    template <typename FormatContext> auto format(const Acl::ControlDataAddress& address, FormatContext& ctx) {
        return formatter<std::string>::format(address.toString(), ctx);
    }
};

5 - include/ControlDataCommon.h

include/ControlDataCommon.h File Reference

Namespaces

Name
Acl
Acl::ControlDataCommon

Classes

Name
structAcl::ControlDataCommon::Response
A response from a ControlDataReceiver to a request. The UUID tells which receiver the response is sent from.
structAcl::ControlDataCommon::StatusMessage
A status message from a ControlDataReceiver. The UUID tells which receiver the message is sent from.
structAcl::ControlDataCommon::ConnectionEvent
A connection related event.
structfmt::formatter< Acl::ControlDataCommon::EventType >

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include "ControlDataAddress.h"
#include "UUID.h"

namespace Acl::ControlDataCommon {

struct Response {
    std::string mMessage;          
    uint64_t mRequestId = 0;       
    UUID mFromUUID;                
    ControlDataAddress mRecipient; 
};

struct StatusMessage {
    std::string mMessage;          
    UUID mFromUUID;                
    ControlDataAddress mRecipient; 
};

enum class EventType : uint8_t {
    kDisconnect, 
    kConnect     
};

struct ConnectionEvent {
    EventType mEventType = EventType::kDisconnect; 
    ControlDataAddress mAddress;                   
    UUID mEventNode;                               
};

} // namespace Acl::ControlDataCommon

template <> struct fmt::formatter<Acl::ControlDataCommon::EventType> : formatter<std::string> {
    template <typename FormatContext> auto format(const Acl::ControlDataCommon::EventType type, FormatContext& ctx) {
        std::string value;
        switch (type) {
        case Acl::ControlDataCommon::EventType::kDisconnect:
            value = "disconnect";
            break;
        case Acl::ControlDataCommon::EventType::kConnect:
            value = "connect";
            break;
        }
        return formatter<std::string>::format(value, ctx);
    }
};

6 - include/ControlDataSender.h

include/ControlDataSender.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::ControlDataSender
A ControlDataSender can send control signals to one or more receivers using a network connection. A single ControlDataSender can connect to multiple receivers, all identified by a UUID. The class is controlled using an ISystemControllerInterface; this interface is responsible for setting up connections to receivers. The ControlDataSender can send asynchronous requests to (all) the receivers and get a response back. Each response is identified with a request ID as well as the UUID of the responding receiver. The ControlDataSender can also receive status messages from the receivers.
structAcl::ControlDataSender::Settings
Settings for a ControlDataSender.

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <functional>
#include <memory>
#include <vector>

#include <ISystemControllerInterface.h>

#include "ControlDataCommon.h"

namespace Acl {

class ControlDataSender final {
public:
    enum class SendRequestStatus {
        kSuccess,             
        kFailed,              
        kSendFailedForSome,   
        kSenderNotConfigured, 
        kNoConnectedReceiver, 
        kInternalError        
    };

    struct Settings {
        std::function<void(const ControlDataCommon::Response&)>
            mResponseCallback; // Callback for response messages from receivers
        std::function<void(const ControlDataCommon::StatusMessage&)>
            mStatusMessageCallback; // Callback for status messages from receivers
        std::function<void(const ControlDataCommon::ConnectionEvent&)>
            mConnectionEventCallback; // Callback for connection events that has been detected by the sender, or passed
                                      // to it from a connected receiver
    };

    ControlDataSender();

    ~ControlDataSender();

    bool configure(const std::shared_ptr<ISystemControllerInterface>& controllerInterface, const Settings& settings);

    SendRequestStatus sendRequestToReceivers(const std::string& request,
                                             uint64_t& requestId,
                                             const UUID& requester = UUID::kNilUUID,
                                             int8_t hops = -1);

    [[nodiscard]] std::vector<UUID> getDirectlyConnectedReceivers() const;

    static std::string getVersion();

    // ControlDataSender is not copyable
    ControlDataSender(ControlDataSender const&) = delete;            // Copy construct
    ControlDataSender& operator=(ControlDataSender const&) = delete; // Copy assign

private:
    class Impl;
    std::unique_ptr<Impl> pImpl;
};

} // namespace Acl

7 - include/DeviceMemory.h

include/DeviceMemory.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::DeviceMemory
RAII class for a CUDA memory buffer.

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <cstddef>
#include <cstdint>
#include <memory>

#include <cuda_runtime.h>

namespace Acl {

class DeviceMemory {
public:
    DeviceMemory() = default;

    explicit DeviceMemory(size_t numberOfBytes);

    explicit DeviceMemory(size_t numberOfBytes, cudaStream_t cudaStream);

    explicit DeviceMemory(void* deviceMemory) noexcept;

    bool allocateMemory(size_t numberOfBytes);

    bool allocateMemoryAsync(size_t numberOfBytes, cudaStream_t cudaStream);

    bool reallocateMemory(size_t numberOfBytes);

    bool reallocateMemoryAsync(size_t numberOfBytes, cudaStream_t cudaStream);

    bool allocateAndResetMemory(size_t numberOfBytes);

    bool allocateAndResetMemoryAsync(size_t numberOfBytes, cudaStream_t cudaStream);

    bool freeMemory();

    bool freeMemoryAsync(cudaStream_t cudaStream);

    void setFreeingCudaStream(cudaStream_t cudaStream);

    ~DeviceMemory();

    template <typename T = uint8_t> [[nodiscard]] T* getDevicePointer() const {
        return reinterpret_cast<T*>(dMemory);
    }

    [[nodiscard]] size_t getSize() const;

    DeviceMemory(DeviceMemory&& other) noexcept;
    DeviceMemory& operator=(DeviceMemory&& other) noexcept;

    void swap(DeviceMemory& other) noexcept;

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

private:
    uint8_t* dMemory = nullptr;
    size_t mAllocatedBytes = 0;
    cudaStream_t mCudaStream = nullptr; // Stream to use for Async free
};

using DeviceMemoryPtr = std::shared_ptr<DeviceMemory>;

} // namespace Acl

8 - include/IControlDataReceiver.h

include/IControlDataReceiver.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::IControlDataReceiver
IControlDataReceiver is the interface class for the control data receiver. An IControlDataReceiver can receive messages from a sender or other IControlDataReceivers using a network connection. It can also connect to and forward the incoming request messages to other receivers. The connections to the sender and the other receivers are controlled by an ISystemControllerInterface instance. The ControlDataReceiver has a receiving or listening side, as well as a sending side. The listening side can listen to one single network port and have multiple ControlDataSenders and ControlDataReceivers connected to that port to receive requests from them. On the sending side of the ControlDataReceiver, it can be connected to the listening side of other ControlDataReceivers, used to forward all incoming messages to that receiver, as well as sending its own requests.
structAcl::IControlDataReceiver::RequestData
An incoming request to this ControlDataReceiver.
classAcl::IControlDataReceiver::IRequest
Interface for a request that can be responded to.
structAcl::IControlDataReceiver::Settings
Settings for a ControlDataReceiver.

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <memory>

#include <ISystemControllerInterface.h>

#include "ControlDataAddress.h"
#include "ControlDataCommon.h"

namespace Acl {

class IControlDataReceiver {
public:
    struct RequestData {
        std::string mMessage; 
        UUID mSenderUUID;     
        ControlDataAddress mRequester; 
        uint64_t mRequestID = 0;       
        int64_t mSenderTimestampUs =
            0; 
        int64_t mDeliveryTimestampUs =
            0; 
    };

    class IRequest {
    public:
        IRequest() = default;

        virtual ~IRequest() = default;

        virtual const RequestData& getRequestData() = 0;

        virtual bool respond(std::string&& message) = 0;
    };

    using IRequestPtr = std::shared_ptr<IRequest>;

    struct Settings {
        UUID mProductionPipelineUUID; 
        std::function<void(const ControlDataCommon::Response&)>
            mResponseCallback; 
        std::function<void(const ControlDataCommon::ConnectionEvent&)>
            mConnectionEventCallback; 
    };

    virtual ~IControlDataReceiver() = default;

    virtual bool configure(const Settings& settings) = 0;

    virtual std::vector<IRequestPtr> getRequests(int64_t timestampUs) = 0;

    virtual bool sendStatusMessageToSender(std::string&& message, const ControlDataAddress& address) = 0;

    virtual bool sendRequestToReceivers(const std::string& request, uint64_t& requestId) = 0;

    virtual size_t getNumberOfConnectedSenders() = 0;

    virtual size_t getNumberOfConnectedReceivers() = 0;
};

} // namespace Acl

9 - include/IMediaStreamer.h

include/IMediaStreamer.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::IMediaStreamer
IMediaStreamer is an interface class for MediaStreamers, that can take a single stream of uncompressed video and/or audio frames and encode and output it in some way. This output can either be a stream to a network or writing down the data to a file on the hard drive. This class is configured from two interfaces. The input configuration (input video resolution, frame rate, pixel format, number of audio channels…) is made through this C++ API. The output stream is then started from the System Controller. Any of these configurations can be made first. The actual stream to output will start once the first call to.
structAcl::IMediaStreamer::Settings
Settings used when creating a new MediaStreamer.
structAcl::IMediaStreamer::Configuration
The input configuration of the frames that will be sent to this MediaStreamer. The output stream configuration is made from the System controller via the ISystemControllerInterface.

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <memory>

#include <ISystemControllerInterface.h>
#include <cuda.h>

#include "AlignedFrame.h"

namespace Acl {

class IMediaStreamer {
public:
    struct Settings {
        std::string mName; // Human-readable name, presented in the REST API
    };

    struct Configuration {
        // Video
        PixelFormat mIncomingPixelFormat = PixelFormat::kUnknown;
        uint32_t mWidth = 0;      // Width of the incoming video frames in pixels
        uint32_t mHeight = 0;     // Height of the incoming video frames in pixels
        uint32_t mFrameRateN = 0; // Frame rate numerator of the incoming video frames
        uint32_t mFrameRateD = 0; // Frame rate denominator of the incoming video frames

        // Audio
        uint32_t mAudioSampleRate = 0;  // Audio sample rate of the incoming frames in Hz
        uint32_t mNumAudioChannels = 0; // Number of audio channels in the incoming frames
    };

    virtual ~IMediaStreamer() = default;

    virtual bool configure(const UUID& uuid, const Settings& settings, CUcontext cudaContext) = 0;

    virtual bool setInputFormatAndStart(const Configuration& configuration) = 0;

    virtual bool stopAndResetFormat() = 0;

    [[nodiscard]] virtual bool hasFormatAndIsRunning() const = 0;

    [[nodiscard]] virtual bool hasOpenOutputStream() const = 0;

    virtual bool outputData(const AlignedFramePtr& frame) = 0;
};

} // namespace Acl

10 - include/IngestApplication.h

include/IngestApplication.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::IngestApplication
structAcl::IngestApplication::Settings

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <memory>

#include "ISystemControllerInterface.h"

namespace Acl {

class IngestApplication {
public:
    struct Settings {};

    IngestApplication();

    ~IngestApplication();

    bool start(const std::shared_ptr<ISystemControllerInterface>& controllerInterface, const Settings& settings);

    bool stop();

    static std::string getVersion();

    static std::string getLibraryVersions();

private:
    class Impl;
    std::unique_ptr<Impl> pImpl;
};

} // namespace Acl

11 - include/IngestUtils.h

include/IngestUtils.h File Reference

Namespaces

Name
Acl
Acl::IngestUtils

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

namespace Acl {

namespace IngestUtils {

bool isRunningWithRootPrivileges();

} // namespace IngestUtils

} // namespace Acl

12 - include/ISystemControllerInterface.h

include/ISystemControllerInterface.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::ISystemControllerInterface
An ISystemControllerInterface is the interface between a component and the System controller controlling the component. The interface allows for two-way communication between the component and the system controller by means of sending requests and getting responses. Classes deriving from the ISystemControllerInterface should provide the component side implementation of the communication with the system controller. This interface can be inherited and implemented by developers to connect to custom system controllers, or to directly control a component programmatically, without the need for connecting to a remote server.
structAcl::ISystemControllerInterface::Response
A response to a request, consists of a status code and an (optional) parameters JSON object.
structAcl::ISystemControllerInterface::Callbacks
A struct containing the callbacks that needs to be registered by the component using this interface.
structfmt::formatter< Acl::ISystemControllerInterface::StatusCode >

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <functional>
#include <json.hpp>
#include <optional>
#include <string>

#include <fmt/format.h>

#include "UUID.h"

namespace Acl {

class ISystemControllerInterface {
public:
    enum class StatusCode : uint32_t {
        SUCCESS = 3001, // Accept / Success

        TOO_MANY_REQUESTS = 3101, // Too many requests, try again later

        UUID_ALREADY_REGISTERED = 3201, // UUID is already registered
        FORMAT_ERROR = 3202,            // Message formatting error
        ALREADY_CONFIGURED = 3203,      // The requested thing to configure is already configured
        OUT_OF_RESOURCES = 3204,  // Out of resources (CPU/GPU close to max utilization, all available slots used, etc.)
        NOT_FOUND = 3205,         // The requested thing was not found
        INTERNAL_ERROR = 3206,    // Internal error when trying to serve the request
        CONNECTION_FAILED = 3207, // Connection failure
        TIMEOUT_EXCEEDED = 3208,  // Timeout exceeded
        KEY_MISMATCH = 3209,      // Key mismatch (might be a timeout, 3007 in the future)
        UNKNOWN_REQUEST = 3210,   // The name of the request was not known
        MALFORMED_REQUEST = 3211, // The request is not correctly formatted
        ALREADY_IN_USE = 3212,    // The requested resource is already in use
        VERSION_MISMATCH = 3213,  // The version of the request is not supported

        // None, yet
    };

    struct Response {
        StatusCode mCode;
        nlohmann::json mParameters; // Can be empty
    };

    struct Callbacks {
        std::function<Response(const std::string&, const nlohmann::json&)>
            mRequestCallback; // Callback called when then controller has sent a request
        std::function<void(uint32_t, const std::string&, const std::error_code&)>
            mConnectionClosedCallback; // Callback called when the connection to the controller is closed
    };

    virtual ~ISystemControllerInterface() = default;

    virtual std::optional<std::string> sendMessage(const std::string& messageTitle,
                                                   const nlohmann::json& parameters) = 0;

    virtual bool registerRequestCallback(const Callbacks& callbacks) = 0;

    virtual bool connect() = 0;

    virtual bool disconnect() = 0;

    [[nodiscard]] virtual bool isConnected() const = 0;

    [[nodiscard]] virtual UUID getUUID() const = 0;
};

} // namespace Acl

template <> struct fmt::formatter<Acl::ISystemControllerInterface::StatusCode> : formatter<std::uint32_t> {
    template <typename FormatContext>
    auto format(Acl::ISystemControllerInterface::StatusCode code, FormatContext& ctx) {
        return formatter<std::uint32_t>::format(static_cast<uint32_t>(code), ctx);
    }
};

13 - include/MediaEnumerations.h

include/MediaEnumerations.h File Reference

Namespaces

Name
Acl

Classes

Name
structfmt::formatter< Acl::FieldOrder >
structfmt::formatter< Acl::AudioChannelLayout >

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <cstdint>
#include <ostream>

#include <fmt/format.h>

namespace Acl {

constexpr uint32_t makeFourCC(char a, char b, char c, char d) {
    return static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8) + (static_cast<uint32_t>(c) << 16) +
           (static_cast<uint32_t>(d) << 24);
}

enum PixelFormat : uint32_t {
    kUnknown = 0,                                // Unknown format
    kNv12 = Acl::makeFourCC('N', 'V', '1', '2'), // 4:2:0 format with Y plane followed by UVUVUV.. plane
    kUyvy = Acl::makeFourCC('U', 'Y', 'V', 'Y'), // 4:2:2 format with packed UYVY macropixels
    kP010 = Acl::makeFourCC('P', '0', '1', '0'), // 4:2:0 P016 with data in the 10 MSB
    kP016 = Acl::makeFourCC('P', '0', '1', '6'), // 4:2:0 format with 16 bit words, Y plane followed by UVUVUV.. plane
    kP210 = Acl::makeFourCC('P', '2', '1', '0'), // 4:2:2 P216 with data in the 10 MSB
    kP216 = Acl::makeFourCC('P', '2', '1', '6'), // 4:2:2 format with 16 bit words, Y plane followed by UVUVUV.. plane
    kRgba =
        Acl::makeFourCC('R', 'G', 'B', 'A'), // 4:4:4:4 RGB format, 8 bit per channel, ordered RGBARGBARG.. in memory
    kV210 = Acl::makeFourCC('V', '2', '1', '0'), // 4:2:2 packed format with 10 bit per component
    kRgba64Le =
        Acl::makeFourCC('R', 'G', 'B', 64) // 16 bit per component, ordered as RGBA in memory with little endian words.
};

std::ostream& operator<<(std::ostream& stream, const PixelFormat& pixelFormat);

enum class FieldOrder : uint8_t {
    kProgressive,     // No fields, i.e. progressive
    kTopFieldFirst,   // Interlaced frame with interleaved fields, top field first
    kBottomFieldFirst // Interlaced frame with interleaved fields, bottom field first
};

std::ostream& operator<<(std::ostream& stream, const FieldOrder& fieldOrder);

enum class AudioFormat : uint16_t {
    kInt16,     // 16 bits signed integer per sample
    kInt24In32, // 24 bits per sample, stored in the LSB of a 32-bit signed integer
    kFloat32    // 32 bit float per sample
};

std::ostream& operator<<(std::ostream& stream, const AudioFormat& audioFormat);

enum class AudioChannelLayout : uint8_t {
    kPlanar,     // The audio samples of each channel are in separate "planes", first comes all channel 1's samples,
                 // then channel 2 and so on.
    kInterleaved // The audio samples are interleaved, first comes sample one of each channel, then sample two, and
                 // so on.
};

std::ostream& operator<<(std::ostream& stream, const AudioChannelLayout& audioChannelLayout);

} // namespace Acl

template <> struct fmt::formatter<Acl::FieldOrder> : formatter<std::string> {
    template <typename FormatContext> auto format(const Acl::FieldOrder fieldOrder, FormatContext& ctx) {
        std::string value;
        switch (fieldOrder) {
        case Acl::FieldOrder::kProgressive:
            value = "progressive";
            break;
        case Acl::FieldOrder::kTopFieldFirst:
            value = "top_field_first";
            break;
        case Acl::FieldOrder::kBottomFieldFirst:
            value = "bottom_field_first";
            break;
        }
        return formatter<std::string>::format(value, ctx);
    }
};

template <> struct fmt::formatter<Acl::AudioChannelLayout> : formatter<std::string> {
    template <typename FormatContext>
    auto format(const Acl::AudioChannelLayout audioChannelLayout, FormatContext& ctx) {
        std::string value;
        switch (audioChannelLayout) {
        case Acl::AudioChannelLayout::kPlanar:
            value = "planar";
            break;
        case Acl::AudioChannelLayout::kInterleaved:
            value = "interleaved";
            break;
        }
        return formatter<std::string>::format(value, ctx);
    }
};

14 - include/MediaReceiver.h

include/MediaReceiver.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::MediaReceiver
A MediaReceiver contains the logic for receiving, decoding and aligning incoming media sources from the Ingests. The aligned data is then delivered to the Rendering Engine which is also responsible for setting up the MediaReceiver. The MediaReceiver has a builtin multi view generator, which can create output streams containing composited subsets of the incoming video sources. This class is controlled using an ISystemControllerInterface provided when starting it.
structAcl::MediaReceiver::NewStreamParameters
A struct containing information on the format of an incoming stream.
structAcl::MediaReceiver::CustomSystemControllerCallResponse
A struct containing the data returned from the Rendering Engine on a custom System Controller call, with information that will be propagated back to the System Controller and its client.
structAcl::MediaReceiver::Settings
Settings for a MediaReceiver.

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <memory>
#include <utility>

#include <cuda.h>

#include "AlignedFrame.h"
#include "ControlDataReceiver.h"
#include "ISystemControllerInterface.h"
#include "MediaStreamer.h"

namespace Acl {

class MediaReceiver {
public:
    struct NewStreamParameters {
        uint32_t mVideoHeight = 0;     // Height of the video in pixels. 0 if the stream does not contain any video
        uint32_t mVideoWidth = 0;      // Width of the video in pixels. 0 if the stream does not contain any video
        uint32_t mFrameRateN = 0;      // Frame rate numerator
        uint32_t mFrameRateD = 1;      // Frame rate denominator
        uint32_t mAudioSampleRate = 0; // Sample rate of the audio in Hz. 0 if the stream does not contain any audio
    };

    struct CustomSystemControllerCallResponse {
        ISystemControllerInterface::StatusCode mCode;
        nlohmann::json mParameters; // Only used if mCode == SUCCESS
        std::string mErrorMessage;  // Only used if mCode != SUCCESS
    };

    struct Settings {
        PixelFormat mDecodedFormat = PixelFormat::kRgba64Le;

        std::function<std::function<void(const AlignedFramePtr&)>(uint32_t inputSlot,
                                                                  const std::string& streamID,
                                                                  const NewStreamParameters& newStreamParameters)>
            mNewConnectionCallback;

        std::function<void(uint32_t inputSlot)> mClosedConnectionCallback;

        std::function<CustomSystemControllerCallResponse(const std::string& request, const nlohmann::json& parameters)>
            mCustomSystemControllerRequestCallback;

        bool mUseMultiViewer = false; 
        bool mDeliverOld = false;     

        CUstream mAlignedFrameFreeStream = nullptr;
    };

    enum class TallyBorderColor : uint32_t { kNone, kRed, kGreen, kYellow };

    MediaReceiver();

    ~MediaReceiver();

    bool start(const std::shared_ptr<ISystemControllerInterface>& controllerInterface,
               CUcontext cudaContext,
               const Settings& settings,
               const ControlDataReceiver::Settings& receiverSettings);

    void stop();

    std::function<void(const AlignedFramePtr&)>
    getCustomMultiViewSourceInput(uint32_t inputSlot, bool fixedFramerate, const std::string& name = "");

    bool removeCustomMultiViewSourceInput(uint32_t inputSlot);

    void clearCustomMultiViewSourceInputs();

    std::shared_ptr<IMediaStreamer> createMediaStreamerOutput(const MediaStreamer::Settings& settings);

    bool removeMediaStreamerOutput(const UUID& uuid);

    void clearMediaStreamerOutputs();

    std::shared_ptr<IControlDataReceiver> getControlDataReceiver();

    void setTallyBorder(uint32_t inputSlot, TallyBorderColor color);

    void clearTallyBorder(uint32_t inputSlot);

    void clearAllTallyBorders();

    [[nodiscard]] MediaReceiver::TallyBorderColor getTallyBorder(uint32_t inputSlot) const;

    MediaReceiver(MediaReceiver const&) = delete;            // Copy construct
    MediaReceiver(MediaReceiver&&) = delete;                 // Move construct
    MediaReceiver& operator=(MediaReceiver const&) = delete; // Copy assign
    MediaReceiver& operator=(MediaReceiver&&) = delete;      // Move assign

    static std::string getVersion();

    static std::string getLibraryVersions();

private:
    class Impl;
    std::unique_ptr<Impl> pImpl;
};

} // namespace Acl

15 - include/SystemControllerConnection.h

include/SystemControllerConnection.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::SystemControllerConnection
An implementation of the ISystemControllerInterface for a System controller residing in a remote server. The connection to the server uses a Websocket.
structAcl::SystemControllerConnection::Settings
Settings for a SystemControllerConnection.
structfmt::formatter< Acl::SystemControllerConnection::ComponentType >

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <chrono>

#include "ISystemControllerInterface.h"
#include "json.hpp"

namespace Acl {

class SystemControllerConnection final : public ISystemControllerInterface {
public:
    enum class ComponentType : uint32_t {
        kIngest,
        kPipeline,
        kControlPanel,
    };

    struct Settings {
        std::string mSystemControllerIP;      // IP of the server
        uint16_t mSystemControllerPort;       // Port of the server
        std::string mSystemControllerPostfix; // Postfix of the address that the backend uses if any
        std::string mPSK;    // The pre shared key used for authorization with the system controller server
        UUID mUUID;          // The UUID of the device using this library
        ComponentType mType; // The component type of the component using this SystemControllerConnection
        std::string mName;   // The component name (optional)
        std::string mMyIP;   // The external IP of the system the component is running on. Will be sent to the system
                             // controller server in the announce message (optional)
        std::chrono::milliseconds mConnectTimeout{
            3000};           // Max time to wait on an announcement response from the server during connection
        bool mEnableHTTPS;   // Enable the communication between the system controller and a component encrypted
        bool mInsecureHTTPS; // Disable the verification of the TLS certificate if requested.
        std::string mCustomCaCertFile; // Custom CA certificate
    };

    SystemControllerConnection();
    ~SystemControllerConnection() override;

    bool configure(const Settings& settings);

    bool connect() override;

    [[nodiscard]] bool isConnected() const override;

    [[nodiscard]] UUID getUUID() const override;

    std::optional<std::string> sendMessage(const std::string& messageTitle, const nlohmann::json& parameters) override;

    bool disconnect() override;

    bool registerRequestCallback(const Callbacks& callbacks) override;

    SystemControllerConnection(SystemControllerConnection const&) = delete;            // Copy construct
    SystemControllerConnection(SystemControllerConnection&&) = delete;                 // Move construct
    SystemControllerConnection& operator=(SystemControllerConnection const&) = delete; // Copy assign
    SystemControllerConnection& operator=(SystemControllerConnection&&) = delete;      // Move assign

private:
    class Impl;
    std::unique_ptr<Impl> pImpl;
};

} // namespace Acl

template <> struct fmt::formatter<Acl::SystemControllerConnection::ComponentType> : formatter<std::string> {
    template <typename FormatContext>
    auto format(Acl::SystemControllerConnection::ComponentType type, FormatContext& ctx) {
        std::string value;
        switch (type) {
        case Acl::SystemControllerConnection::ComponentType::kIngest:
            value = "ingest";
            break;
        case Acl::SystemControllerConnection::ComponentType::kPipeline:
            value = "pipeline";
            break;
        case Acl::SystemControllerConnection::ComponentType::kControlPanel:
            value = "controlpanel";
            break;
        }

        return formatter<std::string>::format(value, ctx);
    }
};

16 - include/TimeCommon.h

include/TimeCommon.h File Reference

Namespaces

Name
Acl
Acl::TimeCommon

Classes

Name
structAcl::TimeCommon::TAIStatus
structAcl::TimeCommon::TimeStructure

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <chrono>
#include <cstdint>
#include <fstream>
#include <sstream>

#include "expected.hpp"

namespace Acl {

namespace TimeCommon {

enum class StratumLevel {
    UnknownStratum,
    stratum0,
    stratum1,
    stratum2,
    stratum3,
    stratum4,
};

struct TAIStatus {
    StratumLevel mStratum = StratumLevel::UnknownStratum;
    bool mHasLock = false;
    double mTimeDiffS = 0.0; // Time diff vs NTP in seconds, +/- value means slow/faster than NTP time
};

// Little endian
// Minimum size packet is 64 - bytes
struct TimeStructure {
    uint64_t t1 = 0;     // 8-bytes / Total 8-bytes  == Client time T1
    uint64_t t2 = 0;     // 8-bytes / Total 16-bytes == Server
    uint64_t t3 = 0;     // 8-bytes / Total 24-bytes
    uint64_t t4 = 0;     // 8-bytes / Total 32-bytes
    uint64_t token = 0;  // 8-bytes / Total 40-bytes == t1 ^ key
    uint64_t dummy1 = 0; // 8-bytes / Total 48-bytes == for future use
    uint64_t dummy2 = 0; // 8-bytes / Total 56-bytes == for future use
    uint64_t dummy3 = 0; // 8-bytes / Total 64-bytes == for future use
};

uint64_t getMonotonicClockMicro();

tl::expected<TimeCommon::TAIStatus, std::string> getStatus();

int64_t getTAIMicro();

std::string taiMicroToString(int64_t taiTimestamp);
} // namespace TimeCommon

} // namespace Acl

17 - include/UUID.h

include/UUID.h File Reference

Namespaces

Name
Acl

Classes

Name
classAcl::UUID
A class holding a UUID, stored as a sequence of bytes. This class only supports version 4 variant 1 of the UUID standard.
structfmt::formatter< Acl::UUID >

Functions

Name
UUID()
Default constructor, returns a nil UUID.
constexprUUID(const std::array< uint8_t, kUUIDSize > & bytes)
Construct a UUID from a sequence of bytes.
UUIDgenerateRandom()
Create a new, randomly generated UUID.
std::optional< UUID >fromString(const std::string & uuid)
Parse a UUID from a string.
std::optional< UUID >fromVector(const std::vector< uint8_t >::const_iterator & start, const std::vector< uint8_t >::const_iterator & end)
Read a UUID from a vector of uint8s.
std::optional< UUID >fromPointer(const uint8_t * start, const uint8_t * end)
Read a UUID from a pointer.
std::stringtoString() const
std::stringtoBitString() const
booloperator==(const UUID & other) const
Compare this UUID to another UUID.
booloperator!=(const UUID & other) const
Compare this UUID to another UUID for inequality.
booloperator<(const UUID & other) const
Less than operator implementation.
std::array< uint8_t, kUUIDSize >::const_iteratorbegin() const
std::array< uint8_t, kUUIDSize >::const_iteratorend() const
constexpr size_tsize() const

Attributes

Name
constexpr size_tkUUIDSize
const UUIDkNilUUID
const UUIDkOmniUUID

Functions Documentation

function UUID

UUID()

Default constructor, returns a nil UUID.

function UUID

explicit constexpr UUID(
    const std::array< uint8_t, kUUIDSize > & bytes
)

Construct a UUID from a sequence of bytes.

Note: This will accept UUIDs that are not valid version 4 UUIDs.

function generateRandom

static UUID generateRandom()

Create a new, randomly generated UUID.

Return: A new, randomly generated UUID

function fromString

static std::optional< UUID > fromString(
    const std::string & uuid
)

Parse a UUID from a string.

Parameters:

  • uuid The string representation of the UUID

Return: An optional containing the UUID on success, or nullopt in case the parsing failed

function fromVector

static std::optional< UUID > fromVector(
    const std::vector< uint8_t >::const_iterator & start,
    const std::vector< uint8_t >::const_iterator & end
)

Read a UUID from a vector of uint8s.

Parameters:

  • start Start iterator to read the UUID from
  • end End iterator to read the UUID from, must be 16 bytes after start

Return: An optional containing the UUID on success, or nullopt in case the parsing failed

function fromPointer

static std::optional< UUID > fromPointer(
    const uint8_t * start,
    const uint8_t * end
)

Read a UUID from a pointer.

Parameters:

  • start Start pointer to read the UUID from
  • end End pointer to read the UUID from, must be 16 bytes after start

Return: An optional containing the UUID on success, or nullopt in case the parsing failed

function toString

std::string toString() const

Return: A string representation of the UUID formatted as hex values

function toBitString

std::string toBitString() const

Return: A string representation of the UUID formatted as bits

function operator==

bool operator==(
    const UUID & other
) const

Compare this UUID to another UUID.

Parameters:

  • other The other UUID to compare this UUID to

Return: True if the UUIDs are identical, false otherwise

function operator!=

bool operator!=(
    const UUID & other
) const

Compare this UUID to another UUID for inequality.

Parameters:

  • other The other UUID to compare this UUID to

Return: True if the UUIDs are not equal, false in case they are identical

function operator<

bool operator<(
    const UUID & other
) const

Less than operator implementation.

Parameters:

  • other The other UUID to compare this UUID to

Return: True if this UUID should be sorted before the other UUID

function begin

std::array< uint8_t, kUUIDSize >::const_iterator begin() const

Return: Begin iterator for the UUID byte sequence

function end

std::array< uint8_t, kUUIDSize >::const_iterator end() const

Return: End iterator for the UUID byte sequence

function size

constexpr size_t size() const

Return: The size in bytes of the UUID. Will always return 16

Attributes Documentation

variable kUUIDSize

static constexpr size_t kUUIDSize = 16;

variable kNilUUID

static const UUID kNilUUID;

variable kOmniUUID

static const UUID kOmniUUID;

Source code

// Copyright (c) 2024, Ateliere. All rights reserved.

#pragma once

#include <array>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>

#include <fmt/format.h>

namespace Acl {

class UUID {
public:
    static constexpr size_t kUUIDSize = 16;
    // Predefined UUID values
    static const UUID kNilUUID;
    static const UUID kOmniUUID;

    UUID();

    constexpr explicit UUID(const std::array<uint8_t, kUUIDSize>& bytes)
        : mUUID{bytes} {
    }

    static UUID generateRandom();

    static std::optional<UUID> fromString(const std::string& uuid);

    static std::optional<UUID> fromVector(const std::vector<uint8_t>::const_iterator& start,
                                          const std::vector<uint8_t>::const_iterator& end);

    static std::optional<UUID> fromPointer(const uint8_t* start, const uint8_t* end);

    [[nodiscard]] std::string toString() const;

    [[nodiscard]] std::string toBitString() const;

    bool operator==(const UUID& other) const;

    bool operator!=(const UUID& other) const;

    bool operator<(const UUID& other) const;

    [[nodiscard]] std::array<uint8_t, kUUIDSize>::const_iterator begin() const;

    [[nodiscard]] std::array<uint8_t, kUUIDSize>::const_iterator end() const;

    [[nodiscard]] constexpr size_t size() const {
        return mUUID.size();
    }

private:
    std::array<uint8_t, kUUIDSize> mUUID{};
} __attribute__((packed));

static_assert(sizeof(UUID) == 16, "UUID has unexpected size");

std::ostream& operator<<(std::ostream& stream, const UUID& uuid);

} // namespace Acl

template <> struct fmt::formatter<Acl::UUID> : formatter<std::string> {
    template <typename FormatContext> auto format(const Acl::UUID& uuid, FormatContext& ctx) {
        return formatter<std::string>::format(uuid.toString(), ctx);
    }
};