diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp index f14854cfb..606427704 100755 --- a/talk/libjingle.gyp +++ b/talk/libjingle.gyp @@ -480,6 +480,8 @@ 'media/base/cpuid.cc', 'media/base/cpuid.h', 'media/base/cryptoparams.h', + 'media/base/device.h', + 'media/base/fakescreencapturerfactory.h', 'media/base/filemediaengine.cc', 'media/base/filemediaengine.h', 'media/base/hybriddataengine.h', @@ -502,6 +504,7 @@ 'media/base/videoadapter.h', 'media/base/videocapturer.cc', 'media/base/videocapturer.h', + 'media/base/videocapturerfactory.h', 'media/base/videocommon.cc', 'media/base/videocommon.h', 'media/base/videoframe.cc', @@ -533,6 +536,8 @@ 'media/webrtc/webrtctexturevideoframe.cc', 'media/webrtc/webrtctexturevideoframe.h', 'media/webrtc/webrtcvideocapturer.cc', + 'media/webrtc/webrtcvideocapturerfactory.h', + 'media/webrtc/webrtcvideocapturerfactory.cc', 'media/webrtc/webrtcvideocapturer.h', 'media/webrtc/webrtcvideodecoderfactory.h', 'media/webrtc/webrtcvideoencoderfactory.h', diff --git a/talk/media/base/device.h b/talk/media/base/device.h new file mode 100755 index 000000000..ced74c61b --- /dev/null +++ b/talk/media/base/device.h @@ -0,0 +1,50 @@ +// libjingle +// Copyright 2014 Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. The name of the author may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef TALK_MEDIA_BASE_DEVICE_H_ +#define TALK_MEDIA_BASE_DEVICE_H_ + +#include "webrtc/base/stringencode.h" + +namespace cricket { + +// Used to represent an audio or video capture or render device. +struct Device { + Device() {} + Device(const std::string& name, int id) + : name(name), + id(rtc::ToString(id)) { + } + Device(const std::string& name, const std::string& id) + : name(name), id(id) {} + + std::string name; + std::string id; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_DEVICE_H_ diff --git a/talk/media/base/fakescreencapturerfactory.h b/talk/media/base/fakescreencapturerfactory.h new file mode 100755 index 000000000..d9fccdc06 --- /dev/null +++ b/talk/media/base/fakescreencapturerfactory.h @@ -0,0 +1,80 @@ +/* + * libjingle + * Copyright 2012 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TALK_MEDIA_BASE_FAKESCREENCAPTURERFACTORY_H_ +#define TALK_MEDIA_BASE_FAKESCREENCAPTURERFACTORY_H_ + +#include "talk/media/base/fakevideocapturer.h" +#include "talk/media/base/videocapturerfactory.h" + +namespace cricket { + +class FakeScreenCapturerFactory + : public cricket::ScreenCapturerFactory, + public sigslot::has_slots<> { + public: + FakeScreenCapturerFactory() + : window_capturer_(NULL), + capture_state_(cricket::CS_STOPPED) {} + + virtual cricket::VideoCapturer* Create(const ScreencastId& window) { + if (window_capturer_ != NULL) { + // Class is only designed to handle one fake screencapturer. + ADD_FAILURE(); + return NULL; + } + window_capturer_ = new cricket::FakeVideoCapturer; + window_capturer_->SignalDestroyed.connect( + this, + &FakeScreenCapturerFactory::OnWindowCapturerDestroyed); + window_capturer_->SignalStateChange.connect( + this, + &FakeScreenCapturerFactory::OnStateChange); + return window_capturer_; + } + + cricket::FakeVideoCapturer* window_capturer() { return window_capturer_; } + + cricket::CaptureState capture_state() { return capture_state_; } + + private: + void OnWindowCapturerDestroyed(cricket::FakeVideoCapturer* capturer) { + if (capturer == window_capturer_) { + window_capturer_ = NULL; + } + } + void OnStateChange(cricket::VideoCapturer*, cricket::CaptureState state) { + capture_state_ = state; + } + + cricket::FakeVideoCapturer* window_capturer_; + cricket::CaptureState capture_state_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_FAKESCREENCAPTURERFACTORY_H_ diff --git a/talk/media/base/videocapturerfactory.h b/talk/media/base/videocapturerfactory.h new file mode 100755 index 000000000..009a5eefc --- /dev/null +++ b/talk/media/base/videocapturerfactory.h @@ -0,0 +1,55 @@ +// libjingle +// Copyright 2014 Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. The name of the author may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef TALK_MEDIA_BASE_VIDEOCAPTURERFACTORY_H_ +#define TALK_MEDIA_BASE_VIDEOCAPTURERFACTORY_H_ + +#include "talk/media/base/device.h" +#include "talk/media/base/screencastid.h" + +namespace cricket { + +class VideoCapturer; + +class VideoDeviceCapturerFactory { + public: + VideoDeviceCapturerFactory() {} + virtual ~VideoDeviceCapturerFactory() {} + + virtual VideoCapturer* Create(const Device& device) = 0; +}; + +class ScreenCapturerFactory { + public: + ScreenCapturerFactory() {} + virtual ~ScreenCapturerFactory() {} + + virtual VideoCapturer* Create(const ScreencastId& screenid) = 0; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_VIDEOCAPTURERFACTORY_H_ diff --git a/talk/media/devices/devicemanager.cc b/talk/media/devices/devicemanager.cc index c331adced..9d7a951e5 100644 --- a/talk/media/devices/devicemanager.cc +++ b/talk/media/devices/devicemanager.cc @@ -35,19 +35,14 @@ #include "webrtc/base/windowpicker.h" #include "webrtc/base/windowpickerfactory.h" #include "talk/media/base/mediacommon.h" +#include "talk/media/base/videocapturerfactory.h" #include "talk/media/devices/deviceinfo.h" #include "talk/media/devices/filevideocapturer.h" #include "talk/media/devices/yuvframescapturer.h" -#if defined(HAVE_WEBRTC_VIDEO) -#include "talk/media/webrtc/webrtcvideocapturer.h" -#endif - - -#if defined(HAVE_WEBRTC_VIDEO) -#define VIDEO_CAPTURER_NAME WebRtcVideoCapturer -#endif - +#ifdef HAVE_WEBRTC_VIDEO +#include "talk/media/webrtc/webrtcvideocapturerfactory.h" +#endif // HAVE_WEBRTC_VIDEO namespace { @@ -64,29 +59,12 @@ namespace cricket { // Initialize to empty string. const char DeviceManagerInterface::kDefaultDeviceName[] = ""; -class DefaultVideoCapturerFactory : public VideoCapturerFactory { - public: - DefaultVideoCapturerFactory() {} - virtual ~DefaultVideoCapturerFactory() {} - - VideoCapturer* Create(const Device& device) { -#if defined(VIDEO_CAPTURER_NAME) - VIDEO_CAPTURER_NAME* return_value = new VIDEO_CAPTURER_NAME; - if (!return_value->Init(device)) { - delete return_value; - return NULL; - } - return return_value; -#else - return NULL; -#endif - } -}; - DeviceManager::DeviceManager() : initialized_(false), - device_video_capturer_factory_(new DefaultVideoCapturerFactory), window_picker_(rtc::WindowPickerFactory::CreateWindowPicker()) { +#ifdef HAVE_WEBRTC_VIDEO + SetVideoDeviceCapturerFactory(new WebRtcVideoDeviceCapturerFactory()); +#endif // HAVE_WEBRTC_VIDEO } DeviceManager::~DeviceManager() { @@ -212,12 +190,16 @@ void DeviceManager::ClearVideoCaptureDeviceMaxFormat( } VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const { - VideoCapturer* capturer = ConstructFakeVideoCapturer(device); + VideoCapturer* capturer = MaybeConstructFakeVideoCapturer(device); if (capturer) { return capturer; } - capturer = device_video_capturer_factory_->Create(device); + if (!video_device_capturer_factory_) { + LOG(LS_ERROR) << "No video capturer factory for devices."; + return NULL; + } + capturer = video_device_capturer_factory_->Create(device); if (!capturer) { return NULL; } @@ -231,7 +213,7 @@ VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const { return capturer; } -VideoCapturer* DeviceManager::ConstructFakeVideoCapturer( +VideoCapturer* DeviceManager::MaybeConstructFakeVideoCapturer( const Device& device) const { // TODO(hellner): Throw out the creation of a file video capturer once the // refactoring is completed. @@ -262,19 +244,6 @@ bool DeviceManager::GetWindows( return window_picker_->GetWindowList(descriptions); } -VideoCapturer* DeviceManager::CreateWindowCapturer(rtc::WindowId window) { -#if defined(WINDOW_CAPTURER_NAME) - WINDOW_CAPTURER_NAME* window_capturer = new WINDOW_CAPTURER_NAME(); - if (!window_capturer->Init(window)) { - delete window_capturer; - return NULL; - } - return window_capturer; -#else - return NULL; -#endif -} - bool DeviceManager::GetDesktops( std::vector* descriptions) { if (!window_picker_) { @@ -283,18 +252,13 @@ bool DeviceManager::GetDesktops( return window_picker_->GetDesktopList(descriptions); } -VideoCapturer* DeviceManager::CreateDesktopCapturer( - rtc::DesktopId desktop) { -#if defined(DESKTOP_CAPTURER_NAME) - DESKTOP_CAPTURER_NAME* desktop_capturer = new DESKTOP_CAPTURER_NAME(); - if (!desktop_capturer->Init(desktop.index())) { - delete desktop_capturer; +VideoCapturer* DeviceManager::CreateScreenCapturer( + const ScreencastId& screenid) const { + if (!screen_capturer_factory_) { + LOG(LS_ERROR) << "No video capturer factory for screens."; return NULL; } - return desktop_capturer; -#else - return NULL; -#endif + return screen_capturer_factory_->Create(screenid); } bool DeviceManager::GetAudioDevices(bool input, diff --git a/talk/media/devices/devicemanager.h b/talk/media/devices/devicemanager.h index 01073480e..74ceb381f 100644 --- a/talk/media/devices/devicemanager.h +++ b/talk/media/devices/devicemanager.h @@ -32,11 +32,14 @@ #include #include +#include "talk/media/base/device.h" +#include "talk/media/base/screencastid.h" +#include "talk/media/base/videocommon.h" +#include "talk/media/base/videocapturerfactory.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/sigslot.h" #include "webrtc/base/stringencode.h" #include "webrtc/base/window.h" -#include "talk/media/base/videocommon.h" namespace rtc { @@ -49,28 +52,6 @@ namespace cricket { class VideoCapturer; -// Used to represent an audio or video capture or render device. -struct Device { - Device() {} - Device(const std::string& first, int second) - : name(first), - id(rtc::ToString(second)) { - } - Device(const std::string& first, const std::string& second) - : name(first), id(second) {} - - std::string name; - std::string id; -}; - -class VideoCapturerFactory { - public: - VideoCapturerFactory() {} - virtual ~VideoCapturerFactory() {} - - virtual VideoCapturer* Create(const Device& device) = 0; -}; - // DeviceManagerInterface - interface to manage the audio and // video devices on the system. class DeviceManagerInterface { @@ -94,6 +75,14 @@ class DeviceManagerInterface { virtual bool GetVideoCaptureDevices(std::vector* devs) = 0; virtual bool GetVideoCaptureDevice(const std::string& name, Device* out) = 0; + // If the device manager needs to create video capturers, here is + // how to control which video capturers are created. These take + // ownership of the factories. + virtual void SetVideoDeviceCapturerFactory( + VideoDeviceCapturerFactory* video_device_capturer_factory) = 0; + virtual void SetScreenCapturerFactory( + ScreenCapturerFactory* screen_capturer_factory) = 0; + // Caps the capture format according to max format for capturers created // by CreateVideoCapturer(). See ConstrainSupportedFormats() in // videocapturer.h for more detail. @@ -109,12 +98,10 @@ class DeviceManagerInterface { virtual bool GetWindows( std::vector* descriptions) = 0; - virtual VideoCapturer* CreateWindowCapturer(rtc::WindowId window) = 0; - virtual bool GetDesktops( std::vector* descriptions) = 0; - virtual VideoCapturer* CreateDesktopCapturer( - rtc::DesktopId desktop) = 0; + virtual VideoCapturer* CreateScreenCapturer( + const ScreencastId& screenid) const = 0; sigslot::signal0<> SignalDevicesChange; @@ -142,11 +129,6 @@ class DeviceManager : public DeviceManagerInterface { DeviceManager(); virtual ~DeviceManager(); - void set_device_video_capturer_factory( - VideoCapturerFactory* device_video_capturer_factory) { - device_video_capturer_factory_.reset(device_video_capturer_factory); - } - // Initialization virtual bool Init(); virtual void Terminate(); @@ -164,19 +146,29 @@ class DeviceManager : public DeviceManagerInterface { virtual bool GetVideoCaptureDevices(std::vector* devs); virtual bool GetVideoCaptureDevice(const std::string& name, Device* out); + virtual void SetVideoDeviceCapturerFactory( + VideoDeviceCapturerFactory* video_device_capturer_factory) { + video_device_capturer_factory_.reset(video_device_capturer_factory); + } + virtual void SetScreenCapturerFactory( + ScreenCapturerFactory* screen_capturer_factory) { + screen_capturer_factory_.reset(screen_capturer_factory); + } + + virtual void SetVideoCaptureDeviceMaxFormat(const std::string& usb_id, const VideoFormat& max_format); virtual void ClearVideoCaptureDeviceMaxFormat(const std::string& usb_id); + // TODO(pthatcher): Rename to CreateVideoDeviceCapturer. virtual VideoCapturer* CreateVideoCapturer(const Device& device) const; virtual bool GetWindows( std::vector* descriptions); - virtual VideoCapturer* CreateWindowCapturer(rtc::WindowId window); - virtual bool GetDesktops( std::vector* descriptions); - virtual VideoCapturer* CreateDesktopCapturer(rtc::DesktopId desktop); + virtual VideoCapturer* CreateScreenCapturer( + const ScreencastId& screenid) const; // The exclusion_list MUST be a NULL terminated list. static bool FilterDevices(std::vector* devices, @@ -202,10 +194,13 @@ class DeviceManager : public DeviceManagerInterface { static bool ShouldDeviceBeIgnored(const std::string& device_name, const char* const exclusion_list[]); bool GetFakeVideoCaptureDevice(const std::string& name, Device* out) const; - VideoCapturer* ConstructFakeVideoCapturer(const Device& device) const; + VideoCapturer* MaybeConstructFakeVideoCapturer(const Device& device) const; bool initialized_; - rtc::scoped_ptr device_video_capturer_factory_; + rtc::scoped_ptr< + VideoDeviceCapturerFactory> video_device_capturer_factory_; + rtc::scoped_ptr< + ScreenCapturerFactory> screen_capturer_factory_; std::map max_formats_; rtc::scoped_ptr watcher_; rtc::scoped_ptr window_picker_; diff --git a/talk/media/devices/devicemanager_unittest.cc b/talk/media/devices/devicemanager_unittest.cc index 3bc0241d8..5dc33f98c 100644 --- a/talk/media/devices/devicemanager_unittest.cc +++ b/talk/media/devices/devicemanager_unittest.cc @@ -41,7 +41,9 @@ #include "webrtc/base/stream.h" #include "webrtc/base/windowpickerfactory.h" #include "talk/media/base/fakevideocapturer.h" +#include "talk/media/base/screencastid.h" #include "talk/media/base/testutils.h" +#include "talk/media/base/videocapturerfactory.h" #include "talk/media/devices/filevideocapturer.h" #include "talk/media/devices/v4llookup.h" @@ -65,24 +67,38 @@ const cricket::VideoFormat kHdFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420); -class FakeVideoCapturerFactory : public cricket::VideoCapturerFactory { +class FakeVideoDeviceCapturerFactory : + public cricket::VideoDeviceCapturerFactory { public: - FakeVideoCapturerFactory() {} - virtual ~FakeVideoCapturerFactory() {} + FakeVideoDeviceCapturerFactory() {} + virtual ~FakeVideoDeviceCapturerFactory() {} virtual cricket::VideoCapturer* Create(const cricket::Device& device) { return new cricket::FakeVideoCapturer; } }; +class FakeScreenCapturerFactory : public cricket::ScreenCapturerFactory { + public: + FakeScreenCapturerFactory() {} + virtual ~FakeScreenCapturerFactory() {} + + virtual cricket::VideoCapturer* Create( + const cricket::ScreencastId& screenid) { + return new cricket::FakeVideoCapturer; + } +}; + class DeviceManagerTestFake : public testing::Test { public: virtual void SetUp() { dm_.reset(DeviceManagerFactory::Create()); EXPECT_TRUE(dm_->Init()); DeviceManager* device_manager = static_cast(dm_.get()); - device_manager->set_device_video_capturer_factory( - new FakeVideoCapturerFactory()); + device_manager->SetVideoDeviceCapturerFactory( + new FakeVideoDeviceCapturerFactory()); + device_manager->SetScreenCapturerFactory( + new FakeScreenCapturerFactory()); } virtual void TearDown() { @@ -371,6 +387,7 @@ TEST(DeviceManagerTest, GetWindows) { return; } scoped_ptr dm(DeviceManagerFactory::Create()); + dm->SetScreenCapturerFactory(new FakeScreenCapturerFactory()); std::vector descriptions; EXPECT_TRUE(dm->Init()); if (!dm->GetWindows(&descriptions) || descriptions.empty()) { @@ -378,8 +395,8 @@ TEST(DeviceManagerTest, GetWindows) { << "windows to capture."; return; } - scoped_ptr capturer(dm->CreateWindowCapturer( - descriptions.front().id())); + scoped_ptr capturer(dm->CreateScreenCapturer( + cricket::ScreencastId(descriptions.front().id()))); EXPECT_FALSE(capturer.get() == NULL); // TODO(hellner): creating a window capturer and immediately deleting it // results in "Continuous Build and Test Mainline - Mac opt" failure (crash). @@ -394,6 +411,7 @@ TEST(DeviceManagerTest, GetDesktops) { return; } scoped_ptr dm(DeviceManagerFactory::Create()); + dm->SetScreenCapturerFactory(new FakeScreenCapturerFactory()); std::vector descriptions; EXPECT_TRUE(dm->Init()); if (!dm->GetDesktops(&descriptions) || descriptions.empty()) { @@ -401,8 +419,8 @@ TEST(DeviceManagerTest, GetDesktops) { << "desktops to capture."; return; } - scoped_ptr capturer(dm->CreateDesktopCapturer( - descriptions.front().id())); + scoped_ptr capturer(dm->CreateScreenCapturer( + cricket::ScreencastId(descriptions.front().id()))); EXPECT_FALSE(capturer.get() == NULL); } #endif // !WIN32 diff --git a/talk/media/devices/fakedevicemanager.h b/talk/media/devices/fakedevicemanager.h index 5fc37158a..e9823ccc2 100644 --- a/talk/media/devices/fakedevicemanager.h +++ b/talk/media/devices/fakedevicemanager.h @@ -79,6 +79,12 @@ class FakeDeviceManager : public DeviceManagerInterface { *devs = vidcap_devices_; return true; } + virtual void SetVideoDeviceCapturerFactory( + VideoDeviceCapturerFactory* video_device_capturer_factory) { + } + virtual void SetScreenCapturerFactory( + ScreenCapturerFactory* screen_capturer_factory) { + } virtual void SetVideoCaptureDeviceMaxFormat(const std::string& usb_id, const VideoFormat& max_format) { max_formats_[usb_id] = max_format; @@ -97,6 +103,10 @@ class FakeDeviceManager : public DeviceManagerInterface { virtual VideoCapturer* CreateVideoCapturer(const Device& device) const { return new FakeVideoCapturer(); } + virtual VideoCapturer* CreateScreenCapturer( + const ScreencastId& screenid) const { + return new FakeVideoCapturer(); + } virtual bool GetWindows( std::vector* descriptions) { descriptions->clear(); diff --git a/talk/media/webrtc/webrtcvideocapturerfactory.cc b/talk/media/webrtc/webrtcvideocapturerfactory.cc new file mode 100755 index 000000000..c62b46a58 --- /dev/null +++ b/talk/media/webrtc/webrtcvideocapturerfactory.cc @@ -0,0 +1,43 @@ +/* + * libjingle + * Copyright 2014 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/scoped_ptr.h" +#include "talk/media/webrtc/webrtcvideocapturer.h" +#include "talk/media/webrtc/webrtcvideocapturerfactory.h" + +namespace cricket { + +VideoCapturer* WebRtcVideoDeviceCapturerFactory::Create(const Device& device) { + talk_base::scoped_ptr capturer( + new WebRtcVideoCapturer()); + if (!capturer->Init(device)) { + return NULL; + } + return capturer.release(); +} + +} // namespace cricket diff --git a/talk/media/webrtc/webrtcvideocapturerfactory.h b/talk/media/webrtc/webrtcvideocapturerfactory.h new file mode 100755 index 000000000..091b07237 --- /dev/null +++ b/talk/media/webrtc/webrtcvideocapturerfactory.h @@ -0,0 +1,43 @@ +// libjingle +// Copyright 2014 Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. The name of the author may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +// TODO(pthatcher): Reneme file to match class name. +#ifndef TALK_MEDIA_WEBRTC_WEBRTCVIDEOCAPTURERFACTORY_H_ +#define TALK_MEDIA_WEBRTC_WEBRTCVIDEOCAPTURERFACTORY_H_ + +#include "talk/media/base/videocapturerfactory.h" + +namespace cricket { + +// Creates instances of cricket::WebRtcVideoCapturer. +class WebRtcVideoDeviceCapturerFactory : public VideoDeviceCapturerFactory { + public: + virtual VideoCapturer* Create(const Device& device); +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEOCAPTURERFACTORY_H_ diff --git a/talk/session/media/call.cc b/talk/session/media/call.cc index fc22eb440..ac02e7ce6 100644 --- a/talk/session/media/call.cc +++ b/talk/session/media/call.cc @@ -493,7 +493,7 @@ cricket::VideoFormat ScreencastFormatFromFps(int fps) { bool Call::StartScreencast(Session* session, const std::string& streamid, uint32 ssrc, - const ScreencastId& screencastid, int fps) { + const ScreencastId& screenid, int fps) { MediaSessionMap::iterator it = media_session_map_.find(session->id()); if (it == media_session_map_.end()) { return false; @@ -506,12 +506,19 @@ bool Call::StartScreencast(Session* session, return false; } - VideoCapturer *capturer = video_channel->AddScreencast(ssrc, screencastid); - if (capturer == NULL) { + VideoCapturer* capturer = session_client_->channel_manager()-> + CreateScreenCapturer(screenid); + if (!capturer) { LOG(LS_WARNING) << "Could not create screencast capturer."; return false; } + if (!video_channel->AddScreencast(ssrc, capturer)) { + delete capturer; + LOG(LS_WARNING) << "Could not add screencast capturer."; + return false; + } + VideoFormat format = ScreencastFormatFromFps(fps); if (!session_client_->channel_manager()->StartVideoCapture( capturer, format)) { diff --git a/talk/session/media/call.h b/talk/session/media/call.h index e61fec82c..3122f5567 100644 --- a/talk/session/media/call.h +++ b/talk/session/media/call.h @@ -115,7 +115,7 @@ class Call : public rtc::MessageHandler, public sigslot::has_slots<> { void PressDTMF(int event); bool StartScreencast(Session* session, const std::string& stream_name, uint32 ssrc, - const ScreencastId& screencastid, int fps); + const ScreencastId& screenid, int fps); bool StopScreencast(Session* session, const std::string& stream_name, uint32 ssrc); diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc index 67bd2da5d..6ab12b692 100644 --- a/talk/session/media/channel.cc +++ b/talk/session/media/channel.cc @@ -73,20 +73,6 @@ static void SafeSetError(const std::string& message, std::string* error_desc) { } } -// TODO(hellner): use the device manager for creation of screen capturers when -// the cl enabling it has landed. -class NullScreenCapturerFactory : public VideoChannel::ScreenCapturerFactory { - public: - VideoCapturer* CreateScreenCapturer(const ScreencastId& window) { - return NULL; - } -}; - - -VideoChannel::ScreenCapturerFactory* CreateScreenCapturerFactory() { - return new NullScreenCapturerFactory(); -} - struct PacketMessageData : public rtc::MessageData { rtc::Buffer packet; rtc::DiffServCodePoint dscp; @@ -1674,7 +1660,6 @@ VideoChannel::VideoChannel(rtc::Thread* thread, rtcp), voice_channel_(voice_channel), renderer_(NULL), - screencapture_factory_(CreateScreenCapturerFactory()), previous_we_(rtc::WE_CLOSE) { } @@ -1729,10 +1714,9 @@ bool VideoChannel::ApplyViewRequest(const ViewRequest& request) { return InvokeOnWorker(Bind(&VideoChannel::ApplyViewRequest_w, this, request)); } -VideoCapturer* VideoChannel::AddScreencast( - uint32 ssrc, const ScreencastId& id) { - return worker_thread()->Invoke(Bind( - &VideoChannel::AddScreencast_w, this, ssrc, id)); +bool VideoChannel::AddScreencast(uint32 ssrc, VideoCapturer* capturer) { + return worker_thread()->Invoke(Bind( + &VideoChannel::AddScreencast_w, this, ssrc, capturer)); } bool VideoChannel::SetCapturer(uint32 ssrc, VideoCapturer* capturer) { @@ -1774,13 +1758,6 @@ bool VideoChannel::RequestIntraFrame() { return true; } -void VideoChannel::SetScreenCaptureFactory( - ScreenCapturerFactory* screencapture_factory) { - worker_thread()->Invoke(Bind( - &VideoChannel::SetScreenCaptureFactory_w, - this, screencapture_factory)); -} - void VideoChannel::ChangeState() { // Render incoming data if we're the active call, and we have the local // content. We receive data on the default channel and multiplexed streams. @@ -1960,20 +1937,13 @@ bool VideoChannel::ApplyViewRequest_w(const ViewRequest& request) { return ret; } -VideoCapturer* VideoChannel::AddScreencast_w( - uint32 ssrc, const ScreencastId& id) { +bool VideoChannel::AddScreencast_w(uint32 ssrc, VideoCapturer* capturer) { if (screencast_capturers_.find(ssrc) != screencast_capturers_.end()) { - return NULL; + return false; } - VideoCapturer* screen_capturer = - screencapture_factory_->CreateScreenCapturer(id); - if (!screen_capturer) { - return NULL; - } - screen_capturer->SignalStateChange.connect(this, - &VideoChannel::OnStateChange); - screencast_capturers_[ssrc] = screen_capturer; - return screen_capturer; + capturer->SignalStateChange.connect(this, &VideoChannel::OnStateChange); + screencast_capturers_[ssrc] = capturer; + return true; } bool VideoChannel::RemoveScreencast_w(uint32 ssrc) { @@ -2003,15 +1973,6 @@ void VideoChannel::GetScreencastDetails_w( data->screencast_max_pixels = capturer->screencast_max_pixels(); } -void VideoChannel::SetScreenCaptureFactory_w( - ScreenCapturerFactory* screencapture_factory) { - if (screencapture_factory == NULL) { - screencapture_factory_.reset(CreateScreenCapturerFactory()); - } else { - screencapture_factory_.reset(screencapture_factory); - } -} - void VideoChannel::OnScreencastWindowEvent_s(uint32 ssrc, rtc::WindowEvent we) { ASSERT(signaling_thread() == rtc::Thread::Current()); diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h index 2480f451e..4d3baf613 100644 --- a/talk/session/media/channel.h +++ b/talk/session/media/channel.h @@ -38,7 +38,6 @@ #include "webrtc/base/window.h" #include "talk/media/base/mediachannel.h" #include "talk/media/base/mediaengine.h" -#include "talk/media/base/screencastid.h" #include "talk/media/base/streamparams.h" #include "talk/media/base/videocapturer.h" #include "talk/p2p/base/session.h" @@ -508,14 +507,6 @@ class VoiceChannel : public BaseChannel { // VideoChannel is a specialization for video. class VideoChannel : public BaseChannel { public: - // Make screen capturer virtual so that it can be overriden in testing. - // E.g. used to test that window events are triggered correctly. - class ScreenCapturerFactory { - public: - virtual VideoCapturer* CreateScreenCapturer(const ScreencastId& window) = 0; - virtual ~ScreenCapturerFactory() {} - }; - VideoChannel(rtc::Thread* thread, MediaEngineInterface* media_engine, VideoMediaChannel* channel, BaseSession* session, const std::string& content_name, bool rtcp, @@ -528,7 +519,8 @@ class VideoChannel : public BaseChannel { // TODO(pthatcher): Refactor to use a "capture id" instead of an // ssrc here as the "key". - VideoCapturer* AddScreencast(uint32 ssrc, const ScreencastId& id); + // Passes ownership of the capturer to the channel. + bool AddScreencast(uint32 ssrc, VideoCapturer* capturer); bool SetCapturer(uint32 ssrc, VideoCapturer* capturer); bool RemoveScreencast(uint32 ssrc); // True if we've added a screencast. Doesn't matter if the capturer @@ -552,9 +544,6 @@ class VideoChannel : public BaseChannel { sigslot::signal3 SignalMediaError; - void SetScreenCaptureFactory( - ScreenCapturerFactory* screencapture_factory); - // Configuration and setting. bool SetChannelOptions(const VideoOptions& options); @@ -579,13 +568,11 @@ class VideoChannel : public BaseChannel { std::string* error_desc); bool ApplyViewRequest_w(const ViewRequest& request); - VideoCapturer* AddScreencast_w(uint32 ssrc, const ScreencastId& id); + bool AddScreencast_w(uint32 ssrc, VideoCapturer* capturer); bool RemoveScreencast_w(uint32 ssrc); void OnScreencastWindowEvent_s(uint32 ssrc, rtc::WindowEvent we); bool IsScreencasting_w() const; void GetScreencastDetails_w(ScreencastDetailsData* d) const; - void SetScreenCaptureFactory_w( - ScreenCapturerFactory* screencapture_factory); bool GetStats_w(VideoMediaInfo* stats); virtual void OnMessage(rtc::Message* pmsg); @@ -604,7 +591,6 @@ class VideoChannel : public BaseChannel { VoiceChannel* voice_channel_; VideoRenderer* renderer_; - rtc::scoped_ptr screencapture_factory_; ScreencastMap screencast_capturers_; rtc::scoped_ptr media_monitor_; diff --git a/talk/session/media/channel_unittest.cc b/talk/session/media/channel_unittest.cc index cf0aad8dd..43fad6d83 100644 --- a/talk/session/media/channel_unittest.cc +++ b/talk/session/media/channel_unittest.cc @@ -33,6 +33,7 @@ #include "webrtc/base/sslidentity.h" #include "webrtc/base/window.h" #include "talk/media/base/fakemediaengine.h" +#include "talk/media/base/fakescreencapturerfactory.h" #include "talk/media/base/fakertp.h" #include "talk/media/base/fakevideocapturer.h" #include "talk/media/base/mediachannel.h" @@ -88,49 +89,6 @@ class Traits { typedef MediaInfoT MediaInfo; }; -class FakeScreenCaptureFactory - : public cricket::VideoChannel::ScreenCapturerFactory, - public sigslot::has_slots<> { - public: - FakeScreenCaptureFactory() - : window_capturer_(NULL), - capture_state_(cricket::CS_STOPPED) {} - - virtual cricket::VideoCapturer* CreateScreenCapturer( - const ScreencastId& window) { - if (window_capturer_ != NULL) { - // Class is only designed to handle one fake screencapturer. - ADD_FAILURE(); - return NULL; - } - window_capturer_ = new cricket::FakeVideoCapturer; - window_capturer_->SignalDestroyed.connect( - this, - &FakeScreenCaptureFactory::OnWindowCapturerDestroyed); - window_capturer_->SignalStateChange.connect( - this, - &FakeScreenCaptureFactory::OnStateChange); - return window_capturer_; - } - - cricket::FakeVideoCapturer* window_capturer() { return window_capturer_; } - - cricket::CaptureState capture_state() { return capture_state_; } - - private: - void OnWindowCapturerDestroyed(cricket::FakeVideoCapturer* capturer) { - if (capturer == window_capturer_) { - window_capturer_ = NULL; - } - } - void OnStateChange(cricket::VideoCapturer*, cricket::CaptureState state) { - capture_state_ = state; - } - - cricket::FakeVideoCapturer* window_capturer_; - cricket::CaptureState capture_state_; -}; - // Controls how long we wait for a session to send messages that we // expect, in milliseconds. We put it high to avoid flaky tests. static const int kEventTimeout = 5000; @@ -2469,28 +2427,31 @@ TEST_F(VideoChannelTest, TestStreams) { TEST_F(VideoChannelTest, TestScreencastEvents) { const int kTimeoutMs = 500; TestInit(); - FakeScreenCaptureFactory* screencapture_factory = - new FakeScreenCaptureFactory(); - channel1_->SetScreenCaptureFactory(screencapture_factory); cricket::ScreencastEventCatcher catcher; channel1_->SignalScreencastWindowEvent.connect( &catcher, &cricket::ScreencastEventCatcher::OnEvent); - EXPECT_TRUE(channel1_->AddScreencast(0, ScreencastId(WindowId(0))) != NULL); - ASSERT_TRUE(screencapture_factory->window_capturer() != NULL); - EXPECT_EQ_WAIT(cricket::CS_STOPPED, screencapture_factory->capture_state(), + + rtc::scoped_ptr + screen_capturer_factory(new cricket::FakeScreenCapturerFactory()); + cricket::VideoCapturer* screen_capturer = screen_capturer_factory->Create( + ScreencastId(WindowId(0))); + ASSERT_TRUE(screen_capturer != NULL); + + EXPECT_TRUE(channel1_->AddScreencast(0, screen_capturer)); + EXPECT_EQ_WAIT(cricket::CS_STOPPED, screen_capturer_factory->capture_state(), kTimeoutMs); - screencapture_factory->window_capturer()->SignalStateChange( - screencapture_factory->window_capturer(), cricket::CS_PAUSED); + + screen_capturer->SignalStateChange(screen_capturer, cricket::CS_PAUSED); EXPECT_EQ_WAIT(rtc::WE_MINIMIZE, catcher.event(), kTimeoutMs); - screencapture_factory->window_capturer()->SignalStateChange( - screencapture_factory->window_capturer(), cricket::CS_RUNNING); + + screen_capturer->SignalStateChange(screen_capturer, cricket::CS_RUNNING); EXPECT_EQ_WAIT(rtc::WE_RESTORE, catcher.event(), kTimeoutMs); - screencapture_factory->window_capturer()->SignalStateChange( - screencapture_factory->window_capturer(), cricket::CS_STOPPED); + + screen_capturer->SignalStateChange(screen_capturer, cricket::CS_STOPPED); EXPECT_EQ_WAIT(rtc::WE_CLOSE, catcher.event(), kTimeoutMs); + EXPECT_TRUE(channel1_->RemoveScreencast(0)); - ASSERT_TRUE(screencapture_factory->window_capturer() == NULL); } TEST_F(VideoChannelTest, TestUpdateStreamsInLocalContent) { diff --git a/talk/session/media/channelmanager.cc b/talk/session/media/channelmanager.cc index 684e9a9c6..8c037dfcc 100644 --- a/talk/session/media/channelmanager.cc +++ b/talk/session/media/channelmanager.cc @@ -710,6 +710,11 @@ VideoCapturer* ChannelManager::CreateVideoCapturer() { return capturer; } +VideoCapturer* ChannelManager::CreateScreenCapturer( + const ScreencastId& screenid) { + return device_manager_->CreateScreenCapturer(screenid); +} + bool ChannelManager::SetCaptureDevice_w(const Device* cam_device) { ASSERT(worker_thread_ == rtc::Thread::Current()); ASSERT(initialized_); diff --git a/talk/session/media/channelmanager.h b/talk/session/media/channelmanager.h index d74228096..9ca93e763 100644 --- a/talk/session/media/channelmanager.h +++ b/talk/session/media/channelmanager.h @@ -157,6 +157,8 @@ class ChannelManager : public rtc::MessageHandler, bool GetVideoCaptureDevice(Device* device); // Create capturer based on what has been set in SetCaptureDevice(). VideoCapturer* CreateVideoCapturer(); + // Create capturer from a screen. + VideoCapturer* CreateScreenCapturer(const ScreencastId& screenid); bool SetCaptureDevice(const std::string& cam_device); bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config); // RTX will be enabled/disabled in engines that support it. The supporting @@ -240,6 +242,9 @@ class ChannelManager : public rtc::MessageHandler, const AudioOptions& options, int delay_offset); int audio_delay_offset() const { return audio_delay_offset_; } + // This is here so that ChannelManager subclasses can set the video + // capturer factories to use. + DeviceManagerInterface* device_manager() { return device_manager_.get(); } private: typedef std::vector VoiceChannels;