Home | History | Annotate | Download | only in audio
      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