blob: 64467c1e34322a80f614cefe5a51d31460945834 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
wu@webrtc.org9143f772012-02-08 00:14:25 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000011#include <assert.h>
12
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000013#include "webrtc/engine_configurations.h"
andrew@webrtc.org9841d922012-10-31 05:22:11 +000014#include "webrtc/modules/video_render/i_video_render.h"
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000015#include "webrtc/modules/video_render/include/video_render_defines.h"
16#include "webrtc/modules/video_render/incoming_video_stream.h"
17#include "webrtc/modules/video_render/video_render_impl.h"
18#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000020
wu@webrtc.orgf3f2f6a2011-10-19 18:42:17 +000021#ifdef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
niklase@google.com470e71d2011-07-07 08:21:25 +000022
23#if defined (_WIN32)
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000024#include "webrtc/modules/video_render/windows/video_render_windows_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000025#define STANDARD_RENDERING kRenderWindows
26
sjlee@webrtc.org414fa7f2012-09-11 17:25:46 +000027// WEBRTC_IOS should go before WEBRTC_MAC because WEBRTC_MAC
28// gets defined if WEBRTC_IOS is defined
fischman@webrtc.orgc6d5b502013-07-18 02:02:07 +000029#elif defined(WEBRTC_IOS) && 0
30// TODO(sjlee): land https://webrtc-codereview.appspot.com/1641004/
niklase@google.com470e71d2011-07-07 08:21:25 +000031#if defined(IPHONE_GLES_RENDERING)
32#define STANDARD_RENDERING kRenderiPhone
33#include "iPhone/video_render_iphone_impl.h"
34#endif
35
andrew@webrtc.orgf3b65db2012-09-06 18:17:00 +000036#elif defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +000037#if defined(COCOA_RENDERING)
38#define STANDARD_RENDERING kRenderCocoa
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000039#include "webrtc/modules/video_render/mac/video_render_mac_cocoa_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000040#elif defined(CARBON_RENDERING)
41#define STANDARD_RENDERING kRenderCarbon
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000042#include "webrtc/modules/video_render/mac/video_render_mac_carbon_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000043#endif
44
leozwang@google.com03bc96d2011-07-26 05:03:10 +000045#elif defined(WEBRTC_ANDROID)
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000046#include "webrtc/modules/video_render/android/video_render_android_impl.h"
47#include "webrtc/modules/video_render/android/video_render_android_native_opengl2.h"
48#include "webrtc/modules/video_render/android/video_render_android_surface_view.h"
fischman@webrtc.orgc6d5b502013-07-18 02:02:07 +000049#define STANDARD_RENDERING kRenderAndroid
niklase@google.com470e71d2011-07-07 08:21:25 +000050
51#elif defined(WEBRTC_LINUX)
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000052#include "webrtc/modules/video_render/linux/video_render_linux_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000053#define STANDARD_RENDERING kRenderX11
54
55#else
56//Other platforms
57#endif
58
wu@webrtc.orgf3f2f6a2011-10-19 18:42:17 +000059#endif // WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
niklase@google.com470e71d2011-07-07 08:21:25 +000060
61// For external rendering
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000062#include "webrtc/modules/video_render/external/video_render_external_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000063#ifndef STANDARD_RENDERING
64#define STANDARD_RENDERING kRenderExternal
65#endif // STANDARD_RENDERING
66
67namespace webrtc {
68
69VideoRender*
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +000070VideoRender::CreateVideoRender(const int32_t id,
niklase@google.com470e71d2011-07-07 08:21:25 +000071 void* window,
72 const bool fullscreen,
73 const VideoRenderType videoRenderType/*=kRenderDefault*/)
74{
niklase@google.com470e71d2011-07-07 08:21:25 +000075 VideoRenderType resultVideoRenderType = videoRenderType;
76 if (videoRenderType == kRenderDefault)
77 {
78 resultVideoRenderType = STANDARD_RENDERING;
79 }
80 return new ModuleVideoRenderImpl(id, resultVideoRenderType, window,
81 fullscreen);
82}
83
84void VideoRender::DestroyVideoRender(
85 VideoRender* module)
86{
87 if (module)
88 {
niklase@google.com470e71d2011-07-07 08:21:25 +000089 delete module;
90 }
91}
92
niklase@google.com470e71d2011-07-07 08:21:25 +000093ModuleVideoRenderImpl::ModuleVideoRenderImpl(
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +000094 const int32_t id,
niklase@google.com470e71d2011-07-07 08:21:25 +000095 const VideoRenderType videoRenderType,
96 void* window,
97 const bool fullscreen) :
98 _id(id), _moduleCrit(*CriticalSectionWrapper::CreateCriticalSection()),
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +000099 _ptrWindow(window), _fullScreen(fullscreen), _ptrRenderer(NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000100{
101
102 // Create platform specific renderer
103 switch (videoRenderType)
104 {
wu@webrtc.orgf3f2f6a2011-10-19 18:42:17 +0000105#ifdef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
niklase@google.com470e71d2011-07-07 08:21:25 +0000106
107#if defined(_WIN32)
108 case kRenderWindows:
109 {
110 VideoRenderWindowsImpl* ptrRenderer;
111 ptrRenderer = new VideoRenderWindowsImpl(_id, videoRenderType, window, _fullScreen);
112 if (ptrRenderer)
113 {
114 _ptrRenderer = reinterpret_cast<IVideoRender*>(ptrRenderer);
115 }
116 }
117 break;
118
fischman@webrtc.orgc6d5b502013-07-18 02:02:07 +0000119#elif defined(WEBRTC_IOS) && 0
120 // TODO(sjlee): land https://webrtc-codereview.appspot.com/1641004/
niklase@google.com470e71d2011-07-07 08:21:25 +0000121 case kRenderiPhone:
122 {
123 VideoRenderIPhoneImpl* ptrRenderer = new VideoRenderIPhoneImpl(_id, videoRenderType, window, _fullScreen);
124 if(ptrRenderer)
125 {
126 _ptrRenderer = reinterpret_cast<IVideoRender*>(ptrRenderer);
127 }
128 }
129 break;
130
andrew@webrtc.orgf3b65db2012-09-06 18:17:00 +0000131#elif defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000132
133#if defined(COCOA_RENDERING)
134 case kRenderCocoa:
135 {
136 VideoRenderMacCocoaImpl* ptrRenderer = new VideoRenderMacCocoaImpl(_id, videoRenderType, window, _fullScreen);
137 if(ptrRenderer)
138 {
139 _ptrRenderer = reinterpret_cast<IVideoRender*>(ptrRenderer);
140 }
141 }
142
143 break;
144#elif defined(CARBON_RENDERING)
145 case kRenderCarbon:
146 {
147 VideoRenderMacCarbonImpl* ptrRenderer = new VideoRenderMacCarbonImpl(_id, videoRenderType, window, _fullScreen);
148 if(ptrRenderer)
149 {
150 _ptrRenderer = reinterpret_cast<IVideoRender*>(ptrRenderer);
151 }
152 }
153 break;
154#endif
155
leozwang@google.com03bc96d2011-07-26 05:03:10 +0000156#elif defined(WEBRTC_ANDROID)
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 case kRenderAndroid:
158 {
159 if(AndroidNativeOpenGl2Renderer::UseOpenGL2(window))
160 {
161 AndroidNativeOpenGl2Renderer* ptrRenderer = NULL;
162 ptrRenderer = new AndroidNativeOpenGl2Renderer(_id, videoRenderType, window, _fullScreen);
163 if (ptrRenderer)
164 {
165 _ptrRenderer = reinterpret_cast<IVideoRender*> (ptrRenderer);
166 }
167 }
168 else
169 {
170 AndroidSurfaceViewRenderer* ptrRenderer = NULL;
171 ptrRenderer = new AndroidSurfaceViewRenderer(_id, videoRenderType, window, _fullScreen);
172 if (ptrRenderer)
173 {
174 _ptrRenderer = reinterpret_cast<IVideoRender*> (ptrRenderer);
175 }
176 }
177
178 }
179 break;
180#elif defined(WEBRTC_LINUX)
181 case kRenderX11:
182 {
183 VideoRenderLinuxImpl* ptrRenderer = NULL;
184 ptrRenderer = new VideoRenderLinuxImpl(_id, videoRenderType, window, _fullScreen);
185 if ( ptrRenderer )
186 {
187 _ptrRenderer = reinterpret_cast<IVideoRender*> (ptrRenderer);
188 }
189 }
190 break;
191
192#else
193 // Other platforms
194#endif
195
wu@webrtc.orgf3f2f6a2011-10-19 18:42:17 +0000196#endif // WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 case kRenderExternal:
198 {
199 VideoRenderExternalImpl* ptrRenderer(NULL);
200 ptrRenderer = new VideoRenderExternalImpl(_id, videoRenderType,
201 window, _fullScreen);
202 if (ptrRenderer)
203 {
204 _ptrRenderer = reinterpret_cast<IVideoRender*> (ptrRenderer);
205 }
206 }
207 break;
208 default:
209 // Error...
210 break;
211 }
212 if (_ptrRenderer)
213 {
214 if (_ptrRenderer->Init() == -1)
215 {
216 }
217 }
218}
219
220ModuleVideoRenderImpl::~ModuleVideoRenderImpl()
221{
222 delete &_moduleCrit;
223
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000224 for (IncomingVideoStreamMap::iterator it = _streamRenderMap.begin();
225 it != _streamRenderMap.end();
226 ++it) {
227 delete it->second;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000229
230 // Delete platform specific renderer
231 if (_ptrRenderer)
232 {
233 VideoRenderType videoRenderType = _ptrRenderer->RenderType();
234 switch (videoRenderType)
235 {
236 case kRenderExternal:
237 {
238 VideoRenderExternalImpl
239 * ptrRenderer =
240 reinterpret_cast<VideoRenderExternalImpl*> (_ptrRenderer);
241 _ptrRenderer = NULL;
242 delete ptrRenderer;
243 }
244 break;
wu@webrtc.orgf3f2f6a2011-10-19 18:42:17 +0000245#ifdef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
niklase@google.com470e71d2011-07-07 08:21:25 +0000246
247#if defined(_WIN32)
248 case kRenderWindows:
249 {
250 VideoRenderWindowsImpl* ptrRenderer = reinterpret_cast<VideoRenderWindowsImpl*>(_ptrRenderer);
251 _ptrRenderer = NULL;
252 delete ptrRenderer;
253 }
254 break;
andrew@webrtc.orgf3b65db2012-09-06 18:17:00 +0000255#elif defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000256
257#if defined(COCOA_RENDERING)
258 case kRenderCocoa:
259 {
260 VideoRenderMacCocoaImpl* ptrRenderer = reinterpret_cast<VideoRenderMacCocoaImpl*> (_ptrRenderer);
261 _ptrRenderer = NULL;
262 delete ptrRenderer;
263 }
264 break;
265#elif defined(CARBON_RENDERING)
266 case kRenderCarbon:
267 {
268 VideoRenderMacCarbonImpl* ptrRenderer = reinterpret_cast<VideoRenderMacCarbonImpl*> (_ptrRenderer);
269 _ptrRenderer = NULL;
270 delete ptrRenderer;
271 }
272 break;
273#endif
274
fischman@webrtc.orgc6d5b502013-07-18 02:02:07 +0000275#elif defined(WEBRTC_IOS) && 0
276 // TODO(sjlee): land https://webrtc-codereview.appspot.com/1641004/
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 case kRenderiPhone:
278 break;
279
leozwang@google.com03bc96d2011-07-26 05:03:10 +0000280#elif defined(WEBRTC_ANDROID)
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 case kRenderAndroid:
282 {
283 VideoRenderAndroid* ptrRenderer = reinterpret_cast<VideoRenderAndroid*> (_ptrRenderer);
284 _ptrRenderer = NULL;
285 delete ptrRenderer;
286 }
287 break;
288
289#elif defined(WEBRTC_LINUX)
290 case kRenderX11:
291 {
292 VideoRenderLinuxImpl* ptrRenderer = reinterpret_cast<VideoRenderLinuxImpl*> (_ptrRenderer);
293 _ptrRenderer = NULL;
294 delete ptrRenderer;
295 }
296 break;
297#else
298 //other platforms
299#endif
300
wu@webrtc.orgf3f2f6a2011-10-19 18:42:17 +0000301#endif // WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
niklase@google.com470e71d2011-07-07 08:21:25 +0000302
303 default:
304 // Error...
305 break;
306 }
307 }
308}
309
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000310int32_t ModuleVideoRenderImpl::ChangeUniqueId(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000311{
niklase@google.com470e71d2011-07-07 08:21:25 +0000312
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000313 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000314
315 _id = id;
316
317 if (_ptrRenderer)
318 {
319 _ptrRenderer->ChangeUniqueId(_id);
320 }
321
322 return 0;
323}
324
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000325int32_t ModuleVideoRenderImpl::TimeUntilNextProcess()
niklase@google.com470e71d2011-07-07 08:21:25 +0000326{
327 // Not used
328 return 50;
329}
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000330int32_t ModuleVideoRenderImpl::Process()
niklase@google.com470e71d2011-07-07 08:21:25 +0000331{
332 // Not used
333 return 0;
334}
335
336void*
337ModuleVideoRenderImpl::Window()
338{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000339 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000340 return _ptrWindow;
341}
342
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000343int32_t ModuleVideoRenderImpl::ChangeWindow(void* window)
niklase@google.com470e71d2011-07-07 08:21:25 +0000344{
345
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000346 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000347
wu@webrtc.orgf3f2f6a2011-10-19 18:42:17 +0000348#ifdef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
niklase@google.com470e71d2011-07-07 08:21:25 +0000349
sjlee@webrtc.org414fa7f2012-09-11 17:25:46 +0000350#if defined(WEBRTC_IOS) // WEBRTC_IOS must go before WEBRTC_MAC
niklase@google.com470e71d2011-07-07 08:21:25 +0000351 _ptrRenderer = NULL;
352 delete _ptrRenderer;
353
fischman@webrtc.orgc6d5b502013-07-18 02:02:07 +0000354#if 0 // TODO(sjlee): land https://webrtc-codereview.appspot.com/1641004/
niklase@google.com470e71d2011-07-07 08:21:25 +0000355 VideoRenderIPhoneImpl* ptrRenderer;
356 ptrRenderer = new VideoRenderIPhoneImpl(_id, kRenderiPhone, window, _fullScreen);
357 if (!ptrRenderer)
358 {
359 return -1;
360 }
361 _ptrRenderer = reinterpret_cast<IVideoRender*>(ptrRenderer);
362 return _ptrRenderer->ChangeWindow(window);
fischman@webrtc.orgc6d5b502013-07-18 02:02:07 +0000363#else
364 return -1;
365#endif
andrew@webrtc.orgf3b65db2012-09-06 18:17:00 +0000366#elif defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000367
368 _ptrRenderer = NULL;
369 delete _ptrRenderer;
370
371#if defined(COCOA_RENDERING)
372 VideoRenderMacCocoaImpl* ptrRenderer;
373 ptrRenderer = new VideoRenderMacCocoaImpl(_id, kRenderCocoa, window, _fullScreen);
374#elif defined(CARBON_RENDERING)
375 VideoRenderMacCarbonImpl* ptrRenderer;
376 ptrRenderer = new VideoRenderMacCarbonImpl(_id, kRenderCarbon, window, _fullScreen);
377#endif
378 if (!ptrRenderer)
379 {
380 return -1;
381 }
382 _ptrRenderer = reinterpret_cast<IVideoRender*>(ptrRenderer);
383 return _ptrRenderer->ChangeWindow(window);
384
385#else
386 if (!_ptrRenderer)
387 {
388 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
389 "%s: No renderer", __FUNCTION__);
390 return -1;
391 }
392 return _ptrRenderer->ChangeWindow(window);
393
394#endif
395
wu@webrtc.orgf3f2f6a2011-10-19 18:42:17 +0000396#else // WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 return -1;
398#endif
399}
400
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000401int32_t ModuleVideoRenderImpl::Id()
niklase@google.com470e71d2011-07-07 08:21:25 +0000402{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000403 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000404 return _id;
405}
406
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000407uint32_t ModuleVideoRenderImpl::GetIncomingFrameRate(const uint32_t streamId) {
408 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000409
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000410 IncomingVideoStreamMap::iterator it = _streamRenderMap.find(streamId);
411
412 if (it == _streamRenderMap.end()) {
413 // This stream doesn't exist
414 WEBRTC_TRACE(kTraceError,
415 kTraceVideoRenderer,
416 _id,
417 "%s: stream doesn't exist",
418 __FUNCTION__);
419 return 0;
420 }
421 assert(it->second != NULL);
422 return it->second->IncomingRate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000423}
424
425VideoRenderCallback*
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000426ModuleVideoRenderImpl::AddIncomingRenderStream(const uint32_t streamId,
427 const uint32_t zOrder,
niklase@google.com470e71d2011-07-07 08:21:25 +0000428 const float left,
429 const float top,
430 const float right,
431 const float bottom)
432{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000433 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000434
435 if (!_ptrRenderer)
436 {
437 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
438 "%s: No renderer", __FUNCTION__);
439 return NULL;
440 }
441
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000442 if (_streamRenderMap.find(streamId) != _streamRenderMap.end()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 // The stream already exists...
444 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
445 "%s: stream already exists", __FUNCTION__);
446 return NULL;
447 }
448
niklase@google.com470e71d2011-07-07 08:21:25 +0000449 VideoRenderCallback* ptrRenderCallback =
450 _ptrRenderer->AddIncomingRenderStream(streamId, zOrder, left, top,
451 right, bottom);
452 if (ptrRenderCallback == NULL)
453 {
454 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
455 "%s: Can't create incoming stream in renderer",
456 __FUNCTION__);
457 return NULL;
458 }
459
wu@webrtc.org9143f772012-02-08 00:14:25 +0000460 // Create platform independant code
461 IncomingVideoStream* ptrIncomingStream = new IncomingVideoStream(_id,
462 streamId);
463 if (ptrIncomingStream == NULL)
464 {
465 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
466 "%s: Can't create incoming stream", __FUNCTION__);
467 return NULL;
468 }
469
470
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 if (ptrIncomingStream->SetRenderCallback(ptrRenderCallback) == -1)
472 {
473 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
474 "%s: Can't set render callback", __FUNCTION__);
475 delete ptrIncomingStream;
476 _ptrRenderer->DeleteIncomingRenderStream(streamId);
477 return NULL;
478 }
479
480 VideoRenderCallback* moduleCallback =
481 ptrIncomingStream->ModuleCallback();
482
483 // Store the stream
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000484 _streamRenderMap[streamId] = ptrIncomingStream;
niklase@google.com470e71d2011-07-07 08:21:25 +0000485
486 return moduleCallback;
487}
488
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000489int32_t ModuleVideoRenderImpl::DeleteIncomingRenderStream(
490 const uint32_t streamId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000491{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000492 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000493
494 if (!_ptrRenderer)
495 {
496 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
497 "%s: No renderer", __FUNCTION__);
498 return -1;
499 }
500
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000501 IncomingVideoStreamMap::iterator item = _streamRenderMap.find(streamId);
502 if (item == _streamRenderMap.end())
niklase@google.com470e71d2011-07-07 08:21:25 +0000503 {
504 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
505 "%s: stream doesn't exist", __FUNCTION__);
506 return -1;
507 }
508
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000509 delete item->second;
510
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 _ptrRenderer->DeleteIncomingRenderStream(streamId);
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000512
513 _streamRenderMap.erase(item);
niklase@google.com470e71d2011-07-07 08:21:25 +0000514
515 return 0;
516}
517
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000518int32_t ModuleVideoRenderImpl::AddExternalRenderCallback(
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000519 const uint32_t streamId,
520 VideoRenderCallback* renderObject) {
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000521 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000522
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000523 IncomingVideoStreamMap::iterator item = _streamRenderMap.find(streamId);
524
525 if (item == _streamRenderMap.end())
niklase@google.com470e71d2011-07-07 08:21:25 +0000526 {
527 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
528 "%s: stream doesn't exist", __FUNCTION__);
529 return -1;
530 }
531
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000532 if (item->second == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
534 "%s: could not get stream", __FUNCTION__);
wu@webrtc.org9143f772012-02-08 00:14:25 +0000535 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000536 }
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000537 return item->second->SetExternalCallback(renderObject);
niklase@google.com470e71d2011-07-07 08:21:25 +0000538}
539
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000540int32_t ModuleVideoRenderImpl::GetIncomingRenderStreamProperties(
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000541 const uint32_t streamId,
542 uint32_t& zOrder,
543 float& left,
544 float& top,
545 float& right,
546 float& bottom) const {
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000547 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000548
549 if (!_ptrRenderer)
550 {
551 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
552 "%s: No renderer", __FUNCTION__);
553 return -1;
554 }
555
556 return _ptrRenderer->GetIncomingRenderStreamProperties(streamId, zOrder,
557 left, top, right,
558 bottom);
559}
560
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000561uint32_t ModuleVideoRenderImpl::GetNumIncomingRenderStreams() const
niklase@google.com470e71d2011-07-07 08:21:25 +0000562{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000563 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000564
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000565 return static_cast<uint32_t>(_streamRenderMap.size());
niklase@google.com470e71d2011-07-07 08:21:25 +0000566}
567
568bool ModuleVideoRenderImpl::HasIncomingRenderStream(
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000569 const uint32_t streamId) const {
570 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000571
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000572 return _streamRenderMap.find(streamId) != _streamRenderMap.end();
niklase@google.com470e71d2011-07-07 08:21:25 +0000573}
574
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000575int32_t ModuleVideoRenderImpl::RegisterRawFrameCallback(
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000576 const uint32_t streamId,
577 VideoRenderCallback* callbackObj) {
578 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000579}
580
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000581int32_t ModuleVideoRenderImpl::StartRender(const uint32_t streamId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000582{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000583 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000584
585 if (!_ptrRenderer)
586 {
587 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
588 "%s: No renderer", __FUNCTION__);
589 return -1;
590 }
591
592 // Start the stream
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000593 IncomingVideoStreamMap::iterator item = _streamRenderMap.find(streamId);
594
595 if (item == _streamRenderMap.end())
niklase@google.com470e71d2011-07-07 08:21:25 +0000596 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 return -1;
598 }
599
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000600 if (item->second->Start() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000601 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 return -1;
603 }
604
605 // Start the HW renderer
606 if (_ptrRenderer->StartRender() == -1)
607 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000608 return -1;
609 }
610 return 0;
611}
612
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000613int32_t ModuleVideoRenderImpl::StopRender(const uint32_t streamId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000614{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000615 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000616
617 if (!_ptrRenderer)
618 {
619 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
620 "%s(%d): No renderer", __FUNCTION__, streamId);
621 return -1;
622 }
623
624 // Stop the incoming stream
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000625 IncomingVideoStreamMap::iterator item = _streamRenderMap.find(streamId);
626
627 if (item == _streamRenderMap.end())
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 return -1;
630 }
631
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000632 if (item->second->Stop() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000633 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 return -1;
635 }
636
637 return 0;
638}
639
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000640int32_t ModuleVideoRenderImpl::ResetRender()
niklase@google.com470e71d2011-07-07 08:21:25 +0000641{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000642 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000643
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000644 int32_t ret = 0;
645 // Loop through all incoming streams and reset them
646 for (IncomingVideoStreamMap::iterator it = _streamRenderMap.begin();
647 it != _streamRenderMap.end();
648 ++it) {
649 if (it->second->Reset() == -1)
650 ret = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 }
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000652 return ret;
niklase@google.com470e71d2011-07-07 08:21:25 +0000653}
654
655RawVideoType ModuleVideoRenderImpl::PreferredVideoType() const
656{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000657 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000658
659 if (_ptrRenderer == NULL)
660 {
661 return kVideoI420;
662 }
663
664 return _ptrRenderer->PerferedVideoType();
665}
666
667bool ModuleVideoRenderImpl::IsFullScreen()
668{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000669 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000670
671 if (!_ptrRenderer)
672 {
673 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
674 "%s: No renderer", __FUNCTION__);
675 return false;
676 }
677 return _ptrRenderer->FullScreen();
678}
679
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000680int32_t ModuleVideoRenderImpl::GetScreenResolution(
681 uint32_t& screenWidth,
682 uint32_t& screenHeight) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000683{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000684 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000685
686 if (!_ptrRenderer)
687 {
688 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
689 "%s: No renderer", __FUNCTION__);
690 return false;
691 }
692 return _ptrRenderer->GetScreenResolution(screenWidth, screenHeight);
693}
694
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000695uint32_t ModuleVideoRenderImpl::RenderFrameRate(
696 const uint32_t streamId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000697{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000698 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000699
700 if (!_ptrRenderer)
701 {
702 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
703 "%s: No renderer", __FUNCTION__);
704 return false;
705 }
706 return _ptrRenderer->RenderFrameRate(streamId);
707}
708
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000709int32_t ModuleVideoRenderImpl::SetStreamCropping(
710 const uint32_t streamId,
niklase@google.com470e71d2011-07-07 08:21:25 +0000711 const float left,
712 const float top,
713 const float right,
714 const float bottom)
715{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000716 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000717
718 if (!_ptrRenderer)
719 {
720 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
721 "%s: No renderer", __FUNCTION__);
722 return false;
723 }
724 return _ptrRenderer->SetStreamCropping(streamId, left, top, right, bottom);
725}
726
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000727int32_t ModuleVideoRenderImpl::SetTransparentBackground(const bool enable)
niklase@google.com470e71d2011-07-07 08:21:25 +0000728{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000729 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000730
731 if (!_ptrRenderer)
732 {
733 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
734 "%s: No renderer", __FUNCTION__);
735 return false;
736 }
737 return _ptrRenderer->SetTransparentBackground(enable);
738}
739
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000740int32_t ModuleVideoRenderImpl::FullScreenRender(void* window, const bool enable)
niklase@google.com470e71d2011-07-07 08:21:25 +0000741{
742 return -1;
743}
744
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000745int32_t ModuleVideoRenderImpl::SetText(
746 const uint8_t textId,
747 const uint8_t* text,
748 const int32_t textLength,
749 const uint32_t textColorRef,
750 const uint32_t backgroundColorRef,
niklase@google.com470e71d2011-07-07 08:21:25 +0000751 const float left, const float top,
752 const float right,
753 const float bottom)
754{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000755 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000756
757 if (!_ptrRenderer)
758 {
759 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
760 "%s: No renderer", __FUNCTION__);
761 return -1;
762 }
763 return _ptrRenderer->SetText(textId, text, textLength, textColorRef,
764 backgroundColorRef, left, top, right, bottom);
765}
766
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000767int32_t ModuleVideoRenderImpl::SetBitmap(const void* bitMap,
768 const uint8_t pictureId,
769 const void* colorKey,
770 const float left,
771 const float top,
772 const float right,
773 const float bottom)
niklase@google.com470e71d2011-07-07 08:21:25 +0000774{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000775 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000776
777 if (!_ptrRenderer)
778 {
779 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
780 "%s: No renderer", __FUNCTION__);
781 return -1;
782 }
783 return _ptrRenderer->SetBitmap(bitMap, pictureId, colorKey, left, top,
784 right, bottom);
785}
786
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000787int32_t ModuleVideoRenderImpl::GetLastRenderedFrame(
788 const uint32_t streamId,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000789 I420VideoFrame &frame) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000790{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000791 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000792
793 if (!_ptrRenderer)
794 {
795 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
796 "%s: No renderer", __FUNCTION__);
797 return -1;
798 }
799
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000800 IncomingVideoStreamMap::const_iterator item =
801 _streamRenderMap.find(streamId);
802 if (item == _streamRenderMap.end())
niklase@google.com470e71d2011-07-07 08:21:25 +0000803 {
804 // This stream doesn't exist
805 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
806 "%s: stream doesn't exist", __FUNCTION__);
807 return 0;
808 }
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000809
810 assert(item->second != NULL);
811 return item->second->GetLastRenderedFrame(frame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000812}
813
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000814int32_t ModuleVideoRenderImpl::SetExpectedRenderDelay(
815 uint32_t stream_id, int32_t delay_ms) {
mflodman@webrtc.orgaeb37d32012-10-11 16:31:00 +0000816 CriticalSectionScoped cs(&_moduleCrit);
mflodman@webrtc.orgf4f21452012-09-28 11:27:35 +0000817
818 if (!_ptrRenderer) {
819 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
820 "%s: No renderer", __FUNCTION__);
821 return false;
822 }
823
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000824 IncomingVideoStreamMap::const_iterator item =
825 _streamRenderMap.find(stream_id);
826 if (item == _streamRenderMap.end()) {
mflodman@webrtc.orgf4f21452012-09-28 11:27:35 +0000827 // This stream doesn't exist
828 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
829 "%s(%u, %d): stream doesn't exist", __FUNCTION__, stream_id,
830 delay_ms);
831 return -1;
832 }
833
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000834 assert(item->second != NULL);
835 return item->second->SetExpectedRenderDelay(delay_ms);
mflodman@webrtc.orgf4f21452012-09-28 11:27:35 +0000836}
837
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000838int32_t ModuleVideoRenderImpl::ConfigureRenderer(
839 const uint32_t streamId,
niklase@google.com470e71d2011-07-07 08:21:25 +0000840 const unsigned int zOrder,
841 const float left,
842 const float top,
843 const float right,
844 const float bottom)
845{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000846 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000847
848 if (!_ptrRenderer)
849 {
850 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
851 "%s: No renderer", __FUNCTION__);
852 return false;
853 }
854 return _ptrRenderer->ConfigureRenderer(streamId, zOrder, left, top, right,
855 bottom);
856}
857
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000858int32_t ModuleVideoRenderImpl::SetStartImage(
859 const uint32_t streamId,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000860 const I420VideoFrame& videoFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000861{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000862 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000863
864 if (!_ptrRenderer)
865 {
866 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
867 "%s: No renderer", __FUNCTION__);
868 return -1;
869 }
870
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000871 IncomingVideoStreamMap::const_iterator item =
872 _streamRenderMap.find(streamId);
873 if (item == _streamRenderMap.end())
niklase@google.com470e71d2011-07-07 08:21:25 +0000874 {
875 // This stream doesn't exist
876 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
877 "%s: stream doesn't exist", __FUNCTION__);
878 return -1;
879 }
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000880 assert (item->second != NULL);
881 return item->second->SetStartImage(videoFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000882
883}
884
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000885int32_t ModuleVideoRenderImpl::SetTimeoutImage(
886 const uint32_t streamId,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000887 const I420VideoFrame& videoFrame,
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000888 const uint32_t timeout)
niklase@google.com470e71d2011-07-07 08:21:25 +0000889{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000890 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000891
892 if (!_ptrRenderer)
893 {
894 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
895 "%s: No renderer", __FUNCTION__);
896 return -1;
897 }
898
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000899 IncomingVideoStreamMap::const_iterator item =
900 _streamRenderMap.find(streamId);
901 if (item == _streamRenderMap.end())
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 {
903 // This stream doesn't exist
904 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
905 "%s: stream doesn't exist", __FUNCTION__);
906 return -1;
907 }
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000908 assert(item->second != NULL);
909 return item->second->SetTimeoutImage(videoFrame, timeout);
niklase@google.com470e71d2011-07-07 08:21:25 +0000910}
911
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000912int32_t ModuleVideoRenderImpl::MirrorRenderStream(const int renderId,
913 const bool enable,
914 const bool mirrorXAxis,
915 const bool mirrorYAxis)
niklase@google.com470e71d2011-07-07 08:21:25 +0000916{
mflodman@webrtc.org0e703f42012-03-06 12:02:20 +0000917 CriticalSectionScoped cs(&_moduleCrit);
niklase@google.com470e71d2011-07-07 08:21:25 +0000918
919 if (!_ptrRenderer)
920 {
921 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
922 "%s: No renderer", __FUNCTION__);
923 return -1;
924 }
925
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000926 IncomingVideoStreamMap::const_iterator item =
927 _streamRenderMap.find(renderId);
928 if (item == _streamRenderMap.end())
niklase@google.com470e71d2011-07-07 08:21:25 +0000929 {
930 // This stream doesn't exist
931 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
932 "%s: stream doesn't exist", __FUNCTION__);
933 return 0;
934 }
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000935 assert(item->second != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000936
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000937 return item->second->EnableMirroring(enable, mirrorXAxis, mirrorYAxis);
niklase@google.com470e71d2011-07-07 08:21:25 +0000938}
939
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000940} // namespace webrtc