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 // MSVC++ requires this to be set before any other includes to get M_PI.
5 #define _USE_MATH_DEFINES
8 #include "media/audio/simple_sources.h"
12 #include "base/files/file.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "media/audio/sounds/wav_audio_handler.h"
16 #include "media/base/audio_bus.h"
20 // Opens |wav_filename|, reads it and loads it as a wav file. This function will
21 // return a null pointer if we can't read the file or if it's malformed. The
22 // caller takes ownership of the returned data. The size of the data is stored
24 static scoped_ptr
<uint8
[]> ReadWavFile(const base::FilePath
& wav_filename
,
25 size_t* file_length
) {
27 wav_filename
, base::File::FLAG_OPEN
| base::File::FLAG_READ
);
28 if (!wav_file
.IsValid()) {
29 LOG(ERROR
) << "Failed to read " << wav_filename
.value()
30 << " as input to the fake device.";
34 size_t wav_file_length
= wav_file
.GetLength();
35 if (wav_file_length
== 0u) {
36 LOG(ERROR
) << "Input file to fake device is empty: "
37 << wav_filename
.value();
41 uint8
* wav_file_data
= new uint8
[wav_file_length
];
42 size_t read_bytes
= wav_file
.Read(0, reinterpret_cast<char*>(wav_file_data
),
44 if (read_bytes
!= wav_file_length
) {
45 LOG(ERROR
) << "Failed to read all bytes of " << wav_filename
.value();
48 *file_length
= wav_file_length
;
49 return scoped_ptr
<uint8
[]>(wav_file_data
);
52 // Opens |wav_filename|, reads it and loads it as a wav file. This function will
53 // bluntly trigger CHECKs if we can't read the file or if it's malformed.
54 static scoped_ptr
<WavAudioHandler
> CreateWavAudioHandler(
55 const base::FilePath
& wav_filename
, const uint8
* wav_file_data
,
56 size_t wav_file_length
, const AudioParameters
& expected_params
) {
57 base::StringPiece
wav_data(reinterpret_cast<const char*>(wav_file_data
),
59 scoped_ptr
<WavAudioHandler
> wav_audio_handler(new WavAudioHandler(wav_data
));
60 return wav_audio_handler
.Pass();
63 // These values are based on experiments for local-to-local
64 // PeerConnection to demonstrate audio/video synchronization.
65 static const int kBeepDurationMilliseconds
= 20;
66 static const int kBeepFrequency
= 400;
68 // Intervals between two automatic beeps.
69 static const int kAutomaticBeepIntervalInMs
= 500;
71 // Automatic beep will be triggered every |kAutomaticBeepIntervalInMs| unless
72 // users explicitly call BeepOnce(), which will disable the automatic beep.
75 BeepContext() : beep_once_(false), automatic_beep_(true) {}
77 void SetBeepOnce(bool enable
) {
78 base::AutoLock
auto_lock(lock_
);
81 // Disable the automatic beep if users explicit set |beep_once_| to true.
83 automatic_beep_
= false;
86 bool beep_once() const {
87 base::AutoLock
auto_lock(lock_
);
91 bool automatic_beep() const {
92 base::AutoLock
auto_lock(lock_
);
93 return automatic_beep_
;
97 mutable base::Lock lock_
;
102 static base::LazyInstance
<BeepContext
>::Leaky g_beep_context
=
103 LAZY_INSTANCE_INITIALIZER
;
105 //////////////////////////////////////////////////////////////////////////////
106 // SineWaveAudioSource implementation.
108 SineWaveAudioSource::SineWaveAudioSource(int channels
,
109 double freq
, double sample_freq
)
110 : channels_(channels
),
111 f_(freq
/ sample_freq
),
118 SineWaveAudioSource::~SineWaveAudioSource() {
121 // The implementation could be more efficient if a lookup table is constructed
122 // but it is efficient enough for our simple needs.
123 int SineWaveAudioSource::OnMoreData(AudioBus
* audio_bus
,
124 uint32 total_bytes_delay
) {
125 base::AutoLock
auto_lock(time_lock_
);
128 // The table is filled with s(t) = kint16max*sin(Theta*t),
129 // where Theta = 2*PI*fs.
130 // We store the discrete time value |t| in a member to ensure that the
131 // next pass starts at a correct state.
132 int max_frames
= cap_
> 0 ?
133 std::min(audio_bus
->frames(), cap_
- time_state_
) : audio_bus
->frames();
134 for (int i
= 0; i
< max_frames
; ++i
)
135 audio_bus
->channel(0)[i
] = sin(2.0 * M_PI
* f_
* time_state_
++);
136 for (int i
= 1; i
< audio_bus
->channels(); ++i
) {
137 memcpy(audio_bus
->channel(i
), audio_bus
->channel(0),
138 max_frames
* sizeof(*audio_bus
->channel(i
)));
143 void SineWaveAudioSource::OnError(AudioOutputStream
* stream
) {
147 void SineWaveAudioSource::CapSamples(int cap
) {
148 base::AutoLock
auto_lock(time_lock_
);
153 void SineWaveAudioSource::Reset() {
154 base::AutoLock
auto_lock(time_lock_
);
158 FileSource::FileSource(const AudioParameters
& params
,
159 const base::FilePath
& path_to_wav_file
)
161 path_to_wav_file_(path_to_wav_file
),
162 wav_file_read_pos_(0),
163 load_failed_(false) {
166 FileSource::~FileSource() {
169 void FileSource::LoadWavFile(const base::FilePath
& path_to_wav_file
) {
170 // Don't try again if we already failed.
174 // Read the file, and put its data in a scoped_ptr so it gets deleted later.
175 size_t file_length
= 0;
176 wav_file_data_
= ReadWavFile(path_to_wav_file
, &file_length
);
177 if (!wav_file_data_
) {
182 wav_audio_handler_
= CreateWavAudioHandler(
183 path_to_wav_file
, wav_file_data_
.get(), file_length
, params_
);
185 // Hook us up so we pull in data from the file into the converter. We need to
186 // modify the wav file's audio parameters since we'll be reading small slices
187 // of it at a time and not the whole thing (like 10 ms at a time).
188 AudioParameters
file_audio_slice(
189 AudioParameters::AUDIO_PCM_LOW_LATENCY
,
190 GuessChannelLayout(wav_audio_handler_
->num_channels()),
191 wav_audio_handler_
->sample_rate(), wav_audio_handler_
->bits_per_sample(),
192 params_
.frames_per_buffer());
194 file_audio_converter_
.reset(
195 new AudioConverter(file_audio_slice
, params_
, false));
196 file_audio_converter_
->AddInput(this);
199 int FileSource::OnMoreData(AudioBus
* audio_bus
, uint32 total_bytes_delay
) {
200 // Load the file if we haven't already. This load needs to happen on the
201 // audio thread, otherwise we'll run on the UI thread on Mac for instance.
202 // This will massively delay the first OnMoreData, but we'll catch up.
203 if (!wav_audio_handler_
)
204 LoadWavFile(path_to_wav_file_
);
208 DCHECK(wav_audio_handler_
.get());
210 // Stop playing if we've played out the whole file.
211 if (wav_audio_handler_
->AtEnd(wav_file_read_pos_
))
214 // This pulls data from ProvideInput.
215 file_audio_converter_
->Convert(audio_bus
);
216 return audio_bus
->frames();
219 double FileSource::ProvideInput(AudioBus
* audio_bus_into_converter
,
220 base::TimeDelta buffer_delay
) {
221 // Unfilled frames will be zeroed by CopyTo.
222 size_t bytes_written
;
223 wav_audio_handler_
->CopyTo(audio_bus_into_converter
, wav_file_read_pos_
,
225 wav_file_read_pos_
+= bytes_written
;
229 void FileSource::OnError(AudioOutputStream
* stream
) {
232 BeepingSource::BeepingSource(const AudioParameters
& params
)
233 : buffer_size_(params
.GetBytesPerBuffer()),
234 buffer_(new uint8
[buffer_size_
]),
236 last_callback_time_(base::TimeTicks::Now()),
237 beep_duration_in_buffers_(kBeepDurationMilliseconds
*
238 params
.sample_rate() /
239 params
.frames_per_buffer() /
241 beep_generated_in_buffers_(0),
242 beep_period_in_frames_(params
.sample_rate() / kBeepFrequency
) {
245 BeepingSource::~BeepingSource() {
248 int BeepingSource::OnMoreData(AudioBus
* audio_bus
, uint32 total_bytes_delay
) {
249 // Accumulate the time from the last beep.
250 interval_from_last_beep_
+= base::TimeTicks::Now() - last_callback_time_
;
252 memset(buffer_
.get(), 0, buffer_size_
);
253 bool should_beep
= false;
254 BeepContext
* beep_context
= g_beep_context
.Pointer();
255 if (beep_context
->automatic_beep()) {
256 base::TimeDelta delta
= interval_from_last_beep_
-
257 base::TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs
);
258 if (delta
> base::TimeDelta()) {
260 interval_from_last_beep_
= delta
;
263 should_beep
= beep_context
->beep_once();
264 beep_context
->SetBeepOnce(false);
267 // If this object was instructed to generate a beep or has started to
268 // generate a beep sound.
269 if (should_beep
|| beep_generated_in_buffers_
) {
270 // Compute the number of frames to output high value. Then compute the
271 // number of bytes based on channels and bits per channel.
272 int high_frames
= beep_period_in_frames_
/ 2;
273 int high_bytes
= high_frames
* params_
.bits_per_sample() *
274 params_
.channels() / 8;
276 // Separate high and low with the same number of bytes to generate a
279 while (position
+ high_bytes
<= buffer_size_
) {
280 // Write high values first.
281 memset(buffer_
.get() + position
, 128, high_bytes
);
282 // Then leave low values in the buffer with |high_bytes|.
283 position
+= high_bytes
* 2;
286 ++beep_generated_in_buffers_
;
287 if (beep_generated_in_buffers_
>= beep_duration_in_buffers_
)
288 beep_generated_in_buffers_
= 0;
291 last_callback_time_
= base::TimeTicks::Now();
292 audio_bus
->FromInterleaved(
293 buffer_
.get(), audio_bus
->frames(), params_
.bits_per_sample() / 8);
294 return audio_bus
->frames();
297 void BeepingSource::OnError(AudioOutputStream
* stream
) {
300 void BeepingSource::BeepOnce() {
301 g_beep_context
.Pointer()->SetBeepOnce(true);