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

#include "content/renderer/media/render_media_client.h"

#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/time/default_tick_clock.h"
#include "content/public/common/content_client.h"
#include "content/public/renderer/content_renderer_client.h"

namespace content {

static base::LazyInstance<RenderMediaClient>::Leaky g_render_media_client =
    LAZY_INSTANCE_INITIALIZER;

void RenderMediaClient::Initialize() {
  g_render_media_client.Get();
}

RenderMediaClient::RenderMediaClient()
    : has_updated_(false),
      is_update_needed_(true),
      tick_clock_(new base::DefaultTickClock()) {
  media::SetMediaClient(this);
}

RenderMediaClient::~RenderMediaClient() {
}

void RenderMediaClient::AddKeySystemsInfoForUMA(
    std::vector<media::KeySystemInfoForUMA>* key_systems_info_for_uma) {
  DVLOG(2) << __func__;
#if defined(WIDEVINE_CDM_AVAILABLE)
  key_systems_info_for_uma->push_back(media::KeySystemInfoForUMA(
      kWidevineKeySystem, kWidevineKeySystemNameForUMA));
#endif  // WIDEVINE_CDM_AVAILABLE
}

bool RenderMediaClient::IsKeySystemsUpdateNeeded() {
  DVLOG(2) << __func__;
  DCHECK(thread_checker_.CalledOnValidThread());

  // Always needs update if we have never updated, regardless the
  // |last_update_time_ticks_|'s initial value.
  if (!has_updated_) {
    DCHECK(is_update_needed_);
    return true;
  }

  if (!is_update_needed_)
    return false;

  // The update could be expensive. For example, it could involve a sync IPC to
  // the browser process. Use a minimum update interval to avoid unnecessarily
  // frequent update.
  static const int kMinUpdateIntervalInMilliseconds = 1000;
  if ((tick_clock_->NowTicks() - last_update_time_ticks_).InMilliseconds() <
      kMinUpdateIntervalInMilliseconds) {
    return false;
  }

  return true;
}

void RenderMediaClient::AddSupportedKeySystems(
    std::vector<std::unique_ptr<media::KeySystemProperties>>*
        key_systems_properties) {
  DVLOG(2) << __func__;
  DCHECK(thread_checker_.CalledOnValidThread());

  GetContentClient()->renderer()->AddSupportedKeySystems(
      key_systems_properties);

  has_updated_ = true;
  last_update_time_ticks_ = tick_clock_->NowTicks();

  // Check whether all potentially supported key systems are supported. If so,
  // no need to update again.
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
  for (const auto& properties : *key_systems_properties) {
    if (properties->GetKeySystemName() == kWidevineKeySystem)
      is_update_needed_ = false;
  }
#else
  is_update_needed_ = false;
#endif
}

void RenderMediaClient::RecordRapporURL(const std::string& metric,
                                        const GURL& url) {
  GetContentClient()->renderer()->RecordRapporURL(metric, url);
}

bool RenderMediaClient::IsSupportedVideoConfig(media::VideoCodec codec,
                                               media::VideoCodecProfile profile,
                                               int level) {
  switch (codec) {
    case media::kCodecH264:
    case media::kCodecVP8:
    case media::kCodecVP9:
    case media::kCodecTheora:
      return true;

    case media::kUnknownVideoCodec:
    case media::kCodecVC1:
    case media::kCodecMPEG2:
    case media::kCodecMPEG4:
    case media::kCodecHEVC:
      return false;
  }

  NOTREACHED();
  return false;
}

void RenderMediaClient::SetTickClockForTesting(
    std::unique_ptr<base::TickClock> tick_clock) {
  tick_clock_.swap(tick_clock);
}

// This functions is for testing purpose only. The declaration in the
// header file is guarded by "#if defined(UNIT_TEST)" so that it can be used
// by tests but not non-test code. However, this .cc file is compiled as part of
// "content" where "UNIT_TEST" is not defined. So we need to specify
// "CONTENT_EXPORT" here again so that it is visible to tests.
CONTENT_EXPORT RenderMediaClient* GetRenderMediaClientInstanceForTesting() {
  return g_render_media_client.Pointer();
}

}  // namespace content
