Home | History | Annotate | Download | only in android
      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