Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: content/renderer/media/audio_track_recorder_unittest.cc

Issue 1406113002: Add AudioTrackRecorder for audio component of MediaStream recording. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: miu's comment Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/renderer/media/audio_track_recorder.cc ('k') | content/test/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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 "content/renderer/media/audio_track_recorder.h"
6
7 #include "base/run_loop.h"
8 #include "base/stl_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/renderer/media/media_stream_audio_source.h"
11 #include "content/renderer/media/mock_media_constraint_factory.h"
12 #include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
13 #include "content/renderer/media/webrtc_local_audio_track.h"
14 #include "media/audio/simple_sources.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/WebKit/public/web/WebHeap.h"
18 #include "third_party/opus/src/include/opus.h"
19
20 using ::testing::_;
21 using ::testing::DoAll;
22 using ::testing::InSequence;
23 using ::testing::Mock;
24 using ::testing::Return;
25 using ::testing::SaveArg;
26 using ::testing::TestWithParam;
27 using ::testing::ValuesIn;
28
29 namespace {
30
31 // Input audio format.
32 const media::AudioParameters::Format kDefaultInputFormat =
33 media::AudioParameters::AUDIO_PCM_LOW_LATENCY;
34 const int kDefaultBitsPerSample = 16;
35 const int kDefaultSampleRate = 48000;
36 // The |frames_per_buffer| field of AudioParameters is not used by ATR.
37 const int kIgnoreFramesPerBuffer = 1;
38 const int kOpusMaxBufferDurationMS = 120;
39
40 } // namespace
41
42 namespace content {
43
44 ACTION_P(RunClosure, closure) {
45 closure.Run();
46 }
47
48 struct ATRTestParams {
49 const media::AudioParameters::Format input_format;
50 const media::ChannelLayout channel_layout;
51 const int sample_rate;
52 const int bits_per_sample;
53 };
54
55 const ATRTestParams kATRTestParams[] = {
56 // Equivalent to default settings:
57 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, /* input format */
58 media::CHANNEL_LAYOUT_STEREO, /* channel layout */
59 kDefaultSampleRate, /* sample rate */
60 kDefaultBitsPerSample}, /* bits per sample */
61 // Change to mono:
62 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
63 kDefaultSampleRate, kDefaultBitsPerSample},
64 // Different sampling rate as well:
65 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
66 24000, kDefaultBitsPerSample},
67 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
68 media::CHANNEL_LAYOUT_STEREO, 8000, kDefaultBitsPerSample},
69 };
70
71 class AudioTrackRecorderTest : public TestWithParam<ATRTestParams> {
72 public:
73 // Initialize |first_params_| based on test parameters, and |second_params_|
74 // to always be the same thing.
75 AudioTrackRecorderTest()
76 : first_params_(GetParam().input_format,
77 GetParam().channel_layout,
78 GetParam().sample_rate,
79 GetParam().bits_per_sample,
80 kIgnoreFramesPerBuffer),
81 second_params_(kDefaultInputFormat,
82 media::CHANNEL_LAYOUT_STEREO,
83 kDefaultSampleRate,
84 kDefaultBitsPerSample,
85 kIgnoreFramesPerBuffer),
86 first_source_(first_params_.channels(), /* # channels */
87 440, /* frequency */
88 first_params_.sample_rate()), /* sample rate */
89 second_source_(second_params_.channels(),
90 440,
91 second_params_.sample_rate()),
92 opus_decoder_(nullptr) {
93 ResetDecoder(first_params_);
94 PrepareBlinkTrack();
95 audio_track_recorder_.reset(new AudioTrackRecorder(
96 blink_track_, base::Bind(&AudioTrackRecorderTest::OnEncodedAudio,
97 base::Unretained(this))));
98 }
99
100 ~AudioTrackRecorderTest() {
101 opus_decoder_destroy(opus_decoder_);
102 opus_decoder_ = nullptr;
103 audio_track_recorder_.reset();
104 blink_track_.reset();
105 blink::WebHeap::collectAllGarbageForTesting();
106 }
107
108 void ResetDecoder(const media::AudioParameters& params) {
109 if (opus_decoder_) {
110 opus_decoder_destroy(opus_decoder_);
111 opus_decoder_ = nullptr;
112 }
113
114 int error;
115 opus_decoder_ =
116 opus_decoder_create(params.sample_rate(), params.channels(), &error);
117 EXPECT_TRUE(error == OPUS_OK && opus_decoder_);
118
119 max_frames_per_buffer_ =
120 kOpusMaxBufferDurationMS * params.sample_rate() / 1000;
121 buffer_.reset(new float[max_frames_per_buffer_ * params.channels()]);
122 }
123
124 scoped_ptr<media::AudioBus> GetFirstSourceAudioBus() {
125 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create(
126 first_params_.channels(),
127 first_params_.sample_rate() *
128 audio_track_recorder_->GetOpusBufferDuration(
129 first_params_.sample_rate()) /
130 1000));
131 first_source_.OnMoreData(bus.get(), 0);
132 return bus.Pass();
133 }
134 scoped_ptr<media::AudioBus> GetSecondSourceAudioBus() {
135 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create(
136 second_params_.channels(),
137 second_params_.sample_rate() *
138 audio_track_recorder_->GetOpusBufferDuration(
139 second_params_.sample_rate()) /
140 1000));
141 second_source_.OnMoreData(bus.get(), 0);
142 return bus.Pass();
143 }
144
145 MOCK_METHOD3(DoOnEncodedAudio,
146 void(const media::AudioParameters& params,
147 std::string encoded_data,
148 base::TimeTicks timestamp));
149
150 void OnEncodedAudio(const media::AudioParameters& params,
151 scoped_ptr<std::string> encoded_data,
152 base::TimeTicks timestamp) {
153 EXPECT_TRUE(!encoded_data->empty());
154
155 // Decode |encoded_data| and check we get the expected number of frames
156 // per buffer.
157 EXPECT_EQ(
158 params.sample_rate() *
159 audio_track_recorder_->GetOpusBufferDuration(params.sample_rate()) /
160 1000,
161 opus_decode_float(
162 opus_decoder_,
163 reinterpret_cast<uint8*>(string_as_array(encoded_data.get())),
164 encoded_data->size(), buffer_.get(), max_frames_per_buffer_, 0));
165
166 DoOnEncodedAudio(params, *encoded_data, timestamp);
167 }
168
169 const base::MessageLoop message_loop_;
170
171 // ATR and WebMediaStreamTrack for fooling it.
172 scoped_ptr<AudioTrackRecorder> audio_track_recorder_;
173 blink::WebMediaStreamTrack blink_track_;
174
175 // Two different sets of AudioParameters for testing re-init of ATR.
176 const media::AudioParameters first_params_;
177 const media::AudioParameters second_params_;
178
179 // AudioSources for creating AudioBuses.
180 media::SineWaveAudioSource first_source_;
181 media::SineWaveAudioSource second_source_;
182
183 // Decoder for verifying data was properly encoded.
184 OpusDecoder* opus_decoder_;
185 int max_frames_per_buffer_;
186 scoped_ptr<float[]> buffer_;
187
188 private:
189 // Prepares a blink track of a given MediaStreamType and attaches the native
190 // track, which can be used to capture audio data and pass it to the producer.
191 // Adapted from media::WebRTCLocalAudioSourceProviderTest.
192 void PrepareBlinkTrack() {
193 MockMediaConstraintFactory constraint_factory;
194 scoped_refptr<WebRtcAudioCapturer> capturer(
195 WebRtcAudioCapturer::CreateCapturer(
196 -1, StreamDeviceInfo(),
197 constraint_factory.CreateWebMediaConstraints(), NULL, NULL));
198 scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter(
199 WebRtcLocalAudioTrackAdapter::Create(std::string(), NULL));
200 scoped_ptr<WebRtcLocalAudioTrack> native_track(
201 new WebRtcLocalAudioTrack(adapter.get(), capturer, NULL));
202 blink::WebMediaStreamSource audio_source;
203 audio_source.initialize(base::UTF8ToUTF16("dummy_source_id"),
204 blink::WebMediaStreamSource::TypeAudio,
205 base::UTF8ToUTF16("dummy_source_name"),
206 false /* remote */, true /* readonly */);
207 blink_track_.initialize(blink::WebString::fromUTF8("audio_track"),
208 audio_source);
209 blink_track_.setExtraData(native_track.release());
210 }
211
212 DISALLOW_COPY_AND_ASSIGN(AudioTrackRecorderTest);
213 };
214
215 TEST_P(AudioTrackRecorderTest, OnData) {
216 InSequence s;
217 base::RunLoop run_loop;
218 base::Closure quit_closure = run_loop.QuitClosure();
219
220 // Give ATR initial audio parameters.
221 audio_track_recorder_->OnSetFormat(first_params_);
222 // TODO(ajose): consider adding WillOnce(SaveArg...) and inspecting, as done
223 // in VTR unittests. http://crbug.com/548856
224 const base::TimeTicks time1 = base::TimeTicks::Now();
225 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, time1)).Times(1);
226 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(), time1);
227
228 // Send more audio.
229 const base::TimeTicks time2 = base::TimeTicks::Now();
230 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _))
231 .Times(1)
232 // Only reset the decoder once we've heard back:
233 .WillOnce(RunClosure(base::Bind(&AudioTrackRecorderTest::ResetDecoder,
234 base::Unretained(this), second_params_)));
235 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(), time2);
236
237 // Give ATR new audio parameters.
238 audio_track_recorder_->OnSetFormat(second_params_);
239
240 // Send audio with different params.
241 const base::TimeTicks time3 = base::TimeTicks::Now();
242 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _))
243 .Times(1)
244 .WillOnce(RunClosure(quit_closure));
245 audio_track_recorder_->OnData(*GetSecondSourceAudioBus(), time3);
246
247 run_loop.Run();
248 Mock::VerifyAndClearExpectations(this);
249 }
250
251 INSTANTIATE_TEST_CASE_P(, AudioTrackRecorderTest, ValuesIn(kATRTestParams));
252
253 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/audio_track_recorder.cc ('k') | content/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698