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

Commit 30404de

Browse files
authored
Merge pull request #721 from jianjunz/quic
Reland "Add an agent for WebTransport Support."
2 parents f899603 + 149b103 commit 30404de

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)