Skip to content
This repository has been archived by the owner on Oct 23, 2024. It is now read-only.

Add plugin mechanism for QUIC agent. #1010

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
178 changes: 178 additions & 0 deletions doc/servermd/QuicAgentPluginDataflow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions doc/servermd/QuicAgentPluginGuide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Introduction
QUIC agent plays the role as a WebTransport server. It's intended to establish WebTransport connections with clients, send and receive arbitrary data to and from clients. The data received from client can be piped to another agent for audio or video processing, or simply forward to another clients. QUIC agent plugin mechanism allows developers to process data before it's delivered to the next node.

# Dataflow
The picture below shows how data flows for a single publication when QUIC agent plugin is enabled.

![QUIC agent plugin dataflow](QuicAgentPluginDataflow.svg)

# Development
To develop a QUIC agent plugin, please implement the interface defined in `source/agent/addons/quic/plugins/QuicAgentPluginInterface.h` and compile your code as a shared library. It's highly recommend to compile your plugin with the same toolchain as OWT conference server, although sometimes it works even they are compiled with different toolchains.

# Deployment
To deploy your plugin to a QUIC agent, please update the value of `pluginPath` in QUIC agent's agent.toml. It will take effect next time QUIC agent boots.
97 changes: 97 additions & 0 deletions source/agent/addons/quic/plugins/QuicAgentPluginInterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

/*
* A plugin instance (PluginInterface) is created when the QUIC agent is
* started. A data processor (ProcessorInterface) is created when a new pipeline
* (publication - subscription pair) is created.
*
* See doc/servermd/QuicAgentPluginGuide.md for detailed information.
*/

#ifndef QUIC_QUICAGENTPLUGININTERFACE_H_
#define QUIC_QUICAGENTPLUGININTERFACE_H_

#include <cstdint>

// Most classes of addons don't have a namespace. Because developers may need to include this file when develop plugins, we add a namespace for it to avoid potential conflicts.
namespace owt {
namespace quic_agent_plugin {
// Connection types for source and sink.
enum class ConnectionType {
kUnknown = 0,
// A WebTransport connection usually means a connection between client and server.
kWebTransport,
// An internal connection is a connection between different agents.
kInternalConnection,
};

// This struct represents a data flow's information.
// See https://github.com/open-webrtc-toolkit/owt-server/blob/master/doc/Client-Portal%20Protocol.md for definitions of publication and subscription.
struct ConnectionInfo {
const ConnectionType type;
// Publication ID or subscription ID.
const char* id;
};

// A frame received of sent by QUIC agent. It's not a QUIC stream frame defined in QUIC spec.
struct Frame {
// Create a frame.
static Frame* Create();
// Delete the frame.
void Dispose();
// Payload of the frame.
uint8_t* payload;
// Payload's length.
uint32_t length;

private:
Frame();
virtual ~Frame();
};

// Interface for data processors.
class ProcessorInterface {
public:
virtual ~ProcessorInterface() = default;
// Invoked when a new subscription is requested for the publication associated with this processor.
virtual void AddSink(const FrameSink& sink);
// Invoked when a new frame is available. Ownership of `frame` is moved to processor. `frame` will not be sent back to the pipeline. If you need the frame to be delivered to the next node, please call `FrameSink`'s `deliverFrame` method explicitly.
virtual void OnFrame(Frame* frame);
// Invoked when a new feedback is available. Ownership of `feedback` is moved to processor. `feedback` will not be sent back to the pipeline. If you need the frame to be delivered to the next node, please call `FrameSource`'s `deliverFeedback` method explicitly.
virtual void OnFeedback(Frame* feedback);
};

class FrameSource {
public:
virtual ~FrameSource() = default;
// Call this function when a new feedback is ready to be delivered to the next node. Ownership of `feedback` is moved to the next node.
virtual void DeliverFeedback(Frame* feedback);
// Get publication infomation.
virtual const ConnectionInfo& ConnectionInfo() const;
};

class FrameSink {
public:
virtual ~FrameSink() = default;
// Call this function when a new frame is ready to be delivered to the next node. Ownership of `frame` is moved to the next node.
virtual void DeliverFrame(Frame* frame);
// Get subscription infomation.
virtual const ConnectionInfo& ConnectionInfo() const;
};

// The interface for QUIC agent plugins. It allows developers to process data received or sent by QUIC agent.
class PluginInterface {
public:
virtual ~PluginInterface() = default;
// Create a data processor for a newly created data source. This method will be invoked when a new data source is created in QUIC agent. Returns nullptr if you don't need a processor for this source.
virtual ProcessorInterface* CreateDataProcessor(const FrameSource& source);
// Other methods for loading a shared library.
};
}
}

#endif
5 changes: 4 additions & 1 deletion source/agent/quic/agent.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,7 @@ keystorePath = "./cert/certificate.pfx"
port = 7700 #default: 7700

# FQDN of QUIC agent. It's included in WebTransport tokens as a part of the WebTransport URL client connects to. IP address will be included in WebTransport tokens if hostname is empty.
hostname = ""
hostname = ""

# Path to QUIC agent plugin. Plugin is enabled only when the value is not an empty string. Default: "".
pluginPath = ""