// 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 <utility>

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/time/time.h"
#include "media/audio/audio_logging.h"
#include "media/audio/audio_manager.h"
#include "media/audio/audio_output_proxy.h"

namespace media {

AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
    AudioManager* audio_manager,
    const AudioParameters& params,
    const std::string& output_device_id,
    base::TimeDelta close_delay)
    : AudioOutputDispatcher(audio_manager),
      params_(params),
      device_id_(output_device_id),
      idle_proxies_(0),
      close_timer_(FROM_HERE,
                   close_delay,
                   this,
                   &AudioOutputDispatcherImpl::CloseAllIdleStreams),
      audio_stream_id_(0),
      weak_factory_(this) {
  DCHECK(audio_manager->GetTaskRunner()->BelongsToCurrentThread());
}

AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());

  // Stop all active streams.
  for (auto& iter : proxy_to_physical_map_) {
    StopPhysicalStream(iter.second);
  }

  // Close all idle streams immediately.  The |close_timer_| will handle
  // invalidating any outstanding tasks upon its destruction.
  CloseAllIdleStreams();

  // All idle physical streams must have been closed during shutdown.
  CHECK(idle_streams_.empty());
}

AudioOutputProxy* AudioOutputDispatcherImpl::CreateStreamProxy() {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  return new AudioOutputProxy(weak_factory_.GetWeakPtr());
}

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

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

  ++idle_proxies_;
  close_timer_.Reset();
  return true;
}

bool AudioOutputDispatcherImpl::StartStream(
    AudioOutputStream::AudioSourceCallback* callback,
    AudioOutputProxy* stream_proxy) {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  DCHECK(proxy_to_physical_map_.find(stream_proxy) ==
         proxy_to_physical_map_.end());

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

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

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

  double volume = 0;
  stream_proxy->GetVolume(&volume);
  physical_stream->SetVolume(volume);
  DCHECK(base::ContainsKey(audio_logs_, physical_stream));
  AudioLog* const audio_log = audio_logs_[physical_stream].get();
  audio_log->OnSetVolume(volume);
  physical_stream->Start(callback);
  audio_log->OnStarted();
  proxy_to_physical_map_[stream_proxy] = physical_stream;

  close_timer_.Reset();
  return true;
}

void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  auto it = proxy_to_physical_map_.find(stream_proxy);
  DCHECK(it != proxy_to_physical_map_.end());
  StopPhysicalStream(it->second);
  proxy_to_physical_map_.erase(it);
  ++idle_proxies_;
}

void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
                                                double volume) {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  auto it = proxy_to_physical_map_.find(stream_proxy);
  if (it != proxy_to_physical_map_.end()) {
    AudioOutputStream* physical_stream = it->second;
    physical_stream->SetVolume(volume);
    DCHECK(base::ContainsKey(audio_logs_, physical_stream));
    audio_logs_[physical_stream]->OnSetVolume(volume);
  }
}

void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  DCHECK_GT(idle_proxies_, 0u);
  --idle_proxies_;

  // Leave at least a single stream running until the close timer fires to help
  // cycle time when streams are opened and closed repeatedly.
  CloseIdleStreams(std::max(idle_proxies_, static_cast<size_t>(1)));
  close_timer_.Reset();
}

bool AudioOutputDispatcherImpl::HasOutputProxies() const {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  return idle_proxies_ || !proxy_to_physical_map_.empty();
}

bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  const int stream_id = audio_stream_id_++;
  std::unique_ptr<AudioLog> audio_log = audio_manager()->CreateAudioLog(
      AudioLogFactory::AUDIO_OUTPUT_STREAM, stream_id);
  AudioOutputStream* stream = audio_manager()->MakeAudioOutputStream(
      params_, device_id_,
      base::BindRepeating(&AudioLog::OnLogMessage,
                          base::Unretained(audio_log.get())));
  if (!stream)
    return false;

  if (!stream->Open()) {
    stream->Close();
    return false;
  }

  audio_log->OnCreated(params_, device_id_);
  audio_logs_[stream] = std::move(audio_log);

  idle_streams_.push_back(stream);
  return true;
}

void AudioOutputDispatcherImpl::CloseAllIdleStreams() {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  CloseIdleStreams(0);
}

void AudioOutputDispatcherImpl::CloseIdleStreams(size_t keep_alive) {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  if (idle_streams_.size() <= keep_alive)
    return;
  for (size_t i = keep_alive; i < idle_streams_.size(); ++i) {
    AudioOutputStream* stream = idle_streams_[i];
    stream->Close();

    auto it = audio_logs_.find(stream);
    DCHECK(it != audio_logs_.end());
    it->second->OnClosed();
    audio_logs_.erase(it);
  }
  idle_streams_.erase(idle_streams_.begin() + keep_alive, idle_streams_.end());
}

void AudioOutputDispatcherImpl::StopPhysicalStream(AudioOutputStream* stream) {
  DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
  stream->Stop();
  DCHECK(base::ContainsKey(audio_logs_, stream));
  audio_logs_[stream]->OnStopped();
  idle_streams_.push_back(stream);
  close_timer_.Reset();
}

}  // namespace media
