1/*
2 *  Copyright (c) 2012 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#include "webrtc/modules/video_render/android/video_render_android_impl.h"
12
13#include "webrtc/modules/video_render/video_render_internal.h"
14#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
15#include "webrtc/system_wrappers/interface/event_wrapper.h"
16#include "webrtc/system_wrappers/interface/thread_wrapper.h"
17#include "webrtc/system_wrappers/interface/tick_util.h"
18
19#ifdef ANDROID
20#include <android/log.h>
21#include <stdio.h>
22
23#undef WEBRTC_TRACE
24#define WEBRTC_TRACE(a,b,c,...)  __android_log_print(ANDROID_LOG_DEBUG, "*WEBRTCN*", __VA_ARGS__)
25#else
26#include "webrtc/system_wrappers/interface/trace.h"
27#endif
28
29namespace webrtc {
30
31JavaVM* VideoRenderAndroid::g_jvm = NULL;
32
33int32_t SetRenderAndroidVM(JavaVM* javaVM) {
34  WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, -1, "%s", __FUNCTION__);
35  VideoRenderAndroid::g_jvm = javaVM;
36  return 0;
37}
38
39VideoRenderAndroid::VideoRenderAndroid(
40    const int32_t id,
41    const VideoRenderType videoRenderType,
42    void* window,
43    const bool /*fullscreen*/):
44    _id(id),
45    _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
46    _renderType(videoRenderType),
47    _ptrWindow((jobject)(window)),
48    _javaShutDownFlag(false),
49    _javaShutdownEvent(*EventWrapper::Create()),
50    _javaRenderEvent(*EventWrapper::Create()),
51    _lastJavaRenderEvent(0),
52    _javaRenderJniEnv(NULL),
53    _javaRenderThread(NULL) {
54}
55
56VideoRenderAndroid::~VideoRenderAndroid() {
57  WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id,
58               "VideoRenderAndroid dtor");
59
60  if (_javaRenderThread)
61    StopRender();
62
63  for (AndroidStreamMap::iterator it = _streamsMap.begin();
64       it != _streamsMap.end();
65       ++it) {
66    delete it->second;
67  }
68  delete &_javaShutdownEvent;
69  delete &_javaRenderEvent;
70  delete &_critSect;
71}
72
73int32_t VideoRenderAndroid::ChangeUniqueId(const int32_t id) {
74  CriticalSectionScoped cs(&_critSect);
75  _id = id;
76
77  return 0;
78}
79
80int32_t VideoRenderAndroid::ChangeWindow(void* /*window*/) {
81  return -1;
82}
83
84VideoRenderCallback*
85VideoRenderAndroid::AddIncomingRenderStream(const uint32_t streamId,
86                                            const uint32_t zOrder,
87                                            const float left, const float top,
88                                            const float right,
89                                            const float bottom) {
90  CriticalSectionScoped cs(&_critSect);
91
92  AndroidStream* renderStream = NULL;
93  AndroidStreamMap::iterator item = _streamsMap.find(streamId);
94  if (item != _streamsMap.end() && item->second != NULL) {
95    WEBRTC_TRACE(kTraceInfo,
96                 kTraceVideoRenderer,
97                 -1,
98                 "%s: Render stream already exists",
99                 __FUNCTION__);
100    return renderStream;
101  }
102
103  renderStream = CreateAndroidRenderChannel(streamId, zOrder, left, top,
104                                            right, bottom, *this);
105  if (renderStream) {
106    _streamsMap[streamId] = renderStream;
107  }
108  else {
109    WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
110                 "(%s:%d): renderStream is NULL", __FUNCTION__, __LINE__);
111    return NULL;
112  }
113  return renderStream;
114}
115
116int32_t VideoRenderAndroid::DeleteIncomingRenderStream(
117    const uint32_t streamId) {
118  CriticalSectionScoped cs(&_critSect);
119
120  AndroidStreamMap::iterator item = _streamsMap.find(streamId);
121  if (item == _streamsMap.end()) {
122    WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
123                 "(%s:%d): renderStream is NULL", __FUNCTION__, __LINE__);
124    return -1;
125  }
126  delete item->second;
127  _streamsMap.erase(item);
128  return 0;
129}
130
131int32_t VideoRenderAndroid::GetIncomingRenderStreamProperties(
132    const uint32_t streamId,
133    uint32_t& zOrder,
134    float& left,
135    float& top,
136    float& right,
137    float& bottom) const {
138  return -1;
139}
140
141int32_t VideoRenderAndroid::StartRender() {
142  CriticalSectionScoped cs(&_critSect);
143
144  if (_javaRenderThread) {
145    // StartRender is called when this stream should start render.
146    // However StopRender is not called when the streams stop rendering.
147    // Thus the the thread  is only deleted when the renderer is removed.
148    WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id,
149                 "%s, Render thread already exist", __FUNCTION__);
150    return 0;
151  }
152
153  _javaRenderThread = ThreadWrapper::CreateThread(JavaRenderThreadFun, this,
154                                                  kRealtimePriority,
155                                                  "AndroidRenderThread");
156  if (!_javaRenderThread) {
157    WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
158                 "%s: No thread", __FUNCTION__);
159    return -1;
160  }
161
162  unsigned int tId = 0;
163  if (_javaRenderThread->Start(tId))
164    WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id,
165                 "%s: thread started: %u", __FUNCTION__, tId);
166  else {
167    WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
168                 "%s: Could not start send thread", __FUNCTION__);
169    return -1;
170  }
171  return 0;
172}
173
174int32_t VideoRenderAndroid::StopRender() {
175  WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:", __FUNCTION__);
176  {
177    CriticalSectionScoped cs(&_critSect);
178    if (!_javaRenderThread)
179    {
180      return -1;
181    }
182    _javaShutDownFlag = true;
183    _javaRenderEvent.Set();
184  }
185
186  _javaShutdownEvent.Wait(3000);
187  CriticalSectionScoped cs(&_critSect);
188  _javaRenderThread->SetNotAlive();
189  if (_javaRenderThread->Stop()) {
190    delete _javaRenderThread;
191    _javaRenderThread = NULL;
192  }
193  else {
194    assert(false);
195    WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
196                 "%s: Not able to stop thread, leaking", __FUNCTION__);
197    _javaRenderThread = NULL;
198  }
199  return 0;
200}
201
202void VideoRenderAndroid::ReDraw() {
203  CriticalSectionScoped cs(&_critSect);
204  // Allow redraw if it was more than 20ms since last.
205  if (_lastJavaRenderEvent < TickTime::MillisecondTimestamp() - 20) {
206    _lastJavaRenderEvent = TickTime::MillisecondTimestamp();
207    _javaRenderEvent.Set();
208  }
209}
210
211bool VideoRenderAndroid::JavaRenderThreadFun(void* obj) {
212  return static_cast<VideoRenderAndroid*> (obj)->JavaRenderThreadProcess();
213}
214
215bool VideoRenderAndroid::JavaRenderThreadProcess()
216{
217  _javaRenderEvent.Wait(1000);
218
219  CriticalSectionScoped cs(&_critSect);
220  if (!_javaRenderJniEnv) {
221    // try to attach the thread and get the env
222    // Attach this thread to JVM
223    jint res = g_jvm->AttachCurrentThread(&_javaRenderJniEnv, NULL);
224
225    // Get the JNI env for this thread
226    if ((res < 0) || !_javaRenderJniEnv) {
227      WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
228                   "%s: Could not attach thread to JVM (%d, %p)",
229                   __FUNCTION__, res, _javaRenderJniEnv);
230      return false;
231    }
232  }
233
234  for (AndroidStreamMap::iterator it = _streamsMap.begin();
235       it != _streamsMap.end();
236       ++it) {
237    it->second->DeliverFrame(_javaRenderJniEnv);
238  }
239
240  if (_javaShutDownFlag) {
241    if (g_jvm->DetachCurrentThread() < 0)
242      WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
243                   "%s: Could not detach thread from JVM", __FUNCTION__);
244    else {
245      WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id,
246                   "%s: Java thread detached", __FUNCTION__);
247    }
248    _javaRenderJniEnv = NULL;
249    _javaShutDownFlag = false;
250    _javaShutdownEvent.Set();
251    return false; // Do not run this thread again.
252  }
253  return true;
254}
255
256VideoRenderType VideoRenderAndroid::RenderType() {
257  return _renderType;
258}
259
260RawVideoType VideoRenderAndroid::PerferedVideoType() {
261  return kVideoI420;
262}
263
264bool VideoRenderAndroid::FullScreen() {
265  return false;
266}
267
268int32_t VideoRenderAndroid::GetGraphicsMemory(
269    uint64_t& /*totalGraphicsMemory*/,
270    uint64_t& /*availableGraphicsMemory*/) const {
271  WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
272               "%s - not supported on Android", __FUNCTION__);
273  return -1;
274}
275
276int32_t VideoRenderAndroid::GetScreenResolution(
277    uint32_t& /*screenWidth*/,
278    uint32_t& /*screenHeight*/) const {
279  WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
280               "%s - not supported on Android", __FUNCTION__);
281  return -1;
282}
283
284uint32_t VideoRenderAndroid::RenderFrameRate(
285    const uint32_t /*streamId*/) {
286  WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
287               "%s - not supported on Android", __FUNCTION__);
288  return -1;
289}
290
291int32_t VideoRenderAndroid::SetStreamCropping(
292    const uint32_t /*streamId*/,
293    const float /*left*/,
294    const float /*top*/,
295    const float /*right*/,
296    const float /*bottom*/) {
297  WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
298               "%s - not supported on Android", __FUNCTION__);
299  return -1;
300}
301
302int32_t VideoRenderAndroid::SetTransparentBackground(const bool enable) {
303  WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
304               "%s - not supported on Android", __FUNCTION__);
305  return -1;
306}
307
308int32_t VideoRenderAndroid::ConfigureRenderer(
309    const uint32_t streamId,
310    const unsigned int zOrder,
311    const float left,
312    const float top,
313    const float right,
314    const float bottom) {
315  WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
316               "%s - not supported on Android", __FUNCTION__);
317  return -1;
318}
319
320int32_t VideoRenderAndroid::SetText(
321    const uint8_t textId,
322    const uint8_t* text,
323    const int32_t textLength,
324    const uint32_t textColorRef,
325    const uint32_t backgroundColorRef,
326    const float left, const float top,
327    const float rigth, const float bottom) {
328  WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
329               "%s - not supported on Android", __FUNCTION__);
330  return -1;
331}
332
333int32_t VideoRenderAndroid::SetBitmap(const void* bitMap,
334                                      const uint8_t pictureId,
335                                      const void* colorKey,
336                                      const float left, const float top,
337                                      const float right,
338                                      const float bottom) {
339  WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
340               "%s - not supported on Android", __FUNCTION__);
341  return -1;
342}
343
344}  // namespace webrtc
345