tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

desktop_device_info.cc (13411B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "desktop_device_info.h"
      6 
      7 #include <cstddef>
      8 #include <cstring>
      9 #include <map>
     10 #include <memory>
     11 
     12 #include "VideoEngine.h"
     13 #include "modules/desktop_capture/desktop_capture_options.h"
     14 #include "modules/desktop_capture/desktop_capturer.h"
     15 #include "mozilla/StaticPrefs_media.h"
     16 #include "mozilla/SyncRunnable.h"
     17 #include "nsIBrowserWindowTracker.h"
     18 #include "nsImportModule.h"
     19 #include "nsPrintfCString.h"
     20 
     21 using mozilla::camera::CaptureDeviceType;
     22 
     23 namespace webrtc {
     24 
     25 void DesktopSource::setScreenId(ScreenId aId) { mScreenId = aId; }
     26 void DesktopSource::setName(nsCString&& aName) { mName = std::move(aName); }
     27 void DesktopSource::setUniqueId(nsCString&& aId) { mUniqueId = std::move(aId); }
     28 void DesktopSource::setPid(const pid_t aPid) { mPid = aPid; }
     29 
     30 ScreenId DesktopSource::getScreenId() const { return mScreenId; }
     31 const nsCString& DesktopSource::getName() const { return mName; }
     32 const nsCString& DesktopSource::getUniqueId() const { return mUniqueId; }
     33 pid_t DesktopSource::getPid() const { return mPid; }
     34 
     35 void TabSource::setBrowserId(uint64_t aId) { mBrowserId = aId; }
     36 void TabSource::setUniqueId(nsCString&& aId) { mUniqueId = std::move(aId); }
     37 void TabSource::setName(nsCString&& aName) { mName = std::move(aName); }
     38 
     39 uint64_t TabSource::getBrowserId() const { return mBrowserId; }
     40 const nsCString& TabSource::getName() const { return mName; }
     41 const nsCString& TabSource::getUniqueId() const { return mUniqueId; }
     42 
     43 template <CaptureDeviceType Type, typename Device>
     44 class DesktopDeviceInfoImpl : public CaptureInfo<Device> {
     45 public:
     46  explicit DesktopDeviceInfoImpl(const DesktopCaptureOptions& aOptions);
     47 
     48  void Refresh() override;
     49  size_t getSourceCount() const override;
     50  const Device* getSource(size_t aIndex) const override;
     51 
     52 protected:
     53  const DesktopCaptureOptions mOptions;
     54  std::map<intptr_t, Device> mDeviceList;
     55 };
     56 
     57 template <CaptureDeviceType Type, typename Device>
     58 DesktopDeviceInfoImpl<Type, Device>::DesktopDeviceInfoImpl(
     59    const DesktopCaptureOptions& aOptions)
     60    : mOptions(aOptions) {}
     61 
     62 template <CaptureDeviceType Type, typename Device>
     63 size_t DesktopDeviceInfoImpl<Type, Device>::getSourceCount() const {
     64  return mDeviceList.size();
     65 }
     66 
     67 template <CaptureDeviceType Type, typename Device>
     68 const Device* DesktopDeviceInfoImpl<Type, Device>::getSource(
     69    size_t aIndex) const {
     70  if (aIndex >= mDeviceList.size()) {
     71    return nullptr;
     72  }
     73  auto it = mDeviceList.begin();
     74  std::advance(it, aIndex);
     75  return &std::get<Device>(*it);
     76 }
     77 
     78 static std::map<intptr_t, TabSource> InitializeTabList() {
     79  std::map<intptr_t, TabSource> tabList;
     80  if (!mozilla::StaticPrefs::media_getusermedia_browser_enabled()) {
     81    return tabList;
     82  }
     83 
     84  // This is a sync dispatch to main thread, which is unfortunate. To
     85  // call JavaScript we have to be on main thread, but the remaining
     86  // DesktopCapturer very much wants to be off main thread. This might
     87  // be solvable by calling this method earlier on while we're still on
     88  // main thread and plumbing the information down to here.
     89  nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(__func__, [&] {
     90    nsresult rv;
     91    nsCOMPtr<nsIBrowserWindowTracker> bwt =
     92        do_ImportESModule("resource:///modules/BrowserWindowTracker.sys.mjs",
     93                          "BrowserWindowTracker", &rv);
     94    if (NS_FAILED(rv)) {
     95      return;
     96    }
     97 
     98    nsTArray<RefPtr<nsIVisibleTab>> tabArray;
     99    rv = bwt->GetAllVisibleTabs(tabArray);
    100    if (NS_FAILED(rv)) {
    101      return;
    102    }
    103 
    104    for (const auto& browserTab : tabArray) {
    105      nsString contentTitle;
    106      browserTab->GetContentTitle(contentTitle);
    107      int64_t browserId;
    108      browserTab->GetBrowserId(&browserId);
    109 
    110      auto result =
    111          tabList.try_emplace(mozilla::AssertedCast<intptr_t>(browserId));
    112      auto& [iter, inserted] = result;
    113      if (!inserted) {
    114        MOZ_ASSERT_UNREACHABLE("Duplicate browser ids");
    115        continue;
    116      }
    117      auto& [key, desktopTab] = *iter;
    118      desktopTab.setBrowserId(browserId);
    119      desktopTab.setName(NS_ConvertUTF16toUTF8(contentTitle));
    120      desktopTab.setUniqueId(nsPrintfCString("%" PRId64, browserId));
    121    }
    122  });
    123  mozilla::SyncRunnable::DispatchToThread(
    124      mozilla::GetMainThreadSerialEventTarget(), runnable);
    125  return tabList;
    126 }
    127 
    128 template <CaptureDeviceType Type, typename Device>
    129 void DesktopDeviceInfoImpl<Type, Device>::Refresh() {
    130  if constexpr (Type == CaptureDeviceType::Browser) {
    131    mDeviceList = InitializeTabList();
    132    return;
    133  }
    134 
    135  mDeviceList.clear();
    136 
    137  std::unique_ptr<DesktopCapturer> cap;
    138  if constexpr (Type == CaptureDeviceType::Screen ||
    139                Type == CaptureDeviceType::Window) {
    140    cap = DesktopCapturer::CreateGenericCapturer(mOptions);
    141    if constexpr (Type == CaptureDeviceType::Screen) {
    142      if (!cap) {
    143        cap = DesktopCapturer::CreateScreenCapturer(mOptions);
    144      }
    145    } else if constexpr (Type == CaptureDeviceType::Window) {
    146      if (cap) {
    147        // We only use the screen side of a generic capturer for enumeration.
    148        return;
    149      }
    150      cap = DesktopCapturer::CreateWindowCapturer(mOptions);
    151    }
    152 
    153    if (!cap) {
    154      return;
    155    }
    156 
    157    DesktopCapturer::SourceList list;
    158    if (!cap->GetSourceList(&list)) {
    159      return;
    160    }
    161 
    162    for (const auto& elem : list) {
    163      auto result = mDeviceList.try_emplace(elem.id);
    164      auto& [iter, inserted] = result;
    165      if (!inserted) {
    166        MOZ_ASSERT_UNREACHABLE("Duplicate screen id");
    167        continue;
    168      }
    169      auto& [key, device] = *iter;
    170      device.setScreenId(elem.id);
    171      device.setUniqueId(nsPrintfCString("%" PRIdPTR, elem.id));
    172      if (Type == CaptureDeviceType::Screen && list.size() == 1) {
    173        device.setName(nsCString("Primary Monitor"));
    174      } else {
    175        device.setName(nsCString(elem.title.c_str()));
    176      }
    177      device.setPid(elem.pid);
    178    }
    179  }
    180 }
    181 
    182 std::unique_ptr<DesktopCaptureInfo> CreateScreenCaptureInfo(
    183    const DesktopCaptureOptions& aOptions) {
    184  std::unique_ptr<DesktopCaptureInfo> info(
    185      new DesktopDeviceInfoImpl<CaptureDeviceType::Screen, DesktopSource>(
    186          aOptions));
    187  info->Refresh();
    188  return info;
    189 }
    190 
    191 std::unique_ptr<DesktopCaptureInfo> CreateWindowCaptureInfo(
    192    const DesktopCaptureOptions& aOptions) {
    193  std::unique_ptr<DesktopCaptureInfo> info(
    194      new DesktopDeviceInfoImpl<CaptureDeviceType::Window, DesktopSource>(
    195          aOptions));
    196  info->Refresh();
    197  return info;
    198 }
    199 
    200 std::unique_ptr<TabCaptureInfo> CreateTabCaptureInfo() {
    201  std::unique_ptr<TabCaptureInfo> info(
    202      new DesktopDeviceInfoImpl<CaptureDeviceType::Browser, TabSource>(
    203          DesktopCaptureOptions()));
    204  info->Refresh();
    205  return info;
    206 }
    207 
    208 // simulate deviceInfo interface for video engine, bridge screen/application and
    209 // real screen/application device info
    210 template <typename Source>
    211 class DesktopCaptureDeviceInfo final : public VideoCaptureModule::DeviceInfo {
    212 public:
    213  DesktopCaptureDeviceInfo(int32_t aId,
    214                           std::unique_ptr<CaptureInfo<Source>>&& aSourceInfo);
    215 
    216  int32_t Refresh() override;
    217 
    218  uint32_t NumberOfDevices() override;
    219  int32_t GetDeviceName(uint32_t aDeviceNumber, char* aDeviceNameUTF8,
    220                        uint32_t aDeviceNameUTF8Size, char* aDeviceUniqueIdUTF8,
    221                        uint32_t aDeviceUniqueIdUTF8Size,
    222                        char* aProductUniqueIdUTF8,
    223                        uint32_t aProductUniqueIdUTF8Size, pid_t* aPid,
    224                        bool* aDeviceIsPlaceholder = nullptr) override;
    225 
    226  int32_t DisplayCaptureSettingsDialogBox(const char* aDeviceUniqueIdUTF8,
    227                                          const char* aDialogTitleUTF8,
    228                                          void* aParentWindow,
    229                                          uint32_t aPositionX,
    230                                          uint32_t aPositionY) override;
    231  int32_t NumberOfCapabilities(const char* aDeviceUniqueIdUTF8) override;
    232  int32_t GetCapability(const char* aDeviceUniqueIdUTF8,
    233                        uint32_t aDeviceCapabilityNumber,
    234                        VideoCaptureCapability& aCapability) override;
    235 
    236  int32_t GetBestMatchedCapability(const char* aDeviceUniqueIdUTF8,
    237                                   const VideoCaptureCapability& aRequested,
    238                                   VideoCaptureCapability& aResulting) override;
    239  int32_t GetOrientation(const char* aDeviceUniqueIdUTF8,
    240                         VideoRotation& aOrientation) override;
    241 
    242 protected:
    243  int32_t mId;
    244  std::unique_ptr<CaptureInfo<Source>> mDeviceInfo;
    245 };
    246 
    247 using DesktopDeviceInfo = DesktopCaptureDeviceInfo<DesktopSource>;
    248 using TabDeviceInfo = DesktopCaptureDeviceInfo<TabSource>;
    249 
    250 template <typename Source>
    251 DesktopCaptureDeviceInfo<Source>::DesktopCaptureDeviceInfo(
    252    int32_t aId, std::unique_ptr<CaptureInfo<Source>>&& aSourceInfo)
    253    : mId(aId), mDeviceInfo(std::move(aSourceInfo)) {}
    254 
    255 template <typename Source>
    256 int32_t DesktopCaptureDeviceInfo<Source>::Refresh() {
    257  mDeviceInfo->Refresh();
    258  return 0;
    259 }
    260 
    261 template <typename Source>
    262 uint32_t DesktopCaptureDeviceInfo<Source>::NumberOfDevices() {
    263  return mDeviceInfo->getSourceCount();
    264 }
    265 
    266 template <>
    267 int32_t DesktopCaptureDeviceInfo<DesktopSource>::GetDeviceName(
    268    uint32_t aDeviceNumber, char* aDeviceNameUTF8, uint32_t aDeviceNameUTF8Size,
    269    char* aDeviceUniqueIdUTF8, uint32_t aDeviceUniqueIdUTF8Size,
    270    char* aProductUniqueIdUTF8, uint32_t aProductUniqueIdUTF8Size, pid_t* aPid,
    271    bool* aDeviceIsPlaceholder) {
    272  // always initialize output
    273  if (aDeviceNameUTF8 && aDeviceNameUTF8Size > 0) {
    274    memset(aDeviceNameUTF8, 0, aDeviceNameUTF8Size);
    275  }
    276  if (aDeviceUniqueIdUTF8 && aDeviceUniqueIdUTF8Size > 0) {
    277    memset(aDeviceUniqueIdUTF8, 0, aDeviceUniqueIdUTF8Size);
    278  }
    279  if (aProductUniqueIdUTF8 && aProductUniqueIdUTF8Size > 0) {
    280    memset(aProductUniqueIdUTF8, 0, aProductUniqueIdUTF8Size);
    281  }
    282 
    283  const DesktopSource* source = mDeviceInfo->getSource(aDeviceNumber);
    284  if (!source) {
    285    return 0;
    286  }
    287 
    288  const nsCString& deviceName = source->getName();
    289  size_t len = deviceName.Length();
    290  if (len && aDeviceNameUTF8 && len < aDeviceNameUTF8Size) {
    291    memcpy(aDeviceNameUTF8, deviceName.Data(), len);
    292  }
    293 
    294  const nsCString& deviceUniqueId = source->getUniqueId();
    295  len = deviceUniqueId.Length();
    296  if (len && aDeviceUniqueIdUTF8 && len < aDeviceUniqueIdUTF8Size) {
    297    memcpy(aDeviceUniqueIdUTF8, deviceUniqueId.Data(), len);
    298  }
    299 
    300  if (aPid) {
    301    *aPid = source->getPid();
    302  }
    303 
    304  return 0;
    305 }
    306 
    307 template <>
    308 int32_t DesktopCaptureDeviceInfo<TabSource>::GetDeviceName(
    309    uint32_t aDeviceNumber, char* aDeviceNameUTF8, uint32_t aDeviceNameUTF8Size,
    310    char* aDeviceUniqueIdUTF8, uint32_t aDeviceUniqueIdUTF8Size,
    311    char* aProductUniqueIdUTF8, uint32_t aProductUniqueIdUTF8Size, pid_t* aPid,
    312    bool* aDeviceIsPlaceholder) {
    313  // always initialize output
    314  if (aDeviceNameUTF8 && aDeviceNameUTF8Size > 0) {
    315    memset(aDeviceNameUTF8, 0, aDeviceNameUTF8Size);
    316  }
    317  if (aDeviceUniqueIdUTF8 && aDeviceUniqueIdUTF8Size > 0) {
    318    memset(aDeviceUniqueIdUTF8, 0, aDeviceUniqueIdUTF8Size);
    319  }
    320  if (aProductUniqueIdUTF8 && aProductUniqueIdUTF8Size > 0) {
    321    memset(aProductUniqueIdUTF8, 0, aProductUniqueIdUTF8Size);
    322  }
    323 
    324  const TabSource* source = mDeviceInfo->getSource(aDeviceNumber);
    325  if (!source) {
    326    return 0;
    327  }
    328 
    329  const nsCString& deviceName = source->getName();
    330  size_t len = deviceName.Length();
    331  if (len && aDeviceNameUTF8 && len < aDeviceNameUTF8Size) {
    332    memcpy(aDeviceNameUTF8, deviceName.Data(), len);
    333  }
    334 
    335  const nsCString& deviceUniqueId = source->getUniqueId();
    336  len = deviceUniqueId.Length();
    337  if (len && aDeviceUniqueIdUTF8 && len < aDeviceUniqueIdUTF8Size) {
    338    memcpy(aDeviceUniqueIdUTF8, deviceUniqueId.Data(), len);
    339  }
    340 
    341  return 0;
    342 }
    343 
    344 template <typename Source>
    345 int32_t DesktopCaptureDeviceInfo<Source>::DisplayCaptureSettingsDialogBox(
    346    const char* aDeviceUniqueIdUTF8, const char* aDialogTitleUTF8,
    347    void* aParentWindow, uint32_t aPositionX, uint32_t aPositionY) {
    348  // no device properties to change
    349  return 0;
    350 }
    351 
    352 template <typename Source>
    353 int32_t DesktopCaptureDeviceInfo<Source>::NumberOfCapabilities(
    354    const char* aDeviceUniqueIdUTF8) {
    355  return 0;
    356 }
    357 
    358 template <typename Source>
    359 int32_t DesktopCaptureDeviceInfo<Source>::GetCapability(
    360    const char* aDeviceUniqueIdUTF8, uint32_t aDeviceCapabilityNumber,
    361    VideoCaptureCapability& aCapability) {
    362  return 0;
    363 }
    364 
    365 template <typename Source>
    366 int32_t DesktopCaptureDeviceInfo<Source>::GetBestMatchedCapability(
    367    const char* aDeviceUniqueIdUTF8, const VideoCaptureCapability& aRequested,
    368    VideoCaptureCapability& aResulting) {
    369  return 0;
    370 }
    371 
    372 template <typename Source>
    373 int32_t DesktopCaptureDeviceInfo<Source>::GetOrientation(
    374    const char* aDeviceUniqueIdUTF8, VideoRotation& aOrientation) {
    375  return 0;
    376 }
    377 
    378 std::shared_ptr<VideoCaptureModule::DeviceInfo> CreateDesktopDeviceInfo(
    379    int32_t aId, std::unique_ptr<DesktopCaptureInfo>&& aInfo) {
    380  return std::make_shared<DesktopDeviceInfo>(aId, std::move(aInfo));
    381 }
    382 
    383 std::shared_ptr<VideoCaptureModule::DeviceInfo> CreateTabDeviceInfo(
    384    int32_t aId, std::unique_ptr<TabCaptureInfo>&& aInfo) {
    385  return std::make_shared<TabDeviceInfo>(aId, std::move(aInfo));
    386 }
    387 }  // namespace webrtc