diff options
author | amistry <amistry@chromium.org> | 2014-09-24 00:53:17 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-24 07:53:30 +0000 |
commit | edf03bca7f54896c848d7b3a92f2c0078edede4b (patch) | |
tree | ad37f43b5750e932855b2ae488a0c5779828038b /ppapi | |
parent | a40c605b9f633c7e2022be24aff5705ef0f89777 (diff) | |
download | chromium_src-edf03bca7f54896c848d7b3a92f2c0078edede4b.zip chromium_src-edf03bca7f54896c848d7b3a92f2c0078edede4b.tar.gz chromium_src-edf03bca7f54896c848d7b3a92f2c0078edede4b.tar.bz2 |
Add a test to verify the waveform from the Pepper MediaStream API is as
expected.
BUG=405413
Review URL: https://codereview.chromium.org/488533002
Cr-Commit-Position: refs/heads/master@{#296364}
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/tests/test_media_stream_audio_track.cc | 140 | ||||
-rw-r--r-- | ppapi/tests/test_media_stream_audio_track.h | 1 |
2 files changed, 139 insertions, 2 deletions
diff --git a/ppapi/tests/test_media_stream_audio_track.cc b/ppapi/tests/test_media_stream_audio_track.cc index 020cf08..6509f2a 100644 --- a/ppapi/tests/test_media_stream_audio_track.cc +++ b/ppapi/tests/test_media_stream_audio_track.cc @@ -6,6 +6,13 @@ #include "ppapi/tests/test_media_stream_audio_track.h" +// For MSVC. +#define _USE_MATH_DEFINES +#include <math.h> +#include <stdint.h> + +#include <algorithm> + #include "ppapi/c/private/ppb_testing_private.h" #include "ppapi/cpp/audio_buffer.h" #include "ppapi/cpp/completion_callback.h" @@ -40,6 +47,31 @@ const char kJSCode[] = "navigator.getUserMedia(constraints," " gotStream, function() {});"; +const char kSineJSCode[] = + // Create oscillators for the left and right channels. Use a sine wave, + // which is the easiest to calculate expected values. The oscillator output + // is low-pass filtered (as per spec) making comparison hard. + "var context = new AudioContext();" + "var l_osc = context.createOscillator();" + "l_osc.type = \"sine\";" + "l_osc.frequency.value = 25;" + "var r_osc = context.createOscillator();" + "r_osc.type = \"sine\";" + "r_osc.frequency.value = 100;" + // Combine the left and right channels. + "var merger = context.createChannelMerger(2);" + "merger.channelInterpretation = \"discrete\";" + "l_osc.connect(merger, 0, 0);" + "r_osc.connect(merger, 0, 1);" + "var dest_stream = context.createMediaStreamDestination();" + "merger.connect(dest_stream);" + // Dump the generated waveform to a MediaStream output. + "l_osc.start();" + "r_osc.start();" + "var track = dest_stream.stream.getAudioTracks()[0];" + "var plugin = document.getElementById('plugin');" + "plugin.postMessage(track);"; + // Helper to check if the |sample_rate| is listed in PP_AudioBuffer_SampleRate // enum. bool IsSampleRateValid(PP_AudioBuffer_SampleRate sample_rate) { @@ -77,6 +109,7 @@ void TestMediaStreamAudioTrack::RunTests(const std::string& filter) { RUN_TEST(GetBuffer, filter); RUN_TEST(Configure, filter); RUN_TEST(ConfigureClose, filter); + RUN_TEST(VerifyWaveform, filter); } void TestMediaStreamAudioTrack::HandleMessage(const pp::Var& message) { @@ -174,8 +207,6 @@ std::string TestMediaStreamAudioTrack::CheckGetBuffer( ASSERT_GE(buffer.GetTimestamp(), timestamp); timestamp = buffer.GetTimestamp(); - // TODO(amistry): Figure out how to inject a predictable audio pattern, such - // as a sawtooth, and check the buffer data to make sure it's correct. ASSERT_TRUE(buffer.GetDataBuffer() != NULL); if (expected_duration > 0) { uint32_t buffer_size = buffer.GetDataBufferSize(); @@ -335,3 +366,108 @@ std::string TestMediaStreamAudioTrack::TestConfigureClose() { PASS(); } + +uint32_t CalculateWaveStartingTime(int16_t sample, int16_t next_sample, + uint32_t period) { + int16_t slope = next_sample - sample; + double angle = asin(sample / (double)INT16_MAX); + if (slope < 0) { + angle = M_PI - angle; + } + if (angle < 0) { + angle += 2 * M_PI; + } + return round(angle * period / (2 * M_PI)); +} + +std::string TestMediaStreamAudioTrack::TestVerifyWaveform() { + // Create a track. + instance_->EvalScript(kSineJSCode); + event_.Wait(); + event_.Reset(); + + ASSERT_FALSE(audio_track_.is_null()); + ASSERT_FALSE(audio_track_.HasEnded()); + ASSERT_FALSE(audio_track_.GetId().empty()); + + // Use a weird buffer length and number of buffers. + const int32_t kBufferSize = 13; + const int32_t kNumBuffers = 3; + + const uint32_t kChannels = 2; + const uint32_t kFreqLeft = 25; + const uint32_t kFreqRight = 100; + + int32_t attrib_list[] = { + PP_MEDIASTREAMAUDIOTRACK_ATTRIB_DURATION, kBufferSize, + PP_MEDIASTREAMAUDIOTRACK_ATTRIB_BUFFERS, kNumBuffers, + PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE, + }; + ASSERT_SUBTEST_SUCCESS(CheckConfigure(attrib_list, PP_OK)); + + // Get kNumBuffers buffers and verify they conform to the expected waveform. + PP_TimeDelta timestamp = 0.0; + int sample_time = 0; + uint32_t left_start = 0; + uint32_t right_start = 0; + for (int j = 0; j < kNumBuffers; ++j) { + TestCompletionCallbackWithOutput<pp::AudioBuffer> cc_get_buffer( + instance_->pp_instance(), false); + cc_get_buffer.WaitForResult( + audio_track_.GetBuffer(cc_get_buffer.GetCallback())); + ASSERT_EQ(PP_OK, cc_get_buffer.result()); + pp::AudioBuffer buffer = cc_get_buffer.output(); + ASSERT_FALSE(buffer.is_null()); + ASSERT_TRUE(IsSampleRateValid(buffer.GetSampleRate())); + ASSERT_EQ(buffer.GetSampleSize(), PP_AUDIOBUFFER_SAMPLESIZE_16_BITS); + ASSERT_EQ(buffer.GetNumberOfChannels(), kChannels); + ASSERT_GE(buffer.GetTimestamp(), timestamp); + timestamp = buffer.GetTimestamp(); + + uint32_t buffer_size = buffer.GetDataBufferSize(); + uint32_t sample_rate = buffer.GetSampleRate(); + uint32_t num_samples = buffer.GetNumberOfSamples(); + uint32_t bytes_per_frame = kChannels * 2; + ASSERT_EQ(num_samples, (kChannels * kBufferSize * sample_rate) / 1000); + ASSERT_EQ(buffer_size % bytes_per_frame, 0U); + ASSERT_EQ(buffer_size, num_samples * 2); + + // Period of sine wave, in samples. + uint32_t left_period = sample_rate / kFreqLeft; + uint32_t right_period = sample_rate / kFreqRight; + + int16_t* data_buffer = static_cast<int16_t*>(buffer.GetDataBuffer()); + ASSERT_TRUE(data_buffer != NULL); + + if (j == 0) { + // The generated wave doesn't necessarily start at 0, so compensate for + // this. + left_start = CalculateWaveStartingTime(data_buffer[0], data_buffer[2], + left_period); + right_start = CalculateWaveStartingTime(data_buffer[1], data_buffer[3], + right_period); + } + + for (uint32_t sample = 0; sample < num_samples; + sample += 2, sample_time++) { + int16_t left = data_buffer[sample]; + int16_t right = data_buffer[sample + 1]; + double angle = (2.0 * M_PI * ((sample_time + left_start) % left_period)) / + left_period; + int16_t expected = INT16_MAX * sin(angle); + // Account for off-by-one errors due to rounding. + ASSERT_GE(left, std::max<int16_t>(expected, INT16_MIN + 1) - 1); + ASSERT_LE(left, std::min<int16_t>(expected, INT16_MAX - 1) + 1); + + angle = (2 * M_PI * ((sample_time + right_start) % right_period)) / + right_period; + expected = INT16_MAX * sin(angle); + ASSERT_GE(right, std::max<int16_t>(expected, INT16_MIN + 1) - 1); + ASSERT_LE(right, std::min<int16_t>(expected, INT16_MAX - 1) + 1); + } + + audio_track_.RecycleBuffer(buffer); + } + + PASS(); +} diff --git a/ppapi/tests/test_media_stream_audio_track.h b/ppapi/tests/test_media_stream_audio_track.h index ee6864c..1dcb3f3 100644 --- a/ppapi/tests/test_media_stream_audio_track.h +++ b/ppapi/tests/test_media_stream_audio_track.h @@ -32,6 +32,7 @@ class TestMediaStreamAudioTrack : public TestCase { std::string TestGetBuffer(); std::string TestConfigure(); std::string TestConfigureClose(); + std::string TestVerifyWaveform(); pp::MediaStreamAudioTrack audio_track_; |