Home | History | Annotate | Download | only in utility
      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 
     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 
     32 TestAudioBusFactory::~TestAudioBusFactory() {}
     33 
     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 
     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 
     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.
    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.
    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