Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / cast / test / utility / audio_utility.cc
blob094f141ab0eca40f603427acb016c1a882e4ac8b
1 // Copyright 2014 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.
5 #include <cmath>
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/time/time.h"
10 #include "media/base/audio_bus.h"
11 #include "media/cast/test/utility/audio_utility.h"
13 namespace media {
14 namespace cast {
16 const double Pi = 3.14159265358979323846;
18 TestAudioBusFactory::TestAudioBusFactory(int num_channels,
19 int sample_rate,
20 float sine_wave_frequency,
21 float volume)
22 : num_channels_(num_channels),
23 sample_rate_(sample_rate),
24 volume_(volume),
25 source_(num_channels, sine_wave_frequency, sample_rate) {
26 CHECK_LT(0, num_channels);
27 CHECK_LT(0, sample_rate);
28 CHECK_LE(0.0f, volume_);
29 CHECK_LE(volume_, 1.0f);
32 TestAudioBusFactory::~TestAudioBusFactory() {}
34 scoped_ptr<AudioBus> TestAudioBusFactory::NextAudioBus(
35 const base::TimeDelta& duration) {
36 const int num_samples = static_cast<int>((sample_rate_ * duration) /
37 base::TimeDelta::FromSeconds(1));
38 scoped_ptr<AudioBus> bus(AudioBus::Create(num_channels_, num_samples));
39 source_.OnMoreData(bus.get(), 0);
40 bus->Scale(volume_);
41 return bus.Pass();
44 int CountZeroCrossings(const float* samples, int length) {
45 // The sample values must pass beyond |kAmplitudeThreshold| on the opposite
46 // side of zero before a crossing will be counted.
47 const float kAmplitudeThreshold = 0.03f; // 3% of max amplitude.
49 int count = 0;
50 int i = 0;
51 float last = 0.0f;
52 for (; i < length && fabsf(last) < kAmplitudeThreshold; ++i)
53 last = samples[i];
54 for (; i < length; ++i) {
55 if (fabsf(samples[i]) >= kAmplitudeThreshold &&
56 (last < 0) != (samples[i] < 0)) {
57 ++count;
58 last = samples[i];
61 return count;
64 // EncodeTimestamp stores a 16-bit number as frequencies in a sample.
65 // Our internal code tends to work on 10ms chunks of data, and to
66 // make sure the decoding always work, I wanted to make sure that the
67 // encoded value can be decoded from 5ms of sample data, assuming a
68 // sampling rate of 48Khz, this turns out to be 240 samples.
69 // Each bit of the timestamp is stored as a frequency, where the
70 // frequency is bit_number * 200 Hz. We also add a 'sense' tone to
71 // the output, this tone is 17 * 200 = 3400Hz, and when we decode,
72 // we can use this tone to make sure that we aren't decoding bogus data.
73 // Also, we use this tone to scale our expectations in case something
74 // changed changed the volume of the audio.
76 // Normally, we will encode 480 samples (10ms) of data, but when we
77 // read it will will scan 240 samples at a time until something that
78 // can be decoded is found.
80 // The intention is to use these routines to encode the frame number
81 // that goes with each chunk of audio, so if our frame rate is
82 // 30Hz, we would encode 48000/30 = 1600 samples of "1", then
83 // 1600 samples of "2", etc. When we decode this, it is possible
84 // that we get a chunk of data that is spanning two frame numbers,
85 // so we gray-code the numbers. Since adjacent gray-coded number
86 // will only differ in one bit, we should never get numbers out
87 // of sequence when decoding, at least not by more than one.
89 const double kBaseFrequency = 200;
90 const int kSamplingFrequency = 48000;
91 const size_t kNumBits = 16;
92 const size_t kSamplesToAnalyze = kSamplingFrequency / kBaseFrequency;
93 const double kSenseFrequency = kBaseFrequency * (kNumBits + 1);
94 const double kMinSense = 1.5;
96 bool EncodeTimestamp(uint16 timestamp,
97 size_t sample_offset,
98 size_t length,
99 float* samples) {
100 if (length < kSamplesToAnalyze) {
101 return false;
103 // gray-code the number
104 timestamp = (timestamp >> 1) ^ timestamp;
105 std::vector<double> frequencies;
106 for (size_t i = 0; i < kNumBits; i++) {
107 if ((timestamp >> i) & 1) {
108 frequencies.push_back(kBaseFrequency * (i+1));
111 // Carrier sense frequency
112 frequencies.push_back(kSenseFrequency);
113 for (size_t i = 0; i < length; i++) {
114 double mix_of_components = 0.0;
115 for (size_t f = 0; f < frequencies.size(); f++) {
116 mix_of_components += sin((i + sample_offset) * Pi * 2.0 * frequencies[f] /
117 kSamplingFrequency);
119 mix_of_components /= kNumBits + 1;
120 DCHECK_LE(fabs(mix_of_components), 1.0);
121 samples[i] = mix_of_components;
123 return true;
126 namespace {
127 // We use a slow DCT here since this code is only used for testing.
128 // While an FFT would probably be faster, it wouldn't be a LOT
129 // faster since we only analyze 17 out of 120 frequencies.
130 // With an FFT we would verify that none of the higher frequencies
131 // contain a lot of energy, which would be useful in detecting
132 // bogus data.
133 double DecodeOneFrequency(const float* samples,
134 size_t length,
135 double frequency) {
136 double sin_sum = 0.0;
137 double cos_sum = 0.0;
138 for (size_t i = 0; i < length; i++) {
139 sin_sum += samples[i] * sin(i * Pi * 2 * frequency / kSamplingFrequency);
140 cos_sum += samples[i] * cos(i * Pi * 2 * frequency / kSamplingFrequency);
142 return sqrt(sin_sum * sin_sum + cos_sum * cos_sum);
144 } // namespace
146 // When decoding, we first check for sense frequency, then we decode
147 // each of the bits. Each frequency must have a strength that is similar to
148 // the sense frequency or to zero, or the decoding fails. If it fails, we
149 // move head by 60 samples and try again until we run out of samples.
150 bool DecodeTimestamp(const float* samples, size_t length, uint16* timestamp) {
151 for (size_t start = 0;
152 start + kSamplesToAnalyze <= length;
153 start += kSamplesToAnalyze / 4) {
154 double sense = DecodeOneFrequency(&samples[start],
155 kSamplesToAnalyze,
156 kSenseFrequency);
157 if (sense < kMinSense) continue;
158 bool success = true;
159 uint16 gray_coded = 0;
160 for (size_t bit = 0; success && bit < kNumBits; bit++) {
161 double signal_strength = DecodeOneFrequency(
162 &samples[start],
163 kSamplesToAnalyze,
164 kBaseFrequency * (bit + 1));
165 if (signal_strength < sense / 4) {
166 // Zero bit, no action
167 } else if (signal_strength > sense * 0.75 &&
168 signal_strength < sense * 1.25) {
169 // One bit
170 gray_coded |= 1 << bit;
171 } else {
172 success = false;
175 if (success) {
176 // Convert from gray-coded number to binary.
177 uint16 mask;
178 for (mask = gray_coded >> 1; mask != 0; mask = mask >> 1) {
179 gray_coded = gray_coded ^ mask;
181 *timestamp = gray_coded;
182 return true;
185 return false;
188 } // namespace cast
189 } // namespace media