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

#include "third_party/blink/public/common/mediastream/media_stream_request.h"

#include "base/check.h"
#include "base/feature_list.h"
#include "build/build_config.h"
#include "media/base/audio_parameters.h"
#include "media/base/channel_layout.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"

namespace blink {
namespace {
// TODO(crbug.com/410466097): Disable the kill switch and remove it once
// restrictOwnAudio has been launched. See
// https://www.w3.org/TR/screen-capture/#dfn-restrictownaudio.
// Note: The implementation of this kill switch is inverted, meaning that the
// kill switch is active when the feature is enabled.
BASE_FEATURE(kDisplayAudioCaptureKillSwitch, base::FEATURE_ENABLED_BY_DEFAULT);
}  // namespace

bool IsAudioInputMediaType(mojom::MediaStreamType type) {
  return (type == mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE ||
          type == mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE ||
          type == mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE ||
          type == mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE);
}

bool IsVideoInputMediaType(mojom::MediaStreamType type) {
  return (type == mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE ||
          type == mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE ||
          type == mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE ||
          type == mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE ||
          type == mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB ||
          type == mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_SET);
}

bool IsScreenCaptureMediaType(mojom::MediaStreamType type) {
  return IsDesktopCaptureMediaType(type) || IsTabCaptureMediaType(type);
}

bool IsVideoScreenCaptureMediaType(mojom::MediaStreamType type) {
  return IsVideoDesktopCaptureMediaType(type) ||
         type == mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE;
}

bool IsDesktopCaptureMediaType(mojom::MediaStreamType type) {
  return (IsAudioDesktopCaptureMediaType(type) ||
          IsVideoDesktopCaptureMediaType(type));
}

bool IsAudioDesktopCaptureMediaType(mojom::MediaStreamType type) {
  return ((type == mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE &&
           !base::FeatureList::IsEnabled(kDisplayAudioCaptureKillSwitch)) ||
          type == mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE);
}

bool IsVideoDesktopCaptureMediaType(mojom::MediaStreamType type) {
  return (type == mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE ||
          type == mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB ||
          type == mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE ||
          type == mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_SET);
}

bool IsTabCaptureMediaType(mojom::MediaStreamType type) {
  return (type == mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE ||
          type == mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE ||
          type == mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB);
}

bool IsDeviceMediaType(mojom::MediaStreamType type) {
  return (type == mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE ||
          type == mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE);
}

bool IsMediaStreamDeviceTransferrable(const MediaStreamDevice& device) {
  // Return |false| if |device.type| is not a valid MediaStreamType or is of
  // device capture type.
  if (device.type == mojom::MediaStreamType::NO_SERVICE ||
      device.type == mojom::MediaStreamType::NUM_MEDIA_TYPES ||
      IsDeviceMediaType(device.type)) {
    return false;
  }
  const auto& info = device.display_media_info;
  return info && info->display_surface ==
                     media::mojom::DisplayCaptureSurfaceType::BROWSER;
}

MediaStreamDevice::MediaStreamDevice()
    : type(mojom::MediaStreamType::NO_SERVICE),
      video_facing(media::MEDIA_VIDEO_FACING_NONE) {}

MediaStreamDevice::MediaStreamDevice(mojom::MediaStreamType type,
                                     const std::string& id,
                                     const std::string& name)
    : type(type),
      id(id),
      video_facing(media::MEDIA_VIDEO_FACING_NONE),
      name(name) {}

MediaStreamDevice::MediaStreamDevice(mojom::MediaStreamType type,
                                     const std::string& id,
                                     const std::string& name,
                                     int64_t display_id)
    : type(type),
      id(id),
      display_id(display_id),
      video_facing(media::MEDIA_VIDEO_FACING_NONE),
      name(name) {}

MediaStreamDevice::MediaStreamDevice(
    mojom::MediaStreamType type,
    const std::string& id,
    const std::string& name,
    const media::VideoCaptureControlSupport& control_support,
    media::VideoFacingMode facing,
    const std::optional<std::string>& group_id)
    : type(type),
      id(id),
      video_control_support(control_support),
      video_facing(facing),
      group_id(group_id),
      name(name) {}

MediaStreamDevice::MediaStreamDevice(
    mojom::MediaStreamType type,
    const std::string& id,
    const std::string& name,
    int sample_rate,
    media::ChannelLayoutConfig channel_layout_config,
    int frames_per_buffer)
    : type(type),
      id(id),
      video_facing(media::MEDIA_VIDEO_FACING_NONE),
      name(name),
      input(media::AudioParameters::AUDIO_FAKE,
            channel_layout_config,
            sample_rate,
            frames_per_buffer) {
  DCHECK(input.IsValid());
}

MediaStreamDevice::MediaStreamDevice(const MediaStreamDevice& other)
    : type(other.type),
      id(other.id),
      display_id(other.display_id),
      video_control_support(other.video_control_support),
      video_facing(other.video_facing),
      group_id(other.group_id),
      matched_output_device_id(other.matched_output_device_id),
      name(other.name),
      input(other.input),
      session_id_(other.session_id_) {
  DCHECK(!session_id_.has_value() || !session_id_->is_empty());
  if (other.display_media_info)
    display_media_info = other.display_media_info->Clone();
}

MediaStreamDevice::~MediaStreamDevice() = default;

MediaStreamDevice& MediaStreamDevice::operator=(
    const MediaStreamDevice& other) {
  if (&other == this)
    return *this;
  type = other.type;
  id = other.id;
  display_id = other.display_id;
  video_control_support = other.video_control_support;
  video_facing = other.video_facing;
  group_id = other.group_id;
  matched_output_device_id = other.matched_output_device_id;
  name = other.name;
  input = other.input;
  session_id_ = other.session_id_;
  DCHECK(!session_id_.has_value() || !session_id_->is_empty());
  if (other.display_media_info)
    display_media_info = other.display_media_info->Clone();
  return *this;
}

bool MediaStreamDevice::IsSameDevice(
    const MediaStreamDevice& other_device) const {
  return type == other_device.type && name == other_device.name &&
         id == other_device.id &&
         input.sample_rate() == other_device.input.sample_rate() &&
         input.channel_layout() == other_device.input.channel_layout() &&
         session_id_ == other_device.session_id_;
}

bool MediaStreamDevice::operator==(
    const MediaStreamDevice& other_device) const {
  return IsSameDevice(other_device);
}

blink::MediaStreamDevices ToMediaStreamDevicesList(
    const blink::mojom::StreamDevicesSet& stream_devices_set) {
  blink::MediaStreamDevices devices;
  for (const blink::mojom::StreamDevicesPtr& devices_to_insert :
       stream_devices_set.stream_devices) {
    if (devices_to_insert->audio_device.has_value()) {
      devices.push_back(devices_to_insert->audio_device.value());
    }
    if (devices_to_insert->video_device.has_value()) {
      devices.push_back(devices_to_insert->video_device.value());
    }
  }
  return devices;
}

size_t CountDevices(const blink::mojom::StreamDevices& devices) {
  return (devices.audio_device.has_value() ? 1u : 0u) +
         (devices.video_device.has_value() ? 1u : 0u);
}

}  // namespace blink
