// 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/audio/audio_output_dispatcher_impl.h"

#include <algorithm>

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_output_proxy.h"

namespace media {

AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
    AudioManager* audio_manager,
    const AudioParameters& params,
    const std::string& output_device_id,
    const std::string& input_device_id,
    const base::TimeDelta& close_delay)
    : AudioOutputDispatcher(audio_manager, params, output_device_id,
          input_device_id),
      pause_delay_(base::TimeDelta::FromMicroseconds(
          2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
          static_cast<float>(params.sample_rate()))),
      paused_proxies_(0),
      weak_this_(this),
      close_timer_(FROM_HERE,
                   close_delay,
                   this,
                   &AudioOutputDispatcherImpl::ClosePendingStreams) {
}

AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
  DCHECK(proxy_to_physical_map_.empty());
  DCHECK(idle_streams_.empty());
  DCHECK(pausing_streams_.empty());
}

bool AudioOutputDispatcherImpl::OpenStream() {
  DCHECK(message_loop_->BelongsToCurrentThread());

  paused_proxies_++;

  // Ensure that there is at least one open stream.
  if (idle_streams_.empty() && !CreateAndOpenStream()) {
    paused_proxies_--;
    return false;
  }

  close_timer_.Reset();
  return true;
}

bool AudioOutputDispatcherImpl::StartStream(
    AudioOutputStream::AudioSourceCallback* callback,
    AudioOutputProxy* stream_proxy) {
  DCHECK(message_loop_->BelongsToCurrentThread());

  if (idle_streams_.empty() && !CreateAndOpenStream())
    return false;

  AudioOutputStream* physical_stream = idle_streams_.back();
  DCHECK(physical_stream);
  idle_streams_.pop_back();

  DCHECK_GT(paused_proxies_, 0u);
  --paused_proxies_;

  close_timer_.Reset();

  // Schedule task to allocate streams for other proxies if we need to.
  message_loop_->PostTask(FROM_HERE, base::Bind(
      &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr()));

  double volume = 0;
  stream_proxy->GetVolume(&volume);
  physical_stream->SetVolume(volume);
  physical_stream->Start(callback);
  proxy_to_physical_map_[stream_proxy] = physical_stream;
  return true;
}

void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
  DCHECK(message_loop_->BelongsToCurrentThread());

  AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
  DCHECK(it != proxy_to_physical_map_.end());
  AudioOutputStream* physical_stream = it->second;
  proxy_to_physical_map_.erase(it);

  physical_stream->Stop();

  ++paused_proxies_;

  pausing_streams_.push_front(physical_stream);

  // Don't recycle stream until two buffers worth of time has elapsed.
  message_loop_->PostDelayedTask(
      FROM_HERE,
      base::Bind(&AudioOutputDispatcherImpl::StopStreamTask,
                 weak_this_.GetWeakPtr()),
      pause_delay_);
}

void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
                                                double volume) {
  DCHECK(message_loop_->BelongsToCurrentThread());
  AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
  if (it != proxy_to_physical_map_.end()) {
    AudioOutputStream* physical_stream = it->second;
    physical_stream->SetVolume(volume);
  }
}

void AudioOutputDispatcherImpl::StopStreamTask() {
  DCHECK(message_loop_->BelongsToCurrentThread());

  if (pausing_streams_.empty())
    return;

  AudioOutputStream* stream = pausing_streams_.back();
  pausing_streams_.pop_back();
  idle_streams_.push_back(stream);
  close_timer_.Reset();
}

void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
  DCHECK(message_loop_->BelongsToCurrentThread());

  while (!pausing_streams_.empty()) {
    idle_streams_.push_back(pausing_streams_.back());
    pausing_streams_.pop_back();
  }

  DCHECK_GT(paused_proxies_, 0u);
  paused_proxies_--;

  while (idle_streams_.size() > paused_proxies_) {
    idle_streams_.back()->Close();
    idle_streams_.pop_back();
  }
}

void AudioOutputDispatcherImpl::Shutdown() {
  DCHECK(message_loop_->BelongsToCurrentThread());

  // Cancel any pending tasks to close paused streams or create new ones.
  weak_this_.InvalidateWeakPtrs();

  // No AudioOutputProxy objects should hold a reference to us when we get
  // to this stage.
  DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";

  AudioOutputStreamList::iterator it = idle_streams_.begin();
  for (; it != idle_streams_.end(); ++it)
    (*it)->Close();
  idle_streams_.clear();

  it = pausing_streams_.begin();
  for (; it != pausing_streams_.end(); ++it)
    (*it)->Close();
  pausing_streams_.clear();
}

bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
  DCHECK(message_loop_->BelongsToCurrentThread());
  AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
      params_, output_device_id_, input_device_id_);
  if (!stream)
    return false;

  if (!stream->Open()) {
    stream->Close();
    return false;
  }
  idle_streams_.push_back(stream);
  return true;
}

void AudioOutputDispatcherImpl::OpenTask() {
  DCHECK(message_loop_->BelongsToCurrentThread());
  // Make sure that we have at least one stream allocated if there
  // are paused streams.
  if (paused_proxies_ > 0 && idle_streams_.empty() &&
      pausing_streams_.empty()) {
    CreateAndOpenStream();
  }

  close_timer_.Reset();
}

// This method is called by |close_timer_|.
void AudioOutputDispatcherImpl::ClosePendingStreams() {
  DCHECK(message_loop_->BelongsToCurrentThread());
  while (!idle_streams_.empty()) {
    idle_streams_.back()->Close();
    idle_streams_.pop_back();
  }
}

}  // namespace media
