• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include <cmath>
6 
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"
12 
13 namespace media {
14 namespace cast {
15 
16 const double Pi = 3.14159265358979323846;
17 
TestAudioBusFactory(int num_channels,int sample_rate,float sine_wave_frequency,float volume)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);
30 }
31 
~TestAudioBusFactory()32 TestAudioBusFactory::~TestAudioBusFactory() {}
33 
NextAudioBus(const base::TimeDelta & duration)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(), AudioBuffersState());
40   bus->Scale(volume_);
41   return bus.Pass();
42 }
43 
CountZeroCrossings(const float * samples,int length)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.
48 
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];
59     }
60   }
61   return count;
62 }
63 
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.
75 //
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.
79 //
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.
88 
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;
95 
EncodeTimestamp(uint16 timestamp,size_t sample_offset,size_t length,float * samples)96 bool EncodeTimestamp(uint16 timestamp,
97                      size_t sample_offset,
98                      size_t length,
99                      float* samples) {
100   if (length < kSamplesToAnalyze) {
101     return false;
102   }
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));
109     }
110   }
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);
118     }
119     mix_of_components /= kNumBits + 1;
120     DCHECK_LE(fabs(mix_of_components), 1.0);
121     samples[i] = mix_of_components;
122   }
123   return true;
124 }
125 
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.
DecodeOneFrequency(const float * samples,size_t length,double frequency)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);
141   }
142   return sqrt(sin_sum * sin_sum + cos_sum * cos_sum);
143 }
144 }  // namespace
145 
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.
DecodeTimestamp(const float * samples,size_t length,uint16 * timestamp)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;
173       }
174     }
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;
180       }
181       *timestamp = gray_coded;
182       return true;
183     }
184   }
185   return false;
186 }
187 
188 }  // namespace cast
189 }  // namespace media
190