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