chromium/android_webview/browser/permission/media_access_permission_request.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/permission/media_access_permission_request.h"

#include <algorithm>
#include <utility>

#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/permission/aw_permission_request.h"
#include "android_webview/common/aw_features.h"
#include "content/public/browser/media_capture_devices.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"

using blink::MediaStreamDevice;
using blink::MediaStreamDevices;
using content::MediaCaptureDevices;

namespace android_webview {

namespace {

// Return the device specified by |device_id| if exists, otherwise the first
// available device is returned.
const MediaStreamDevice* GetDeviceByIdOrFirstAvailable(
    const MediaStreamDevices& devices,
    const std::vector<std::string>& device_ids) {
  if (devices.empty())
    return nullptr;

  if (!device_ids.empty()) {
    for (const auto& device : devices) {
      if (device.id == device_ids.front()) {
        return &device;
      }
    }
  }

  return &devices.front();
}

}  // namespace

MediaAccessPermissionRequest::MediaAccessPermissionRequest(
    const content::MediaStreamRequest& request,
    content::MediaResponseCallback callback,
    AwPermissionManager& permission_manager,
    bool can_cache_file_url_permissions)
    : request_(request),
      callback_(std::move(callback)),
      permission_manager_(permission_manager),
      can_cache_file_url_permissions_(can_cache_file_url_permissions) {}

MediaAccessPermissionRequest::~MediaAccessPermissionRequest() {}

void MediaAccessPermissionRequest::NotifyRequestResult(bool allowed) {
  std::unique_ptr<content::MediaStreamUI> ui;
  if (!allowed) {
    permission_manager_->ClearEnumerateDevicesCachedPermission(
        request_.url_origin,
        /* remove_audio */ request_.audio_type ==
            blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
        /* remove_video */ request_.video_type ==
            blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE);
    std::move(callback_).Run(
        blink::mojom::StreamDevicesSet(),
        blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
        std::move(ui));
    return;
  }

  blink::mojom::StreamDevicesSet stream_devices_set;
  stream_devices_set.stream_devices.emplace_back(
      blink::mojom::StreamDevices::New());
  blink::mojom::StreamDevices& devices = *stream_devices_set.stream_devices[0];
  if (request_.audio_type ==
      blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) {
    const MediaStreamDevices& audio_devices =
        audio_test_devices_.empty()
            ? MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices()
            : audio_test_devices_;
    const MediaStreamDevice* device = GetDeviceByIdOrFirstAvailable(
        audio_devices, request_.requested_audio_device_ids);
    if (device)
      devices.audio_device = *device;
    if (base::FeatureList::IsEnabled(features::kWebViewEnumerateDevicesCache) &&
        (request_.url_origin.scheme() != url::kFileScheme ||
         can_cache_file_url_permissions_)) {
      permission_manager_->SetOriginCanReadEnumerateDevicesAudioLabels(
          request_.url_origin, true);
    }
  }

  if (request_.video_type ==
      blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) {
    const MediaStreamDevices& video_devices =
        video_test_devices_.empty()
            ? MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices()
            : video_test_devices_;
    const MediaStreamDevice* device = GetDeviceByIdOrFirstAvailable(
        video_devices, request_.requested_video_device_ids);
    if (device)
      devices.video_device = *device;
    if (base::FeatureList::IsEnabled(features::kWebViewEnumerateDevicesCache) &&
        (request_.url_origin.scheme() != url::kFileScheme ||
         can_cache_file_url_permissions_)) {
      permission_manager_->SetOriginCanReadEnumerateDevicesVideoLabels(
          request_.url_origin, true);
    }
  }

  const bool has_no_hardware =
      !devices.audio_device.has_value() && !devices.video_device.has_value();
  if (has_no_hardware) {
    stream_devices_set.stream_devices.clear();
  }
  std::move(callback_).Run(
      stream_devices_set,
      has_no_hardware ? blink::mojom::MediaStreamRequestResult::NO_HARDWARE
                      : blink::mojom::MediaStreamRequestResult::OK,
      std::move(ui));
}

const GURL& MediaAccessPermissionRequest::GetOrigin() {
  return request_.security_origin;
}

int64_t MediaAccessPermissionRequest::GetResources() {
  return (request_.audio_type ==
                  blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE
              ? AwPermissionRequest::AudioCapture
              : 0) |
         (request_.video_type ==
                  blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE
              ? AwPermissionRequest::VideoCapture
              : 0);
}

}  // namespace android_webview