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_recorder.h" 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <algorithm> 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <vector> 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 "base/synchronization/waitable_event.h" 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/copresence/public/copresence_constants.h" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/public/browser/browser_thread.h" 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/audio/audio_manager.h" 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/audio/audio_manager_base.h" 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/base/audio_bus.h" 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace copresence { 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace { 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const float kProcessIntervalMs = 500.0f; // milliseconds. 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioBusToString(scoped_ptr<media::AudioBus> source, std::string* buffer) { 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer->resize(source->frames() * source->channels() * sizeof(float)); 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) float* buffer_view = reinterpret_cast<float*>(string_as_array(buffer)); 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int channels = source->channels(); 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (int ch = 0; ch < channels; ++ch) { 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (int si = 0, di = ch; si < source->frames(); ++si, di += channels) 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_view[di] = source->channel(ch)[si]; 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Called every kProcessIntervalMs to process the recorded audio. This 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// converts our samples to the required sample rate, interleaves the samples 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// and sends them to the whispernet decoder to process. 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ProcessSamples(scoped_ptr<media::AudioBus> bus, 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const AudioRecorder::DecodeSamplesCallback& callback) { 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string samples; 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) AudioBusToString(bus.Pass(), &samples); 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::BrowserThread::PostTask( 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::BrowserThread::UI, FROM_HERE, base::Bind(callback, samples)); 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Public methods. 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)AudioRecorder::AudioRecorder(const DecodeSamplesCallback& decode_callback) 546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) : is_recording_(false), 556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) stream_(NULL), 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) decode_callback_(decode_callback), 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) total_buffer_frames_(0), 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_frame_index_(0) { 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::Initialize() { 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioManager::Get()->GetTaskRunner()->PostTask( 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&AudioRecorder::InitializeOnAudioThread, 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Unretained(this))); 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)AudioRecorder::~AudioRecorder() { 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::Record() { 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioManager::Get()->GetTaskRunner()->PostTask( 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&AudioRecorder::RecordOnAudioThread, base::Unretained(this))); 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::Stop() { 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioManager::Get()->GetTaskRunner()->PostTask( 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&AudioRecorder::StopOnAudioThread, base::Unretained(this))); 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool AudioRecorder::IsRecording() { 846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return is_recording_; 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::Finalize() { 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioManager::Get()->GetTaskRunner()->PostTask( 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&AudioRecorder::FinalizeOnAudioThread, 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Unretained(this))); 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Private methods. 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::InitializeOnAudioThread() { 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioParameters params = 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) params_for_testing_ 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ? *params_for_testing_ 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : media::AudioManager::Get()->GetInputStreamParameters( 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioManagerBase::kDefaultDeviceId); 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const media::AudioParameters dest_params(params.format(), 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) kDefaultChannelLayout, 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) kDefaultSampleRate, 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) kDefaultBitsPerSample, 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) params.frames_per_buffer(), 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioParameters::NO_EFFECTS); 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) converter_.reset(new media::AudioConverter( 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) params, dest_params, params.sample_rate() == dest_params.sample_rate())); 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) converter_->AddInput(this); 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) total_buffer_frames_ = kProcessIntervalMs * dest_params.sample_rate() / 1000; 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_ = 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioBus::Create(dest_params.channels(), total_buffer_frames_); 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_frame_index_ = 0; 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stream_ = input_stream_for_testing_ 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ? input_stream_for_testing_.get() 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : media::AudioManager::Get()->MakeAudioInputStream( 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) params, media::AudioManagerBase::kDefaultDeviceId); 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!stream_ || !stream_->Open()) { 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Failed to open an input stream."; 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (stream_) { 1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stream_->Close(); 1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stream_ = NULL; 1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stream_->SetVolume(stream_->GetMaxVolume()); 1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::RecordOnAudioThread() { 1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!stream_ || is_recording_) 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) converter_->Reset(); 1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stream_->Start(this); 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) is_recording_ = true; 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::StopOnAudioThread() { 1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!stream_ || !is_recording_) 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stream_->Stop(); 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) is_recording_ = false; 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::StopAndCloseOnAudioThread() { 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!stream_) 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) StopOnAudioThread(); 1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stream_->Close(); 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stream_ = NULL; 1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::FinalizeOnAudioThread() { 1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) StopAndCloseOnAudioThread(); 1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delete this; 1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::OnData(media::AudioInputStream* stream, 1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const media::AudioBus* source, 1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) uint32 /* hardware_delay_bytes */, 1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) double /* volume */) { 1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) temp_conversion_buffer_ = source; 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while (temp_conversion_buffer_) { 1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // source->frames() == source_params.frames_per_buffer(), so we only have 1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // one chunk of data in the source; correspondingly set the destination 1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // size to one chunk. 1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // TODO(rkc): Optimize this to directly write into buffer_ so we can avoid 1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // the copy into this buffer and then the copy back into buffer_. 1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_ptr<media::AudioBus> converted_source = 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioBus::Create(kDefaultChannels, converter_->ChunkSize()); 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Convert accumulated samples into converted_source. Note: One call may not 1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // be enough to consume the samples from |source|. The converter may have 1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // accumulated samples over time due to a fractional input:output sample 1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // rate ratio. Since |source| is ephemeral, Convert() must be called until 1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // |source| is at least buffered into the converter. Once |source| is 1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // consumed during ProvideInput(), |temp_conversion_buffer_| will be set to 1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // NULL, which will break the conversion loop. 1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) converter_->Convert(converted_source.get()); 1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int remaining_buffer_frames = buffer_->frames() - buffer_frame_index_; 1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int frames_to_copy = 1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::min(remaining_buffer_frames, converted_source->frames()); 1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) converted_source->CopyPartialFramesTo( 1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 0, frames_to_copy, buffer_frame_index_, buffer_.get()); 2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_frame_index_ += frames_to_copy; 2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Buffer full, send it for processing. 2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (buffer_->frames() == buffer_frame_index_) { 2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ProcessSamples(buffer_.Pass(), decode_callback_); 2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_ = media::AudioBus::Create(kDefaultChannels, total_buffer_frames_); 2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_frame_index_ = 0; 2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Copy any remaining frames in the source to our buffer. 2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int remaining_source_frames = converted_source->frames() - frames_to_copy; 2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) converted_source->CopyPartialFramesTo(frames_to_copy, 2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) remaining_source_frames, 2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_frame_index_, 2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_.get()); 2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_frame_index_ += remaining_source_frames; 2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::OnError(media::AudioInputStream* /* stream */) { 2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Error during sound recording."; 2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioManager::Get()->GetTaskRunner()->PostTask( 2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&AudioRecorder::StopAndCloseOnAudioThread, 2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Unretained(this))); 2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)double AudioRecorder::ProvideInput(media::AudioBus* dest, 2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::TimeDelta /* buffer_delay */) { 2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(temp_conversion_buffer_); 2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_LE(temp_conversion_buffer_->frames(), dest->frames()); 2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) temp_conversion_buffer_->CopyTo(dest); 2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) temp_conversion_buffer_ = NULL; 2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 1.0; 2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AudioRecorder::FlushAudioLoopForTesting() { 2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()) 2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Queue task on the audio thread, when it is executed, that means we've 2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // successfully executed all the tasks before us. 2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::RunLoop rl; 2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) media::AudioManager::Get()->GetTaskRunner()->PostTaskAndReply( 2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(base::IgnoreResult(&AudioRecorder::FlushAudioLoopForTesting), 2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Unretained(this)), 2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) rl.QuitClosure()); 2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) rl.Run(); 2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace copresence 252