| /* | |
| * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "modules/audio_device/fine_audio_buffer.h" | |
| #include <limits.h> | |
| #include <memory> | |
| #include "api/array_view.h" | |
| #include "api/task_queue/default_task_queue_factory.h" | |
| #include "modules/audio_device/mock_audio_device_buffer.h" | |
| #include "test/gmock.h" | |
| #include "test/gtest.h" | |
| using ::testing::_; | |
| using ::testing::AtLeast; | |
| using ::testing::InSequence; | |
| using ::testing::Return; | |
| namespace webrtc { | |
| const int kSampleRate = 44100; | |
| const int kChannels = 2; | |
| const int kSamplesPer10Ms = kSampleRate * 10 / 1000; | |
| // The fake audio data is 0,1,..SCHAR_MAX-1,0,1,... This is to make it easy | |
| // to detect errors. This function verifies that the buffers contain such data. | |
| // E.g. if there are two buffers of size 3, buffer 1 would contain 0,1,2 and | |
| // buffer 2 would contain 3,4,5. Note that SCHAR_MAX is 127 so wrap-around | |
| // will happen. | |
| // `buffer` is the audio buffer to verify. | |
| bool VerifyBuffer(const int16_t* buffer, int buffer_number, int size) { | |
| int start_value = (buffer_number * size) % SCHAR_MAX; | |
| for (int i = 0; i < size; ++i) { | |
| if (buffer[i] != (i + start_value) % SCHAR_MAX) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| // This function replaces the real AudioDeviceBuffer::GetPlayoutData when it's | |
| // called (which is done implicitly when calling GetBufferData). It writes the | |
| // sequence 0,1,..SCHAR_MAX-1,0,1,... to the buffer. Note that this is likely a | |
| // buffer of different size than the one VerifyBuffer verifies. | |
| // `iteration` is the number of calls made to UpdateBuffer prior to this call. | |
| // `samples_per_10_ms` is the number of samples that should be written to the | |
| // buffer (`arg0`). | |
| ACTION_P2(UpdateBuffer, iteration, samples_per_10_ms) { | |
| int16_t* buffer = static_cast<int16_t*>(arg0); | |
| int start_value = (iteration * samples_per_10_ms) % SCHAR_MAX; | |
| for (int i = 0; i < samples_per_10_ms; ++i) { | |
| buffer[i] = (i + start_value) % SCHAR_MAX; | |
| } | |
| // Should return samples per channel. | |
| return samples_per_10_ms / kChannels; | |
| } | |
| // Writes a periodic ramp pattern to the supplied `buffer`. See UpdateBuffer() | |
| // for details. | |
| void UpdateInputBuffer(int16_t* buffer, int iteration, int size) { | |
| int start_value = (iteration * size) % SCHAR_MAX; | |
| for (int i = 0; i < size; ++i) { | |
| buffer[i] = (i + start_value) % SCHAR_MAX; | |
| } | |
| } | |
| // Action macro which verifies that the recorded 10ms chunk of audio data | |
| // (in `arg0`) contains the correct reference values even if they have been | |
| // supplied using a buffer size that is smaller or larger than 10ms. | |
| // See VerifyBuffer() for details. | |
| ACTION_P2(VerifyInputBuffer, iteration, samples_per_10_ms) { | |
| const int16_t* buffer = static_cast<const int16_t*>(arg0); | |
| int start_value = (iteration * samples_per_10_ms) % SCHAR_MAX; | |
| for (int i = 0; i < samples_per_10_ms; ++i) { | |
| EXPECT_EQ(buffer[i], (i + start_value) % SCHAR_MAX); | |
| } | |
| return 0; | |
| } | |
| void RunFineBufferTest(int frame_size_in_samples) { | |
| const int kFrameSizeSamples = frame_size_in_samples; | |
| const int kNumberOfFrames = 5; | |
| // Ceiling of integer division: 1 + ((x - 1) / y) | |
| const int kNumberOfUpdateBufferCalls = | |
| 1 + ((kNumberOfFrames * frame_size_in_samples - 1) / kSamplesPer10Ms); | |
| auto task_queue_factory = CreateDefaultTaskQueueFactory(); | |
| MockAudioDeviceBuffer audio_device_buffer(task_queue_factory.get()); | |
| audio_device_buffer.SetPlayoutSampleRate(kSampleRate); | |
| audio_device_buffer.SetPlayoutChannels(kChannels); | |
| audio_device_buffer.SetRecordingSampleRate(kSampleRate); | |
| audio_device_buffer.SetRecordingChannels(kChannels); | |
| EXPECT_CALL(audio_device_buffer, RequestPlayoutData(_)) | |
| .WillRepeatedly(Return(kSamplesPer10Ms)); | |
| { | |
| InSequence s; | |
| for (int i = 0; i < kNumberOfUpdateBufferCalls; ++i) { | |
| EXPECT_CALL(audio_device_buffer, GetPlayoutData(_)) | |
| .WillOnce(UpdateBuffer(i, kChannels * kSamplesPer10Ms)) | |
| .RetiresOnSaturation(); | |
| } | |
| } | |
| { | |
| InSequence s; | |
| for (int j = 0; j < kNumberOfUpdateBufferCalls - 1; ++j) { | |
| EXPECT_CALL(audio_device_buffer, SetRecordedBuffer(_, kSamplesPer10Ms)) | |
| .WillOnce(VerifyInputBuffer(j, kChannels * kSamplesPer10Ms)) | |
| .RetiresOnSaturation(); | |
| } | |
| } | |
| EXPECT_CALL(audio_device_buffer, SetVQEData(_, _)) | |
| .Times(kNumberOfUpdateBufferCalls - 1); | |
| EXPECT_CALL(audio_device_buffer, DeliverRecordedData()) | |
| .Times(kNumberOfUpdateBufferCalls - 1) | |
| .WillRepeatedly(Return(0)); | |
| FineAudioBuffer fine_buffer(&audio_device_buffer); | |
| std::unique_ptr<int16_t[]> out_buffer( | |
| new int16_t[kChannels * kFrameSizeSamples]); | |
| std::unique_ptr<int16_t[]> in_buffer( | |
| new int16_t[kChannels * kFrameSizeSamples]); | |
| for (int i = 0; i < kNumberOfFrames; ++i) { | |
| fine_buffer.GetPlayoutData( | |
| rtc::ArrayView<int16_t>(out_buffer.get(), | |
| kChannels * kFrameSizeSamples), | |
| 0); | |
| EXPECT_TRUE( | |
| VerifyBuffer(out_buffer.get(), i, kChannels * kFrameSizeSamples)); | |
| UpdateInputBuffer(in_buffer.get(), i, kChannels * kFrameSizeSamples); | |
| fine_buffer.DeliverRecordedData( | |
| rtc::ArrayView<const int16_t>(in_buffer.get(), | |
| kChannels * kFrameSizeSamples), | |
| 0); | |
| } | |
| } | |
| TEST(FineBufferTest, BufferLessThan10ms) { | |
| const int kFrameSizeSamples = kSamplesPer10Ms - 50; | |
| RunFineBufferTest(kFrameSizeSamples); | |
| } | |
| TEST(FineBufferTest, GreaterThan10ms) { | |
| const int kFrameSizeSamples = kSamplesPer10Ms + 50; | |
| RunFineBufferTest(kFrameSizeSamples); | |
| } | |
| } // namespace webrtc |