15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/fake_audio_input_stream.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_manager_base.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)using base::TimeTicks; 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta; 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These values are based on experiments for local-to-local 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PeerConnection to demonstrate audio/video synchronization. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBeepDurationMilliseconds = 20; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBeepFrequency = 400; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct BeepContext { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BeepContext() : beep_once(false) {} 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Lock beep_lock; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool beep_once; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<BeepContext> g_beep_context = 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LAZY_INSTANCE_INITIALIZER; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* FakeAudioInputStream::MakeFakeStream( 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioManagerBase* manager, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new FakeAudioInputStream(manager, params); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager, 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : audio_manager_(manager), 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_(NULL), 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_size_((params.channels() * params.bits_per_sample() * 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.frames_per_buffer()) / 8), 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params_(params), 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_("FakeAudioRecordingThread"), 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_interval_(base::TimeDelta::FromMilliseconds( 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (params.frames_per_buffer() * 1000) / params.sample_rate())), 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) beep_duration_in_buffers_( 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kBeepDurationMilliseconds * params.sample_rate() / 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.frames_per_buffer() / 1000), 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) beep_generated_in_buffers_(0), 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) beep_period_in_frames_(params.sample_rate() / kBeepFrequency), 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frames_elapsed_(0) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FakeAudioInputStream::~FakeAudioInputStream() {} 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FakeAudioInputStream::Open() { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_.reset(new uint8[buffer_size_]); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(buffer_.get(), 0, buffer_size_); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FakeAudioInputStream::Start(AudioInputCallback* callback) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!thread_.IsRunning()); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_ = callback; 697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) last_callback_time_ = TimeTicks::Now(); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_.Start(); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_.message_loop()->PostDelayedTask( 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&FakeAudioInputStream::DoCallback, base::Unretained(this)), 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_interval_); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FakeAudioInputStream::DoCallback() { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(callback_); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(buffer_.get(), 0, buffer_size_); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_beep = false; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BeepContext* beep_context = g_beep_context.Pointer(); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock auto_lock(beep_context->beep_lock); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_beep = beep_context->beep_once; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) beep_context->beep_once = false; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this object was instructed to generate a beep or has started to 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // generate a beep sound. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (should_beep || beep_generated_in_buffers_) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Compute the number of frames to output high value. Then compute the 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // number of bytes based on channels and bits per channel. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int high_frames = beep_period_in_frames_ / 2; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int high_bytes = high_frames * params_.bits_per_sample() * 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params_.channels() / 8; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Separate high and low with the same number of bytes to generate a 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // square wave. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int position = 0; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (position + high_bytes <= buffer_size_) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write high values first. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(buffer_.get() + position, 128, high_bytes); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Then leave low values in the buffer with |high_bytes|. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) position += high_bytes * 2; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++beep_generated_in_buffers_; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (beep_generated_in_buffers_ >= beep_duration_in_buffers_) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) beep_generated_in_buffers_ = 0; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_->OnData(this, buffer_.get(), buffer_size_, buffer_size_, 1.0); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frames_elapsed_ += params_.frames_per_buffer(); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const TimeTicks now = TimeTicks::Now(); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta next_callback_time = 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_callback_time_ + callback_interval_ * 2 - now; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we are falling behind, try to catch up as much as we can in the next 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // callback. 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_callback_time < base::TimeDelta()) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_callback_time = base::TimeDelta(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_callback_time_ = now; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_.message_loop()->PostDelayedTask( 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&FakeAudioInputStream::DoCallback, base::Unretained(this)), 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_callback_time); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FakeAudioInputStream::Stop() { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_.Stop(); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FakeAudioInputStream::Close() { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_->OnClose(this); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_ = NULL; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_manager_->ReleaseInputStream(this); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double FakeAudioInputStream::GetMaxVolume() { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1.0; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FakeAudioInputStream::SetVolume(double volume) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double FakeAudioInputStream::GetVolume() { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1.0; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FakeAudioInputStream::SetAutomaticGainControl(bool enabled) {} 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FakeAudioInputStream::GetAutomaticGainControl() { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FakeAudioInputStream::BeepOnce() { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BeepContext* beep_context = g_beep_context.Pointer(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock auto_lock(beep_context->beep_lock); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) beep_context->beep_once = true; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 171