15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/copresence/mediums/audio/audio_player.h"
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <algorithm>
86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include <string>
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/bind.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/bind_helpers.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h"
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/run_loop.h"
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/copresence/public/copresence_constants.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/audio/audio_manager.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/audio/audio_parameters.h"
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/base/audio_bus.h"
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace {
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kDefaultFrameCount = 1024;
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const double kOutputVolumePercent = 1.0f;
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace copresence {
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Public methods.
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)AudioPlayer::AudioPlayer()
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : is_playing_(false), stream_(NULL), frame_index_(0) {
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)AudioPlayer::~AudioPlayer() {
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::Initialize() {
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::AudioManager::Get()->GetTaskRunner()->PostTask(
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&AudioPlayer::InitializeOnAudioThread,
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 base::Unretained(this)));
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::Play(
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const scoped_refptr<media::AudioBusRefCounted>& samples) {
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::AudioManager::Get()->GetTaskRunner()->PostTask(
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          &AudioPlayer::PlayOnAudioThread, base::Unretained(this), samples));
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::Stop() {
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::AudioManager::Get()->GetTaskRunner()->PostTask(
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&AudioPlayer::StopOnAudioThread, base::Unretained(this)));
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool AudioPlayer::IsPlaying() {
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return is_playing_;
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::Finalize() {
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::AudioManager::Get()->GetTaskRunner()->PostTask(
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&AudioPlayer::FinalizeOnAudioThread, base::Unretained(this)));
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Private methods.
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::InitializeOnAudioThread() {
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  stream_ = output_stream_for_testing_
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                ? output_stream_for_testing_.get()
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                : media::AudioManager::Get()->MakeAudioOutputStreamProxy(
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                      media::AudioParameters(
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          media::CHANNEL_LAYOUT_MONO,
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          kDefaultSampleRate,
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          kDefaultBitsPerSample,
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          kDefaultFrameCount),
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                      std::string());
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!stream_ || !stream_->Open()) {
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Failed to open an output stream.";
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (stream_) {
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      stream_->Close();
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      stream_ = NULL;
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  stream_->SetVolume(kOutputVolumePercent);
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::PlayOnAudioThread(
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const scoped_refptr<media::AudioBusRefCounted>& samples) {
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!stream_)
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::AutoLock al(state_lock_);
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    samples_ = samples;
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    frame_index_ = 0;
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (is_playing_)
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  is_playing_ = true;
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  stream_->Start(this);
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::StopOnAudioThread() {
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!stream_)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  stream_->Stop();
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  is_playing_ = false;
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::StopAndCloseOnAudioThread() {
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!stream_)
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (is_playing_)
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    stream_->Stop();
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  stream_->Close();
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  stream_ = NULL;
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  is_playing_ = false;
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::FinalizeOnAudioThread() {
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  StopAndCloseOnAudioThread();
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delete this;
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int AudioPlayer::OnMoreData(media::AudioBus* dest,
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            media::AudioBuffersState /* state */) {
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::AutoLock al(state_lock_);
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Continuously play our samples till explicitly told to stop.
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int leftover_frames = samples_->frames() - frame_index_;
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int frames_to_copy = std::min(dest->frames(), leftover_frames);
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  samples_->CopyPartialFramesTo(frame_index_, frames_to_copy, 0, dest);
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  frame_index_ += frames_to_copy;
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If we didn't fill the destination audio bus, wrap around and fill the rest.
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (leftover_frames <= dest->frames()) {
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    samples_->CopyPartialFramesTo(
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        0, dest->frames() - frames_to_copy, frames_to_copy, dest);
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    frame_index_ = dest->frames() - frames_to_copy;
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return dest->frames();
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::OnError(media::AudioOutputStream* /* stream */) {
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LOG(ERROR) << "Error during system sound reproduction.";
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::AudioManager::Get()->GetTaskRunner()->PostTask(
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&AudioPlayer::StopAndCloseOnAudioThread,
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 base::Unretained(this)));
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioPlayer::FlushAudioLoopForTesting() {
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread())
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Queue task on the audio thread, when it is executed, that means we've
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // successfully executed all the tasks before us.
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::RunLoop rl;
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::AudioManager::Get()->GetTaskRunner()->PostTaskAndReply(
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(base::IgnoreResult(&AudioPlayer::FlushAudioLoopForTesting),
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 base::Unretained(this)),
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      rl.QuitClosure());
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  rl.Run();
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace copresence
187