• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2013 The WebRTC project authors. All Rights Reserved.
3  *
4  *  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.
9  */
10 
11 // This file contains Macros for creating proxies for webrtc MediaStream and
12 // PeerConnection classes.
13 // TODO(deadbeef): Move this to pc/; this is part of the implementation.
14 
15 //
16 // Example usage:
17 //
18 // class TestInterface : public rtc::RefCountInterface {
19 //  public:
20 //   std::string FooA() = 0;
21 //   std::string FooB(bool arg1) const = 0;
22 //   std::string FooC(bool arg1) = 0;
23 //  };
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)
32 //   PROXY_SIGNALING_THREAD_DESTRUCTOR()
33 //   PROXY_METHOD0(std::string, FooA)
34 //   PROXY_CONSTMETHOD1(std::string, FooB, arg1)
35 //   PROXY_WORKER_METHOD1(std::string, FooC, arg1)
36 // END_PROXY_MAP()
37 //
38 // Where the destructor and first two methods are invoked on the signaling
39 // thread, and the third is invoked on the worker thread.
40 //
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.
48 //
49 // The variant defined with BEGIN_OWNED_PROXY_MAP does not use
50 // refcounting, and instead just takes ownership of the object being proxied.
51 
52 #ifndef API_PROXY_H_
53 #define API_PROXY_H_
54 
55 #include <memory>
56 #include <string>
57 #include <tuple>
58 #include <type_traits>
59 #include <utility>
60 
61 #include "api/scoped_refptr.h"
62 #include "rtc_base/event.h"
63 #include "rtc_base/message_handler.h"
64 #include "rtc_base/ref_counted_object.h"
65 #include "rtc_base/system/rtc_export.h"
66 #include "rtc_base/thread.h"
67 
68 namespace rtc {
69 class Location;
70 }
71 
72 namespace webrtc {
73 
74 template <typename R>
75 class ReturnType {
76  public:
77   template <typename C, typename M, typename... Args>
Invoke(C * c,M m,Args &&...args)78   void Invoke(C* c, M m, Args&&... args) {
79     r_ = (c->*m)(std::forward<Args>(args)...);
80   }
81 
moved_result()82   R moved_result() { return std::move(r_); }
83 
84  private:
85   R r_;
86 };
87 
88 template <>
89 class ReturnType<void> {
90  public:
91   template <typename C, typename M, typename... Args>
Invoke(C * c,M m,Args &&...args)92   void Invoke(C* c, M m, Args&&... args) {
93     (c->*m)(std::forward<Args>(args)...);
94   }
95 
moved_result()96   void moved_result() {}
97 };
98 
99 namespace internal {
100 
101 class RTC_EXPORT SynchronousMethodCall : public rtc::MessageData,
102                                          public rtc::MessageHandler {
103  public:
104   explicit SynchronousMethodCall(rtc::MessageHandler* proxy);
105   ~SynchronousMethodCall() override;
106 
107   void Invoke(const rtc::Location& posted_from, rtc::Thread* t);
108 
109  private:
110   void OnMessage(rtc::Message*) override;
111 
112   rtc::Event e_;
113   rtc::MessageHandler* proxy_;
114 };
115 
116 }  // namespace internal
117 
118 template <typename C, typename R, typename... Args>
119 class MethodCall : public rtc::Message, public rtc::MessageHandler {
120  public:
121   typedef R (C::*Method)(Args...);
MethodCall(C * c,Method m,Args &&...args)122   MethodCall(C* c, Method m, Args&&... args)
123       : c_(c),
124         m_(m),
125         args_(std::forward_as_tuple(std::forward<Args>(args)...)) {}
126 
Marshal(const rtc::Location & posted_from,rtc::Thread * t)127   R Marshal(const rtc::Location& posted_from, rtc::Thread* t) {
128     internal::SynchronousMethodCall(this).Invoke(posted_from, t);
129     return r_.moved_result();
130   }
131 
132  private:
OnMessage(rtc::Message *)133   void OnMessage(rtc::Message*) { Invoke(std::index_sequence_for<Args...>()); }
134 
135   template <size_t... Is>
Invoke(std::index_sequence<Is...>)136   void Invoke(std::index_sequence<Is...>) {
137     r_.Invoke(c_, m_, std::move(std::get<Is>(args_))...);
138   }
139 
140   C* c_;
141   Method m_;
142   ReturnType<R> r_;
143   std::tuple<Args&&...> args_;
144 };
145 
146 template <typename C, typename R, typename... Args>
147 class ConstMethodCall : public rtc::Message, public rtc::MessageHandler {
148  public:
149   typedef R (C::*Method)(Args...) const;
ConstMethodCall(const C * c,Method m,Args &&...args)150   ConstMethodCall(const C* c, Method m, Args&&... args)
151       : c_(c),
152         m_(m),
153         args_(std::forward_as_tuple(std::forward<Args>(args)...)) {}
154 
Marshal(const rtc::Location & posted_from,rtc::Thread * t)155   R Marshal(const rtc::Location& posted_from, rtc::Thread* t) {
156     internal::SynchronousMethodCall(this).Invoke(posted_from, t);
157     return r_.moved_result();
158   }
159 
160  private:
OnMessage(rtc::Message *)161   void OnMessage(rtc::Message*) { Invoke(std::index_sequence_for<Args...>()); }
162 
163   template <size_t... Is>
Invoke(std::index_sequence<Is...>)164   void Invoke(std::index_sequence<Is...>) {
165     r_.Invoke(c_, m_, std::move(std::get<Is>(args_))...);
166   }
167 
168   const C* c_;
169   Method m_;
170   ReturnType<R> r_;
171   std::tuple<Args&&...> args_;
172 };
173 
174 // Helper macros to reduce code duplication.
175 #define PROXY_MAP_BOILERPLATE(c)                          \
176   template <class INTERNAL_CLASS>                         \
177   class c##ProxyWithInternal;                             \
178   typedef c##ProxyWithInternal<c##Interface> c##Proxy;    \
179   template <class INTERNAL_CLASS>                         \
180   class c##ProxyWithInternal : public c##Interface {      \
181    protected:                                             \
182     typedef c##Interface C;                               \
183                                                           \
184    public:                                                \
185     const INTERNAL_CLASS* internal() const { return c_; } \
186     INTERNAL_CLASS* internal() { return c_; }
187 
188 // clang-format off
189 // clang-format would put the semicolon alone,
190 // leading to a presubmit error (cpplint.py)
191 #define END_PROXY_MAP() \
192   };
193 // clang-format on
194 
195 #define SIGNALING_PROXY_MAP_BOILERPLATE(c)                               \
196  protected:                                                              \
197   c##ProxyWithInternal(rtc::Thread* signaling_thread, INTERNAL_CLASS* c) \
198       : signaling_thread_(signaling_thread), c_(c) {}                    \
199                                                                          \
200  private:                                                                \
201   mutable rtc::Thread* signaling_thread_;
202 
203 #define WORKER_PROXY_MAP_BOILERPLATE(c)                               \
204  protected:                                                           \
205   c##ProxyWithInternal(rtc::Thread* signaling_thread,                 \
206                        rtc::Thread* worker_thread, INTERNAL_CLASS* c) \
207       : signaling_thread_(signaling_thread),                          \
208         worker_thread_(worker_thread),                                \
209         c_(c) {}                                                      \
210                                                                       \
211  private:                                                             \
212   mutable rtc::Thread* signaling_thread_;                             \
213   mutable rtc::Thread* worker_thread_;
214 
215 // Note that the destructor is protected so that the proxy can only be
216 // destroyed via RefCountInterface.
217 #define REFCOUNTED_PROXY_MAP_BOILERPLATE(c)            \
218  protected:                                            \
219   ~c##ProxyWithInternal() {                            \
220     MethodCall<c##ProxyWithInternal, void> call(       \
221         this, &c##ProxyWithInternal::DestroyInternal); \
222     call.Marshal(RTC_FROM_HERE, destructor_thread());  \
223   }                                                    \
224                                                        \
225  private:                                              \
226   void DestroyInternal() { c_ = nullptr; }             \
227   rtc::scoped_refptr<INTERNAL_CLASS> c_;
228 
229 // Note: This doesn't use a unique_ptr, because it intends to handle a corner
230 // case where an object's deletion triggers a callback that calls back into
231 // this proxy object. If relying on a unique_ptr to delete the object, its
232 // inner pointer would be set to null before this reentrant callback would have
233 // a chance to run, resulting in a segfault.
234 #define OWNED_PROXY_MAP_BOILERPLATE(c)                 \
235  public:                                               \
236   ~c##ProxyWithInternal() {                            \
237     MethodCall<c##ProxyWithInternal, void> call(       \
238         this, &c##ProxyWithInternal::DestroyInternal); \
239     call.Marshal(RTC_FROM_HERE, destructor_thread());  \
240   }                                                    \
241                                                        \
242  private:                                              \
243   void DestroyInternal() { delete c_; }                \
244   INTERNAL_CLASS* c_;
245 
246 #define BEGIN_SIGNALING_PROXY_MAP(c)                                         \
247   PROXY_MAP_BOILERPLATE(c)                                                   \
248   SIGNALING_PROXY_MAP_BOILERPLATE(c)                                         \
249   REFCOUNTED_PROXY_MAP_BOILERPLATE(c)                                        \
250  public:                                                                     \
251   static rtc::scoped_refptr<c##ProxyWithInternal> Create(                    \
252       rtc::Thread* signaling_thread, INTERNAL_CLASS* c) {                    \
253     return new rtc::RefCountedObject<c##ProxyWithInternal>(signaling_thread, \
254                                                            c);               \
255   }
256 
257 #define BEGIN_PROXY_MAP(c)                                                    \
258   PROXY_MAP_BOILERPLATE(c)                                                    \
259   WORKER_PROXY_MAP_BOILERPLATE(c)                                             \
260   REFCOUNTED_PROXY_MAP_BOILERPLATE(c)                                         \
261  public:                                                                      \
262   static rtc::scoped_refptr<c##ProxyWithInternal> Create(                     \
263       rtc::Thread* signaling_thread, rtc::Thread* worker_thread,              \
264       INTERNAL_CLASS* c) {                                                    \
265     return new rtc::RefCountedObject<c##ProxyWithInternal>(signaling_thread,  \
266                                                            worker_thread, c); \
267   }
268 
269 #define BEGIN_OWNED_PROXY_MAP(c)                                   \
270   PROXY_MAP_BOILERPLATE(c)                                         \
271   WORKER_PROXY_MAP_BOILERPLATE(c)                                  \
272   OWNED_PROXY_MAP_BOILERPLATE(c)                                   \
273  public:                                                           \
274   static std::unique_ptr<c##Interface> Create(                     \
275       rtc::Thread* signaling_thread, rtc::Thread* worker_thread,   \
276       std::unique_ptr<INTERNAL_CLASS> c) {                         \
277     return std::unique_ptr<c##Interface>(new c##ProxyWithInternal( \
278         signaling_thread, worker_thread, c.release()));            \
279   }
280 
281 #define PROXY_SIGNALING_THREAD_DESTRUCTOR()                            \
282  private:                                                              \
283   rtc::Thread* destructor_thread() const { return signaling_thread_; } \
284                                                                        \
285  public:  // NOLINTNEXTLINE
286 
287 #define PROXY_WORKER_THREAD_DESTRUCTOR()                            \
288  private:                                                           \
289   rtc::Thread* destructor_thread() const { return worker_thread_; } \
290                                                                     \
291  public:  // NOLINTNEXTLINE
292 
293 #define PROXY_METHOD0(r, method)                           \
294   r method() override {                                    \
295     MethodCall<C, r> call(c_, &C::method);                 \
296     return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
297   }
298 
299 #define PROXY_CONSTMETHOD0(r, method)                      \
300   r method() const override {                              \
301     ConstMethodCall<C, r> call(c_, &C::method);            \
302     return call.Marshal(RTC_FROM_HERE, signaling_thread_); \
303   }
304 
305 #define PROXY_METHOD1(r, method, t1)                          \
306   r method(t1 a1) override {                                  \
307     MethodCall<C, r, t1> call(c_, &C::method, std::move(a1)); \
308     return call.Marshal(RTC_FROM_HERE, signaling_thread_);    \
309   }
310 
311 #define PROXY_CONSTMETHOD1(r, method, t1)                          \
312   r method(t1 a1) const override {                                 \
313     ConstMethodCall<C, r, t1> call(c_, &C::method, std::move(a1)); \
314     return call.Marshal(RTC_FROM_HERE, signaling_thread_);         \
315   }
316 
317 #define PROXY_METHOD2(r, method, t1, t2)                         \
318   r method(t1 a1, t2 a2) override {                              \
319     MethodCall<C, r, t1, t2> call(c_, &C::method, std::move(a1), \
320                                   std::move(a2));                \
321     return call.Marshal(RTC_FROM_HERE, signaling_thread_);       \
322   }
323 
324 #define PROXY_METHOD3(r, method, t1, t2, t3)                         \
325   r method(t1 a1, t2 a2, t3 a3) override {                           \
326     MethodCall<C, r, t1, t2, t3> call(c_, &C::method, std::move(a1), \
327                                       std::move(a2), std::move(a3)); \
328     return call.Marshal(RTC_FROM_HERE, signaling_thread_);           \
329   }
330 
331 #define PROXY_METHOD4(r, method, t1, t2, t3, t4)                         \
332   r method(t1 a1, t2 a2, t3 a3, t4 a4) override {                        \
333     MethodCall<C, r, t1, t2, t3, t4> call(c_, &C::method, std::move(a1), \
334                                           std::move(a2), std::move(a3),  \
335                                           std::move(a4));                \
336     return call.Marshal(RTC_FROM_HERE, signaling_thread_);               \
337   }
338 
339 #define PROXY_METHOD5(r, method, t1, t2, t3, t4, t5)                         \
340   r method(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) override {                     \
341     MethodCall<C, r, t1, t2, t3, t4, t5> call(c_, &C::method, std::move(a1), \
342                                               std::move(a2), std::move(a3),  \
343                                               std::move(a4), std::move(a5)); \
344     return call.Marshal(RTC_FROM_HERE, signaling_thread_);                   \
345   }
346 
347 // Define methods which should be invoked on the worker thread.
348 #define PROXY_WORKER_METHOD0(r, method)                 \
349   r method() override {                                 \
350     MethodCall<C, r> call(c_, &C::method);              \
351     return call.Marshal(RTC_FROM_HERE, worker_thread_); \
352   }
353 
354 #define PROXY_WORKER_CONSTMETHOD0(r, method)            \
355   r method() const override {                           \
356     ConstMethodCall<C, r> call(c_, &C::method);         \
357     return call.Marshal(RTC_FROM_HERE, worker_thread_); \
358   }
359 
360 #define PROXY_WORKER_METHOD1(r, method, t1)                   \
361   r method(t1 a1) override {                                  \
362     MethodCall<C, r, t1> call(c_, &C::method, std::move(a1)); \
363     return call.Marshal(RTC_FROM_HERE, worker_thread_);       \
364   }
365 
366 #define PROXY_WORKER_CONSTMETHOD1(r, method, t1)                   \
367   r method(t1 a1) const override {                                 \
368     ConstMethodCall<C, r, t1> call(c_, &C::method, std::move(a1)); \
369     return call.Marshal(RTC_FROM_HERE, worker_thread_);            \
370   }
371 
372 #define PROXY_WORKER_METHOD2(r, method, t1, t2)                  \
373   r method(t1 a1, t2 a2) override {                              \
374     MethodCall<C, r, t1, t2> call(c_, &C::method, std::move(a1), \
375                                   std::move(a2));                \
376     return call.Marshal(RTC_FROM_HERE, worker_thread_);          \
377   }
378 
379 #define PROXY_WORKER_CONSTMETHOD2(r, method, t1, t2)                  \
380   r method(t1 a1, t2 a2) const override {                             \
381     ConstMethodCall<C, r, t1, t2> call(c_, &C::method, std::move(a1), \
382                                        std::move(a2));                \
383     return call.Marshal(RTC_FROM_HERE, worker_thread_);               \
384   }
385 
386 #define PROXY_WORKER_METHOD3(r, method, t1, t2, t3)                  \
387   r method(t1 a1, t2 a2, t3 a3) override {                           \
388     MethodCall<C, r, t1, t2, t3> call(c_, &C::method, std::move(a1), \
389                                       std::move(a2), std::move(a3)); \
390     return call.Marshal(RTC_FROM_HERE, worker_thread_);              \
391   }
392 
393 #define PROXY_WORKER_CONSTMETHOD3(r, method, t1, t2)                      \
394   r method(t1 a1, t2 a2, t3 a3) const override {                          \
395     ConstMethodCall<C, r, t1, t2, t3> call(c_, &C::method, std::move(a1), \
396                                            std::move(a2), std::move(a3)); \
397     return call.Marshal(RTC_FROM_HERE, worker_thread_);                   \
398   }
399 
400 // For use when returning purely const state (set during construction).
401 // Use with caution. This method should only be used when the return value will
402 // always be the same.
403 #define BYPASS_PROXY_CONSTMETHOD0(r, method)                            \
404   r method() const override {                                           \
405     static_assert(!std::is_pointer<r>::value, "Type is a pointer");     \
406     static_assert(!std::is_reference<r>::value, "Type is a reference"); \
407     return c_->method();                                                \
408   }
409 
410 }  // namespace webrtc
411 
412 #endif  //  API_PROXY_H_
413