// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Unit test for VideoCaptureManager. #include #include "base/bind.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "content/browser/browser_thread_impl.h" #include "content/browser/renderer_host/media/media_stream_provider.h" #include "content/browser/renderer_host/media/video_capture_manager.h" #include "content/common/media/media_stream_options.h" #include "media/video/capture/video_capture_device.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::_; using ::testing::AnyNumber; using ::testing::InSequence; using testing::SaveArg; using ::testing::Return; namespace content { // Listener class used to track progress of VideoCaptureManager test. class MockMediaStreamProviderListener : public MediaStreamProviderListener { public: MockMediaStreamProviderListener() {} ~MockMediaStreamProviderListener() {} MOCK_METHOD2(Opened, void(MediaStreamType, int)); MOCK_METHOD2(Closed, void(MediaStreamType, int)); MOCK_METHOD2(DevicesEnumerated, void(MediaStreamType, const StreamDeviceInfoArray&)); MOCK_METHOD3(Error, void(MediaStreamType, int, MediaStreamProviderError)); }; // class MockMediaStreamProviderListener // Needed as an input argument to Start(). class MockFrameObserver : public media::VideoCaptureDevice::EventHandler { public: virtual scoped_refptr ReserveOutputBuffer() OVERRIDE { return NULL; } virtual void OnError() OVERRIDE {} virtual void OnFrameInfo( const media::VideoCaptureCapability& info) OVERRIDE {} virtual void OnIncomingCapturedFrame(const uint8* data, int length, base::Time timestamp, int rotation, bool flip_vert, bool flip_horiz) OVERRIDE {} virtual void OnIncomingCapturedVideoFrame( const scoped_refptr& frame, base::Time timestamp) OVERRIDE {} }; // Test class class VideoCaptureManagerTest : public testing::Test { public: VideoCaptureManagerTest() {} virtual ~VideoCaptureManagerTest() {} protected: virtual void SetUp() OVERRIDE { listener_.reset(new MockMediaStreamProviderListener()); message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO)); io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO, message_loop_.get())); vcm_ = new VideoCaptureManager(); vcm_->UseFakeDevice(); vcm_->Register(listener_.get(), message_loop_->message_loop_proxy().get()); frame_observer_.reset(new MockFrameObserver()); } virtual void TearDown() OVERRIDE {} scoped_refptr vcm_; scoped_ptr listener_; scoped_ptr message_loop_; scoped_ptr io_thread_; scoped_ptr frame_observer_; private: DISALLOW_COPY_AND_ASSIGN(VideoCaptureManagerTest); }; // Test cases // Try to open, start, stop and close a device. TEST_F(VideoCaptureManagerTest, CreateAndClose) { StreamDeviceInfoArray devices; InSequence s; EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) .Times(1).WillOnce(SaveArg<1>(&devices)); EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(1); EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(1); vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); // Wait to get device callback. message_loop_->RunUntilIdle(); int video_session_id = vcm_->Open(devices.front()); media::VideoCaptureParams capture_params; capture_params.session_id = video_session_id; capture_params.width = 320; capture_params.height = 240; capture_params.frame_rate = 30; vcm_->Start(capture_params, frame_observer_.get()); vcm_->Stop(video_session_id, base::Closure()); vcm_->Close(video_session_id); // Wait to check callbacks before removing the listener. message_loop_->RunUntilIdle(); vcm_->Unregister(); } // Open the same device twice. TEST_F(VideoCaptureManagerTest, OpenTwice) { StreamDeviceInfoArray devices; InSequence s; EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) .Times(1).WillOnce(SaveArg<1>(&devices)); EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2); EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2); vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); // Wait to get device callback. message_loop_->RunUntilIdle(); int video_session_id_first = vcm_->Open(devices.front()); // This should trigger an error callback with error code // 'kDeviceAlreadyInUse'. int video_session_id_second = vcm_->Open(devices.front()); EXPECT_NE(video_session_id_first, video_session_id_second); vcm_->Close(video_session_id_first); vcm_->Close(video_session_id_second); // Wait to check callbacks before removing the listener. message_loop_->RunUntilIdle(); vcm_->Unregister(); } // Open two different devices. TEST_F(VideoCaptureManagerTest, OpenTwo) { StreamDeviceInfoArray devices; InSequence s; EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) .Times(1).WillOnce(SaveArg<1>(&devices)); EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2); EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2); vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); // Wait to get device callback. message_loop_->RunUntilIdle(); StreamDeviceInfoArray::iterator it = devices.begin(); int video_session_id_first = vcm_->Open(*it); ++it; int video_session_id_second = vcm_->Open(*it); vcm_->Close(video_session_id_first); vcm_->Close(video_session_id_second); // Wait to check callbacks before removing the listener. message_loop_->RunUntilIdle(); vcm_->Unregister(); } // Try open a non-existing device. TEST_F(VideoCaptureManagerTest, OpenNotExisting) { StreamDeviceInfoArray devices; InSequence s; EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) .Times(1).WillOnce(SaveArg<1>(&devices)); EXPECT_CALL(*listener_, Error(MEDIA_DEVICE_VIDEO_CAPTURE, _, kDeviceNotAvailable)) .Times(1); vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); // Wait to get device callback. message_loop_->RunUntilIdle(); MediaStreamType stream_type = MEDIA_DEVICE_VIDEO_CAPTURE; std::string device_name("device_doesnt_exist"); std::string device_id("id_doesnt_exist"); StreamDeviceInfo dummy_device(stream_type, device_name, device_id, false); // This should fail with error code 'kDeviceNotAvailable'. vcm_->Open(dummy_device); // Wait to check callbacks before removing the listener. message_loop_->RunUntilIdle(); vcm_->Unregister(); } // Start a device using "magic" id, i.e. call Start without calling Open. TEST_F(VideoCaptureManagerTest, StartUsingId) { InSequence s; EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(1); EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(1); media::VideoCaptureParams capture_params; capture_params.session_id = VideoCaptureManager::kStartOpenSessionId; capture_params.width = 320; capture_params.height = 240; capture_params.frame_rate = 30; // Start shall trigger the Open callback. vcm_->Start(capture_params, frame_observer_.get()); // Stop shall trigger the Close callback vcm_->Stop(VideoCaptureManager::kStartOpenSessionId, base::Closure()); // Wait to check callbacks before removing the listener. message_loop_->RunUntilIdle(); vcm_->Unregister(); } // Open and start a device, close it before calling Stop. TEST_F(VideoCaptureManagerTest, CloseWithoutStop) { StreamDeviceInfoArray devices; InSequence s; EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) .Times(1).WillOnce(SaveArg<1>(&devices)); EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(1); EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(1); vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); // Wait to get device callback. message_loop_->RunUntilIdle(); int video_session_id = vcm_->Open(devices.front()); media::VideoCaptureParams capture_params; capture_params.session_id = video_session_id; capture_params.width = 320; capture_params.height = 240; capture_params.frame_rate = 30; vcm_->Start(capture_params, frame_observer_.get()); // Close will stop the running device, an assert will be triggered in // VideoCaptureManager destructor otherwise. vcm_->Close(video_session_id); vcm_->Stop(video_session_id, base::Closure()); // Wait to check callbacks before removing the listener message_loop_->RunUntilIdle(); vcm_->Unregister(); } } // namespace content