// Copyright 2014 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/40285824): Remove this and convert code to safer constructs. #pragma allow_unsafe_buffers #endif #include <cmath> #include <numbers> #include <vector> #include "base/check_op.h" #include "base/time/time.h" #include "media/base/audio_bus.h" #include "media/cast/test/utility/audio_utility.h" namespace media { namespace cast { TestAudioBusFactory::TestAudioBusFactory(int num_channels, int sample_rate, float sine_wave_frequency, float volume) : … { … } TestAudioBusFactory::~TestAudioBusFactory() = default; std::unique_ptr<AudioBus> TestAudioBusFactory::NextAudioBus( const base::TimeDelta& duration) { … } int CountZeroCrossings(const float* samples, int length) { … } // EncodeTimestamp stores a 16-bit number as frequencies in a sample. // Our internal code tends to work on 10ms chunks of data, and to // make sure the decoding always work, I wanted to make sure that the // encoded value can be decoded from 5ms of sample data, assuming a // sampling rate of 48Khz, this turns out to be 240 samples. // Each bit of the timestamp is stored as a frequency, where the // frequency is bit_number * 200 Hz. We also add a 'sense' tone to // the output, this tone is 17 * 200 = 3400Hz, and when we decode, // we can use this tone to make sure that we aren't decoding bogus data. // Also, we use this tone to scale our expectations in case something // changed changed the volume of the audio. // // Normally, we will encode 480 samples (10ms) of data, but when we // read it will will scan 240 samples at a time until something that // can be decoded is found. // // The intention is to use these routines to encode the frame number // that goes with each chunk of audio, so if our frame rate is // 30Hz, we would encode 48000/30 = 1600 samples of "1", then // 1600 samples of "2", etc. When we decode this, it is possible // that we get a chunk of data that is spanning two frame numbers, // so we gray-code the numbers. Since adjacent gray-coded number // will only differ in one bit, we should never get numbers out // of sequence when decoding, at least not by more than one. const double kBaseFrequency = …; const int kSamplingFrequency = …; const size_t kNumBits = …; const size_t kSamplesToAnalyze = …; const double kSenseFrequency = …; const double kMinSense = …; bool EncodeTimestamp(uint16_t timestamp, size_t sample_offset, size_t length, float* samples) { … } namespace { // We use a slow DCT here since this code is only used for testing. // While an FFT would probably be faster, it wouldn't be a LOT // faster since we only analyze 17 out of 120 frequencies. // With an FFT we would verify that none of the higher frequencies // contain a lot of energy, which would be useful in detecting // bogus data. double DecodeOneFrequency(const float* samples, size_t length, double frequency) { … } } // namespace // When decoding, we first check for sense frequency, then we decode // each of the bits. Each frequency must have a strength that is similar to // the sense frequency or to zero, or the decoding fails. If it fails, we // move head by 60 samples and try again until we run out of samples. bool DecodeTimestamp(const float* samples, size_t length, uint16_t* timestamp) { … } } // namespace cast } // namespace media