1 /*
2  * libjingle
3  * Copyright 2013 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 // This file contains Macros for creating proxies for webrtc MediaStream and
29 // PeerConnection classes.
30 
31 //
32 // Example usage:
33 //
34 // class TestInterface : public rtc::RefCountInterface {
35 //  public:
36 //   std::string FooA() = 0;
37 //   std::string FooB(bool arg1) const = 0;
38 //   std::string FooC(bool arg1)= 0;
39 //  };
40 //
41 // Note that return types can not be a const reference.
42 //
43 // class Test : public TestInterface {
44 // ... implementation of the interface.
45 // };
46 //
47 // BEGIN_PROXY_MAP(Test)
48 //   PROXY_METHOD0(std::string, FooA)
49 //   PROXY_CONSTMETHOD1(std::string, FooB, arg1)
50 //   PROXY_METHOD1(std::string, FooC, arg1)
51 // END_PROXY()
52 //
53 // The proxy can be created using TestProxy::Create(Thread*, TestInterface*).
54 
55 #ifndef TALK_APP_WEBRTC_PROXY_H_
56 #define TALK_APP_WEBRTC_PROXY_H_
57 
58 #include "webrtc/base/event.h"
59 #include "webrtc/base/thread.h"
60 
61 namespace webrtc {
62 
63 template <typename R>
64 class ReturnType {
65  public:
66   template<typename C, typename M>
Invoke(C * c,M m)67   void Invoke(C* c, M m) { r_ = (c->*m)(); }
68   template<typename C, typename M, typename T1>
Invoke(C * c,M m,T1 a1)69   void Invoke(C* c, M m, T1 a1) { r_ = (c->*m)(a1); }
70   template<typename C, typename M, typename T1, typename T2>
Invoke(C * c,M m,T1 a1,T2 a2)71   void Invoke(C* c, M m, T1 a1, T2 a2) { r_ = (c->*m)(a1, a2); }
72   template<typename C, typename M, typename T1, typename T2, typename T3>
Invoke(C * c,M m,T1 a1,T2 a2,T3 a3)73   void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3) { r_ = (c->*m)(a1, a2, a3); }
74   template<typename C, typename M, typename T1, typename T2, typename T3,
75       typename T4>
Invoke(C * c,M m,T1 a1,T2 a2,T3 a3,T4 a4)76   void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3, T4 a4) {
77     r_ = (c->*m)(a1, a2, a3, a4);
78   }
79   template<typename C, typename M, typename T1, typename T2, typename T3,
80      typename T4, typename T5>
Invoke(C * c,M m,T1 a1,T2 a2,T3 a3,T4 a4,T5 a5)81   void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
82     r_ = (c->*m)(a1, a2, a3, a4, a5);
83   }
84 
value()85   R value() { return r_; }
86 
87  private:
88   R r_;
89 };
90 
91 template <>
92 class ReturnType<void> {
93  public:
94   template<typename C, typename M>
Invoke(C * c,M m)95   void Invoke(C* c, M m) { (c->*m)(); }
96   template<typename C, typename M, typename T1>
Invoke(C * c,M m,T1 a1)97   void Invoke(C* c, M m, T1 a1) { (c->*m)(a1); }
98   template<typename C, typename M, typename T1, typename T2>
Invoke(C * c,M m,T1 a1,T2 a2)99   void Invoke(C* c, M m, T1 a1, T2 a2) { (c->*m)(a1, a2); }
100   template<typename C, typename M, typename T1, typename T2, typename T3>
Invoke(C * c,M m,T1 a1,T2 a2,T3 a3)101   void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3) { (c->*m)(a1, a2, a3); }
102 
value()103   void value() {}
104 };
105 
106 namespace internal {
107 
108 class SynchronousMethodCall
109     : public rtc::MessageData,
110       public rtc::MessageHandler {
111  public:
SynchronousMethodCall(rtc::MessageHandler * proxy)112   explicit SynchronousMethodCall(rtc::MessageHandler* proxy)
113       : e_(), proxy_(proxy) {}
~SynchronousMethodCall()114   ~SynchronousMethodCall() {}
115 
Invoke(rtc::Thread * t)116   void Invoke(rtc::Thread* t) {
117     if (t->IsCurrent()) {
118       proxy_->OnMessage(NULL);
119     } else {
120       e_.reset(new rtc::Event(false, false));
121       t->Post(this, 0);
122       e_->Wait(rtc::Event::kForever);
123     }
124   }
125 
126  private:
OnMessage(rtc::Message *)127   void OnMessage(rtc::Message*) { proxy_->OnMessage(NULL); e_->Set(); }
128   rtc::scoped_ptr<rtc::Event> e_;
129   rtc::MessageHandler* proxy_;
130 };
131 
132 }  // namespace internal
133 
134 template <typename C, typename R>
135 class MethodCall0 : public rtc::Message,
136                     public rtc::MessageHandler {
137  public:
138   typedef R (C::*Method)();
MethodCall0(C * c,Method m)139   MethodCall0(C* c, Method m) : c_(c), m_(m) {}
140 
Marshal(rtc::Thread * t)141   R Marshal(rtc::Thread* t) {
142     internal::SynchronousMethodCall(this).Invoke(t);
143     return r_.value();
144   }
145 
146  private:
OnMessage(rtc::Message *)147   void OnMessage(rtc::Message*) {  r_.Invoke(c_, m_); }
148 
149   C* c_;
150   Method m_;
151   ReturnType<R> r_;
152 };
153 
154 template <typename C, typename R>
155 class ConstMethodCall0 : public rtc::Message,
156                          public rtc::MessageHandler {
157  public:
158   typedef R (C::*Method)() const;
ConstMethodCall0(C * c,Method m)159   ConstMethodCall0(C* c, Method m) : c_(c), m_(m) {}
160 
Marshal(rtc::Thread * t)161   R Marshal(rtc::Thread* t) {
162     internal::SynchronousMethodCall(this).Invoke(t);
163     return r_.value();
164   }
165 
166  private:
OnMessage(rtc::Message *)167   void OnMessage(rtc::Message*) { r_.Invoke(c_, m_); }
168 
169   C* c_;
170   Method m_;
171   ReturnType<R> r_;
172 };
173 
174 template <typename C, typename R,  typename T1>
175 class MethodCall1 : public rtc::Message,
176                     public rtc::MessageHandler {
177  public:
178   typedef R (C::*Method)(T1 a1);
MethodCall1(C * c,Method m,T1 a1)179   MethodCall1(C* c, Method m, T1 a1) : c_(c), m_(m), a1_(a1) {}
180 
Marshal(rtc::Thread * t)181   R Marshal(rtc::Thread* t) {
182     internal::SynchronousMethodCall(this).Invoke(t);
183     return r_.value();
184   }
185 
186  private:
OnMessage(rtc::Message *)187   void OnMessage(rtc::Message*) { r_.Invoke(c_, m_, a1_); }
188 
189   C* c_;
190   Method m_;
191   ReturnType<R> r_;
192   T1 a1_;
193 };
194 
195 template <typename C, typename R,  typename T1>
196 class ConstMethodCall1 : public rtc::Message,
197                          public rtc::MessageHandler {
198  public:
199   typedef R (C::*Method)(T1 a1) const;
ConstMethodCall1(C * c,Method m,T1 a1)200   ConstMethodCall1(C* c, Method m, T1 a1) : c_(c), m_(m), a1_(a1) {}
201 
Marshal(rtc::Thread * t)202   R Marshal(rtc::Thread* t) {
203     internal::SynchronousMethodCall(this).Invoke(t);
204     return r_.value();
205   }
206 
207  private:
OnMessage(rtc::Message *)208   void OnMessage(rtc::Message*) { r_.Invoke(c_, m_, a1_); }
209 
210   C* c_;
211   Method m_;
212   ReturnType<R> r_;
213   T1 a1_;
214 };
215 
216 template <typename C, typename R, typename T1, typename T2>
217 class MethodCall2 : public rtc::Message,
218                     public rtc::MessageHandler {
219  public:
220   typedef R (C::*Method)(T1 a1, T2 a2);
MethodCall2(C * c,Method m,T1 a1,T2 a2)221   MethodCall2(C* c, Method m, T1 a1, T2 a2) : c_(c), m_(m), a1_(a1), a2_(a2) {}
222 
Marshal(rtc::Thread * t)223   R Marshal(rtc::Thread* t) {
224     internal::SynchronousMethodCall(this).Invoke(t);
225     return r_.value();
226   }
227 
228  private:
OnMessage(rtc::Message *)229   void OnMessage(rtc::Message*) { r_.Invoke(c_, m_, a1_, a2_); }
230 
231   C* c_;
232   Method m_;
233   ReturnType<R> r_;
234   T1 a1_;
235   T2 a2_;
236 };
237 
238 template <typename C, typename R, typename T1, typename T2, typename T3>
239 class MethodCall3 : public rtc::Message,
240                     public rtc::MessageHandler {
241  public:
242   typedef R (C::*Method)(T1 a1, T2 a2, T3 a3);
MethodCall3(C * c,Method m,T1 a1,T2 a2,T3 a3)243   MethodCall3(C* c, Method m, T1 a1, T2 a2, T3 a3)
244       : c_(c), m_(m), a1_(a1), a2_(a2), a3_(a3) {}
245 
Marshal(rtc::Thread * t)246   R Marshal(rtc::Thread* t) {
247     internal::SynchronousMethodCall(this).Invoke(t);
248     return r_.value();
249   }
250 
251  private:
OnMessage(rtc::Message *)252   void OnMessage(rtc::Message*) { r_.Invoke(c_, m_, a1_, a2_, a3_); }
253 
254   C* c_;
255   Method m_;
256   ReturnType<R> r_;
257   T1 a1_;
258   T2 a2_;
259   T3 a3_;
260 };
261 
262 template <typename C, typename R, typename T1, typename T2, typename T3,
263     typename T4>
264 class MethodCall4 : public rtc::Message,
265                     public rtc::MessageHandler {
266  public:
267   typedef R (C::*Method)(T1 a1, T2 a2, T3 a3, T4 a4);
MethodCall4(C * c,Method m,T1 a1,T2 a2,T3 a3,T4 a4)268   MethodCall4(C* c, Method m, T1 a1, T2 a2, T3 a3, T4 a4)
269       : c_(c), m_(m), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {}
270 
Marshal(rtc::Thread * t)271   R Marshal(rtc::Thread* t) {
272     internal::SynchronousMethodCall(this).Invoke(t);
273     return r_.value();
274   }
275 
276  private:
OnMessage(rtc::Message *)277   void OnMessage(rtc::Message*) { r_.Invoke(c_, m_, a1_, a2_, a3_, a4_); }
278 
279   C* c_;
280   Method m_;
281   ReturnType<R> r_;
282   T1 a1_;
283   T2 a2_;
284   T3 a3_;
285   T4 a4_;
286 };
287 
288 template <typename C, typename R, typename T1, typename T2, typename T3,
289     typename T4, typename T5>
290 class MethodCall5 : public rtc::Message,
291                     public rtc::MessageHandler {
292  public:
293   typedef R (C::*Method)(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
MethodCall5(C * c,Method m,T1 a1,T2 a2,T3 a3,T4 a4,T5 a5)294   MethodCall5(C* c, Method m, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
295       : c_(c), m_(m), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {}
296 
Marshal(rtc::Thread * t)297   R Marshal(rtc::Thread* t) {
298     internal::SynchronousMethodCall(this).Invoke(t);
299     return r_.value();
300   }
301 
302  private:
OnMessage(rtc::Message *)303   void OnMessage(rtc::Message*) { r_.Invoke(c_, m_, a1_, a2_, a3_, a4_, a5_); }
304 
305   C* c_;
306   Method m_;
307   ReturnType<R> r_;
308   T1 a1_;
309   T2 a2_;
310   T3 a3_;
311   T4 a4_;
312   T5 a5_;
313 };
314 
315 #define BEGIN_PROXY_MAP(c)                                                \
316   class c##Proxy : public c##Interface {                                  \
317    protected:                                                             \
318     typedef c##Interface C;                                               \
319     c##Proxy(rtc::Thread* thread, C* c) : owner_thread_(thread), c_(c) {} \
320     ~c##Proxy() {                                                         \
321       MethodCall0<c##Proxy, void> call(this, &c##Proxy::Release_s);       \
322       call.Marshal(owner_thread_);                                        \
323     }                                                                     \
324                                                                           \
325    public:                                                                \
326     static rtc::scoped_refptr<C> Create(rtc::Thread* thread, C* c) {      \
327       return new rtc::RefCountedObject<c##Proxy>(thread, c);              \
328     }
329 
330 #define PROXY_METHOD0(r, method)                  \
331   r method() override {                           \
332     MethodCall0<C, r> call(c_.get(), &C::method); \
333     return call.Marshal(owner_thread_);           \
334   }
335 
336 #define PROXY_CONSTMETHOD0(r, method)                  \
337   r method() const override {                          \
338     ConstMethodCall0<C, r> call(c_.get(), &C::method); \
339     return call.Marshal(owner_thread_);                \
340   }
341 
342 #define PROXY_METHOD1(r, method, t1)                      \
343   r method(t1 a1) override {                              \
344     MethodCall1<C, r, t1> call(c_.get(), &C::method, a1); \
345     return call.Marshal(owner_thread_);                   \
346   }
347 
348 #define PROXY_CONSTMETHOD1(r, method, t1)                      \
349   r method(t1 a1) const override {                             \
350     ConstMethodCall1<C, r, t1> call(c_.get(), &C::method, a1); \
351     return call.Marshal(owner_thread_);                        \
352   }
353 
354 #define PROXY_METHOD2(r, method, t1, t2)                          \
355   r method(t1 a1, t2 a2) override {                               \
356     MethodCall2<C, r, t1, t2> call(c_.get(), &C::method, a1, a2); \
357     return call.Marshal(owner_thread_);                           \
358   }
359 
360 #define PROXY_METHOD3(r, method, t1, t2, t3)                              \
361   r method(t1 a1, t2 a2, t3 a3) override {                                \
362     MethodCall3<C, r, t1, t2, t3> call(c_.get(), &C::method, a1, a2, a3); \
363     return call.Marshal(owner_thread_);                                   \
364   }
365 
366 #define PROXY_METHOD4(r, method, t1, t2, t3, t4)                             \
367   r method(t1 a1, t2 a2, t3 a3, t4 a4) override {                            \
368     MethodCall4<C, r, t1, t2, t3, t4> call(c_.get(), &C::method, a1, a2, a3, \
369                                            a4);                              \
370     return call.Marshal(owner_thread_);                                      \
371   }
372 
373 #define PROXY_METHOD5(r, method, t1, t2, t3, t4, t5)                         \
374   r method(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) override {                     \
375     MethodCall5<C, r, t1, t2, t3, t4, t5> call(c_.get(), &C::method, a1, a2, \
376                                                a3, a4, a5);                  \
377     return call.Marshal(owner_thread_);                                      \
378   }
379 
380 #define END_PROXY() \
381    private:\
382     void Release_s() {\
383       c_ = NULL;\
384     }\
385     mutable rtc::Thread* owner_thread_;\
386     rtc::scoped_refptr<C> c_;\
387   };\
388 
389 }  // namespace webrtc
390 
391 #endif  //  TALK_APP_WEBRTC_PROXY_H_
392