fake_audio_input_stream.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/audio/fake_audio_input_stream.h" 6 7#include "base/bind.h" 8#include "base/lazy_instance.h" 9#include "media/audio/audio_manager_base.h" 10#include "media/base/audio_bus.h" 11 12using base::TimeTicks; 13using base::TimeDelta; 14 15namespace media { 16 17namespace { 18 19// These values are based on experiments for local-to-local 20// PeerConnection to demonstrate audio/video synchronization. 21const int kBeepDurationMilliseconds = 20; 22const int kBeepFrequency = 400; 23 24// Intervals between two automatic beeps. 25const int kAutomaticBeepIntervalInMs = 500; 26 27// Automatic beep will be triggered every |kAutomaticBeepIntervalInMs| unless 28// users explicitly call BeepOnce(), which will disable the automatic beep. 29struct BeepContext { 30 BeepContext() : beep_once(false), automatic(true) {} 31 base::Lock beep_lock; 32 bool beep_once; 33 bool automatic; 34}; 35 36static base::LazyInstance<BeepContext> g_beep_context = 37 LAZY_INSTANCE_INITIALIZER; 38 39} // namespace 40 41AudioInputStream* FakeAudioInputStream::MakeFakeStream( 42 AudioManagerBase* manager, 43 const AudioParameters& params) { 44 return new FakeAudioInputStream(manager, params); 45} 46 47FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager, 48 const AudioParameters& params) 49 : audio_manager_(manager), 50 callback_(NULL), 51 buffer_size_((params.channels() * params.bits_per_sample() * 52 params.frames_per_buffer()) / 53 8), 54 params_(params), 55 thread_("FakeAudioRecordingThread"), 56 callback_interval_(base::TimeDelta::FromMilliseconds( 57 (params.frames_per_buffer() * 1000) / params.sample_rate())), 58 beep_duration_in_buffers_(kBeepDurationMilliseconds * 59 params.sample_rate() / 60 params.frames_per_buffer() / 61 1000), 62 beep_generated_in_buffers_(0), 63 beep_period_in_frames_(params.sample_rate() / kBeepFrequency), 64 frames_elapsed_(0), 65 audio_bus_(AudioBus::Create(params)) { 66} 67 68FakeAudioInputStream::~FakeAudioInputStream() {} 69 70bool FakeAudioInputStream::Open() { 71 buffer_.reset(new uint8[buffer_size_]); 72 memset(buffer_.get(), 0, buffer_size_); 73 audio_bus_->Zero(); 74 return true; 75} 76 77void FakeAudioInputStream::Start(AudioInputCallback* callback) { 78 DCHECK(!thread_.IsRunning()); 79 DCHECK(!callback_); 80 callback_ = callback; 81 last_callback_time_ = TimeTicks::Now(); 82 thread_.Start(); 83 thread_.message_loop()->PostDelayedTask( 84 FROM_HERE, 85 base::Bind(&FakeAudioInputStream::DoCallback, base::Unretained(this)), 86 callback_interval_); 87} 88 89void FakeAudioInputStream::DoCallback() { 90 DCHECK(callback_); 91 92 const TimeTicks now = TimeTicks::Now(); 93 base::TimeDelta next_callback_time = 94 last_callback_time_ + callback_interval_ * 2 - now; 95 96 // If we are falling behind, try to catch up as much as we can in the next 97 // callback. 98 if (next_callback_time < base::TimeDelta()) 99 next_callback_time = base::TimeDelta(); 100 101 // Accumulate the time from the last beep. 102 interval_from_last_beep_ += now - last_callback_time_; 103 104 last_callback_time_ = now; 105 106 memset(buffer_.get(), 0, buffer_size_); 107 108 bool should_beep = false; 109 { 110 BeepContext* beep_context = g_beep_context.Pointer(); 111 base::AutoLock auto_lock(beep_context->beep_lock); 112 if (beep_context->automatic) { 113 base::TimeDelta delta = interval_from_last_beep_ - 114 TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs); 115 if (delta > base::TimeDelta()) { 116 should_beep = true; 117 interval_from_last_beep_ = delta; 118 } 119 } else { 120 should_beep = beep_context->beep_once; 121 beep_context->beep_once = false; 122 } 123 } 124 125 // If this object was instructed to generate a beep or has started to 126 // generate a beep sound. 127 if (should_beep || beep_generated_in_buffers_) { 128 // Compute the number of frames to output high value. Then compute the 129 // number of bytes based on channels and bits per channel. 130 int high_frames = beep_period_in_frames_ / 2; 131 int high_bytes = high_frames * params_.bits_per_sample() * 132 params_.channels() / 8; 133 134 // Separate high and low with the same number of bytes to generate a 135 // square wave. 136 int position = 0; 137 while (position + high_bytes <= buffer_size_) { 138 // Write high values first. 139 memset(buffer_.get() + position, 128, high_bytes); 140 // Then leave low values in the buffer with |high_bytes|. 141 position += high_bytes * 2; 142 } 143 144 ++beep_generated_in_buffers_; 145 if (beep_generated_in_buffers_ >= beep_duration_in_buffers_) 146 beep_generated_in_buffers_ = 0; 147 } 148 149 audio_bus_->FromInterleaved( 150 buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8); 151 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0); 152 frames_elapsed_ += params_.frames_per_buffer(); 153 154 thread_.message_loop()->PostDelayedTask( 155 FROM_HERE, 156 base::Bind(&FakeAudioInputStream::DoCallback, base::Unretained(this)), 157 next_callback_time); 158} 159 160void FakeAudioInputStream::Stop() { 161 thread_.Stop(); 162 callback_ = NULL; 163} 164 165void FakeAudioInputStream::Close() { 166 audio_manager_->ReleaseInputStream(this); 167} 168 169double FakeAudioInputStream::GetMaxVolume() { 170 return 1.0; 171} 172 173void FakeAudioInputStream::SetVolume(double volume) { 174} 175 176double FakeAudioInputStream::GetVolume() { 177 return 1.0; 178} 179 180void FakeAudioInputStream::SetAutomaticGainControl(bool enabled) {} 181 182bool FakeAudioInputStream::GetAutomaticGainControl() { 183 return true; 184} 185 186// static 187void FakeAudioInputStream::BeepOnce() { 188 BeepContext* beep_context = g_beep_context.Pointer(); 189 base::AutoLock auto_lock(beep_context->beep_lock); 190 beep_context->beep_once = true; 191 beep_context->automatic = false; 192} 193 194} // namespace media 195