blob: 05f7414bc0c5c086a1481ad8645adf17bfc542a5 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2013 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
11// This file contains Macros for creating proxies for webrtc MediaStream and
12// PeerConnection classes.
deadbeefb10f32f2017-02-08 01:38:21 -080013// TODO(deadbeef): Move this to pc/; this is part of the implementation.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014
15//
16// Example usage:
17//
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000018// class TestInterface : public rtc::RefCountInterface {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019// public:
20// std::string FooA() = 0;
21// std::string FooB(bool arg1) const = 0;
nisse72c8d2b2016-04-15 03:49:07 -070022// std::string FooC(bool arg1) = 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000023// };
24//
25// Note that return types can not be a const reference.
26//
27// class Test : public TestInterface {
28// ... implementation of the interface.
29// };
30//
31// BEGIN_PROXY_MAP(Test)
deadbeefd99a2002017-01-18 08:55:23 -080032// PROXY_SIGNALING_THREAD_DESTRUCTOR()
henrike@webrtc.org28e20752013-07-10 00:45:36 +000033// PROXY_METHOD0(std::string, FooA)
34// PROXY_CONSTMETHOD1(std::string, FooB, arg1)
nisse72c8d2b2016-04-15 03:49:07 -070035// PROXY_WORKER_METHOD1(std::string, FooC, arg1)
deadbeefd99a2002017-01-18 08:55:23 -080036// END_PROXY_MAP()
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037//
deadbeefd99a2002017-01-18 08:55:23 -080038// Where the destructor and first two methods are invoked on the signaling
39// thread, and the third is invoked on the worker thread.
nisse72c8d2b2016-04-15 03:49:07 -070040//
41// The proxy can be created using
42//
43// TestProxy::Create(Thread* signaling_thread, Thread* worker_thread,
44// TestInterface*).
45//
46// The variant defined with BEGIN_SIGNALING_PROXY_MAP is unaware of
47// the worker thread, and invokes all methods on the signaling thread.
deadbeefd99a2002017-01-18 08:55:23 -080048//
49// The variant defined with BEGIN_OWNED_PROXY_MAP does not use
50// refcounting, and instead just takes ownership of the object being proxied.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000051
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020052#ifndef API_PROXY_H_
53#define API_PROXY_H_
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054
kwibergd1fe2812016-04-27 06:47:29 -070055#include <memory>
Yves Gerey3e707812018-11-28 16:47:49 +010056#include <string>
Steve Antonc3639822019-11-26 15:27:50 -080057#include <tuple>
Tomas Gunnarsson0ca13d92020-06-10 12:17:50 +020058#include <type_traits>
oprypin803dc292017-02-01 01:55:59 -080059#include <utility>
kwibergd1fe2812016-04-27 06:47:29 -070060
Mirko Bonadeid9708072019-01-25 20:26:48 +010061#include "api/scoped_refptr.h"
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +020062#include "api/task_queue/queued_task.h"
63#include "api/task_queue/task_queue_base.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020064#include "rtc_base/event.h"
Steve Anton10542f22019-01-11 09:11:00 -080065#include "rtc_base/message_handler.h"
Steve Anton10542f22019-01-11 09:11:00 -080066#include "rtc_base/ref_counted_object.h"
Mirko Bonadei35214fc2019-09-23 14:54:28 +020067#include "rtc_base/system/rtc_export.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020068#include "rtc_base/thread.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069
Yves Gerey3e707812018-11-28 16:47:49 +010070namespace rtc {
71class Location;
72}
73
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074namespace webrtc {
75
Guido Urdanetaccab06f2020-01-15 11:30:29 +000076template <typename R>
77class ReturnType {
78 public:
79 template <typename C, typename M, typename... Args>
80 void Invoke(C* c, M m, Args&&... args) {
81 r_ = (c->*m)(std::forward<Args>(args)...);
82 }
83
84 R moved_result() { return std::move(r_); }
85
86 private:
87 R r_;
88};
89
90template <>
91class ReturnType<void> {
92 public:
93 template <typename C, typename M, typename... Args>
94 void Invoke(C* c, M m, Args&&... args) {
95 (c->*m)(std::forward<Args>(args)...);
96 }
97
98 void moved_result() {}
99};
100
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000101template <typename C, typename R, typename... Args>
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +0200102class MethodCall : public QueuedTask {
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000103 public:
104 typedef R (C::*Method)(Args...);
105 MethodCall(C* c, Method m, Args&&... args)
106 : c_(c),
107 m_(m),
108 args_(std::forward_as_tuple(std::forward<Args>(args)...)) {}
109
110 R Marshal(const rtc::Location& posted_from, rtc::Thread* t) {
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +0200111 if (t->IsCurrent()) {
112 Invoke(std::index_sequence_for<Args...>());
113 } else {
114 t->PostTask(std::unique_ptr<QueuedTask>(this));
115 event_.Wait(rtc::Event::kForever);
116 }
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000117 return r_.moved_result();
118 }
119
120 private:
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +0200121 bool Run() override {
122 Invoke(std::index_sequence_for<Args...>());
123 event_.Set();
124 return false;
125 }
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000126
127 template <size_t... Is>
128 void Invoke(std::index_sequence<Is...>) {
129 r_.Invoke(c_, m_, std::move(std::get<Is>(args_))...);
130 }
131
132 C* c_;
133 Method m_;
134 ReturnType<R> r_;
135 std::tuple<Args&&...> args_;
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +0200136 rtc::Event event_;
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000137};
138
139template <typename C, typename R, typename... Args>
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +0200140class ConstMethodCall : public QueuedTask {
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000141 public:
142 typedef R (C::*Method)(Args...) const;
143 ConstMethodCall(const C* c, Method m, Args&&... args)
144 : c_(c),
145 m_(m),
146 args_(std::forward_as_tuple(std::forward<Args>(args)...)) {}
147
148 R Marshal(const rtc::Location& posted_from, rtc::Thread* t) {
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +0200149 if (t->IsCurrent()) {
150 Invoke(std::index_sequence_for<Args...>());
151 } else {
152 t->PostTask(std::unique_ptr<QueuedTask>(this));
153 event_.Wait(rtc::Event::kForever);
154 }
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000155 return r_.moved_result();
156 }
157
158 private:
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +0200159 bool Run() override {
160 Invoke(std::index_sequence_for<Args...>());
161 event_.Set();
162 return false;
163 }
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000164
165 template <size_t... Is>
166 void Invoke(std::index_sequence<Is...>) {
167 r_.Invoke(c_, m_, std::move(std::get<Is>(args_))...);
168 }
169
170 const C* c_;
171 Method m_;
172 ReturnType<R> r_;
173 std::tuple<Args&&...> args_;
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +0200174 rtc::Event event_;
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000175};
176
deadbeefd99a2002017-01-18 08:55:23 -0800177// Helper macros to reduce code duplication.
deadbeefe814a0d2017-02-25 18:15:09 -0800178#define PROXY_MAP_BOILERPLATE(c) \
179 template <class INTERNAL_CLASS> \
180 class c##ProxyWithInternal; \
181 typedef c##ProxyWithInternal<c##Interface> c##Proxy; \
182 template <class INTERNAL_CLASS> \
183 class c##ProxyWithInternal : public c##Interface { \
184 protected: \
185 typedef c##Interface C; \
186 \
187 public: \
188 const INTERNAL_CLASS* internal() const { return c_; } \
189 INTERNAL_CLASS* internal() { return c_; }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190
Yves Gerey665174f2018-06-19 15:03:05 +0200191// clang-format off
192// clang-format would put the semicolon alone,
193// leading to a presubmit error (cpplint.py)
oprypin803dc292017-02-01 01:55:59 -0800194#define END_PROXY_MAP() \
195 };
Yves Gerey665174f2018-06-19 15:03:05 +0200196// clang-format on
oprypin803dc292017-02-01 01:55:59 -0800197
deadbeefd99a2002017-01-18 08:55:23 -0800198#define SIGNALING_PROXY_MAP_BOILERPLATE(c) \
199 protected: \
200 c##ProxyWithInternal(rtc::Thread* signaling_thread, INTERNAL_CLASS* c) \
201 : signaling_thread_(signaling_thread), c_(c) {} \
202 \
203 private: \
204 mutable rtc::Thread* signaling_thread_;
205
206#define WORKER_PROXY_MAP_BOILERPLATE(c) \
207 protected: \
208 c##ProxyWithInternal(rtc::Thread* signaling_thread, \
209 rtc::Thread* worker_thread, INTERNAL_CLASS* c) \
210 : signaling_thread_(signaling_thread), \
211 worker_thread_(worker_thread), \
212 c_(c) {} \
213 \
214 private: \
215 mutable rtc::Thread* signaling_thread_; \
216 mutable rtc::Thread* worker_thread_;
217
218// Note that the destructor is protected so that the proxy can only be
219// destroyed via RefCountInterface.
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000220#define REFCOUNTED_PROXY_MAP_BOILERPLATE(c) \
221 protected: \
222 ~c##ProxyWithInternal() { \
223 MethodCall<c##ProxyWithInternal, void> call( \
224 this, &c##ProxyWithInternal::DestroyInternal); \
225 call.Marshal(RTC_FROM_HERE, destructor_thread()); \
226 } \
227 \
228 private: \
229 void DestroyInternal() { c_ = nullptr; } \
deadbeefd99a2002017-01-18 08:55:23 -0800230 rtc::scoped_refptr<INTERNAL_CLASS> c_;
231
deadbeefe814a0d2017-02-25 18:15:09 -0800232// Note: This doesn't use a unique_ptr, because it intends to handle a corner
233// case where an object's deletion triggers a callback that calls back into
234// this proxy object. If relying on a unique_ptr to delete the object, its
235// inner pointer would be set to null before this reentrant callback would have
236// a chance to run, resulting in a segfault.
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000237#define OWNED_PROXY_MAP_BOILERPLATE(c) \
238 public: \
239 ~c##ProxyWithInternal() { \
240 MethodCall<c##ProxyWithInternal, void> call( \
241 this, &c##ProxyWithInternal::DestroyInternal); \
242 call.Marshal(RTC_FROM_HERE, destructor_thread()); \
243 } \
244 \
245 private: \
246 void DestroyInternal() { delete c_; } \
deadbeefe814a0d2017-02-25 18:15:09 -0800247 INTERNAL_CLASS* c_;
deadbeefd99a2002017-01-18 08:55:23 -0800248
249#define BEGIN_SIGNALING_PROXY_MAP(c) \
250 PROXY_MAP_BOILERPLATE(c) \
251 SIGNALING_PROXY_MAP_BOILERPLATE(c) \
252 REFCOUNTED_PROXY_MAP_BOILERPLATE(c) \
253 public: \
254 static rtc::scoped_refptr<c##ProxyWithInternal> Create( \
255 rtc::Thread* signaling_thread, INTERNAL_CLASS* c) { \
256 return new rtc::RefCountedObject<c##ProxyWithInternal>(signaling_thread, \
257 c); \
258 }
259
260#define BEGIN_PROXY_MAP(c) \
261 PROXY_MAP_BOILERPLATE(c) \
262 WORKER_PROXY_MAP_BOILERPLATE(c) \
263 REFCOUNTED_PROXY_MAP_BOILERPLATE(c) \
264 public: \
265 static rtc::scoped_refptr<c##ProxyWithInternal> Create( \
266 rtc::Thread* signaling_thread, rtc::Thread* worker_thread, \
267 INTERNAL_CLASS* c) { \
268 return new rtc::RefCountedObject<c##ProxyWithInternal>(signaling_thread, \
269 worker_thread, c); \
270 }
271
deadbeefe814a0d2017-02-25 18:15:09 -0800272#define BEGIN_OWNED_PROXY_MAP(c) \
273 PROXY_MAP_BOILERPLATE(c) \
274 WORKER_PROXY_MAP_BOILERPLATE(c) \
275 OWNED_PROXY_MAP_BOILERPLATE(c) \
276 public: \
277 static std::unique_ptr<c##Interface> Create( \
278 rtc::Thread* signaling_thread, rtc::Thread* worker_thread, \
279 std::unique_ptr<INTERNAL_CLASS> c) { \
280 return std::unique_ptr<c##Interface>(new c##ProxyWithInternal( \
281 signaling_thread, worker_thread, c.release())); \
deadbeefd99a2002017-01-18 08:55:23 -0800282 }
283
284#define PROXY_SIGNALING_THREAD_DESTRUCTOR() \
285 private: \
286 rtc::Thread* destructor_thread() const { return signaling_thread_; } \
287 \
oprypin803dc292017-02-01 01:55:59 -0800288 public: // NOLINTNEXTLINE
deadbeefd99a2002017-01-18 08:55:23 -0800289
290#define PROXY_WORKER_THREAD_DESTRUCTOR() \
291 private: \
292 rtc::Thread* destructor_thread() const { return worker_thread_; } \
293 \
oprypin803dc292017-02-01 01:55:59 -0800294 public: // NOLINTNEXTLINE
deadbeefd99a2002017-01-18 08:55:23 -0800295
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000296#define PROXY_METHOD0(r, method) \
297 r method() override { \
298 MethodCall<C, r> call(c_, &C::method); \
299 return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000300 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000302#define PROXY_CONSTMETHOD0(r, method) \
303 r method() const override { \
304 ConstMethodCall<C, r> call(c_, &C::method); \
305 return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000306 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000308#define PROXY_METHOD1(r, method, t1) \
309 r method(t1 a1) override { \
310 MethodCall<C, r, t1> call(c_, &C::method, std::move(a1)); \
311 return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000312 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000313
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000314#define PROXY_CONSTMETHOD1(r, method, t1) \
315 r method(t1 a1) const override { \
316 ConstMethodCall<C, r, t1> call(c_, &C::method, std::move(a1)); \
317 return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000318 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000319
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000320#define PROXY_METHOD2(r, method, t1, t2) \
321 r method(t1 a1, t2 a2) override { \
322 MethodCall<C, r, t1, t2> call(c_, &C::method, std::move(a1), \
323 std::move(a2)); \
324 return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000325 }
perkj@webrtc.org81134d02015-01-12 08:30:16 +0000326
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000327#define PROXY_METHOD3(r, method, t1, t2, t3) \
328 r method(t1 a1, t2 a2, t3 a3) override { \
329 MethodCall<C, r, t1, t2, t3> call(c_, &C::method, std::move(a1), \
330 std::move(a2), std::move(a3)); \
331 return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
deadbeefd99a2002017-01-18 08:55:23 -0800332 }
333
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000334#define PROXY_METHOD4(r, method, t1, t2, t3, t4) \
335 r method(t1 a1, t2 a2, t3 a3, t4 a4) override { \
336 MethodCall<C, r, t1, t2, t3, t4> call(c_, &C::method, std::move(a1), \
337 std::move(a2), std::move(a3), \
338 std::move(a4)); \
339 return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
340 }
deadbeefd99a2002017-01-18 08:55:23 -0800341
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000342#define PROXY_METHOD5(r, method, t1, t2, t3, t4, t5) \
343 r method(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) override { \
344 MethodCall<C, r, t1, t2, t3, t4, t5> call(c_, &C::method, std::move(a1), \
345 std::move(a2), std::move(a3), \
346 std::move(a4), std::move(a5)); \
347 return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
348 }
nisse5b68ab52016-04-07 07:45:54 -0700349
350// Define methods which should be invoked on the worker thread.
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000351#define PROXY_WORKER_METHOD0(r, method) \
352 r method() override { \
353 MethodCall<C, r> call(c_, &C::method); \
354 return call.Marshal(RTC_FROM_HERE, worker_thread_); \
355 }
nisse5b68ab52016-04-07 07:45:54 -0700356
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000357#define PROXY_WORKER_CONSTMETHOD0(r, method) \
358 r method() const override { \
359 ConstMethodCall<C, r> call(c_, &C::method); \
360 return call.Marshal(RTC_FROM_HERE, worker_thread_); \
361 }
perkj@webrtc.org81134d02015-01-12 08:30:16 +0000362
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000363#define PROXY_WORKER_METHOD1(r, method, t1) \
364 r method(t1 a1) override { \
365 MethodCall<C, r, t1> call(c_, &C::method, std::move(a1)); \
366 return call.Marshal(RTC_FROM_HERE, worker_thread_); \
367 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000369#define PROXY_WORKER_CONSTMETHOD1(r, method, t1) \
370 r method(t1 a1) const override { \
371 ConstMethodCall<C, r, t1> call(c_, &C::method, std::move(a1)); \
372 return call.Marshal(RTC_FROM_HERE, worker_thread_); \
373 }
deadbeefd99a2002017-01-18 08:55:23 -0800374
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000375#define PROXY_WORKER_METHOD2(r, method, t1, t2) \
376 r method(t1 a1, t2 a2) override { \
377 MethodCall<C, r, t1, t2> call(c_, &C::method, std::move(a1), \
378 std::move(a2)); \
379 return call.Marshal(RTC_FROM_HERE, worker_thread_); \
380 }
deadbeefd99a2002017-01-18 08:55:23 -0800381
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000382#define PROXY_WORKER_CONSTMETHOD2(r, method, t1, t2) \
383 r method(t1 a1, t2 a2) const override { \
384 ConstMethodCall<C, r, t1, t2> call(c_, &C::method, std::move(a1), \
385 std::move(a2)); \
386 return call.Marshal(RTC_FROM_HERE, worker_thread_); \
387 }
deadbeefe814a0d2017-02-25 18:15:09 -0800388
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000389#define PROXY_WORKER_METHOD3(r, method, t1, t2, t3) \
390 r method(t1 a1, t2 a2, t3 a3) override { \
391 MethodCall<C, r, t1, t2, t3> call(c_, &C::method, std::move(a1), \
392 std::move(a2), std::move(a3)); \
393 return call.Marshal(RTC_FROM_HERE, worker_thread_); \
394 }
Steve Antonc3639822019-11-26 15:27:50 -0800395
Guido Urdanetaccab06f2020-01-15 11:30:29 +0000396#define PROXY_WORKER_CONSTMETHOD3(r, method, t1, t2) \
397 r method(t1 a1, t2 a2, t3 a3) const override { \
398 ConstMethodCall<C, r, t1, t2, t3> call(c_, &C::method, std::move(a1), \
399 std::move(a2), std::move(a3)); \
400 return call.Marshal(RTC_FROM_HERE, worker_thread_); \
401 }
deadbeefd99a2002017-01-18 08:55:23 -0800402
Tomas Gunnarsson0ca13d92020-06-10 12:17:50 +0200403// For use when returning purely const state (set during construction).
404// Use with caution. This method should only be used when the return value will
405// always be the same.
Taylor Brandstetterc88fe702020-08-03 16:36:16 -0700406#define BYPASS_PROXY_CONSTMETHOD0(r, method) \
407 r method() const override { \
408 static_assert( \
409 std::is_same<r, rtc::Thread*>::value || !std::is_pointer<r>::value, \
410 "Type is a pointer"); \
411 static_assert(!std::is_reference<r>::value, "Type is a reference"); \
412 return c_->method(); \
Tomas Gunnarsson0ca13d92020-06-10 12:17:50 +0200413 }
414
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415} // namespace webrtc
416
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200417#endif // API_PROXY_H_