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

Commit b0f500a

Browse files
authored
Add an agent for WebTransport Support. (#113)
* Add RTCIceTransport and RTCIceCandidate. Change-Id: If39775bf3494bdceeef44846abfb775dbd4e8a65 * Add RTCQuicTransport. * Receive data from client. OnData event is not complied with spec. Fin is not respected. * Write data to QuicStream. * Add a task runner to call QUIC APIs. * Fix a memory leak issue. * Move QUIC to a separate directory. * Separate WebRTC and QUIC code. This experimental change makes WebRTC agent running QUIC code. We'll move QUIC to a standalone agent in future changes. * Add signaling support for publishing a QUIC stream. * Forwarding data through QUIC data channel. This change adds data filed to publication and subscription. * Adding interfaces for data pipeline in C++ level. * QuicStream implements FrameSource and FrameDestination. * Forward data in C++ level. * Add documentation for how to run server with QUIC enabled. * Update doc for CHROMIUM_HOME. * Fix argument issue for quicConnection.js. * Fix dependency issue during building. Certificate is not used right now, so we don't need to initialize SSL at this time. It removes its dependent to rtc_base. * Copy data during forwarding. QuicStringPiece may read freed buffer when write to transport. * Fix a memery leak issue. * Move QUIC transport to a standalone agent. * Add more files to QUIC agent. * QUIC agent can be started and stopped. * Enable unit tests for RTCIceTransport. * Add an implementation of P2PQuicPacketTransportInterface. * Refactor QUIC addon. Moving QUIC implementation to QUIC SDK. * Implement RTCQuicTransport::listen. * Enable write observer and read delegate. * Implement delegate for P2PQuicTransport. This commit also removes some unused files. * QuicStream is able to receive data. * Implement write for QuicStream. * Remove an EscapableHandleScope and add dtor for QuicStream. * Remove branch specific section for README.md. * Modify documentation for QUIC addon. * Remove patches for Chromium. QUIC addon depends on QUIC SDK now. Changes for Chromium will be performed in QUIC SDK repo. * Restore build configuration. We used to add QUIC as a feature for webrtc agent, but we decided to add a new QUIC agent for QUIC connections now. This change restores modifications for webrtc agent. * Exclude quic-agent from full package. Don't pack quic-agent by default because CI for QUIC SDK is not ready. So it cannot get the binary of QUIC SDK. * Restore changes made outside QUIC addon. * Adding QUIC agent. * Add QUIC subscription support. * Recover connections.js. * QUIC P2P multiplexing support. * Add QUIC transport server. * Rename QuicStream to RTCQuicStream. * Add QUIC transport streams. * QUIC transport server is able to receive data. * Quic transport server is able to send data. * Remove code for QUIC API for Peer-to-peer Connections. We will implement QuicTransport of WebTransport in server. * Make QUIC agent to build with node.js v12. * Add contentsessionid event for QuicTransportStream. This event is fired when a QuicTransportStream could be associated with a publication or subscription. Since server side defines session ID as a published stream ID or a subscription ID, we use `contentsessionid` here to distingulish it from Quic session. * Fix data is undefined. * Fix some issues to run QuicTransportServer in QUIC agent. * Use UUID for publication and subscription ID. UUID is better to be encoded for QuicTransport. This commit adds a new dependency: uuid. https://www.npmjs.com/package/uuid. * Parse the first 16 bytes of QuicStream as UUID. * Participants recieve notification when a data stream is added. * Stream info has data property. It indicates whether this is a data stream. * Add subscription support for QUIC agent. * Add support to subscribe data streams. * Linkup publications and subscriptions for data streams. * Enhance readme. * Enable data stream forwarding. * Enable authentication for QUIC transport. QUIC transport is authenticated by transport ID which is issued by the signaling module of portal. In the future, when QUIC transport is allowed for signaling, other authentication method should be used. A possible one is token, which is similar to the socket.io channel we are using today. * Remove P2P QUIC and code cleanup. * Don't pack QUIC agent by default. QUIC agent depends on QUIC SDK, which is not supported by testing system. * Add data source for linkup. * Add unit test for QuicTransportServer. * Fix build issues after rebasing. * Don't start quic-agent by default. * Clean up. * Close connection if no transport ID is received after 10s. * Update QuicFactory for QUIC SDK API change. * Address some format and naming issues. * Port number is configurable. * Change QUIC agent port configuration from a range to a value. QUIC agent always uses the minimal port number configured. So the range actually is not respected. * QUIC agent reads certificate path from configuration file. * Fix an issue introduced by rebasing. A new parameter was add for roomController.publish. * Remove unused flags from build script. * Fix race conditions by minimizing lock usages. * Tokens have URL for WebTransport connections. A new property webTransportUrl is added to tokens if a QUIC agent is running. * Add token for WebTransport in the response of join. No update for tests for portal because it looks like no check in or night testing is running the test code, and some cases are failed in my development environment. * Authenticate WebTransport connections with tokens. Tokens are issued by portal after joining. QUIC agent asks portal for authentication. * Fix issues for publications after rebasing. * Fix publish method after rebasing. Server can detect new streams from QUIC agent, but this change breaks rtcController and stream events sent from server don't have "data" property. These issues along with other subscribe issues will be fixed in following commits. * Fix subscribe method after rebasing. * Separate rtcController and quicController. Conference sessions over QUIC used to be handled by accessController. But a recent change added rtcController, moved some logicals out of accessController. So we need to either have a quicController or extend rtcController or accessController. This change adds a quicController. However, it would be better to redesign the interface of *Controller, and create a single controller for each conference. * Fix WebRTC agent. Changes for adding WebTransport support broken WebRTC agent. This change fixes these issues. * Add back origin info. Don't know why origin is a property of media. Add it to publish info and subscribe info. * Terminate a session returns a promise. A session might be managed by rtcController or quicController, since accessController doesn't know a session's type, try to terminate it in either rtcControoler or quicController. * Add a configuration item to disable WebTransport support. * Restore v11Client.js. Protocol version was upgraded to v1.2. We don't need to touch v1.1 protocol handler. * Add a guide for WebTransport. * Clean up. * Address comments.
1 parent facc5d2 commit b0f500a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+9281
-235
lines changed

doc/servermd/WebTransportGuide.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Open WebRTC Toolkit WebTransport Support
2+
3+
## Overview
4+
5+
Open WebRTC Toolkit (OWT) added [WebTransport](https://w3c.github.io/webtransport/) over [QUIC](https://tools.ietf.org/html/draft-ietf-quic-transport-32) support since 5.0. At this moment, it only supports simple data forwarding.
6+
7+
WebTransport over other protocols are not support.
8+
9+
## Streams
10+
11+
Similar to media streams, a stream for arbitrary data also supports `publish` and `subscribe`. A new property `data` is added to indicate if a stream is for arbitrary data. Media features like mixing and transcoding are not supported. If you develop client applications without OWT Client SDKs, please refer to [PR 125](https://github.com/open-webrtc-toolkit/owt-server/pull/125) for protocol changes and payload format. OWT JavaScript SDK and C++ SDK support streams for arbitrary data, please see API references of these two SDKs for newly added APIs. Basically, client side creates data streams, then `publish` and `subscribe` just as media streams. `streamadded` event also fires for data streams.
12+
13+
## QUIC agent
14+
15+
QUIC agent handles WebTransport connections from clients. It depends on [OWT QUIC SDK](https://github.com/open-webrtc-toolkit/owt-deps-quic). By default, it listens on 7700 port. Only one instance is running on a single machine or a docker environment.
16+
17+
## Roadmap
18+
19+
We are planning to support follow features, but we don't have an ETA so far.
20+
21+
- Signaling over QUIC. Instead of creating a WebSocket connection between a client and portal, we could use a WebTransport connection for both signaling and other data.
22+
- Media over QUIC. Sending and receiving audio and video data over QUIC instead of WebRTC.
23+
- Datagram support. Datagram support with FEC and NACK may help us to reduce the latency when sending media over QUIC.

scripts/build.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,4 @@ Promise.all(works)
170170
let checkOutput = execSync(`node ${moduleTestScript} ${runtimeAddonDir}`).toString();
171171
console.log(checkOutput);
172172
}
173-
});
173+
});

scripts/build.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@
4949
"webrtc-frame"
5050
]
5151
},
52+
"mcu-quic": {
53+
"include":[
54+
"mcu",
55+
"quic"
56+
]
57+
},
5258
"video-mixer-sw" : {
5359
"path" : "source/agent/video/videoMixer/videoMixer_sw",
5460
"gyp" : "binding.sw.gyp"
@@ -111,5 +117,9 @@
111117
},
112118
"resource-util" : {
113119
"path" : "source/agent/addons/resourceUtil"
120+
},
121+
"quic" : {
122+
"path" : "source/agent/addons/quic",
123+
"description": "QUIC agent supports WebTransport - QuicTransport connections. Experimental feature."
114124
}
115125
}

scripts/pack.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ const originCwd = cwd();
4040
const osScript = path.join(rootDir, 'scripts/detectOS.sh');
4141
const osType = execSync(`bash ${osScript}`).toString().toLowerCase();
4242

43+
const experimentalTargets = ['quic-agent'];
44+
4345
var allTargets = [];
4446

4547
if (options.full) {
@@ -131,7 +133,8 @@ function getPackList(targets) {
131133
}
132134

133135
var packList = targets.filter((element) => {
134-
if (options.target.includes('all')) return true;
136+
// Don't include QUIC agent by default until CI is added for QUIC SDK.
137+
if (options.target.includes('all') && !experimentalTargets.includes(element.rules.name)) return true;
135138
return options.target.includes(element.rules.name);
136139
});
137140
if (packList.length === 0) {
@@ -598,6 +601,9 @@ function packScripts() {
598601
}
599602
scriptItems.push('app');
600603
scriptItems.forEach((m) => {
604+
if (experimentalTargets.includes(m)) {
605+
return;
606+
}
601607
startCommands += '${bin}/daemon.sh start ' + m + ' $1\n';
602608
stopCommands += '${bin}/daemon.sh stop ' + m + '\n';
603609
});

scripts/release/daemon-bin.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ case $startStop in
169169
> "${stdout}" 2>&1 </dev/null &
170170
echo $! > ${pid}
171171
;;
172+
quic-agent )
173+
cd ${OWT_HOME}/quic_agent
174+
export LD_LIBRARY_PATH=./lib:${LD_LIBRARY_PATH}
175+
nohup nice -n ${OWT_NICENESS} ./OWT-MCU-Agent . -U quic\
176+
> "${stdout}" 2>&1 </dev/null &
177+
echo $! > ${pid}
178+
;;
172179
management-console )
173180
cd ${OWT_HOME}/management_console
174181
nohup nice -n ${OWT_NICENESS} node . \

scripts/release/daemon-mcu.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ case $startStop in
169169
> "${stdout}" 2>&1 </dev/null &
170170
echo $! > ${pid}
171171
;;
172+
quic-agent )
173+
cd ${OWT_HOME}/quic_agent
174+
export LD_LIBRARY_PATH=./lib:${LD_LIBRARY_PATH}
175+
nohup nice -n ${OWT_NICENESS} node . -U quic\
176+
> "${stdout}" 2>&1 </dev/null &
177+
echo $! > ${pid}
178+
;;
172179
analytics-agent )
173180
cd ${OWT_HOME}/analytics_agent
174181
export LD_LIBRARY_PATH=./lib:${LD_LIBRARY_PATH}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (C) 2019 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "QuicFactory.h"
8+
#include "owt/quic/quic_transport_factory.h"
9+
#include <mutex>
10+
11+
DEFINE_LOGGER(QuicFactory, "QuicFactory");
12+
13+
std::once_flag getQuicFactoryOnce;
14+
15+
std::shared_ptr<QuicFactory> QuicFactory::s_quicFactory = nullptr;
16+
17+
QuicFactory::QuicFactory()
18+
: m_quicTransportFactory(std::shared_ptr<owt::quic::QuicTransportFactory>(owt::quic::QuicTransportFactory::Create()))
19+
{
20+
}
21+
22+
std::shared_ptr<owt::quic::QuicTransportFactory> QuicFactory::getQuicTransportFactory()
23+
{
24+
std::call_once(getQuicFactoryOnce, []() {
25+
QuicFactory* factory = new QuicFactory();
26+
s_quicFactory = std::shared_ptr<QuicFactory>(factory);
27+
});
28+
return s_quicFactory->m_quicTransportFactory;
29+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (C) 2019 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef QUIC_QUICFACTORY_H_
8+
#define QUIC_QUICFACTORY_H_
9+
10+
#include <memory>
11+
#include <logger.h>
12+
13+
namespace owt {
14+
namespace quic {
15+
class QuicTransportFactory;
16+
}
17+
}
18+
19+
class QuicFactory {
20+
public:
21+
DECLARE_LOGGER();
22+
virtual ~QuicFactory() = default;
23+
static std::shared_ptr<owt::quic::QuicTransportFactory> getQuicTransportFactory();
24+
25+
private:
26+
explicit QuicFactory();
27+
28+
static std::shared_ptr<QuicFactory> s_quicFactory;
29+
std::shared_ptr<owt::quic::QuicTransportFactory> m_quicTransportFactory;
30+
};
31+
32+
#endif
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright (C) 2020 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "QuicTransportConnection.h"
8+
#include "QuicTransportStream.h"
9+
10+
using v8::Function;
11+
using v8::FunctionTemplate;
12+
using v8::Local;
13+
using v8::Object;
14+
using v8::ObjectTemplate;
15+
using v8::Value;
16+
17+
Nan::Persistent<v8::Function> QuicTransportConnection::s_constructor;
18+
19+
DEFINE_LOGGER(QuicTransportConnection, "QuicTransportConnection");
20+
21+
QuicTransportConnection::QuicTransportConnection()
22+
: m_session(nullptr)
23+
, m_visitor(nullptr)
24+
{
25+
}
26+
27+
QuicTransportConnection::~QuicTransportConnection()
28+
{
29+
if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(&m_asyncOnStream))) {
30+
uv_close(reinterpret_cast<uv_handle_t*>(&m_asyncOnStream), NULL);
31+
}
32+
m_session->SetVisitor(nullptr);
33+
}
34+
35+
NAN_MODULE_INIT(QuicTransportConnection::init)
36+
{
37+
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(newInstance);
38+
tpl->SetClassName(Nan::New("QuicTransportConnection").ToLocalChecked());
39+
Local<ObjectTemplate> instanceTpl = tpl->InstanceTemplate();
40+
instanceTpl->SetInternalFieldCount(1);
41+
42+
Nan::SetPrototypeMethod(tpl, "createBidirectionalStream", createBidirectionalStream);
43+
44+
s_constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked());
45+
Nan::Set(target, Nan::New("QuicTransportConnection").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());
46+
}
47+
48+
void QuicTransportConnection::setVisitor(Visitor* visitor)
49+
{
50+
m_visitor = visitor;
51+
}
52+
53+
void QuicTransportConnection::OnIncomingStream(owt::quic::QuicTransportStreamInterface* stream)
54+
{
55+
ELOG_DEBUG("OnIncomingStream.");
56+
{
57+
std::lock_guard<std::mutex> lock(m_streamQueueMutex);
58+
m_streamsToBeNotified.push(stream);
59+
}
60+
m_asyncOnStream.data = this;
61+
uv_async_send(&m_asyncOnStream);
62+
}
63+
64+
void QuicTransportConnection::onEnded()
65+
{
66+
}
67+
68+
NAN_METHOD(QuicTransportConnection::newInstance)
69+
{
70+
if (!info.IsConstructCall()) {
71+
ELOG_DEBUG("Not construct call.");
72+
return;
73+
}
74+
QuicTransportConnection* obj = new QuicTransportConnection();
75+
obj->Wrap(info.This());
76+
uv_async_init(uv_default_loop(), &obj->m_asyncOnStream, &QuicTransportConnection::onStreamCallback);
77+
info.GetReturnValue().Set(info.This());
78+
}
79+
80+
v8::Local<v8::Object> QuicTransportConnection::newInstance(owt::quic::QuicTransportSessionInterface* session)
81+
{
82+
Local<Object> connectionObject = Nan::NewInstance(Nan::New(QuicTransportConnection::s_constructor)).ToLocalChecked();
83+
QuicTransportConnection* obj = Nan::ObjectWrap::Unwrap<QuicTransportConnection>(connectionObject);
84+
obj->m_session = session;
85+
return connectionObject;
86+
}
87+
88+
NAUV_WORK_CB(QuicTransportConnection::onStreamCallback)
89+
{
90+
ELOG_DEBUG("OnStreamCallback.");
91+
Nan::HandleScope scope;
92+
QuicTransportConnection* obj = reinterpret_cast<QuicTransportConnection*>(async->data);
93+
if (obj == nullptr || obj->m_streamsToBeNotified.empty()) {
94+
return;
95+
}
96+
while (!obj->m_streamsToBeNotified.empty()) {
97+
obj->m_streamQueueMutex.lock();
98+
auto quicStream=obj->m_streamsToBeNotified.front();
99+
obj->m_streamsToBeNotified.pop();
100+
obj->m_streamQueueMutex.unlock();
101+
v8::Local<v8::Object> streamObject = QuicTransportStream::newInstance(quicStream);
102+
QuicTransportStream* stream = Nan::ObjectWrap::Unwrap<QuicTransportStream>(streamObject);
103+
quicStream->SetVisitor(stream);
104+
Nan::MaybeLocal<v8::Value> onEvent = Nan::Get(obj->handle(), Nan::New<v8::String>("onincomingstream").ToLocalChecked());
105+
if (!onEvent.IsEmpty()) {
106+
v8::Local<v8::Value> onEventLocal = onEvent.ToLocalChecked();
107+
if (onEventLocal->IsFunction()) {
108+
v8::Local<v8::Function> eventCallback = onEventLocal.As<Function>();
109+
Nan::AsyncResource* resource = new Nan::AsyncResource(Nan::New<v8::String>("onincomingstream").ToLocalChecked());
110+
Local<Value> args[] = { streamObject };
111+
resource->runInAsyncScope(Nan::GetCurrentContext()->Global(), eventCallback, 1, args);
112+
}
113+
} else {
114+
ELOG_DEBUG("onEvent is empty");
115+
}
116+
}
117+
}
118+
119+
NAN_METHOD(QuicTransportConnection::createBidirectionalStream){
120+
QuicTransportConnection* obj = Nan::ObjectWrap::Unwrap<QuicTransportConnection>(info.Holder());
121+
auto stream=obj->m_session->CreateBidirectionalStream();
122+
v8::Local<v8::Object> streamObject = QuicTransportStream::newInstance(stream);
123+
info.GetReturnValue().Set(streamObject);
124+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (C) 2020 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef QUIC_QUICTRANSPORTCONNECTION_H_
8+
#define QUIC_QUICTRANSPORTCONNECTION_H_
9+
10+
#include <memory>
11+
#include <mutex>
12+
#include <unordered_map>
13+
#include <vector>
14+
15+
#include <logger.h>
16+
#include <nan.h>
17+
18+
#include "QuicTransportStream.h"
19+
#include "owt/quic/quic_transport_session_interface.h"
20+
21+
class QuicTransportConnection : public Nan::ObjectWrap, public owt::quic::QuicTransportSessionInterface::Visitor, QuicTransportStream::Visitor {
22+
DECLARE_LOGGER();
23+
24+
public:
25+
class Visitor {
26+
// Authentication passed with user ID `id`.
27+
virtual void onAuthentication(const std::string& id) = 0;
28+
// Connection is closed.
29+
virtual void onClose() = 0;
30+
};
31+
explicit QuicTransportConnection();
32+
~QuicTransportConnection();
33+
void setVisitor(Visitor* visitor);
34+
static v8::Local<v8::Object> newInstance(owt::quic::QuicTransportSessionInterface* session);
35+
36+
static NAN_MODULE_INIT(init);
37+
static NAN_METHOD(newInstance);
38+
static NAN_METHOD(createBidirectionalStream);
39+
static NAUV_WORK_CB(onStreamCallback);
40+
41+
static Nan::Persistent<v8::Function> s_constructor;
42+
43+
protected:
44+
// Overrides owt::quic::QuicTransportSessionInterface::Visitor.
45+
void OnIncomingStream(owt::quic::QuicTransportStreamInterface*) override;
46+
void OnCanCreateNewOutgoingStream(bool unidirectional) override { }
47+
48+
// Overrides QuicTransportStream::Visitor.
49+
void onEnded() override;
50+
51+
private:
52+
owt::quic::QuicTransportSessionInterface* m_session;
53+
Visitor* m_visitor;
54+
// Key is content session ID, i.e.: publication ID, subscription ID.
55+
std::unordered_map<std::string, std::unique_ptr<QuicTransportStream>> m_streams;
56+
// Move to `m_streams` after associate with a publication or subscription.
57+
std::vector<std::unique_ptr<QuicTransportStream>> m_unassociatedStreams;
58+
59+
uv_async_t m_asyncOnStream;
60+
std::mutex m_streamQueueMutex;
61+
std::queue<owt::quic::QuicTransportStreamInterface*> m_streamsToBeNotified;
62+
};
63+
64+
#endif

0 commit comments

Comments
 (0)