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/simple_sources.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 
11 #include "base/files/file.h"
12 #include "base/logging.h"
13 #include "base/numerics/math_constants.h"
14 #include "base/thread_annotations.h"
15 #include "base/time/time.h"
16 #include "media/audio/wav_audio_handler.h"
17 #include "media/base/audio_bus.h"
18 
19 namespace media {
20 namespace {
21 // Opens |wav_filename|, reads it and loads it as a wav file. This function will
22 // return a null pointer if we can't read the file or if it's malformed. The
23 // caller takes ownership of the returned data. The size of the data is stored
24 // in |read_length|.
ReadWavFile(const base::FilePath & wav_filename,size_t * read_length)25 std::unique_ptr<char[]> ReadWavFile(const base::FilePath& wav_filename,
26                                     size_t* read_length) {
27   base::File wav_file(
28       wav_filename, base::File::FLAG_OPEN | base::File::FLAG_READ);
29   if (!wav_file.IsValid()) {
30     LOG(ERROR) << "Failed to read " << wav_filename.value()
31                << " as input to the fake device.";
32     return nullptr;
33   }
34 
35   int64_t wav_file_length = wav_file.GetLength();
36   if (wav_file_length < 0) {
37     LOG(ERROR) << "Failed to get size of " << wav_filename.value();
38     return nullptr;
39   }
40   if (wav_file_length == 0) {
41     LOG(ERROR) << "Input file to fake device is empty: "
42                << wav_filename.value();
43     return nullptr;
44   }
45 
46   std::unique_ptr<char[]> data(new char[wav_file_length]);
47   int read_bytes = wav_file.Read(0, data.get(), wav_file_length);
48   if (read_bytes != wav_file_length) {
49     LOG(ERROR) << "Failed to read all bytes of " << wav_filename.value();
50     return nullptr;
51   }
52   *read_length = wav_file_length;
53   return data;
54 }
55 
56 // These values are based on experiments for local-to-local
57 // PeerConnection to demonstrate audio/video synchronization.
58 static const int kBeepDurationMilliseconds = 20;
59 static const int kBeepFrequency = 400;
60 
61 // Intervals between two automatic beeps.
62 static const int kAutomaticBeepIntervalInMs = 500;
63 
64 // Automatic beep will be triggered every |kAutomaticBeepIntervalInMs| unless
65 // users explicitly call BeepOnce(), which will disable the automatic beep.
66 class BeepContext {
67  public:
BeepContext()68   BeepContext() : beep_once_(false), automatic_beep_(true) {}
69 
SetBeepOnce(bool enable)70   void SetBeepOnce(bool enable) {
71     base::AutoLock auto_lock(lock_);
72     beep_once_ = enable;
73 
74     // Disable the automatic beep if users explicit set |beep_once_| to true.
75     if (enable)
76       automatic_beep_ = false;
77   }
78 
beep_once() const79   bool beep_once() const {
80     base::AutoLock auto_lock(lock_);
81     return beep_once_;
82   }
83 
automatic_beep() const84   bool automatic_beep() const {
85     base::AutoLock auto_lock(lock_);
86     return automatic_beep_;
87   }
88 
89  private:
90   mutable base::Lock lock_;
91   bool beep_once_ GUARDED_BY(lock_);
92   bool automatic_beep_ GUARDED_BY(lock_);
93 };
94 
GetBeepContext()95 BeepContext* GetBeepContext() {
96   static BeepContext* context = new BeepContext();
97   return context;
98 }
99 
100 }  // namespace
101 
102 //////////////////////////////////////////////////////////////////////////////
103 // SineWaveAudioSource implementation.
104 
SineWaveAudioSource(int channels,double freq,double sample_freq)105 SineWaveAudioSource::SineWaveAudioSource(int channels,
106                                          double freq,
107                                          double sample_freq)
108     : channels_(channels), f_(freq / sample_freq) {}
109 
110 SineWaveAudioSource::~SineWaveAudioSource() = default;
111 
112 // The implementation could be more efficient if a lookup table is constructed
113 // but it is efficient enough for our simple needs.
OnMoreData(base::TimeDelta,base::TimeTicks,int,AudioBus * dest)114 int SineWaveAudioSource::OnMoreData(base::TimeDelta /* delay */,
115                                     base::TimeTicks /* delay_timestamp */,
116                                     int /* prior_frames_skipped */,
117                                     AudioBus* dest) {
118   int max_frames;
119 
120   {
121     base::AutoLock auto_lock(lock_);
122     callbacks_++;
123 
124     // The table is filled with s(t) = kint16max*sin(Theta*t),
125     // where Theta = 2*PI*fs.
126     // We store the discrete time value |t| in a member to ensure that the
127     // next pass starts at a correct state.
128     max_frames = cap_ > 0 ? std::min(dest->frames(), cap_ - pos_samples_)
129                           : dest->frames();
130     for (int i = 0; i < max_frames; ++i)
131       dest->channel(0)[i] = sin(2.0 * base::kPiDouble * f_ * pos_samples_++);
132     for (int i = 1; i < dest->channels(); ++i) {
133       memcpy(dest->channel(i), dest->channel(0),
134              max_frames * sizeof(*dest->channel(i)));
135     }
136   }
137 
138   if (on_more_data_callback_)
139     on_more_data_callback_.Run();
140 
141   return max_frames;
142 }
143 
OnError(ErrorType type)144 void SineWaveAudioSource::OnError(ErrorType type) {
145   errors_++;
146 }
147 
CapSamples(int cap)148 void SineWaveAudioSource::CapSamples(int cap) {
149   base::AutoLock auto_lock(lock_);
150   DCHECK_GT(cap, 0);
151   cap_ = cap;
152 }
153 
Reset()154 void SineWaveAudioSource::Reset() {
155   base::AutoLock auto_lock(lock_);
156   pos_samples_ = 0;
157 }
158 
FileSource(const AudioParameters & params,const base::FilePath & path_to_wav_file,bool loop)159 FileSource::FileSource(const AudioParameters& params,
160                        const base::FilePath& path_to_wav_file,
161                        bool loop)
162     : params_(params),
163       path_to_wav_file_(path_to_wav_file),
164       wav_file_read_pos_(0),
165       load_failed_(false),
166       looping_(loop) {}
167 
168 FileSource::~FileSource() = default;
169 
LoadWavFile(const base::FilePath & path_to_wav_file)170 void FileSource::LoadWavFile(const base::FilePath& path_to_wav_file) {
171   // Don't try again if we already failed.
172   if (load_failed_)
173     return;
174 
175   // Read the file, and put its data in a scoped_ptr so it gets deleted when
176   // this class destructs. This data must be valid for the lifetime of
177   // |wav_audio_handler_|.
178   size_t length = 0u;
179   raw_wav_data_ = ReadWavFile(path_to_wav_file, &length);
180   if (!raw_wav_data_) {
181     load_failed_ = true;
182     return;
183   }
184 
185   // Attempt to create a handler with this data. If the data is invalid, return.
186   wav_audio_handler_ =
187       WavAudioHandler::Create(base::StringPiece(raw_wav_data_.get(), length));
188   if (!wav_audio_handler_) {
189     LOG(ERROR) << "WAV data could be read but is not valid";
190     load_failed_ = true;
191     return;
192   }
193 
194   // Hook us up so we pull in data from the file into the converter. We need to
195   // modify the wav file's audio parameters since we'll be reading small slices
196   // of it at a time and not the whole thing (like 10 ms at a time).
197   AudioParameters file_audio_slice(
198       AudioParameters::AUDIO_PCM_LOW_LATENCY,
199       GuessChannelLayout(wav_audio_handler_->num_channels()),
200       wav_audio_handler_->sample_rate(), params_.frames_per_buffer());
201 
202   file_audio_converter_.reset(
203       new AudioConverter(file_audio_slice, params_, false));
204   file_audio_converter_->AddInput(this);
205 }
206 
OnMoreData(base::TimeDelta,base::TimeTicks,int,AudioBus * dest)207 int FileSource::OnMoreData(base::TimeDelta /* delay */,
208                            base::TimeTicks /* delay_timestamp */,
209                            int /* prior_frames_skipped */,
210                            AudioBus* dest) {
211   // Load the file if we haven't already. This load needs to happen on the
212   // audio thread, otherwise we'll run on the UI thread on Mac for instance.
213   // This will massively delay the first OnMoreData, but we'll catch up.
214   if (!wav_audio_handler_)
215     LoadWavFile(path_to_wav_file_);
216   if (load_failed_)
217     return 0;
218 
219   DCHECK(wav_audio_handler_.get());
220 
221   if (wav_audio_handler_->AtEnd(wav_file_read_pos_)) {
222     if (looping_)
223       Rewind();
224     else
225       return 0;
226   }
227 
228   // This pulls data from ProvideInput.
229   file_audio_converter_->Convert(dest);
230   return dest->frames();
231 }
232 
Rewind()233 void FileSource::Rewind() {
234   wav_file_read_pos_ = 0;
235 }
236 
ProvideInput(AudioBus * audio_bus_into_converter,uint32_t frames_delayed)237 double FileSource::ProvideInput(AudioBus* audio_bus_into_converter,
238                                 uint32_t frames_delayed) {
239   // Unfilled frames will be zeroed by CopyTo.
240   size_t bytes_written;
241   wav_audio_handler_->CopyTo(audio_bus_into_converter, wav_file_read_pos_,
242                              &bytes_written);
243   wav_file_read_pos_ += bytes_written;
244   return 1.0;
245 }
246 
OnError(ErrorType type)247 void FileSource::OnError(ErrorType type) {}
248 
BeepingSource(const AudioParameters & params)249 BeepingSource::BeepingSource(const AudioParameters& params)
250     : buffer_size_(params.GetBytesPerBuffer(kSampleFormatU8)),
251       buffer_(new uint8_t[buffer_size_]),
252       params_(params),
253       last_callback_time_(base::TimeTicks::Now()),
254       beep_duration_in_buffers_(kBeepDurationMilliseconds *
255                                 params.sample_rate() /
256                                 params.frames_per_buffer() / 1000),
257       beep_generated_in_buffers_(0),
258       beep_period_in_frames_(params.sample_rate() / kBeepFrequency) {}
259 
260 BeepingSource::~BeepingSource() = default;
261 
OnMoreData(base::TimeDelta,base::TimeTicks,int,AudioBus * dest)262 int BeepingSource::OnMoreData(base::TimeDelta /* delay */,
263                               base::TimeTicks /* delay_timestamp */,
264                               int /* prior_frames_skipped */,
265                               AudioBus* dest) {
266   // Accumulate the time from the last beep.
267   interval_from_last_beep_ += base::TimeTicks::Now() - last_callback_time_;
268 
269   memset(buffer_.get(), 128, buffer_size_);
270   bool should_beep = false;
271   BeepContext* beep_context = GetBeepContext();
272   if (beep_context->automatic_beep()) {
273     base::TimeDelta delta = interval_from_last_beep_ -
274         base::TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs);
275     if (delta > base::TimeDelta()) {
276       should_beep = true;
277       interval_from_last_beep_ = delta;
278     }
279   } else {
280     should_beep = beep_context->beep_once();
281     beep_context->SetBeepOnce(false);
282   }
283 
284   // If this object was instructed to generate a beep or has started to
285   // generate a beep sound.
286   if (should_beep || beep_generated_in_buffers_) {
287     // Compute the number of frames to output high value. Then compute the
288     // number of bytes based on channels.
289     int high_frames = beep_period_in_frames_ / 2;
290     int high_bytes = high_frames * params_.channels();
291 
292     // Separate high and low with the same number of bytes to generate a
293     // square wave.
294     int position = 0;
295     while (position + high_bytes <= buffer_size_) {
296       // Write high values first.
297       memset(buffer_.get() + position, 255, high_bytes);
298       // Then leave low values in the buffer with |high_bytes|.
299       position += high_bytes * 2;
300     }
301 
302     ++beep_generated_in_buffers_;
303     if (beep_generated_in_buffers_ >= beep_duration_in_buffers_)
304       beep_generated_in_buffers_ = 0;
305   }
306 
307   last_callback_time_ = base::TimeTicks::Now();
308   dest->FromInterleaved<UnsignedInt8SampleTypeTraits>(buffer_.get(),
309                                                       dest->frames());
310   return dest->frames();
311 }
312 
OnError(ErrorType type)313 void BeepingSource::OnError(ErrorType type) {}
314 
BeepOnce()315 void BeepingSource::BeepOnce() {
316   GetBeepContext()->SetBeepOnce(true);
317 }
318 
319 }  // namespace media
320