// Copyright (c) 2013 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/fake_audio_worker.h"

#include <utility>

#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/check_op.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_timestamp_helper.h"

namespace media {

class FakeAudioWorker::Worker
    : public base::RefCountedThreadSafe<FakeAudioWorker::Worker> {
 public:
  Worker(const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
         const AudioParameters& params);

  bool IsStopped();
  void Start(FakeAudioWorker::Callback worker_cb);
  void Stop();

 private:
  friend class base::RefCountedThreadSafe<Worker>;
  ~Worker();

  // Initialize and start regular calls to DoRead() on the worker thread.
  void DoStart();

  // Cancel any delayed callbacks to DoRead() in the worker loop's queue.
  void DoCancel();

  // Task that regularly calls |worker_cb_| according to the playback rate as
  // determined by the audio parameters given during construction.  Runs on
  // the worker loop.
  void DoRead();

  const scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner_;
  const int sample_rate_;
  const int frames_per_read_;

  base::Lock worker_cb_lock_;  // Held while mutating or running |worker_cb_|.
  FakeAudioWorker::Callback worker_cb_ GUARDED_BY(worker_cb_lock_);
  base::TimeTicks first_read_time_;
  int64_t frames_elapsed_;

  // Used to cancel any delayed tasks still inside the worker loop's queue.
  base::CancelableRepeatingClosure worker_task_cb_;

  THREAD_CHECKER(thread_checker_);

  DISALLOW_COPY_AND_ASSIGN(Worker);
};

FakeAudioWorker::FakeAudioWorker(
    const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
    const AudioParameters& params)
    : worker_(new Worker(worker_task_runner, params)) {}

FakeAudioWorker::~FakeAudioWorker() {
  DCHECK(worker_->IsStopped());
}

void FakeAudioWorker::Start(FakeAudioWorker::Callback worker_cb) {
  DCHECK(worker_->IsStopped());
  worker_->Start(std::move(worker_cb));
}

void FakeAudioWorker::Stop() {
  worker_->Stop();
}

// static
base::TimeDelta FakeAudioWorker::ComputeFakeOutputDelay(
    const AudioParameters& params) {
  // Typical delay values used by real AudioOutputStreams on Win, Mac, and Linux
  // tend to be around 1.5X to 3X of the buffer duration. So, 2X is chosen as a
  // general-purpose value.
  constexpr int kDelayFactor = 2;
  return AudioTimestampHelper::FramesToTime(
      params.frames_per_buffer() * kDelayFactor, params.sample_rate());
}

FakeAudioWorker::Worker::Worker(
    const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
    const AudioParameters& params)
    : worker_task_runner_(worker_task_runner),
      sample_rate_(params.sample_rate()),
      frames_per_read_(params.frames_per_buffer()) {
  // Worker can be constructed on any thread, but will DCHECK that its
  // Start/Stop methods are called from the same thread.
  DETACH_FROM_THREAD(thread_checker_);
}

FakeAudioWorker::Worker::~Worker() {
  DCHECK(!worker_cb_);
}

bool FakeAudioWorker::Worker::IsStopped() {
  base::AutoLock scoped_lock(worker_cb_lock_);
  return !worker_cb_;
}

void FakeAudioWorker::Worker::Start(FakeAudioWorker::Callback worker_cb) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(worker_cb);
  {
    base::AutoLock scoped_lock(worker_cb_lock_);
    DCHECK(!worker_cb_);
    worker_cb_ = std::move(worker_cb);
  }
  worker_task_runner_->PostTask(FROM_HERE,
                                base::BindOnce(&Worker::DoStart, this));
}

void FakeAudioWorker::Worker::DoStart() {
  DCHECK(worker_task_runner_->BelongsToCurrentThread());
  first_read_time_ = base::TimeTicks::Now();
  frames_elapsed_ = 0;
  worker_task_cb_.Reset(base::BindRepeating(&Worker::DoRead, this));
  worker_task_cb_.callback().Run();
}

void FakeAudioWorker::Worker::Stop() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  {
    base::AutoLock scoped_lock(worker_cb_lock_);
    if (!worker_cb_)
      return;
    worker_cb_.Reset();
  }
  worker_task_runner_->PostTask(FROM_HERE,
                                base::BindOnce(&Worker::DoCancel, this));
}

void FakeAudioWorker::Worker::DoCancel() {
  DCHECK(worker_task_runner_->BelongsToCurrentThread());
  worker_task_cb_.Cancel();
}

void FakeAudioWorker::Worker::DoRead() {
  DCHECK(worker_task_runner_->BelongsToCurrentThread());

  const base::TimeTicks read_time =
      first_read_time_ +
      AudioTimestampHelper::FramesToTime(frames_elapsed_, sample_rate_);
  frames_elapsed_ += frames_per_read_;
  base::TimeTicks next_read_time =
      first_read_time_ +
      AudioTimestampHelper::FramesToTime(frames_elapsed_, sample_rate_);

  base::TimeTicks now;
  {
    base::AutoLock scoped_lock(worker_cb_lock_);
    // Important to sample the clock after waiting to acquire the lock.
    now = base::TimeTicks::Now();

    // Note: Even if we're late, this callback must be called. In many cases we
    // are driving an underlying "samples consumed" based clock with these
    // calls.
    if (worker_cb_)
      worker_cb_.Run(read_time, now);
  }

  // If we're behind, find the next nearest ontime interval. Note, we could be
  // behind many intervals (e.g., if the system is resuming from sleep).
  if (next_read_time <= now) {
    frames_elapsed_ = AudioTimestampHelper::TimeToFrames(now - first_read_time_,
                                                         sample_rate_);
    frames_elapsed_ =
        ((frames_elapsed_ / frames_per_read_) + 1) * frames_per_read_;
    next_read_time = first_read_time_ + AudioTimestampHelper::FramesToTime(
                                            frames_elapsed_, sample_rate_);
  }

  worker_task_runner_->PostDelayedTask(FROM_HERE, worker_task_cb_.callback(),
                                       next_read_time - now);
}

}  // namespace media
