| 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 <stddef.h> | 5 #include <stddef.h> |
| 6 | 6 |
| 7 #include "base/macros.h" | 7 #include "base/macros.h" |
| 8 #include "base/run_loop.h" | 8 #include "base/run_loop.h" |
| 9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "content/child/child_process.h" | 10 #include "content/child/child_process.h" |
| 11 #include "content/renderer/media/media_recorder_handler.h" | 11 #include "content/renderer/media/media_recorder_handler.h" |
| 12 #include "content/renderer/media/mock_media_stream_registry.h" | 12 #include "content/renderer/media/mock_media_stream_registry.h" |
| 13 #include "media/audio/simple_sources.h" | 13 #include "media/audio/simple_sources.h" |
| 14 #include "media/base/audio_bus.h" | 14 #include "media/base/audio_bus.h" |
| 15 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
| 16 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h" | 18 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h" |
| 19 #include "third_party/WebKit/public/platform/WebString.h" | 19 #include "third_party/WebKit/public/platform/WebString.h" |
| 20 #include "third_party/WebKit/public/web/WebHeap.h" | 20 #include "third_party/WebKit/public/web/WebHeap.h" |
| 21 | 21 |
| 22 using ::testing::_; | 22 using ::testing::_; |
| 23 using ::testing::AtLeast; | 23 using ::testing::AtLeast; |
| 24 using ::testing::InSequence; | 24 using ::testing::InSequence; |
| 25 using ::testing::Gt; |
| 25 using ::testing::Lt; | 26 using ::testing::Lt; |
| 26 using ::testing::Mock; | 27 using ::testing::Mock; |
| 27 using ::testing::TestWithParam; | 28 using ::testing::TestWithParam; |
| 28 using ::testing::ValuesIn; | 29 using ::testing::ValuesIn; |
| 29 | 30 |
| 30 using blink::WebString; | 31 using blink::WebString; |
| 31 | 32 |
| 32 namespace content { | 33 namespace content { |
| 33 | 34 |
| 34 ACTION_P(RunClosure, closure) { | 35 ACTION_P(RunClosure, closure) { |
| 35 closure.Run(); | 36 closure.Run(); |
| 36 } | 37 } |
| 37 | 38 |
| 38 static const std::string kTestStreamUrl = "stream_url"; | 39 static const std::string kTestStreamUrl = "stream_url"; |
| 39 static const std::string kTestVideoTrackId = "video_track_id"; | 40 static const std::string kTestVideoTrackId = "video_track_id"; |
| 40 static const std::string kTestAudioTrackId = "audio_track_id"; | 41 static const std::string kTestAudioTrackId = "audio_track_id"; |
| 41 static const int kTestAudioChannels = 2; | 42 static const int kTestAudioChannels = 2; |
| 42 static const int kTestAudioBitsPerSample = 16; | 43 static const int kTestAudioBitsPerSample = 16; |
| 43 static const int kTestAudioSampleRate = 48000; | 44 static const int kTestAudioSampleRate = 48000; |
| 44 static const int kTestAudioBufferDurationMS = 60; | 45 static const int kTestAudioBufferDurationMs = 10; |
| 46 // Opus works with 60ms buffers, so 6 MediaStreamAudioTrack Buffers are needed |
| 47 // to encode one output buffer. |
| 48 static const int kRatioOpusToTestAudioBuffers = 6; |
| 45 | 49 |
| 46 struct MediaRecorderTestParams { | 50 struct MediaRecorderTestParams { |
| 47 const bool has_video; | 51 const bool has_video; |
| 48 const bool has_audio; | 52 const bool has_audio; |
| 49 const char* const mime_type; | 53 const char* const mime_type; |
| 50 const char* const codecs; | 54 const char* const codecs; |
| 51 const size_t first_encoded_video_frame_size; | |
| 52 const size_t second_encoded_video_frame_size; | |
| 53 const size_t first_encoded_audio_frame_size; | |
| 54 const size_t second_encoded_audio_frame_size; | |
| 55 }; | 55 }; |
| 56 | 56 |
| 57 // Array of valid combinations of video/audio/codecs and expected collected | 57 // Array of valid combinations of video/audio/codecs and expected collected |
| 58 // encoded sizes to use for parameterizing MediaRecorderHandlerTest. | 58 // encoded sizes to use for parameterizing MediaRecorderHandlerTest. |
| 59 static const MediaRecorderTestParams kMediaRecorderTestParams[] = { | 59 static const MediaRecorderTestParams kMediaRecorderTestParams[] = { |
| 60 {true, false, "video/webm", "vp8", 52, 32, 0, 0}, | 60 {true, false, "video/webm", "vp8"}, |
| 61 {true, false, "video/webm", "vp9", 33, 18, 0, 0}, | 61 {true, false, "video/webm", "vp9"}, |
| 62 {false, true, "video/webm", "vp8", 0, 0, 990, 706}}; | 62 {false, true, "video/webm", "vp8"}}; |
| 63 | 63 |
| 64 class MediaRecorderHandlerTest : public TestWithParam<MediaRecorderTestParams>, | 64 class MediaRecorderHandlerTest : public TestWithParam<MediaRecorderTestParams>, |
| 65 public blink::WebMediaRecorderHandlerClient { | 65 public blink::WebMediaRecorderHandlerClient { |
| 66 public: | 66 public: |
| 67 MediaRecorderHandlerTest() | 67 MediaRecorderHandlerTest() |
| 68 : media_recorder_handler_(new MediaRecorderHandler()), | 68 : media_recorder_handler_(new MediaRecorderHandler()), |
| 69 audio_source_(kTestAudioChannels, | 69 audio_source_(kTestAudioChannels, |
| 70 440 /* freq */, | 70 440 /* freq */, |
| 71 kTestAudioSampleRate) { | 71 kTestAudioSampleRate) { |
| 72 EXPECT_FALSE(media_recorder_handler_->recording_); | 72 EXPECT_FALSE(media_recorder_handler_->recording_); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 // Avoid issues with non-parameterized tests by calling this outside of ctr. | 106 // Avoid issues with non-parameterized tests by calling this outside of ctr. |
| 107 if (GetParam().has_video) | 107 if (GetParam().has_video) |
| 108 registry_.AddVideoTrack(kTestVideoTrackId); | 108 registry_.AddVideoTrack(kTestVideoTrackId); |
| 109 if (GetParam().has_audio) | 109 if (GetParam().has_audio) |
| 110 registry_.AddAudioTrack(kTestAudioTrackId); | 110 registry_.AddAudioTrack(kTestAudioTrackId); |
| 111 } | 111 } |
| 112 | 112 |
| 113 scoped_ptr<media::AudioBus> NextAudioBus() { | 113 scoped_ptr<media::AudioBus> NextAudioBus() { |
| 114 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create( | 114 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create( |
| 115 kTestAudioChannels, | 115 kTestAudioChannels, |
| 116 kTestAudioSampleRate * kTestAudioBufferDurationMS / 1000)); | 116 kTestAudioSampleRate * kTestAudioBufferDurationMs / 1000)); |
| 117 audio_source_.OnMoreData(bus.get(), 0, 0); | 117 audio_source_.OnMoreData(bus.get(), 0, 0); |
| 118 return bus; | 118 return bus; |
| 119 } | 119 } |
| 120 | 120 |
| 121 // A ChildProcess and a MessageLoopForUI are both needed to fool the Tracks | 121 // A ChildProcess and a MessageLoopForUI are both needed to fool the Tracks |
| 122 // and Sources in |registry_| into believing they are on the right threads. | 122 // and Sources in |registry_| into believing they are on the right threads. |
| 123 const base::MessageLoopForUI message_loop_; | 123 const base::MessageLoopForUI message_loop_; |
| 124 const ChildProcess child_process_; | 124 const ChildProcess child_process_; |
| 125 MockMediaStreamRegistry registry_; | 125 MockMediaStreamRegistry registry_; |
| 126 | 126 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 const WebString mime_type(base::UTF8ToUTF16(GetParam().mime_type)); | 214 const WebString mime_type(base::UTF8ToUTF16(GetParam().mime_type)); |
| 215 const WebString codecs(base::UTF8ToUTF16(GetParam().codecs)); | 215 const WebString codecs(base::UTF8ToUTF16(GetParam().codecs)); |
| 216 EXPECT_TRUE(media_recorder_handler_->initialize(this, registry_.test_stream(), | 216 EXPECT_TRUE(media_recorder_handler_->initialize(this, registry_.test_stream(), |
| 217 mime_type, codecs, 0, 0)); | 217 mime_type, codecs, 0, 0)); |
| 218 EXPECT_TRUE(media_recorder_handler_->start()); | 218 EXPECT_TRUE(media_recorder_handler_->start()); |
| 219 | 219 |
| 220 InSequence s; | 220 InSequence s; |
| 221 const scoped_refptr<media::VideoFrame> video_frame = | 221 const scoped_refptr<media::VideoFrame> video_frame = |
| 222 media::VideoFrame::CreateBlackFrame(gfx::Size(160, 80)); | 222 media::VideoFrame::CreateBlackFrame(gfx::Size(160, 80)); |
| 223 | 223 |
| 224 const size_t kEncodedSizeThreshold = 16; |
| 224 { | 225 { |
| 225 base::RunLoop run_loop; | 226 base::RunLoop run_loop; |
| 226 base::Closure quit_closure = run_loop.QuitClosure(); | 227 base::Closure quit_closure = run_loop.QuitClosure(); |
| 227 // writeData() is pinged a number of times as the WebM header is written; | 228 // writeData() is pinged a number of times as the WebM header is written; |
| 228 // the last time it is called it has the encoded data. | 229 // the last time it is called it has the encoded data. |
| 229 const size_t encoded_data_size = GetParam().first_encoded_video_frame_size; | 230 EXPECT_CALL(*this, writeData(_, Lt(kEncodedSizeThreshold), _)) |
| 230 EXPECT_CALL(*this, writeData(_, Lt(encoded_data_size), _)) | |
| 231 .Times(AtLeast(1)); | 231 .Times(AtLeast(1)); |
| 232 EXPECT_CALL(*this, writeData(_, encoded_data_size, _)) | 232 EXPECT_CALL(*this, writeData(_, Gt(kEncodedSizeThreshold), _)) |
| 233 .Times(1) | 233 .Times(1) |
| 234 .WillOnce(RunClosure(quit_closure)); | 234 .WillOnce(RunClosure(quit_closure)); |
| 235 | 235 |
| 236 OnVideoFrameForTesting(video_frame); | 236 OnVideoFrameForTesting(video_frame); |
| 237 run_loop.Run(); | 237 run_loop.Run(); |
| 238 } | 238 } |
| 239 Mock::VerifyAndClearExpectations(this); |
| 239 | 240 |
| 240 { | 241 { |
| 241 base::RunLoop run_loop; | 242 base::RunLoop run_loop; |
| 242 base::Closure quit_closure = run_loop.QuitClosure(); | 243 base::Closure quit_closure = run_loop.QuitClosure(); |
| 243 // The second time around writeData() is called a number of times to write | 244 // The second time around writeData() is called a number of times to write |
| 244 // the WebM frame header, and then is pinged with the encoded data. | 245 // the WebM frame header, and then is pinged with the encoded data. |
| 245 const size_t encoded_data_size = GetParam().second_encoded_video_frame_size; | 246 EXPECT_CALL(*this, writeData(_, Lt(kEncodedSizeThreshold), _)) |
| 246 EXPECT_CALL(*this, writeData(_, Lt(encoded_data_size), _)) | |
| 247 .Times(AtLeast(1)); | 247 .Times(AtLeast(1)); |
| 248 EXPECT_CALL(*this, writeData(_, encoded_data_size, _)) | 248 EXPECT_CALL(*this, writeData(_, Gt(kEncodedSizeThreshold), _)) |
| 249 .Times(1) | 249 .Times(1) |
| 250 .WillOnce(RunClosure(quit_closure)); | 250 .WillOnce(RunClosure(quit_closure)); |
| 251 | 251 |
| 252 OnVideoFrameForTesting(video_frame); | 252 OnVideoFrameForTesting(video_frame); |
| 253 run_loop.Run(); | 253 run_loop.Run(); |
| 254 } | 254 } |
| 255 | 255 |
| 256 media_recorder_handler_->stop(); | 256 media_recorder_handler_->stop(); |
| 257 | 257 |
| 258 // Expect a last call on destruction, with size 0 and |lastInSlice| true. | 258 // Expect a last call on destruction, with size 0 and |lastInSlice| true. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 277 this, registry_.test_stream(), mime_type, WebString(), 0, 0)); | 277 this, registry_.test_stream(), mime_type, WebString(), 0, 0)); |
| 278 EXPECT_TRUE(media_recorder_handler_->start()); | 278 EXPECT_TRUE(media_recorder_handler_->start()); |
| 279 | 279 |
| 280 InSequence s; | 280 InSequence s; |
| 281 const scoped_ptr<media::AudioBus> audio_bus1 = NextAudioBus(); | 281 const scoped_ptr<media::AudioBus> audio_bus1 = NextAudioBus(); |
| 282 const scoped_ptr<media::AudioBus> audio_bus2 = NextAudioBus(); | 282 const scoped_ptr<media::AudioBus> audio_bus2 = NextAudioBus(); |
| 283 | 283 |
| 284 media::AudioParameters params( | 284 media::AudioParameters params( |
| 285 media::AudioParameters::AUDIO_PCM_LINEAR, media::CHANNEL_LAYOUT_STEREO, | 285 media::AudioParameters::AUDIO_PCM_LINEAR, media::CHANNEL_LAYOUT_STEREO, |
| 286 kTestAudioSampleRate, kTestAudioBitsPerSample, | 286 kTestAudioSampleRate, kTestAudioBitsPerSample, |
| 287 kTestAudioSampleRate * kTestAudioBufferDurationMS / 1000); | 287 kTestAudioSampleRate * kTestAudioBufferDurationMs / 1000); |
| 288 SetAudioFormatForTesting(params); | 288 SetAudioFormatForTesting(params); |
| 289 | 289 |
| 290 const size_t kEncodedSizeThreshold = 24; |
| 290 { | 291 { |
| 291 base::RunLoop run_loop; | 292 base::RunLoop run_loop; |
| 292 base::Closure quit_closure = run_loop.QuitClosure(); | 293 base::Closure quit_closure = run_loop.QuitClosure(); |
| 293 // writeData() is pinged a number of times as the WebM header is written; | 294 // writeData() is pinged a number of times as the WebM header is written; |
| 294 // the last time it is called it has the encoded data. | 295 // the last time it is called it has the encoded data. |
| 295 const size_t kEncodedDataSize = GetParam().first_encoded_audio_frame_size; | 296 EXPECT_CALL(*this, writeData(_, Lt(kEncodedSizeThreshold), _)) |
| 296 EXPECT_CALL(*this, writeData(_, Lt(kEncodedDataSize), _)).Times(AtLeast(1)); | 297 .Times(AtLeast(1)); |
| 297 EXPECT_CALL(*this, writeData(_, kEncodedDataSize, _)) | 298 EXPECT_CALL(*this, writeData(_, Gt(kEncodedSizeThreshold), _)) |
| 298 .Times(1) | 299 .Times(1) |
| 299 .WillOnce(RunClosure(quit_closure)); | 300 .WillOnce(RunClosure(quit_closure)); |
| 300 | 301 |
| 301 OnAudioBusForTesting(*audio_bus1); | 302 for (int i = 0; i < kRatioOpusToTestAudioBuffers; ++i) |
| 303 OnAudioBusForTesting(*audio_bus1); |
| 302 run_loop.Run(); | 304 run_loop.Run(); |
| 303 } | 305 } |
| 306 Mock::VerifyAndClearExpectations(this); |
| 304 | 307 |
| 305 { | 308 { |
| 306 base::RunLoop run_loop; | 309 base::RunLoop run_loop; |
| 307 base::Closure quit_closure = run_loop.QuitClosure(); | 310 base::Closure quit_closure = run_loop.QuitClosure(); |
| 308 // The second time around writeData() is called a number of times to write | 311 // The second time around writeData() is called a number of times to write |
| 309 // the WebM frame header, and then is pinged with the encoded data. | 312 // the WebM frame header, and then is pinged with the encoded data. |
| 310 const size_t kSecondEncodedDataSize = | 313 EXPECT_CALL(*this, writeData(_, Lt(kEncodedSizeThreshold), _)) |
| 311 GetParam().second_encoded_audio_frame_size; | |
| 312 EXPECT_CALL(*this, writeData(_, Lt(kSecondEncodedDataSize), _)) | |
| 313 .Times(AtLeast(1)); | 314 .Times(AtLeast(1)); |
| 314 EXPECT_CALL(*this, writeData(_, kSecondEncodedDataSize, _)) | 315 EXPECT_CALL(*this, writeData(_, Gt(kEncodedSizeThreshold), _)) |
| 315 .Times(1) | 316 .Times(1) |
| 316 .WillOnce(RunClosure(quit_closure)); | 317 .WillOnce(RunClosure(quit_closure)); |
| 317 | 318 |
| 318 OnAudioBusForTesting(*audio_bus2); | 319 for (int i = 0; i < kRatioOpusToTestAudioBuffers; ++i) |
| 320 OnAudioBusForTesting(*audio_bus2); |
| 319 run_loop.Run(); | 321 run_loop.Run(); |
| 320 } | 322 } |
| 321 | 323 |
| 322 media_recorder_handler_->stop(); | 324 media_recorder_handler_->stop(); |
| 323 | 325 |
| 324 // Expect a last call on destruction, with size 0 and |lastInSlice| true. | 326 // Expect a last call on destruction, with size 0 and |lastInSlice| true. |
| 325 EXPECT_CALL(*this, writeData(nullptr, 0, true)).Times(1); | 327 EXPECT_CALL(*this, writeData(nullptr, 0, true)).Times(1); |
| 326 media_recorder_handler_.reset(); | 328 media_recorder_handler_.reset(); |
| 327 } | 329 } |
| 328 | 330 |
| 329 } // namespace content | 331 } // namespace content |
| OLD | NEW |