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 11 using base::TimeTicks; 12 using base::TimeDelta; 13 14 namespace media { 15 16 namespace { 17 18 // These values are based on experiments for local-to-local 19 // PeerConnection to demonstrate audio/video synchronization. 20 const int kBeepDurationMilliseconds = 20; 21 const int kBeepFrequency = 400; 22 23 struct BeepContext { 24 BeepContext() : beep_once(false) {} 25 base::Lock beep_lock; 26 bool beep_once; 27 }; 28 29 static base::LazyInstance<BeepContext> g_beep_context = 30 LAZY_INSTANCE_INITIALIZER; 31 32 } // namespace 33 34 AudioInputStream* FakeAudioInputStream::MakeFakeStream( 35 AudioManagerBase* manager, 36 const AudioParameters& params) { 37 return new FakeAudioInputStream(manager, params); 38 } 39 40 FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager, 41 const AudioParameters& params) 42 : audio_manager_(manager), 43 callback_(NULL), 44 buffer_size_((params.channels() * params.bits_per_sample() * 45 params.frames_per_buffer()) / 8), 46 params_(params), 47 thread_("FakeAudioRecordingThread"), 48 callback_interval_(base::TimeDelta::FromMilliseconds( 49 (params.frames_per_buffer() * 1000) / params.sample_rate())), 50 beep_duration_in_buffers_( 51 kBeepDurationMilliseconds * params.sample_rate() / 52 params.frames_per_buffer() / 1000), 53 beep_generated_in_buffers_(0), 54 beep_period_in_frames_(params.sample_rate() / kBeepFrequency), 55 frames_elapsed_(0) { 56 } 57 58 FakeAudioInputStream::~FakeAudioInputStream() {} 59 60 bool FakeAudioInputStream::Open() { 61 buffer_.reset(new uint8[buffer_size_]); 62 memset(buffer_.get(), 0, buffer_size_); 63 return true; 64 } 65 66 void FakeAudioInputStream::Start(AudioInputCallback* callback) { 67 DCHECK(!thread_.IsRunning()); 68 callback_ = callback; 69 last_callback_time_ = TimeTicks::Now(); 70 thread_.Start(); 71 thread_.message_loop()->PostDelayedTask( 72 FROM_HERE, 73 base::Bind(&FakeAudioInputStream::DoCallback, base::Unretained(this)), 74 callback_interval_); 75 } 76 77 void FakeAudioInputStream::DoCallback() { 78 DCHECK(callback_); 79 80 memset(buffer_.get(), 0, buffer_size_); 81 82 bool should_beep = false; 83 { 84 BeepContext* beep_context = g_beep_context.Pointer(); 85 base::AutoLock auto_lock(beep_context->beep_lock); 86 should_beep = beep_context->beep_once; 87 beep_context->beep_once = false; 88 } 89 90 // If this object was instructed to generate a beep or has started to 91 // generate a beep sound. 92 if (should_beep || beep_generated_in_buffers_) { 93 // Compute the number of frames to output high value. Then compute the 94 // number of bytes based on channels and bits per channel. 95 int high_frames = beep_period_in_frames_ / 2; 96 int high_bytes = high_frames * params_.bits_per_sample() * 97 params_.channels() / 8; 98 99 // Separate high and low with the same number of bytes to generate a 100 // square wave. 101 int position = 0; 102 while (position + high_bytes <= buffer_size_) { 103 // Write high values first. 104 memset(buffer_.get() + position, 128, high_bytes); 105 106 // Then leave low values in the buffer with |high_bytes|. 107 position += high_bytes * 2; 108 } 109 110 ++beep_generated_in_buffers_; 111 if (beep_generated_in_buffers_ >= beep_duration_in_buffers_) 112 beep_generated_in_buffers_ = 0; 113 } 114 115 callback_->OnData(this, buffer_.get(), buffer_size_, buffer_size_, 1.0); 116 frames_elapsed_ += params_.frames_per_buffer(); 117 118 const TimeTicks now = TimeTicks::Now(); 119 base::TimeDelta next_callback_time = 120 last_callback_time_ + callback_interval_ * 2 - now; 121 122 // If we are falling behind, try to catch up as much as we can in the next 123 // callback. 124 if (next_callback_time < base::TimeDelta()) 125 next_callback_time = base::TimeDelta(); 126 127 last_callback_time_ = now; 128 thread_.message_loop()->PostDelayedTask( 129 FROM_HERE, 130 base::Bind(&FakeAudioInputStream::DoCallback, base::Unretained(this)), 131 next_callback_time); 132 } 133 134 void FakeAudioInputStream::Stop() { 135 thread_.Stop(); 136 } 137 138 void FakeAudioInputStream::Close() { 139 if (callback_) { 140 callback_->OnClose(this); 141 callback_ = NULL; 142 } 143 audio_manager_->ReleaseInputStream(this); 144 } 145 146 double FakeAudioInputStream::GetMaxVolume() { 147 return 1.0; 148 } 149 150 void FakeAudioInputStream::SetVolume(double volume) { 151 } 152 153 double FakeAudioInputStream::GetVolume() { 154 return 1.0; 155 } 156 157 void FakeAudioInputStream::SetAutomaticGainControl(bool enabled) {} 158 159 bool FakeAudioInputStream::GetAutomaticGainControl() { 160 return true; 161 } 162 163 // static 164 void FakeAudioInputStream::BeepOnce() { 165 BeepContext* beep_context = g_beep_context.Pointer(); 166 base::AutoLock auto_lock(beep_context->beep_lock); 167 beep_context->beep_once = true; 168 } 169 170 } // namespace media 171