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