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 29 namespace webrtc { 30 31 JavaVM* VideoRenderAndroid::g_jvm = NULL; 32 33 int32_t SetRenderAndroidVM(JavaVM* javaVM) { 34 WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, -1, "%s", __FUNCTION__); 35 VideoRenderAndroid::g_jvm = javaVM; 36 return 0; 37 } 38 39 VideoRenderAndroid::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 56 VideoRenderAndroid::~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 73 int32_t VideoRenderAndroid::ChangeUniqueId(const int32_t id) { 74 CriticalSectionScoped cs(&_critSect); 75 _id = id; 76 77 return 0; 78 } 79 80 int32_t VideoRenderAndroid::ChangeWindow(void* /*window*/) { 81 return -1; 82 } 83 84 VideoRenderCallback* 85 VideoRenderAndroid::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 116 int32_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 131 int32_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 141 int32_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 174 int32_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 202 void 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 211 bool VideoRenderAndroid::JavaRenderThreadFun(void* obj) { 212 return static_cast<VideoRenderAndroid*> (obj)->JavaRenderThreadProcess(); 213 } 214 215 bool 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 256 VideoRenderType VideoRenderAndroid::RenderType() { 257 return _renderType; 258 } 259 260 RawVideoType VideoRenderAndroid::PerferedVideoType() { 261 return kVideoI420; 262 } 263 264 bool VideoRenderAndroid::FullScreen() { 265 return false; 266 } 267 268 int32_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 276 int32_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 284 uint32_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 291 int32_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 302 int32_t VideoRenderAndroid::SetTransparentBackground(const bool enable) { 303 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 304 "%s - not supported on Android", __FUNCTION__); 305 return -1; 306 } 307 308 int32_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 320 int32_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 333 int32_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