// Copyright (c) 2012 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 "media/base/audio_renderer_mixer.h"

#include <cmath>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
#include "media/base/audio_renderer_mixer_input.h"
#include "media/base/audio_timestamp_helper.h"

namespace media {

enum { kPauseDelaySeconds = 10 };

// Tracks the maximum value of a counter and logs it into a UMA histogram upon
// each increase of the maximum. NOT thread-safe, make sure it is used under
// lock.
class AudioRendererMixer::UMAMaxValueTracker {
 public:
  UMAMaxValueTracker(UmaLogCallback log_callback)
      : log_callback_(std::move(log_callback)), count_(0), max_count_(0) {}

  ~UMAMaxValueTracker() = default;

  // Increments the counter, updates the maximum.
  void Increment() {
    ++count_;
    if (max_count_ < count_) {
      max_count_ = count_;
      log_callback_.Run(max_count_);
    }
  }

  // Decrements the counter.
  void Decrement() {
    DCHECK_GE(count_, 0);
    --count_;
  }

 private:
  const UmaLogCallback log_callback_;
  int count_;
  int max_count_;
  DISALLOW_COPY_AND_ASSIGN(UMAMaxValueTracker);
};

AudioRendererMixer::AudioRendererMixer(const AudioParameters& output_params,
                                       scoped_refptr<AudioRendererSink> sink,
                                       UmaLogCallback log_callback)
    : output_params_(output_params),
      audio_sink_(std::move(sink)),
      master_converter_(output_params, output_params, true),
      pause_delay_(base::TimeDelta::FromSeconds(kPauseDelaySeconds)),
      last_play_time_(base::TimeTicks::Now()),
      // Initialize |playing_| to true since Start() results in an auto-play.
      playing_(true),
      input_count_tracker_(new UMAMaxValueTracker(std::move(log_callback))) {
  DCHECK(audio_sink_);
  audio_sink_->Initialize(output_params, this);
  audio_sink_->Start();
}

AudioRendererMixer::~AudioRendererMixer() {
  // AudioRendererSink must be stopped before mixer is destructed.
  audio_sink_->Stop();

  // Ensure that all mixer inputs have removed themselves prior to destruction.
  DCHECK(master_converter_.empty());
  DCHECK(converters_.empty());
  DCHECK(error_callbacks_.empty());
}

void AudioRendererMixer::AddMixerInput(const AudioParameters& input_params,
                                       AudioConverter::InputCallback* input) {
  base::AutoLock auto_lock(lock_);
  if (!playing_) {
    playing_ = true;
    last_play_time_ = base::TimeTicks::Now();
    audio_sink_->Play();
  }

  int input_sample_rate = input_params.sample_rate();
  if (is_master_sample_rate(input_sample_rate)) {
    master_converter_.AddInput(input);
  } else {
    auto converter = converters_.find(input_sample_rate);
    if (converter == converters_.end()) {
      std::pair<AudioConvertersMap::iterator, bool> result =
          converters_.insert(std::make_pair(
              input_sample_rate, std::make_unique<LoopbackAudioConverter>(
                                     // We expect all InputCallbacks to be
                                     // capable of handling arbitrary buffer
                                     // size requests, disabling FIFO.
                                     input_params, output_params_, true)));
      converter = result.first;

      // Add newly-created resampler as an input to the master mixer.
      master_converter_.AddInput(converter->second.get());
    }
    converter->second->AddInput(input);
  }

  input_count_tracker_->Increment();
}

void AudioRendererMixer::RemoveMixerInput(
    const AudioParameters& input_params,
    AudioConverter::InputCallback* input) {
  base::AutoLock auto_lock(lock_);

  int input_sample_rate = input_params.sample_rate();
  if (is_master_sample_rate(input_sample_rate)) {
    master_converter_.RemoveInput(input);
  } else {
    auto converter = converters_.find(input_sample_rate);
    DCHECK(converter != converters_.end());
    converter->second->RemoveInput(input);
    if (converter->second->empty()) {
      // Remove converter when it's empty.
      master_converter_.RemoveInput(converter->second.get());
      converters_.erase(converter);
    }
  }

  input_count_tracker_->Decrement();
}

void AudioRendererMixer::AddErrorCallback(AudioRendererMixerInput* input) {
  base::AutoLock auto_lock(lock_);
  error_callbacks_.insert(input);
}

void AudioRendererMixer::RemoveErrorCallback(AudioRendererMixerInput* input) {
  base::AutoLock auto_lock(lock_);
  error_callbacks_.erase(input);
}

bool AudioRendererMixer::CurrentThreadIsRenderingThread() {
  return audio_sink_->CurrentThreadIsRenderingThread();
}

void AudioRendererMixer::SetPauseDelayForTesting(base::TimeDelta delay) {
  base::AutoLock auto_lock(lock_);
  pause_delay_ = delay;
}

int AudioRendererMixer::Render(base::TimeDelta delay,
                               base::TimeTicks delay_timestamp,
                               int prior_frames_skipped,
                               AudioBus* audio_bus) {
  TRACE_EVENT0("audio", "AudioRendererMixer::Render");
  base::AutoLock auto_lock(lock_);

  // If there are no mixer inputs and we haven't seen one for a while, pause the
  // sink to avoid wasting resources when media elements are present but remain
  // in the pause state.
  const base::TimeTicks now = base::TimeTicks::Now();
  if (!master_converter_.empty()) {
    last_play_time_ = now;
  } else if (now - last_play_time_ >= pause_delay_ && playing_) {
    audio_sink_->Pause();
    playing_ = false;
  }

  uint32_t frames_delayed =
      AudioTimestampHelper::TimeToFrames(delay, output_params_.sample_rate());
  master_converter_.ConvertWithDelay(frames_delayed, audio_bus);
  return audio_bus->frames();
}

void AudioRendererMixer::OnRenderError() {
  // Call each mixer input and signal an error.
  base::AutoLock auto_lock(lock_);
  for (auto* input : error_callbacks_)
    input->OnRenderError();
}

}  // namespace media
