Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/systemservices/VideoEngine.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set sw=2 ts=8 et ft=cpp : */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "VideoEngine.h"
8
#include "webrtc/video_engine/browser_capture_impl.h"
9
#include "webrtc/system_wrappers/include/clock.h"
10
#ifdef WEBRTC_ANDROID
11
#include "webrtc/modules/video_capture/video_capture.h"
12
#endif
13
14
#ifdef MOZ_WIDGET_ANDROID
15
#include "mozilla/jni/Utils.h"
16
#endif
17
18
namespace mozilla {
19
namespace camera {
20
21
#undef LOG
22
#undef LOG_ENABLED
23
mozilla::LazyLogModule gVideoEngineLog("VideoEngine");
24
0
#define LOG(args) MOZ_LOG(gVideoEngineLog, mozilla::LogLevel::Debug, args)
25
#define LOG_ENABLED() MOZ_LOG_TEST(gVideoEngineLog, mozilla::LogLevel::Debug)
26
27
int VideoEngine::sId = 0;
28
#if defined(ANDROID)
29
int VideoEngine::SetAndroidObjects() {
30
  LOG((__PRETTY_FUNCTION__));
31
32
  JavaVM* const javaVM = mozilla::jni::GetVM();
33
  if (!javaVM || webrtc::SetCaptureAndroidVM(javaVM) != 0) {
34
    LOG(("Could not set capture Android VM"));
35
    return -1;
36
  }
37
#ifdef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
38
  if (webrtc::SetRenderAndroidVM(javaVM) != 0) {
39
    LOG(("Could not set render Android VM"));
40
    return -1;
41
  }
42
#endif
43
  return 0;
44
}
45
#endif
46
47
void
48
0
VideoEngine::CreateVideoCapture(int32_t& id, const char* deviceUniqueIdUTF8) {
49
0
  LOG((__PRETTY_FUNCTION__));
50
0
  MOZ_ASSERT(deviceUniqueIdUTF8);
51
0
52
0
  id = GenerateId();
53
0
  LOG(("CaptureDeviceInfo.type=%s id=%d",mCaptureDevInfo.TypeName(),id));
54
0
55
0
  for (auto &it : mCaps) {
56
0
    if (it.second.VideoCapture() &&
57
0
        it.second.VideoCapture()->CurrentDeviceName() &&
58
0
        strcmp(it.second.VideoCapture()->CurrentDeviceName(), deviceUniqueIdUTF8) == 0) {
59
0
      mIdMap.emplace(id, it.first);
60
0
      return;
61
0
    }
62
0
  }
63
0
64
0
  CaptureEntry entry = {-1, nullptr};
65
0
66
0
  if (mCaptureDevInfo.type == webrtc::CaptureDeviceType::Camera) {
67
0
    entry = CaptureEntry(id,
68
0
             webrtc::VideoCaptureFactory::Create(deviceUniqueIdUTF8));
69
0
  } else {
70
0
#ifndef WEBRTC_ANDROID
71
0
#ifdef MOZ_X11
72
0
    webrtc::VideoCaptureModule* captureModule;
73
0
    auto type = mCaptureDevInfo.type;
74
0
    nsresult result = NS_DispatchToMainThread(media::NewRunnableFrom(
75
0
      [&captureModule, id, deviceUniqueIdUTF8, type]() -> nsresult {
76
0
        captureModule = webrtc::DesktopCaptureImpl::Create(id, deviceUniqueIdUTF8, type);
77
0
        return NS_OK;
78
0
      }), nsIEventTarget::DISPATCH_SYNC);
79
0
80
0
    if (result == NS_OK) {
81
0
      entry = CaptureEntry(id, captureModule);
82
0
    } else {
83
0
      return;
84
0
    }
85
#else
86
    entry = CaptureEntry(
87
        id,
88
        webrtc::DesktopCaptureImpl::Create(id, deviceUniqueIdUTF8, mCaptureDevInfo.type));
89
#endif
90
#else
91
    MOZ_ASSERT("CreateVideoCapture NO DESKTOP CAPTURE IMPL ON ANDROID" == nullptr);
92
#endif
93
  }
94
0
  mCaps.emplace(id, std::move(entry));
95
0
  mIdMap.emplace(id, id);
96
0
}
97
98
int
99
0
VideoEngine::ReleaseVideoCapture(const int32_t id) {
100
0
  bool found = false;
101
0
102
#ifdef DEBUG
103
  {
104
    auto it = mIdMap.find(id);
105
    MOZ_ASSERT(it != mIdMap.end());
106
    Unused << it;
107
  }
108
#endif
109
110
0
  for (auto &it : mIdMap) {
111
0
    if (it.first != id && it.second == mIdMap[id]) {
112
0
      // There are other tracks still using this hardware.
113
0
      found = true;
114
0
    }
115
0
  }
116
0
117
0
  if (!found) {
118
0
    WithEntry(id, [&found](CaptureEntry& cap) {
119
0
      cap.mVideoCaptureModule = nullptr;
120
0
      found = true;
121
0
    });
122
0
    MOZ_ASSERT(found);
123
0
    if (found) {
124
0
      auto it = mCaps.find(mIdMap[id]);
125
0
      MOZ_ASSERT(it != mCaps.end());
126
0
      mCaps.erase(it);
127
0
    }
128
0
  }
129
0
130
0
  mIdMap.erase(id);
131
0
  return found ? 0 : (-1);
132
0
}
133
134
std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo>
135
0
VideoEngine::GetOrCreateVideoCaptureDeviceInfo() {
136
0
  LOG((__PRETTY_FUNCTION__));
137
0
  int64_t currentTime = 0;
138
0
139
0
  const char * capDevTypeName =
140
0
    webrtc::CaptureDeviceInfo(mCaptureDevInfo.type).TypeName();
141
0
142
0
  if (mDeviceInfo) {
143
0
    LOG(("Device cache available."));
144
0
    // Camera cache is invalidated by HW change detection elsewhere
145
0
    if (mCaptureDevInfo.type == webrtc::CaptureDeviceType::Camera) {
146
0
      LOG(("returning cached CaptureDeviceInfo of type %s", capDevTypeName));
147
0
      return mDeviceInfo;
148
0
    }
149
0
    // Screen sharing cache is invalidated after the expiration time
150
0
    currentTime = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
151
0
    LOG(("Checking expiry, fetched current time of: %" PRId64, currentTime));
152
0
    LOG(("device cache expiration is %" PRId64, mExpiryTimeInMs));
153
0
    if (currentTime <= mExpiryTimeInMs) {
154
0
      LOG(("returning cached CaptureDeviceInfo of type %s", capDevTypeName));
155
0
      return mDeviceInfo;
156
0
    }
157
0
  }
158
0
159
0
  if (currentTime == 0) {
160
0
   currentTime = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
161
0
   LOG(("Fetched current time of: %" PRId64, currentTime));
162
0
  }
163
0
  mExpiryTimeInMs = currentTime + kCacheExpiryPeriodMs;
164
0
  LOG(("new device cache expiration is %" PRId64, mExpiryTimeInMs));
165
0
  LOG(("creating a new VideoCaptureDeviceInfo of type %s", capDevTypeName));
166
0
167
0
  switch (mCaptureDevInfo.type) {
168
0
    case webrtc::CaptureDeviceType::Camera: {
169
#ifdef MOZ_WIDGET_ANDROID
170
      if (SetAndroidObjects()) {
171
        LOG(("VideoEngine::SetAndroidObjects Failed"));
172
        break;
173
      }
174
#endif
175
      mDeviceInfo.reset(webrtc::VideoCaptureFactory::CreateDeviceInfo());
176
0
      LOG(("webrtc::CaptureDeviceType::Camera: Finished creating new device."));
177
0
      break;
178
0
    }
179
0
    case webrtc::CaptureDeviceType::Browser: {
180
0
      mDeviceInfo.reset(webrtc::BrowserDeviceInfoImpl::CreateDeviceInfo());
181
0
      LOG(("webrtc::CaptureDeviceType::Browser: Finished creating new device."));
182
0
      break;
183
0
    }
184
0
    // Window, Application, and Screen types are handled by DesktopCapture
185
0
    case webrtc::CaptureDeviceType::Window:
186
0
    case webrtc::CaptureDeviceType::Application:
187
0
    case webrtc::CaptureDeviceType::Screen: {
188
0
#if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_IOS)
189
0
      mDeviceInfo.reset(webrtc::DesktopCaptureImpl::CreateDeviceInfo(mId,mCaptureDevInfo.type));
190
0
      LOG(("screen capture: Finished creating new device."));
191
#else
192
      MOZ_ASSERT("GetVideoCaptureDeviceInfo NO DESKTOP CAPTURE IMPL ON ANDROID" == nullptr);
193
      mDeviceInfo.reset();
194
#endif
195
      break;
196
0
    }
197
0
  }
198
0
  LOG(("EXIT %s", __PRETTY_FUNCTION__));
199
0
  return mDeviceInfo;
200
0
}
201
202
const UniquePtr<const webrtc::Config>&
203
0
VideoEngine::GetConfiguration() {
204
0
  return mConfig;
205
0
}
206
207
already_AddRefed<VideoEngine>
208
VideoEngine::Create(UniquePtr<const webrtc::Config>&& aConfig)
209
0
{
210
0
  LOG((__PRETTY_FUNCTION__));
211
0
  LOG(("Creating new VideoEngine with CaptureDeviceType %s",
212
0
       aConfig->Get<webrtc::CaptureDeviceInfo>().TypeName()));
213
0
  return do_AddRef(new VideoEngine(std::move(aConfig)));
214
0
}
215
216
VideoEngine::CaptureEntry::CaptureEntry(int32_t aCapnum,
217
                                        rtc::scoped_refptr<webrtc::VideoCaptureModule> aCapture)
218
  : mCapnum(aCapnum)
219
  , mVideoCaptureModule(aCapture)
220
0
{}
221
222
rtc::scoped_refptr<webrtc::VideoCaptureModule>
223
0
VideoEngine::CaptureEntry::VideoCapture() {
224
0
  return mVideoCaptureModule;
225
0
}
226
227
int32_t
228
0
VideoEngine::CaptureEntry::Capnum() const {
229
0
  return mCapnum;
230
0
}
231
232
bool VideoEngine::WithEntry(const int32_t entryCapnum,
233
0
          const std::function<void(CaptureEntry &entry)>&& fn) {
234
#ifdef DEBUG
235
  {
236
    auto it = mIdMap.find(entryCapnum);
237
    MOZ_ASSERT(it != mIdMap.end());
238
    Unused << it;
239
  }
240
#endif
241
242
0
  auto it = mCaps.find(mIdMap[entryCapnum]);
243
0
  MOZ_ASSERT(it != mCaps.end());
244
0
  if (it == mCaps.end()) {
245
0
    return false;
246
0
  }
247
0
  fn(it->second);
248
0
  return true;
249
0
}
250
251
int32_t
252
0
VideoEngine::GenerateId() {
253
0
  // XXX Something better than this (a map perhaps, or a simple boolean TArray, given
254
0
  // the number in-use is O(1) normally!)
255
0
  return mId = sId++;
256
0
}
257
258
VideoEngine::VideoEngine(UniquePtr<const webrtc::Config>&& aConfig):
259
  mId(0),
260
  mCaptureDevInfo(aConfig->Get<webrtc::CaptureDeviceInfo>()),
261
  mDeviceInfo(nullptr),
262
  mConfig(std::move(aConfig))
263
0
{
264
0
  LOG((__PRETTY_FUNCTION__));
265
0
}
266
267
}
268
}