fake_audio_input_stream.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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 11using base::TimeTicks; 12using base::TimeDelta; 13 14namespace media { 15 16namespace { 17 18// These values are based on experiments for local-to-local 19// PeerConnection to demonstrate audio/video synchronization. 20const int kBeepDurationMilliseconds = 20; 21const int kBeepFrequency = 400; 22 23struct BeepContext { 24 BeepContext() : beep_once(false) {} 25 base::Lock beep_lock; 26 bool beep_once; 27}; 28 29static base::LazyInstance<BeepContext> g_beep_context = 30 LAZY_INSTANCE_INITIALIZER; 31 32} // namespace 33 34AudioInputStream* FakeAudioInputStream::MakeFakeStream( 35 AudioManagerBase* manager, 36 const AudioParameters& params) { 37 return new FakeAudioInputStream(manager, params); 38} 39 40FakeAudioInputStream::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 58FakeAudioInputStream::~FakeAudioInputStream() {} 59 60bool FakeAudioInputStream::Open() { 61 buffer_.reset(new uint8[buffer_size_]); 62 memset(buffer_.get(), 0, buffer_size_); 63 return true; 64} 65 66void 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 77void 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 134void FakeAudioInputStream::Stop() { 135 thread_.Stop(); 136} 137 138void FakeAudioInputStream::Close() { 139 if (callback_) { 140 callback_->OnClose(this); 141 callback_ = NULL; 142 } 143 audio_manager_->ReleaseInputStream(this); 144} 145 146double FakeAudioInputStream::GetMaxVolume() { 147 return 1.0; 148} 149 150void FakeAudioInputStream::SetVolume(double volume) { 151} 152 153double FakeAudioInputStream::GetVolume() { 154 return 1.0; 155} 156 157void FakeAudioInputStream::SetAutomaticGainControl(bool enabled) {} 158 159bool FakeAudioInputStream::GetAutomaticGainControl() { 160 return true; 161} 162 163// static 164void 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