OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/run_loop.h" | 5 #include "base/run_loop.h" |
6 #include "base/strings/utf_string_conversions.h" | 6 #include "base/strings/utf_string_conversions.h" |
7 #include "content/child/child_process.h" | 7 #include "content/child/child_process.h" |
8 #include "content/renderer/media/media_recorder_handler.h" | 8 #include "content/renderer/media/media_recorder_handler.h" |
9 #include "content/renderer/media/mock_media_stream_registry.h" | 9 #include "content/renderer/media/mock_media_stream_registry.h" |
10 #include "media/audio/simple_sources.h" | |
11 #include "media/base/audio_bus.h" | |
10 #include "media/base/video_frame.h" | 12 #include "media/base/video_frame.h" |
11 #include "testing/gmock/include/gmock/gmock.h" | 13 #include "testing/gmock/include/gmock/gmock.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
13 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h" | 15 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h" |
14 #include "third_party/WebKit/public/platform/WebString.h" | 16 #include "third_party/WebKit/public/platform/WebString.h" |
15 #include "third_party/WebKit/public/web/WebHeap.h" | 17 #include "third_party/WebKit/public/web/WebHeap.h" |
16 | 18 |
17 using ::testing::_; | 19 using ::testing::_; |
18 using ::testing::AtLeast; | 20 using ::testing::AtLeast; |
19 using ::testing::InSequence; | 21 using ::testing::InSequence; |
20 using ::testing::Lt; | 22 using ::testing::Lt; |
21 using ::testing::Mock; | 23 using ::testing::Mock; |
22 using ::testing::TestWithParam; | 24 using ::testing::TestWithParam; |
23 using ::testing::ValuesIn; | 25 using ::testing::ValuesIn; |
24 | 26 |
25 using blink::WebString; | 27 using blink::WebString; |
26 | 28 |
27 namespace content { | 29 namespace content { |
28 | 30 |
29 ACTION_P(RunClosure, closure) { | 31 ACTION_P(RunClosure, closure) { |
30 closure.Run(); | 32 closure.Run(); |
31 } | 33 } |
32 | 34 |
33 static const std::string kTestStreamUrl = "stream_url"; | 35 static const std::string kTestStreamUrl = "stream_url"; |
34 static const std::string kTestVideoTrackId = "video_track_id"; | 36 static const std::string kTestVideoTrackId = "video_track_id"; |
37 static const std::string kTestAudioTrackId = "audio_track_id"; | |
38 static const int kTestAudioChannels = 2; | |
39 static const int kTestAudioBitsPerSample = 16; | |
40 static const int kTestAudioSampleRate = 48000; | |
41 static const int kTestAudioBufferDurationMS = 60; | |
35 | 42 |
36 struct MediaRecorderTestParams { | 43 struct MediaRecorderTestParams { |
44 const bool has_video; | |
45 const bool has_audio; | |
37 const char* const mime_type; | 46 const char* const mime_type; |
38 const size_t first_encoded_frame_size; | 47 const size_t first_encoded_video_frame_size; |
39 const size_t second_encoded_frame_size; | 48 const size_t second_encoded_video_frame_size; |
49 const size_t first_encoded_audio_frame_size; | |
50 const size_t second_encoded_audio_frame_size; | |
40 }; | 51 }; |
41 | 52 |
42 static const MediaRecorderTestParams kMediaRecorderTestParams[] = { | 53 static const MediaRecorderTestParams kMediaRecorderTestParams[] = { |
43 {"video/vp8", 52, 32}, | 54 {true, false, "video/vp8", 52, 32, 0, 0}, |
44 {"video/vp9", 33, 18}}; | 55 {true, false, "video/vp9", 33, 18, 0, 0}, |
56 {false, true, "video/vp8", 0, 0, 990, 706}}; | |
45 | 57 |
46 class MediaRecorderHandlerTest : public TestWithParam<MediaRecorderTestParams>, | 58 class MediaRecorderHandlerTest : public TestWithParam<MediaRecorderTestParams>, |
47 public blink::WebMediaRecorderHandlerClient { | 59 public blink::WebMediaRecorderHandlerClient { |
48 public: | 60 public: |
49 MediaRecorderHandlerTest() | 61 MediaRecorderHandlerTest() |
50 : media_recorder_handler_(new MediaRecorderHandler()) { | 62 : media_recorder_handler_(new MediaRecorderHandler()), |
63 audio_source_(kTestAudioChannels, | |
64 440 /* freq */, | |
65 kTestAudioSampleRate) { | |
51 EXPECT_FALSE(media_recorder_handler_->recording_); | 66 EXPECT_FALSE(media_recorder_handler_->recording_); |
52 | 67 |
53 registry_.Init(kTestStreamUrl); | 68 registry_.Init(kTestStreamUrl); |
54 registry_.AddVideoTrack(kTestVideoTrackId); | 69 if (GetParam().has_video) |
70 registry_.AddVideoTrack(kTestVideoTrackId); | |
71 if (GetParam().has_audio) | |
72 registry_.AddAudioTrack(kTestAudioTrackId); | |
55 } | 73 } |
56 | 74 |
57 ~MediaRecorderHandlerTest() { | 75 ~MediaRecorderHandlerTest() { |
58 registry_.reset(); | 76 registry_.reset(); |
59 blink::WebHeap::collectAllGarbageForTesting(); | 77 blink::WebHeap::collectAllGarbageForTesting(); |
60 } | 78 } |
61 | 79 |
62 MOCK_METHOD3(writeData, void(const char*, size_t, bool)); | 80 MOCK_METHOD3(writeData, void(const char*, size_t, bool)); |
63 MOCK_METHOD1(failOutOfMemory, void(const WebString& message)); | 81 MOCK_METHOD1(failOutOfMemory, void(const WebString& message)); |
64 MOCK_METHOD1(failIllegalStreamModification, void(const WebString& message)); | 82 MOCK_METHOD1(failIllegalStreamModification, void(const WebString& message)); |
65 MOCK_METHOD1(failOtherRecordingError, void(const WebString& message)); | 83 MOCK_METHOD1(failOtherRecordingError, void(const WebString& message)); |
66 | 84 |
67 bool recording() const { return media_recorder_handler_->recording_; } | 85 bool recording() const { return media_recorder_handler_->recording_; } |
68 bool hasVideoRecorders() const { | 86 bool hasVideoRecorders() const { |
69 return !media_recorder_handler_->video_recorders_.empty(); | 87 return !media_recorder_handler_->video_recorders_.empty(); |
70 } | 88 } |
89 bool hasAudioRecorders() const { | |
90 return !media_recorder_handler_->audio_recorders_.empty(); | |
91 } | |
71 | 92 |
72 void OnVideoFrameForTesting(const scoped_refptr<media::VideoFrame>& frame) { | 93 void OnVideoFrameForTesting(const scoped_refptr<media::VideoFrame>& frame) { |
73 media_recorder_handler_->OnVideoFrameForTesting(frame, | 94 media_recorder_handler_->OnVideoFrameForTesting(frame, |
74 base::TimeTicks::Now()); | 95 base::TimeTicks::Now()); |
75 } | 96 } |
97 void OnAudioBusForTesting(const media::AudioBus& audio_bus) { | |
98 media_recorder_handler_->OnAudioBusForTesting(audio_bus, | |
99 base::TimeTicks::Now()); | |
100 } | |
101 void SetAudioFormatForTesting(const media::AudioParameters& params) { | |
102 media_recorder_handler_->SetAudioFormatForTesting(params); | |
103 } | |
104 | |
105 scoped_ptr<media::AudioBus> NextAudioBus() { | |
106 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create( | |
107 kTestAudioChannels, | |
108 kTestAudioSampleRate * kTestAudioBufferDurationMS / 1000)); | |
109 audio_source_.OnMoreData(bus.get(), 0); | |
110 return bus.Pass(); | |
111 } | |
76 | 112 |
77 // A ChildProcess and a MessageLoopForUI are both needed to fool the Tracks | 113 // A ChildProcess and a MessageLoopForUI are both needed to fool the Tracks |
78 // and Sources in |registry_| into believing they are on the right threads. | 114 // and Sources in |registry_| into believing they are on the right threads. |
79 const base::MessageLoopForUI message_loop_; | 115 const base::MessageLoopForUI message_loop_; |
80 const ChildProcess child_process_; | 116 const ChildProcess child_process_; |
81 MockMediaStreamRegistry registry_; | 117 MockMediaStreamRegistry registry_; |
82 | 118 |
83 // The Class under test. Needs to be scoped_ptr to force its destruction. | 119 // The Class under test. Needs to be scoped_ptr to force its destruction. |
84 scoped_ptr<MediaRecorderHandler> media_recorder_handler_; | 120 scoped_ptr<MediaRecorderHandler> media_recorder_handler_; |
85 | 121 |
122 // For generating test AudioBuses | |
123 media::SineWaveAudioSource audio_source_; | |
124 | |
86 private: | 125 private: |
87 DISALLOW_COPY_AND_ASSIGN(MediaRecorderHandlerTest); | 126 DISALLOW_COPY_AND_ASSIGN(MediaRecorderHandlerTest); |
88 }; | 127 }; |
89 | 128 |
90 // Checks that canSupportMimeType() works as expected. | 129 // Checks that canSupportMimeType() works as expected. |
91 // TODO(mcasas): revisit this when canSupportMimeType() is fully implemented. | 130 // TODO(mcasas): revisit this when canSupportMimeType() is fully implemented. |
92 TEST_F(MediaRecorderHandlerTest, CanSupportMimeType) { | 131 TEST_P(MediaRecorderHandlerTest, CanSupportMimeType) { |
mcasas
2015/11/19 00:49:52
Hmm this should not be parameterised, right?
Keep
ajose
2015/11/19 22:17:19
Done.
| |
93 const WebString good_mime_type_vp8(base::UTF8ToUTF16("video/vp8")); | 132 const WebString good_mime_type_vp8(base::UTF8ToUTF16("video/vp8")); |
94 EXPECT_TRUE(media_recorder_handler_->canSupportMimeType(good_mime_type_vp8)); | 133 EXPECT_TRUE(media_recorder_handler_->canSupportMimeType(good_mime_type_vp8)); |
95 | 134 |
96 const WebString good_mime_type_vp9(base::UTF8ToUTF16("video/vp9")); | 135 const WebString good_mime_type_vp9(base::UTF8ToUTF16("video/vp9")); |
97 EXPECT_TRUE(media_recorder_handler_->canSupportMimeType(good_mime_type_vp9)); | 136 EXPECT_TRUE(media_recorder_handler_->canSupportMimeType(good_mime_type_vp9)); |
98 | 137 |
138 const WebString audio_mime_type(base::UTF8ToUTF16("audio/opus")); | |
139 EXPECT_TRUE(media_recorder_handler_->canSupportMimeType(audio_mime_type)); | |
140 | |
99 const WebString bad_mime_type(base::UTF8ToUTF16("video/unsupportedcodec")); | 141 const WebString bad_mime_type(base::UTF8ToUTF16("video/unsupportedcodec")); |
100 EXPECT_FALSE(media_recorder_handler_->canSupportMimeType(bad_mime_type)); | 142 EXPECT_FALSE(media_recorder_handler_->canSupportMimeType(bad_mime_type)); |
101 | 143 |
102 const WebString empty_mime_type(base::UTF8ToUTF16("")); | 144 const WebString empty_mime_type(base::UTF8ToUTF16("")); |
103 EXPECT_TRUE(media_recorder_handler_->canSupportMimeType(empty_mime_type)); | 145 EXPECT_TRUE(media_recorder_handler_->canSupportMimeType(empty_mime_type)); |
104 } | 146 } |
mcasas
2015/11/19 00:49:52
Guess this test should at least try an OK combinat
ajose
2015/11/19 22:17:19
Done.
| |
105 | 147 |
106 // Checks that the initialization-destruction sequence works fine. | 148 // Checks that the initialization-destruction sequence works fine. |
107 TEST_P(MediaRecorderHandlerTest, InitializeStartStop) { | 149 TEST_P(MediaRecorderHandlerTest, InitializeStartStop) { |
108 const WebString mime_type(base::UTF8ToUTF16(GetParam().mime_type)); | 150 const WebString mime_type(base::UTF8ToUTF16(GetParam().mime_type)); |
109 EXPECT_TRUE(media_recorder_handler_->initialize(this, | 151 EXPECT_TRUE(media_recorder_handler_->initialize(this, |
110 registry_.test_stream(), | 152 registry_.test_stream(), |
111 mime_type)); | 153 mime_type)); |
112 EXPECT_FALSE(recording()); | 154 EXPECT_FALSE(recording()); |
113 EXPECT_FALSE(hasVideoRecorders()); | 155 EXPECT_FALSE(hasVideoRecorders()); |
156 EXPECT_FALSE(hasAudioRecorders()); | |
114 | 157 |
115 EXPECT_TRUE(media_recorder_handler_->start()); | 158 EXPECT_TRUE(media_recorder_handler_->start()); |
116 EXPECT_TRUE(recording()); | 159 EXPECT_TRUE(recording()); |
117 EXPECT_TRUE(hasVideoRecorders()); | 160 |
161 if (GetParam().has_video) | |
162 EXPECT_TRUE(hasVideoRecorders()); | |
163 else | |
164 EXPECT_FALSE(hasVideoRecorders()); | |
mcasas
2015/11/19 00:49:52
EXPECT_TRUE(hasVideoRecorders() || !GetParam().has
ajose
2015/11/19 22:17:19
Done.
| |
165 | |
166 if (GetParam().has_audio) | |
167 EXPECT_TRUE(hasAudioRecorders()); | |
168 else | |
169 EXPECT_FALSE(hasAudioRecorders()); | |
118 | 170 |
119 media_recorder_handler_->stop(); | 171 media_recorder_handler_->stop(); |
120 EXPECT_FALSE(recording()); | 172 EXPECT_FALSE(recording()); |
121 EXPECT_FALSE(hasVideoRecorders()); | 173 EXPECT_FALSE(hasVideoRecorders()); |
174 EXPECT_FALSE(hasAudioRecorders()); | |
122 | 175 |
123 // Expect a last call on destruction. | 176 // Expect a last call on destruction. |
124 EXPECT_CALL(*this, writeData(_, _, true)).Times(1); | 177 EXPECT_CALL(*this, writeData(_, _, true)).Times(1); |
125 media_recorder_handler_.reset(); | 178 media_recorder_handler_.reset(); |
126 } | 179 } |
127 | 180 |
128 // Sends 2 frames and expect them as WebM contained encoded data in writeData(). | 181 // Sends 2 frames and expect them as WebM contained encoded data in writeData(). |
129 TEST_P(MediaRecorderHandlerTest, EncodeVideoFrames) { | 182 TEST_P(MediaRecorderHandlerTest, EncodeVideoFrames) { |
183 // Video-only test. | |
184 if (GetParam().has_audio) { | |
mcasas
2015/11/19 00:49:52
no {}
ajose
2015/11/19 22:17:19
Done.
| |
185 return; | |
186 } | |
187 | |
130 const WebString mime_type(base::UTF8ToUTF16(GetParam().mime_type)); | 188 const WebString mime_type(base::UTF8ToUTF16(GetParam().mime_type)); |
131 EXPECT_TRUE(media_recorder_handler_->initialize(this, registry_.test_stream(), | 189 EXPECT_TRUE(media_recorder_handler_->initialize(this, registry_.test_stream(), |
132 mime_type)); | 190 mime_type)); |
133 EXPECT_TRUE(media_recorder_handler_->start()); | 191 EXPECT_TRUE(media_recorder_handler_->start()); |
134 | 192 |
135 InSequence s; | 193 InSequence s; |
136 const scoped_refptr<media::VideoFrame> video_frame = | 194 const scoped_refptr<media::VideoFrame> video_frame = |
137 media::VideoFrame::CreateBlackFrame(gfx::Size(160, 80)); | 195 media::VideoFrame::CreateBlackFrame(gfx::Size(160, 80)); |
138 | 196 |
139 { | 197 { |
140 base::RunLoop run_loop; | 198 base::RunLoop run_loop; |
141 base::Closure quit_closure = run_loop.QuitClosure(); | 199 base::Closure quit_closure = run_loop.QuitClosure(); |
142 // writeData() is pinged a number of times as the WebM header is written; | 200 // writeData() is pinged a number of times as the WebM header is written; |
143 // the last time it is called it has the encoded data. | 201 // the last time it is called it has the encoded data. |
144 const size_t encoded_data_size = GetParam().first_encoded_frame_size; | 202 const size_t encoded_data_size = GetParam().first_encoded_video_frame_size; |
145 EXPECT_CALL(*this, writeData(_, Lt(encoded_data_size), _)) | 203 EXPECT_CALL(*this, writeData(_, Lt(encoded_data_size), _)) |
146 .Times(AtLeast(1)); | 204 .Times(AtLeast(1)); |
147 EXPECT_CALL(*this, writeData(_, encoded_data_size, _)) | 205 EXPECT_CALL(*this, writeData(_, encoded_data_size, _)) |
148 .Times(1) | 206 .Times(1) |
149 .WillOnce(RunClosure(quit_closure)); | 207 .WillOnce(RunClosure(quit_closure)); |
150 | 208 |
151 OnVideoFrameForTesting(video_frame); | 209 OnVideoFrameForTesting(video_frame); |
152 run_loop.Run(); | 210 run_loop.Run(); |
153 } | 211 } |
154 | 212 |
155 { | 213 { |
156 base::RunLoop run_loop; | 214 base::RunLoop run_loop; |
157 base::Closure quit_closure = run_loop.QuitClosure(); | 215 base::Closure quit_closure = run_loop.QuitClosure(); |
158 // The second time around writeData() is called a number of times to write | 216 // The second time around writeData() is called a number of times to write |
159 // the WebM frame header, and then is pinged with the encoded data. | 217 // the WebM frame header, and then is pinged with the encoded data. |
160 const size_t encoded_data_size = GetParam().second_encoded_frame_size; | 218 const size_t encoded_data_size = GetParam().second_encoded_video_frame_size; |
161 EXPECT_CALL(*this, writeData(_, Lt(encoded_data_size), _)) | 219 EXPECT_CALL(*this, writeData(_, Lt(encoded_data_size), _)) |
162 .Times(AtLeast(1)); | 220 .Times(AtLeast(1)); |
163 EXPECT_CALL(*this, writeData(_, encoded_data_size, _)) | 221 EXPECT_CALL(*this, writeData(_, encoded_data_size, _)) |
164 .Times(1) | 222 .Times(1) |
165 .WillOnce(RunClosure(quit_closure)); | 223 .WillOnce(RunClosure(quit_closure)); |
166 | 224 |
167 OnVideoFrameForTesting(video_frame); | 225 OnVideoFrameForTesting(video_frame); |
168 run_loop.Run(); | 226 run_loop.Run(); |
169 } | 227 } |
170 | 228 |
171 media_recorder_handler_->stop(); | 229 media_recorder_handler_->stop(); |
172 | 230 |
173 // Expect a last call on destruction, with size 0 and |lastInSlice| true. | 231 // Expect a last call on destruction, with size 0 and |lastInSlice| true. |
174 EXPECT_CALL(*this, writeData(nullptr, 0, true)).Times(1); | 232 EXPECT_CALL(*this, writeData(nullptr, 0, true)).Times(1); |
175 media_recorder_handler_.reset(); | 233 media_recorder_handler_.reset(); |
176 } | 234 } |
177 | 235 |
178 INSTANTIATE_TEST_CASE_P(, | 236 INSTANTIATE_TEST_CASE_P(, |
179 MediaRecorderHandlerTest, | 237 MediaRecorderHandlerTest, |
180 ValuesIn(kMediaRecorderTestParams)); | 238 ValuesIn(kMediaRecorderTestParams)); |
181 | 239 |
240 // Sends 2 frames and expect them as WebM contained encoded data in writeData(). | |
241 TEST_P(MediaRecorderHandlerTest, EncodeAudioFrames) { | |
242 // Audio-only test. | |
243 if (GetParam().has_video) { | |
244 return; | |
245 } | |
mcasas
2015/11/19 00:49:52
no {}
ajose
2015/11/19 22:17:19
Done.
| |
246 | |
247 const WebString mime_type(base::UTF8ToUTF16("audio/opus")); | |
248 EXPECT_TRUE(media_recorder_handler_->initialize(this, registry_.test_stream(), | |
249 mime_type)); | |
250 EXPECT_TRUE(media_recorder_handler_->start()); | |
251 | |
252 InSequence s; | |
253 const scoped_ptr<media::AudioBus> audio_bus1 = NextAudioBus(); | |
254 const scoped_ptr<media::AudioBus> audio_bus2 = NextAudioBus(); | |
255 | |
256 media::AudioParameters params( | |
257 media::AudioParameters::AUDIO_PCM_LINEAR, media::CHANNEL_LAYOUT_STEREO, | |
258 kTestAudioSampleRate, kTestAudioBitsPerSample, | |
259 kTestAudioSampleRate * kTestAudioBufferDurationMS / 1000); | |
260 SetAudioFormatForTesting(params); | |
261 | |
262 { | |
263 base::RunLoop run_loop; | |
264 base::Closure quit_closure = run_loop.QuitClosure(); | |
265 // writeData() is pinged a number of times as the WebM header is written; | |
266 // the last time it is called it has the encoded data. | |
267 const size_t kEncodedDataSize = GetParam().first_encoded_audio_frame_size; | |
268 EXPECT_CALL(*this, writeData(_, Lt(kEncodedDataSize), _)).Times(AtLeast(1)); | |
269 EXPECT_CALL(*this, writeData(_, kEncodedDataSize, _)) | |
270 .Times(1) | |
271 .WillOnce(RunClosure(quit_closure)); | |
272 | |
273 OnAudioBusForTesting(*audio_bus1); | |
274 run_loop.Run(); | |
275 } | |
276 | |
277 { | |
278 base::RunLoop run_loop; | |
279 base::Closure quit_closure = run_loop.QuitClosure(); | |
280 // The second time around writeData() is called a number of times to write | |
281 // the WebM frame header, and then is pinged with the encoded data. | |
282 const size_t kSecondEncodedDataSize = | |
283 GetParam().second_encoded_audio_frame_size; | |
284 EXPECT_CALL(*this, writeData(_, Lt(kSecondEncodedDataSize), _)) | |
285 .Times(AtLeast(1)); | |
286 EXPECT_CALL(*this, writeData(_, kSecondEncodedDataSize, _)) | |
287 .Times(1) | |
288 .WillOnce(RunClosure(quit_closure)); | |
289 | |
290 OnAudioBusForTesting(*audio_bus2); | |
291 run_loop.Run(); | |
292 } | |
293 | |
294 media_recorder_handler_->stop(); | |
295 | |
296 // Expect a last call on destruction, with size 0 and |lastInSlice| true. | |
297 EXPECT_CALL(*this, writeData(nullptr, 0, true)).Times(1); | |
298 media_recorder_handler_.reset(); | |
299 } | |
300 | |
182 } // namespace content | 301 } // namespace content |
OLD | NEW |