Remove DeviceManager and DeviceInfo.
BUG=webrtc:5615, webrtc:5620 Review URL: https://codereview.webrtc.org/1715883002 Cr-Commit-Position: refs/heads/master@{#12020}
This commit is contained in:
parent
34b11eb66e
commit
8ad582d83f
@ -178,6 +178,7 @@
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'-framework Cocoa',
|
||||
'-framework OpenGL',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@ -34,25 +34,16 @@
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/media/base/videocapturer.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
#include "webrtc/media/engine/webrtcvideocapturerfactory.h"
|
||||
|
||||
@implementation RTCVideoCapturer {
|
||||
std::unique_ptr<cricket::VideoCapturer> _capturer;
|
||||
}
|
||||
|
||||
+ (RTCVideoCapturer*)capturerWithDeviceName:(NSString*)deviceName {
|
||||
const std::string& device_name = std::string([deviceName UTF8String]);
|
||||
std::unique_ptr<cricket::DeviceManagerInterface> device_manager(
|
||||
cricket::DeviceManagerFactory::Create());
|
||||
bool initialized = device_manager->Init();
|
||||
NSAssert(initialized, @"DeviceManager::Init() failed");
|
||||
cricket::Device device;
|
||||
if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
|
||||
LOG(LS_ERROR) << "GetVideoCaptureDevice failed";
|
||||
return 0;
|
||||
}
|
||||
std::unique_ptr<cricket::VideoCapturer> capturer(
|
||||
device_manager->CreateVideoCapturer(device));
|
||||
cricket::WebRtcVideoDeviceCapturerFactory factory;
|
||||
cricket::Device device(std::string(deviceName.UTF8String), 0);
|
||||
rtc::scoped_ptr<cricket::VideoCapturer> capturer(factory.Create(device));
|
||||
RTCVideoCapturer* rtcCapturer =
|
||||
[[RTCVideoCapturer alloc] initWithCapturer:capturer.release()];
|
||||
return rtcCapturer;
|
||||
|
||||
@ -236,6 +236,13 @@
|
||||
'objc/RTCNSGLVideoView.h',
|
||||
'objc/RTCNSGLVideoView.m',
|
||||
],
|
||||
'link_settings': {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'-framework OpenGL',
|
||||
],
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
}
|
||||
|
||||
@ -19,7 +19,8 @@
|
||||
#include "webrtc/base/json.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/examples/peerconnection/client/defaults.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
#include "webrtc/media/engine/webrtcvideocapturerfactory.h"
|
||||
#include "webrtc/modules/video_capture/video_capture_factory.h"
|
||||
|
||||
// Names used for a IceCandidate JSON object.
|
||||
const char kCandidateSdpMidName[] = "sdpMid";
|
||||
@ -369,23 +370,31 @@ void Conductor::ConnectToPeer(int peer_id) {
|
||||
}
|
||||
|
||||
cricket::VideoCapturer* Conductor::OpenVideoCaptureDevice() {
|
||||
rtc::scoped_ptr<cricket::DeviceManagerInterface> dev_manager(
|
||||
cricket::DeviceManagerFactory::Create());
|
||||
if (!dev_manager->Init()) {
|
||||
LOG(LS_ERROR) << "Can't create device manager";
|
||||
return NULL;
|
||||
std::vector<std::string> device_names;
|
||||
{
|
||||
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
|
||||
webrtc::VideoCaptureFactory::CreateDeviceInfo(0));
|
||||
if (!info) {
|
||||
return nullptr;
|
||||
}
|
||||
int num_devices = info->NumberOfDevices();
|
||||
for (int i = 0; i < num_devices; ++i) {
|
||||
const uint32_t kSize = 256;
|
||||
char name[kSize] = {0};
|
||||
char id[kSize] = {0};
|
||||
if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
|
||||
device_names.push_back(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<cricket::Device> devs;
|
||||
if (!dev_manager->GetVideoCaptureDevices(&devs)) {
|
||||
LOG(LS_ERROR) << "Can't enumerate video devices";
|
||||
return NULL;
|
||||
}
|
||||
std::vector<cricket::Device>::iterator dev_it = devs.begin();
|
||||
cricket::VideoCapturer* capturer = NULL;
|
||||
for (; dev_it != devs.end(); ++dev_it) {
|
||||
capturer = dev_manager->CreateVideoCapturer(*dev_it);
|
||||
if (capturer != NULL)
|
||||
|
||||
cricket::WebRtcVideoDeviceCapturerFactory factory;
|
||||
cricket::VideoCapturer* capturer = nullptr;
|
||||
for (const auto& name : device_names) {
|
||||
capturer = factory.Create(cricket::Device(name, 0));
|
||||
if (capturer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return capturer;
|
||||
}
|
||||
|
||||
@ -750,11 +750,6 @@ class FakeVideoEngine : public FakeBaseEngine {
|
||||
const std::vector<VideoCodec>& codecs() const { return codecs_; }
|
||||
void SetCodecs(const std::vector<VideoCodec> codecs) { codecs_ = codecs; }
|
||||
|
||||
bool SetCaptureDevice(const Device* device) {
|
||||
in_device_ = (device) ? device->name : "";
|
||||
options_changed_ = true;
|
||||
return true;
|
||||
}
|
||||
bool SetCapture(bool capture) {
|
||||
capture_ = capture;
|
||||
return true;
|
||||
@ -763,7 +758,6 @@ class FakeVideoEngine : public FakeBaseEngine {
|
||||
private:
|
||||
std::vector<FakeVideoMediaChannel*> channels_;
|
||||
std::vector<VideoCodec> codecs_;
|
||||
std::string in_device_;
|
||||
bool capture_;
|
||||
VideoOptions options_;
|
||||
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
#include "webrtc/media/base/mediacommon.h"
|
||||
#include "webrtc/media/base/videocapturer.h"
|
||||
#include "webrtc/media/base/videocommon.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
#if defined(GOOGLE_CHROME_BUILD) || defined(CHROMIUM_BUILD)
|
||||
#define DISABLE_MEDIA_ENGINE_FACTORY
|
||||
|
||||
@ -30,7 +30,6 @@
|
||||
#include "webrtc/media/base/videobroadcaster.h"
|
||||
#include "webrtc/media/base/videocommon.h"
|
||||
#include "webrtc/media/base/videoframefactory.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
|
||||
namespace cricket {
|
||||
|
||||
@ -109,7 +109,6 @@ class VideoMediaChannelTest : public testing::Test,
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
cricket::Device device("test", "device");
|
||||
engine_.Init();
|
||||
channel_.reset(engine_.CreateChannel(call_.get(), cricket::MediaConfig(),
|
||||
cricket::VideoOptions()));
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MEDIA_DEVICES_DEVICEINFO_H_
|
||||
#define WEBRTC_MEDIA_DEVICES_DEVICEINFO_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
bool GetUsbId(const Device& device, std::string* usb_id);
|
||||
bool GetUsbVersion(const Device& device, std::string* usb_version);
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // WEBRTC_MEDIA_DEVICES_DEVICEINFO_H_
|
||||
@ -1,305 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
#include "webrtc/base/fileutils.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/pathutils.h"
|
||||
#include "webrtc/base/stringutils.h"
|
||||
#include "webrtc/base/thread.h"
|
||||
#include "webrtc/base/windowpicker.h"
|
||||
#include "webrtc/base/windowpickerfactory.h"
|
||||
#include "webrtc/media/base/mediacommon.h"
|
||||
#include "webrtc/media/base/videocapturer.h"
|
||||
#include "webrtc/media/base/videocapturerfactory.h"
|
||||
#include "webrtc/media/devices/deviceinfo.h"
|
||||
|
||||
#ifdef HAVE_WEBRTC_VIDEO
|
||||
#include "webrtc/media/engine/webrtcvideocapturerfactory.h"
|
||||
#endif // HAVE_WEBRTC_VIDEO
|
||||
|
||||
namespace {
|
||||
|
||||
bool StringMatchWithWildcard(
|
||||
const std::pair<const std::basic_string<char>, cricket::VideoFormat> key,
|
||||
const std::string& val) {
|
||||
return rtc::string_match(val.c_str(), key.first.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace cricket {
|
||||
|
||||
// Initialize to empty string.
|
||||
const char DeviceManagerInterface::kDefaultDeviceName[] = "";
|
||||
|
||||
DeviceManager::DeviceManager()
|
||||
: initialized_(false),
|
||||
window_picker_(rtc::WindowPickerFactory::CreateWindowPicker()) {
|
||||
#ifdef HAVE_WEBRTC_VIDEO
|
||||
SetVideoDeviceCapturerFactory(new WebRtcVideoDeviceCapturerFactory());
|
||||
#endif // HAVE_WEBRTC_VIDEO
|
||||
}
|
||||
|
||||
DeviceManager::~DeviceManager() {
|
||||
if (initialized()) {
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceManager::Init() {
|
||||
if (!initialized()) {
|
||||
if (!watcher()->Start()) {
|
||||
return false;
|
||||
}
|
||||
set_initialized(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceManager::Terminate() {
|
||||
if (initialized()) {
|
||||
watcher()->Stop();
|
||||
set_initialized(false);
|
||||
}
|
||||
}
|
||||
|
||||
int DeviceManager::GetCapabilities() {
|
||||
std::vector<Device> devices;
|
||||
int caps = VIDEO_RECV;
|
||||
if (GetAudioInputDevices(&devices) && !devices.empty()) {
|
||||
caps |= AUDIO_SEND;
|
||||
}
|
||||
if (GetAudioOutputDevices(&devices) && !devices.empty()) {
|
||||
caps |= AUDIO_RECV;
|
||||
}
|
||||
if (GetVideoCaptureDevices(&devices) && !devices.empty()) {
|
||||
caps |= VIDEO_SEND;
|
||||
}
|
||||
return caps;
|
||||
}
|
||||
|
||||
bool DeviceManager::GetAudioInputDevices(std::vector<Device>* devices) {
|
||||
return GetAudioDevices(true, devices);
|
||||
}
|
||||
|
||||
bool DeviceManager::GetAudioOutputDevices(std::vector<Device>* devices) {
|
||||
return GetAudioDevices(false, devices);
|
||||
}
|
||||
|
||||
bool DeviceManager::GetAudioInputDevice(const std::string& name, Device* out) {
|
||||
return GetAudioDevice(true, name, out);
|
||||
}
|
||||
|
||||
bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) {
|
||||
return GetAudioDevice(false, name, out);
|
||||
}
|
||||
|
||||
bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
|
||||
devices->clear();
|
||||
#if defined(ANDROID) || defined(WEBRTC_IOS)
|
||||
// On Android and iOS, we treat the camera(s) as a single device. Even if
|
||||
// there are multiple cameras, that's abstracted away at a higher level.
|
||||
Device dev("camera", "1"); // name and ID
|
||||
devices->push_back(dev);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DeviceManager::GetVideoCaptureDevice(const std::string& name,
|
||||
Device* out) {
|
||||
// If the name is empty, return the default device.
|
||||
if (name.empty() || name == kDefaultDeviceName) {
|
||||
return GetDefaultVideoCaptureDevice(out);
|
||||
}
|
||||
|
||||
std::vector<Device> devices;
|
||||
if (!GetVideoCaptureDevices(&devices)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::vector<Device>::const_iterator it = devices.begin();
|
||||
it != devices.end(); ++it) {
|
||||
if (name == it->name) {
|
||||
*out = *it;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceManager::SetVideoCaptureDeviceMaxFormat(
|
||||
const std::string& usb_id,
|
||||
const VideoFormat& max_format) {
|
||||
max_formats_[usb_id] = max_format;
|
||||
}
|
||||
|
||||
void DeviceManager::ClearVideoCaptureDeviceMaxFormat(
|
||||
const std::string& usb_id) {
|
||||
max_formats_.erase(usb_id);
|
||||
}
|
||||
|
||||
VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const {
|
||||
if (!video_device_capturer_factory_) {
|
||||
LOG(LS_ERROR) << "No video capturer factory for devices.";
|
||||
return NULL;
|
||||
}
|
||||
cricket::VideoCapturer* capturer =
|
||||
video_device_capturer_factory_->Create(device);
|
||||
if (!capturer) {
|
||||
return NULL;
|
||||
}
|
||||
LOG(LS_INFO) << "Created VideoCapturer for " << device.name;
|
||||
VideoFormat video_format;
|
||||
bool has_max = GetMaxFormat(device, &video_format);
|
||||
capturer->set_enable_camera_list(has_max);
|
||||
if (has_max) {
|
||||
capturer->ConstrainSupportedFormats(video_format);
|
||||
}
|
||||
return capturer;
|
||||
}
|
||||
|
||||
bool DeviceManager::GetWindows(
|
||||
std::vector<rtc::WindowDescription>* descriptions) {
|
||||
if (!window_picker_) {
|
||||
return false;
|
||||
}
|
||||
return window_picker_->GetWindowList(descriptions);
|
||||
}
|
||||
|
||||
bool DeviceManager::GetDesktops(
|
||||
std::vector<rtc::DesktopDescription>* descriptions) {
|
||||
if (!window_picker_) {
|
||||
return false;
|
||||
}
|
||||
return window_picker_->GetDesktopList(descriptions);
|
||||
}
|
||||
|
||||
VideoCapturer* DeviceManager::CreateScreenCapturer(
|
||||
const ScreencastId& screenid) const {
|
||||
if (!screen_capturer_factory_) {
|
||||
LOG(LS_ERROR) << "No video capturer factory for screens.";
|
||||
return NULL;
|
||||
}
|
||||
return screen_capturer_factory_->Create(screenid);
|
||||
}
|
||||
|
||||
bool DeviceManager::GetAudioDevices(bool input,
|
||||
std::vector<Device>* devs) {
|
||||
devs->clear();
|
||||
#if defined(ANDROID)
|
||||
// Under Android, 0 is always required for the playout device and 0 is the
|
||||
// default for the recording device.
|
||||
devs->push_back(Device("default-device", 0));
|
||||
return true;
|
||||
#else
|
||||
// Other platforms either have their own derived class implementation
|
||||
// (desktop) or don't use device manager for audio devices (iOS).
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name,
|
||||
Device* out) {
|
||||
// If the name is empty, return the default device id.
|
||||
if (name.empty() || name == kDefaultDeviceName) {
|
||||
*out = Device(name, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Device> devices;
|
||||
bool ret = is_input ? GetAudioInputDevices(&devices) :
|
||||
GetAudioOutputDevices(&devices);
|
||||
if (ret) {
|
||||
ret = false;
|
||||
for (size_t i = 0; i < devices.size(); ++i) {
|
||||
if (devices[i].name == name) {
|
||||
*out = devices[i];
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
|
||||
bool ret = false;
|
||||
// We just return the first device.
|
||||
std::vector<Device> devices;
|
||||
ret = (GetVideoCaptureDevices(&devices) && !devices.empty());
|
||||
if (ret) {
|
||||
*device = devices[0];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DeviceManager::IsInWhitelist(const std::string& key,
|
||||
VideoFormat* video_format) const {
|
||||
std::map<std::string, VideoFormat>::const_iterator found =
|
||||
std::search_n(max_formats_.begin(), max_formats_.end(), 1, key,
|
||||
StringMatchWithWildcard);
|
||||
if (found == max_formats_.end()) {
|
||||
return false;
|
||||
}
|
||||
*video_format = found->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceManager::GetMaxFormat(const Device& device,
|
||||
VideoFormat* video_format) const {
|
||||
// Match USB ID if available. Failing that, match device name.
|
||||
std::string usb_id;
|
||||
if (GetUsbId(device, &usb_id) && IsInWhitelist(usb_id, video_format)) {
|
||||
return true;
|
||||
}
|
||||
return IsInWhitelist(device.name, video_format);
|
||||
}
|
||||
|
||||
bool DeviceManager::ShouldDeviceBeIgnored(const std::string& device_name,
|
||||
const char* const exclusion_list[]) {
|
||||
// If exclusion_list is empty return directly.
|
||||
if (!exclusion_list)
|
||||
return false;
|
||||
|
||||
int i = 0;
|
||||
while (exclusion_list[i]) {
|
||||
if (strnicmp(device_name.c_str(), exclusion_list[i],
|
||||
strlen(exclusion_list[i])) == 0) {
|
||||
LOG(LS_INFO) << "Ignoring device " << device_name;
|
||||
return true;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceManager::FilterDevices(std::vector<Device>* devices,
|
||||
const char* const exclusion_list[]) {
|
||||
if (!devices) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::vector<Device>::iterator it = devices->begin();
|
||||
it != devices->end(); ) {
|
||||
if (ShouldDeviceBeIgnored(it->name, exclusion_list)) {
|
||||
it = devices->erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MEDIA_DEVICES_DEVICEMANAGER_H_
|
||||
#define WEBRTC_MEDIA_DEVICES_DEVICEMANAGER_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/sigslot.h"
|
||||
#include "webrtc/base/stringencode.h"
|
||||
#include "webrtc/base/window.h"
|
||||
#include "webrtc/media/base/device.h"
|
||||
#include "webrtc/media/base/screencastid.h"
|
||||
#include "webrtc/media/base/videocapturerfactory.h"
|
||||
#include "webrtc/media/base/videocommon.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class DesktopDescription;
|
||||
class WindowDescription;
|
||||
class WindowPicker;
|
||||
|
||||
}
|
||||
namespace cricket {
|
||||
|
||||
class VideoCapturer;
|
||||
|
||||
// DeviceManagerInterface - interface to manage the audio and
|
||||
// video devices on the system.
|
||||
class DeviceManagerInterface {
|
||||
public:
|
||||
virtual ~DeviceManagerInterface() { }
|
||||
|
||||
// Initialization
|
||||
virtual bool Init() = 0;
|
||||
virtual void Terminate() = 0;
|
||||
|
||||
// Capabilities
|
||||
virtual int GetCapabilities() = 0;
|
||||
|
||||
// Device enumeration
|
||||
virtual bool GetAudioInputDevices(std::vector<Device>* devices) = 0;
|
||||
virtual bool GetAudioOutputDevices(std::vector<Device>* devices) = 0;
|
||||
|
||||
virtual bool GetAudioInputDevice(const std::string& name, Device* out) = 0;
|
||||
virtual bool GetAudioOutputDevice(const std::string& name, Device* out) = 0;
|
||||
|
||||
virtual bool GetVideoCaptureDevices(std::vector<Device>* 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.
|
||||
// Note that once a VideoCapturer has been created, calling this API will
|
||||
// not affect it.
|
||||
virtual void SetVideoCaptureDeviceMaxFormat(
|
||||
const std::string& usb_id,
|
||||
const VideoFormat& max_format) = 0;
|
||||
virtual void ClearVideoCaptureDeviceMaxFormat(const std::string& usb_id) = 0;
|
||||
|
||||
// Device creation
|
||||
virtual VideoCapturer* CreateVideoCapturer(const Device& device) const = 0;
|
||||
|
||||
virtual bool GetWindows(
|
||||
std::vector<rtc::WindowDescription>* descriptions) = 0;
|
||||
virtual bool GetDesktops(
|
||||
std::vector<rtc::DesktopDescription>* descriptions) = 0;
|
||||
virtual VideoCapturer* CreateScreenCapturer(
|
||||
const ScreencastId& screenid) const = 0;
|
||||
|
||||
sigslot::signal0<> SignalDevicesChange;
|
||||
|
||||
static const char kDefaultDeviceName[];
|
||||
};
|
||||
|
||||
class DeviceWatcher {
|
||||
public:
|
||||
explicit DeviceWatcher(DeviceManagerInterface* dm) {}
|
||||
virtual ~DeviceWatcher() {}
|
||||
virtual bool Start() { return true; }
|
||||
virtual void Stop() {}
|
||||
};
|
||||
|
||||
class DeviceManagerFactory {
|
||||
public:
|
||||
static DeviceManagerInterface* Create();
|
||||
|
||||
private:
|
||||
DeviceManagerFactory() {}
|
||||
};
|
||||
|
||||
class DeviceManager : public DeviceManagerInterface {
|
||||
public:
|
||||
DeviceManager();
|
||||
virtual ~DeviceManager();
|
||||
|
||||
// Initialization
|
||||
virtual bool Init();
|
||||
virtual void Terminate();
|
||||
|
||||
// Capabilities
|
||||
virtual int GetCapabilities();
|
||||
|
||||
// Device enumeration
|
||||
virtual bool GetAudioInputDevices(std::vector<Device>* devices);
|
||||
virtual bool GetAudioOutputDevices(std::vector<Device>* devices);
|
||||
|
||||
virtual bool GetAudioInputDevice(const std::string& name, Device* out);
|
||||
virtual bool GetAudioOutputDevice(const std::string& name, Device* out);
|
||||
|
||||
virtual bool GetVideoCaptureDevices(std::vector<Device>* 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<rtc::WindowDescription>* descriptions);
|
||||
virtual bool GetDesktops(
|
||||
std::vector<rtc::DesktopDescription>* descriptions);
|
||||
virtual VideoCapturer* CreateScreenCapturer(
|
||||
const ScreencastId& screenid) const;
|
||||
|
||||
// The exclusion_list MUST be a NULL terminated list.
|
||||
static bool FilterDevices(std::vector<Device>* devices,
|
||||
const char* const exclusion_list[]);
|
||||
bool initialized() const { return initialized_; }
|
||||
|
||||
protected:
|
||||
virtual bool GetAudioDevices(bool input, std::vector<Device>* devs);
|
||||
virtual bool GetAudioDevice(bool is_input, const std::string& name,
|
||||
Device* out);
|
||||
virtual bool GetDefaultVideoCaptureDevice(Device* device);
|
||||
bool IsInWhitelist(const std::string& key, VideoFormat* video_format) const;
|
||||
virtual bool GetMaxFormat(const Device& device,
|
||||
VideoFormat* video_format) const;
|
||||
|
||||
void set_initialized(bool initialized) { initialized_ = initialized; }
|
||||
|
||||
void set_watcher(DeviceWatcher* watcher) { watcher_.reset(watcher); }
|
||||
DeviceWatcher* watcher() { return watcher_.get(); }
|
||||
|
||||
private:
|
||||
// The exclusion_list MUST be a NULL terminated list.
|
||||
static bool ShouldDeviceBeIgnored(const std::string& device_name,
|
||||
const char* const exclusion_list[]);
|
||||
|
||||
bool initialized_;
|
||||
std::unique_ptr<
|
||||
VideoDeviceCapturerFactory> video_device_capturer_factory_;
|
||||
std::unique_ptr<
|
||||
ScreenCapturerFactory> screen_capturer_factory_;
|
||||
std::map<std::string, VideoFormat> max_formats_;
|
||||
std::unique_ptr<DeviceWatcher> watcher_;
|
||||
std::unique_ptr<rtc::WindowPicker> window_picker_;
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // WEBRTC_MEDIA_DEVICES_DEVICEMANAGER_H_
|
||||
@ -1,443 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <objbase.h>
|
||||
#include "webrtc/base/win32.h"
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/arraysize.h"
|
||||
#include "webrtc/base/fileutils.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/pathutils.h"
|
||||
#include "webrtc/base/stream.h"
|
||||
#include "webrtc/base/windowpickerfactory.h"
|
||||
#include "webrtc/media/base/fakevideocapturer.h"
|
||||
#include "webrtc/media/base/screencastid.h"
|
||||
#include "webrtc/media/base/testutils.h"
|
||||
#include "webrtc/media/base/videocapturerfactory.h"
|
||||
#include "webrtc/media/devices/v4llookup.h"
|
||||
|
||||
#ifdef WEBRTC_LINUX
|
||||
// TODO(juberti): Figure out why this doesn't compile on Windows.
|
||||
#include "webrtc/base/fileutils_mock.h"
|
||||
#endif // WEBRTC_LINUX
|
||||
|
||||
using rtc::Pathname;
|
||||
using rtc::FileTimeType;
|
||||
using cricket::Device;
|
||||
using cricket::DeviceManager;
|
||||
using cricket::DeviceManagerFactory;
|
||||
using cricket::DeviceManagerInterface;
|
||||
|
||||
const cricket::VideoFormat kVgaFormat(640, 480,
|
||||
cricket::VideoFormat::FpsToInterval(30),
|
||||
cricket::FOURCC_I420);
|
||||
const cricket::VideoFormat kHdFormat(1280, 720,
|
||||
cricket::VideoFormat::FpsToInterval(30),
|
||||
cricket::FOURCC_I420);
|
||||
|
||||
class FakeVideoDeviceCapturerFactory :
|
||||
public cricket::VideoDeviceCapturerFactory {
|
||||
public:
|
||||
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<DeviceManager*>(dm_.get());
|
||||
device_manager->SetVideoDeviceCapturerFactory(
|
||||
new FakeVideoDeviceCapturerFactory());
|
||||
device_manager->SetScreenCapturerFactory(
|
||||
new FakeScreenCapturerFactory());
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
dm_->Terminate();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<DeviceManagerInterface> dm_;
|
||||
};
|
||||
|
||||
|
||||
// Test that we startup/shutdown properly.
|
||||
TEST(DeviceManagerTest, StartupShutdown) {
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
EXPECT_TRUE(dm->Init());
|
||||
dm->Terminate();
|
||||
}
|
||||
|
||||
// Test CoInitEx behavior
|
||||
#ifdef WIN32
|
||||
TEST(DeviceManagerTest, CoInitialize) {
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
std::vector<Device> devices;
|
||||
// Ensure that calls to video device work if COM is not yet initialized.
|
||||
EXPECT_TRUE(dm->Init());
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevices(&devices));
|
||||
dm->Terminate();
|
||||
// Ensure that the ref count is correct.
|
||||
EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
CoUninitialize();
|
||||
// Ensure that Init works in COINIT_APARTMENTTHREADED setting.
|
||||
EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
|
||||
EXPECT_TRUE(dm->Init());
|
||||
dm->Terminate();
|
||||
CoUninitialize();
|
||||
// Ensure that the ref count is correct.
|
||||
EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
|
||||
CoUninitialize();
|
||||
// Ensure that Init works in COINIT_MULTITHREADED setting.
|
||||
EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
EXPECT_TRUE(dm->Init());
|
||||
dm->Terminate();
|
||||
CoUninitialize();
|
||||
// Ensure that the ref count is correct.
|
||||
EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
CoUninitialize();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test enumerating devices (although we may not find any).
|
||||
TEST(DeviceManagerTest, GetDevices) {
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
std::vector<Device> audio_ins, audio_outs, video_ins;
|
||||
std::vector<cricket::Device> video_in_devs;
|
||||
cricket::Device def_video;
|
||||
EXPECT_TRUE(dm->Init());
|
||||
EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins));
|
||||
EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs));
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_in_devs));
|
||||
EXPECT_EQ(video_ins.size(), video_in_devs.size());
|
||||
// If we have any video devices, we should be able to pick a default.
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevice(
|
||||
cricket::DeviceManagerInterface::kDefaultDeviceName, &def_video)
|
||||
!= video_ins.empty());
|
||||
}
|
||||
|
||||
// Test that we return correct ids for default and bogus devices.
|
||||
TEST(DeviceManagerTest, GetAudioDeviceIds) {
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
Device device;
|
||||
EXPECT_TRUE(dm->Init());
|
||||
EXPECT_TRUE(dm->GetAudioInputDevice(
|
||||
cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
|
||||
EXPECT_EQ("-1", device.id);
|
||||
EXPECT_TRUE(dm->GetAudioOutputDevice(
|
||||
cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
|
||||
EXPECT_EQ("-1", device.id);
|
||||
EXPECT_FALSE(dm->GetAudioInputDevice("_NOT A REAL DEVICE_", &device));
|
||||
EXPECT_FALSE(dm->GetAudioOutputDevice("_NOT A REAL DEVICE_", &device));
|
||||
}
|
||||
|
||||
// Test that we get the video capture device by name properly.
|
||||
TEST(DeviceManagerTest, GetVideoDeviceIds) {
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
Device device;
|
||||
EXPECT_TRUE(dm->Init());
|
||||
EXPECT_FALSE(dm->GetVideoCaptureDevice("_NOT A REAL DEVICE_", &device));
|
||||
std::vector<Device> video_ins;
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
|
||||
if (!video_ins.empty()) {
|
||||
// Get the default device with the parameter kDefaultDeviceName.
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevice(
|
||||
cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
|
||||
|
||||
// Get the first device with the parameter video_ins[0].name.
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevice(video_ins[0].name, &device));
|
||||
EXPECT_EQ(device.name, video_ins[0].name);
|
||||
EXPECT_EQ(device.id, video_ins[0].id);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DeviceManagerTest, VerifyDevicesListsAreCleared) {
|
||||
const std::string imaginary("_NOT A REAL DEVICE_");
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
std::vector<Device> audio_ins, audio_outs, video_ins;
|
||||
audio_ins.push_back(Device(imaginary, imaginary));
|
||||
audio_outs.push_back(Device(imaginary, imaginary));
|
||||
video_ins.push_back(Device(imaginary, imaginary));
|
||||
EXPECT_TRUE(dm->Init());
|
||||
EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins));
|
||||
EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs));
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
|
||||
for (size_t i = 0; i < audio_ins.size(); ++i) {
|
||||
EXPECT_NE(imaginary, audio_ins[i].name);
|
||||
}
|
||||
for (size_t i = 0; i < audio_outs.size(); ++i) {
|
||||
EXPECT_NE(imaginary, audio_outs[i].name);
|
||||
}
|
||||
for (size_t i = 0; i < video_ins.size(); ++i) {
|
||||
EXPECT_NE(imaginary, video_ins[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
static bool CompareDeviceList(std::vector<Device>& devices,
|
||||
const char* const device_list[], int list_size) {
|
||||
if (list_size != static_cast<int>(devices.size())) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < list_size; ++i) {
|
||||
if (devices[i].name.compare(device_list[i]) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(DeviceManagerTest, VerifyFilterDevices) {
|
||||
static const char* const kTotalDevicesName[] = {
|
||||
"Google Camera Adapters are tons of fun.",
|
||||
"device1",
|
||||
"device2",
|
||||
"device3",
|
||||
"device4",
|
||||
"device5",
|
||||
"Google Camera Adapter 0",
|
||||
"Google Camera Adapter 1",
|
||||
};
|
||||
static const char* const kFilteredDevicesName[] = {
|
||||
"device2",
|
||||
"device4",
|
||||
"Google Camera Adapter",
|
||||
NULL,
|
||||
};
|
||||
static const char* const kDevicesName[] = {
|
||||
"device1",
|
||||
"device3",
|
||||
"device5",
|
||||
};
|
||||
std::vector<Device> devices;
|
||||
for (int i = 0; i < arraysize(kTotalDevicesName); ++i) {
|
||||
devices.push_back(Device(kTotalDevicesName[i], i));
|
||||
}
|
||||
EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName,
|
||||
arraysize(kTotalDevicesName)));
|
||||
// Return false if given NULL as the exclusion list.
|
||||
EXPECT_TRUE(DeviceManager::FilterDevices(&devices, NULL));
|
||||
// The devices should not change.
|
||||
EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName,
|
||||
arraysize(kTotalDevicesName)));
|
||||
EXPECT_TRUE(DeviceManager::FilterDevices(&devices, kFilteredDevicesName));
|
||||
EXPECT_TRUE(CompareDeviceList(devices, kDevicesName,
|
||||
arraysize(kDevicesName)));
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_LINUX
|
||||
class FakeV4LLookup : public cricket::V4LLookup {
|
||||
public:
|
||||
explicit FakeV4LLookup(std::vector<std::string> device_paths)
|
||||
: device_paths_(device_paths) {}
|
||||
|
||||
protected:
|
||||
bool CheckIsV4L2Device(const std::string& device) {
|
||||
return std::find(device_paths_.begin(), device_paths_.end(), device)
|
||||
!= device_paths_.end();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> device_paths_;
|
||||
};
|
||||
|
||||
TEST(DeviceManagerTest, GetVideoCaptureDevices_K2_6) {
|
||||
std::vector<std::string> devices;
|
||||
devices.push_back("/dev/video0");
|
||||
devices.push_back("/dev/video5");
|
||||
cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices));
|
||||
|
||||
std::vector<rtc::FakeFileSystem::File> files;
|
||||
files.push_back(rtc::FakeFileSystem::File("/dev/video0", ""));
|
||||
files.push_back(rtc::FakeFileSystem::File("/dev/video5", ""));
|
||||
files.push_back(rtc::FakeFileSystem::File(
|
||||
"/sys/class/video4linux/video0/name", "Video Device 1"));
|
||||
files.push_back(rtc::FakeFileSystem::File(
|
||||
"/sys/class/video4linux/video1/model", "Bad Device"));
|
||||
files.push_back(
|
||||
rtc::FakeFileSystem::File("/sys/class/video4linux/video5/model",
|
||||
"Video Device 2"));
|
||||
rtc::FilesystemScope fs(new rtc::FakeFileSystem(files));
|
||||
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
std::vector<Device> video_ins;
|
||||
EXPECT_TRUE(dm->Init());
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
|
||||
EXPECT_EQ(2u, video_ins.size());
|
||||
EXPECT_EQ("Video Device 1", video_ins.at(0).name);
|
||||
EXPECT_EQ("Video Device 2", video_ins.at(1).name);
|
||||
}
|
||||
|
||||
TEST(DeviceManagerTest, GetVideoCaptureDevices_K2_4) {
|
||||
std::vector<std::string> devices;
|
||||
devices.push_back("/dev/video0");
|
||||
devices.push_back("/dev/video5");
|
||||
cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices));
|
||||
|
||||
std::vector<rtc::FakeFileSystem::File> files;
|
||||
files.push_back(rtc::FakeFileSystem::File("/dev/video0", ""));
|
||||
files.push_back(rtc::FakeFileSystem::File("/dev/video5", ""));
|
||||
files.push_back(rtc::FakeFileSystem::File(
|
||||
"/proc/video/dev/video0",
|
||||
"param1: value1\nname: Video Device 1\n param2: value2\n"));
|
||||
files.push_back(rtc::FakeFileSystem::File(
|
||||
"/proc/video/dev/video1",
|
||||
"param1: value1\nname: Bad Device\n param2: value2\n"));
|
||||
files.push_back(rtc::FakeFileSystem::File(
|
||||
"/proc/video/dev/video5",
|
||||
"param1: value1\nname: Video Device 2\n param2: value2\n"));
|
||||
rtc::FilesystemScope fs(new rtc::FakeFileSystem(files));
|
||||
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
std::vector<Device> video_ins;
|
||||
EXPECT_TRUE(dm->Init());
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
|
||||
EXPECT_EQ(2u, video_ins.size());
|
||||
EXPECT_EQ("Video Device 1", video_ins.at(0).name);
|
||||
EXPECT_EQ("Video Device 2", video_ins.at(1).name);
|
||||
}
|
||||
|
||||
TEST(DeviceManagerTest, GetVideoCaptureDevices_KUnknown) {
|
||||
std::vector<std::string> devices;
|
||||
devices.push_back("/dev/video0");
|
||||
devices.push_back("/dev/video5");
|
||||
cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices));
|
||||
|
||||
std::vector<rtc::FakeFileSystem::File> files;
|
||||
files.push_back(rtc::FakeFileSystem::File("/dev/video0", ""));
|
||||
files.push_back(rtc::FakeFileSystem::File("/dev/video1", ""));
|
||||
files.push_back(rtc::FakeFileSystem::File("/dev/video5", ""));
|
||||
rtc::FilesystemScope fs(new rtc::FakeFileSystem(files));
|
||||
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
std::vector<Device> video_ins;
|
||||
EXPECT_TRUE(dm->Init());
|
||||
EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
|
||||
EXPECT_EQ(2u, video_ins.size());
|
||||
EXPECT_EQ("/dev/video0", video_ins.at(0).name);
|
||||
EXPECT_EQ("/dev/video5", video_ins.at(1).name);
|
||||
}
|
||||
#endif // WEBRTC_LINUX
|
||||
|
||||
// TODO(noahric): These are flaky on windows on headless machines.
|
||||
#ifndef WIN32
|
||||
TEST(DeviceManagerTest, GetWindows) {
|
||||
if (!rtc::WindowPickerFactory::IsSupported()) {
|
||||
LOG(LS_INFO) << "skipping test: window capturing is not supported with "
|
||||
<< "current configuration.";
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
dm->SetScreenCapturerFactory(new FakeScreenCapturerFactory());
|
||||
std::vector<rtc::WindowDescription> descriptions;
|
||||
EXPECT_TRUE(dm->Init());
|
||||
if (!dm->GetWindows(&descriptions) || descriptions.empty()) {
|
||||
LOG(LS_INFO) << "skipping test: window capturing. Does not have any "
|
||||
<< "windows to capture.";
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<cricket::VideoCapturer> 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).
|
||||
// Remove the following line as soon as this has been resolved.
|
||||
rtc::Thread::Current()->ProcessMessages(1);
|
||||
}
|
||||
|
||||
TEST(DeviceManagerTest, GetDesktops) {
|
||||
if (!rtc::WindowPickerFactory::IsSupported()) {
|
||||
LOG(LS_INFO) << "skipping test: desktop capturing is not supported with "
|
||||
<< "current configuration.";
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
|
||||
dm->SetScreenCapturerFactory(new FakeScreenCapturerFactory());
|
||||
std::vector<rtc::DesktopDescription> descriptions;
|
||||
EXPECT_TRUE(dm->Init());
|
||||
if (!dm->GetDesktops(&descriptions) || descriptions.empty()) {
|
||||
LOG(LS_INFO) << "skipping test: desktop capturing. Does not have any "
|
||||
<< "desktops to capture.";
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<cricket::VideoCapturer> capturer(dm->CreateScreenCapturer(
|
||||
cricket::ScreencastId(descriptions.front().id())));
|
||||
EXPECT_FALSE(capturer.get() == NULL);
|
||||
}
|
||||
#endif // !WIN32
|
||||
|
||||
TEST_F(DeviceManagerTestFake, CaptureConstraintsWhitelisted) {
|
||||
const Device device("white", "white_id");
|
||||
dm_->SetVideoCaptureDeviceMaxFormat(device.name, kHdFormat);
|
||||
std::unique_ptr<cricket::VideoCapturer> capturer(
|
||||
dm_->CreateVideoCapturer(device));
|
||||
cricket::VideoFormat best_format;
|
||||
capturer->set_enable_camera_list(true);
|
||||
EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format));
|
||||
EXPECT_EQ(kHdFormat, best_format);
|
||||
}
|
||||
|
||||
TEST_F(DeviceManagerTestFake, CaptureConstraintsNotWhitelisted) {
|
||||
const Device device("regular", "regular_id");
|
||||
std::unique_ptr<cricket::VideoCapturer> capturer(
|
||||
dm_->CreateVideoCapturer(device));
|
||||
cricket::VideoFormat best_format;
|
||||
capturer->set_enable_camera_list(true);
|
||||
EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format));
|
||||
EXPECT_EQ(kHdFormat, best_format);
|
||||
}
|
||||
|
||||
TEST_F(DeviceManagerTestFake, CaptureConstraintsUnWhitelisted) {
|
||||
const Device device("un_white", "un_white_id");
|
||||
dm_->SetVideoCaptureDeviceMaxFormat(device.name, kHdFormat);
|
||||
dm_->ClearVideoCaptureDeviceMaxFormat(device.name);
|
||||
std::unique_ptr<cricket::VideoCapturer> capturer(
|
||||
dm_->CreateVideoCapturer(device));
|
||||
cricket::VideoFormat best_format;
|
||||
capturer->set_enable_camera_list(true);
|
||||
EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format));
|
||||
EXPECT_EQ(kHdFormat, best_format);
|
||||
}
|
||||
|
||||
TEST_F(DeviceManagerTestFake, CaptureConstraintsWildcard) {
|
||||
const Device device("any_device", "any_device");
|
||||
dm_->SetVideoCaptureDeviceMaxFormat("*", kHdFormat);
|
||||
std::unique_ptr<cricket::VideoCapturer> capturer(
|
||||
dm_->CreateVideoCapturer(device));
|
||||
cricket::VideoFormat best_format;
|
||||
capturer->set_enable_camera_list(true);
|
||||
EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format));
|
||||
EXPECT_EQ(kHdFormat, best_format);
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/media/devices/dummydevicemanager.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
const char DeviceManagerInterface::kDefaultDeviceName[] = "";
|
||||
|
||||
DeviceManagerInterface* DeviceManagerFactory::Create() {
|
||||
return new DummyDeviceManager();
|
||||
}
|
||||
|
||||
}; // namespace cricket
|
||||
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MEDIA_DEVICES_DUMMYDEVICEMANAGER_H_
|
||||
#define WEBRTC_MEDIA_DEVICES_DUMMYDEVICEMANAGER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/media/base/mediacommon.h"
|
||||
#include "webrtc/media/devices/fakedevicemanager.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class DummyDeviceManager : public FakeDeviceManager {
|
||||
public:
|
||||
DummyDeviceManager() {
|
||||
std::vector<std::string> devices;
|
||||
devices.push_back(DeviceManagerInterface::kDefaultDeviceName);
|
||||
SetAudioInputDevices(devices);
|
||||
SetAudioOutputDevices(devices);
|
||||
SetVideoCaptureDevices(devices);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // WEBRTC_MEDIA_DEVICES_DUMMYDEVICEMANAGER_H_
|
||||
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/media/devices/dummydevicemanager.h"
|
||||
|
||||
using cricket::Device;
|
||||
using cricket::DummyDeviceManager;
|
||||
|
||||
// Test that we startup/shutdown properly.
|
||||
TEST(DummyDeviceManagerTest, StartupShutdown) {
|
||||
DummyDeviceManager dm;
|
||||
EXPECT_TRUE(dm.Init());
|
||||
dm.Terminate();
|
||||
}
|
||||
|
||||
// Test enumerating capabilities.
|
||||
TEST(DummyDeviceManagerTest, GetCapabilities) {
|
||||
DummyDeviceManager dm;
|
||||
int capabilities = dm.GetCapabilities();
|
||||
EXPECT_EQ((cricket::AUDIO_SEND | cricket::AUDIO_RECV |
|
||||
cricket::VIDEO_SEND | cricket::VIDEO_RECV), capabilities);
|
||||
}
|
||||
|
||||
// Test enumerating devices.
|
||||
TEST(DummyDeviceManagerTest, GetDevices) {
|
||||
DummyDeviceManager dm;
|
||||
EXPECT_TRUE(dm.Init());
|
||||
std::vector<Device> audio_ins, audio_outs, video_ins;
|
||||
EXPECT_TRUE(dm.GetAudioInputDevices(&audio_ins));
|
||||
EXPECT_TRUE(dm.GetAudioOutputDevices(&audio_outs));
|
||||
EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_ins));
|
||||
}
|
||||
|
||||
// Test that we return correct ids for default and bogus devices.
|
||||
TEST(DummyDeviceManagerTest, GetAudioDeviceIds) {
|
||||
DummyDeviceManager dm;
|
||||
Device device;
|
||||
EXPECT_TRUE(dm.Init());
|
||||
EXPECT_TRUE(dm.GetAudioInputDevice(
|
||||
cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
|
||||
EXPECT_EQ("-1", device.id);
|
||||
EXPECT_TRUE(dm.GetAudioOutputDevice(
|
||||
cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
|
||||
EXPECT_EQ("-1", device.id);
|
||||
EXPECT_FALSE(dm.GetAudioInputDevice("_NOT A REAL DEVICE_", &device));
|
||||
EXPECT_FALSE(dm.GetAudioOutputDevice("_NOT A REAL DEVICE_", &device));
|
||||
}
|
||||
|
||||
// Test that we get the video capture device by name properly.
|
||||
TEST(DummyDeviceManagerTest, GetVideoDeviceIds) {
|
||||
DummyDeviceManager dm;
|
||||
Device device;
|
||||
EXPECT_TRUE(dm.Init());
|
||||
EXPECT_FALSE(dm.GetVideoCaptureDevice("_NOT A REAL DEVICE_", &device));
|
||||
EXPECT_TRUE(dm.GetVideoCaptureDevice(
|
||||
cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
|
||||
}
|
||||
|
||||
TEST(DummyDeviceManagerTest, VerifyDevicesListsAreCleared) {
|
||||
const std::string imaginary("_NOT A REAL DEVICE_");
|
||||
DummyDeviceManager dm;
|
||||
std::vector<Device> audio_ins, audio_outs, video_ins;
|
||||
audio_ins.push_back(Device(imaginary, imaginary));
|
||||
audio_outs.push_back(Device(imaginary, imaginary));
|
||||
video_ins.push_back(Device(imaginary, imaginary));
|
||||
EXPECT_TRUE(dm.Init());
|
||||
EXPECT_TRUE(dm.GetAudioInputDevices(&audio_ins));
|
||||
EXPECT_TRUE(dm.GetAudioOutputDevices(&audio_outs));
|
||||
EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_ins));
|
||||
for (size_t i = 0; i < audio_ins.size(); ++i) {
|
||||
EXPECT_NE(imaginary, audio_ins[i].name);
|
||||
}
|
||||
for (size_t i = 0; i < audio_outs.size(); ++i) {
|
||||
EXPECT_NE(imaginary, audio_outs[i].name);
|
||||
}
|
||||
for (size_t i = 0; i < video_ins.size(); ++i) {
|
||||
EXPECT_NE(imaginary, video_ins[i].name);
|
||||
}
|
||||
}
|
||||
@ -1,222 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MEDIA_DEVICES_FAKEDEVICEMANAGER_H_
|
||||
#define WEBRTC_MEDIA_DEVICES_FAKEDEVICEMANAGER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/window.h"
|
||||
#include "webrtc/base/windowpicker.h"
|
||||
#include "webrtc/media/base/fakevideocapturer.h"
|
||||
#include "webrtc/media/base/mediacommon.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class FakeDeviceManager : public DeviceManagerInterface {
|
||||
public:
|
||||
FakeDeviceManager() {}
|
||||
virtual bool Init() {
|
||||
return true;
|
||||
}
|
||||
virtual void Terminate() {
|
||||
}
|
||||
virtual int GetCapabilities() {
|
||||
std::vector<Device> devices;
|
||||
int caps = VIDEO_RECV;
|
||||
if (!input_devices_.empty()) {
|
||||
caps |= AUDIO_SEND;
|
||||
}
|
||||
if (!output_devices_.empty()) {
|
||||
caps |= AUDIO_RECV;
|
||||
}
|
||||
if (!vidcap_devices_.empty()) {
|
||||
caps |= VIDEO_SEND;
|
||||
}
|
||||
return caps;
|
||||
}
|
||||
virtual bool GetAudioInputDevices(std::vector<Device>* devs) {
|
||||
*devs = input_devices_;
|
||||
return true;
|
||||
}
|
||||
virtual bool GetAudioOutputDevices(std::vector<Device>* devs) {
|
||||
*devs = output_devices_;
|
||||
return true;
|
||||
}
|
||||
virtual bool GetAudioInputDevice(const std::string& name, Device* out) {
|
||||
return GetAudioDevice(true, name, out);
|
||||
}
|
||||
virtual bool GetAudioOutputDevice(const std::string& name, Device* out) {
|
||||
return GetAudioDevice(false, name, out);
|
||||
}
|
||||
virtual bool GetVideoCaptureDevices(std::vector<Device>* devs) {
|
||||
*devs = vidcap_devices_;
|
||||
return true;
|
||||
}
|
||||
virtual void SetVideoDeviceCapturerFactory(
|
||||
VideoDeviceCapturerFactory* 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) {
|
||||
max_formats_[usb_id] = max_format;
|
||||
}
|
||||
bool IsMaxFormatForDevice(const std::string& usb_id,
|
||||
const VideoFormat& max_format) const {
|
||||
std::map<std::string, VideoFormat>::const_iterator found =
|
||||
max_formats_.find(usb_id);
|
||||
return (found != max_formats_.end()) ?
|
||||
max_format == found->second :
|
||||
false;
|
||||
}
|
||||
virtual void ClearVideoCaptureDeviceMaxFormat(const std::string& usb_id) {
|
||||
max_formats_.erase(usb_id);
|
||||
}
|
||||
virtual VideoCapturer* CreateVideoCapturer(const Device& device) const {
|
||||
return new FakeVideoCapturer();
|
||||
}
|
||||
virtual VideoCapturer* CreateScreenCapturer(
|
||||
const ScreencastId& screenid) const {
|
||||
if (!screen_capturer_factory_) {
|
||||
return new FakeVideoCapturer();
|
||||
}
|
||||
return screen_capturer_factory_->Create(screenid);
|
||||
}
|
||||
virtual bool GetWindows(
|
||||
std::vector<rtc::WindowDescription>* descriptions) {
|
||||
descriptions->clear();
|
||||
const uint32_t id = 1u; // Note that 0 is not a valid ID.
|
||||
const rtc::WindowId window_id =
|
||||
rtc::WindowId::Cast(id);
|
||||
std::string title = "FakeWindow";
|
||||
rtc::WindowDescription window_description(window_id, title);
|
||||
descriptions->push_back(window_description);
|
||||
return true;
|
||||
}
|
||||
virtual VideoCapturer* CreateWindowCapturer(rtc::WindowId window) {
|
||||
if (!window.IsValid()) {
|
||||
return NULL;
|
||||
}
|
||||
return new FakeVideoCapturer;
|
||||
}
|
||||
virtual bool GetDesktops(
|
||||
std::vector<rtc::DesktopDescription>* descriptions) {
|
||||
descriptions->clear();
|
||||
const int id = 0;
|
||||
const int valid_index = 0;
|
||||
const rtc::DesktopId desktop_id =
|
||||
rtc::DesktopId::Cast(id, valid_index);
|
||||
std::string title = "FakeDesktop";
|
||||
rtc::DesktopDescription desktop_description(desktop_id, title);
|
||||
descriptions->push_back(desktop_description);
|
||||
return true;
|
||||
}
|
||||
virtual VideoCapturer* CreateDesktopCapturer(rtc::DesktopId desktop) {
|
||||
if (!desktop.IsValid()) {
|
||||
return NULL;
|
||||
}
|
||||
return new FakeVideoCapturer;
|
||||
}
|
||||
|
||||
virtual bool GetDefaultVideoCaptureDevice(Device* device) {
|
||||
if (vidcap_devices_.empty()) {
|
||||
return false;
|
||||
}
|
||||
*device = vidcap_devices_[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
|
||||
bool QtKitToSgDevice(const std::string& qtkit_name, Device* out) {
|
||||
out->name = qtkit_name;
|
||||
out->id = "sg:" + qtkit_name;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SetAudioInputDevices(const std::vector<std::string>& devices) {
|
||||
input_devices_.clear();
|
||||
for (size_t i = 0; i < devices.size(); ++i) {
|
||||
input_devices_.push_back(Device(devices[i],
|
||||
static_cast<int>(i)));
|
||||
}
|
||||
SignalDevicesChange();
|
||||
}
|
||||
void SetAudioOutputDevices(const std::vector<std::string>& devices) {
|
||||
output_devices_.clear();
|
||||
for (size_t i = 0; i < devices.size(); ++i) {
|
||||
output_devices_.push_back(Device(devices[i],
|
||||
static_cast<int>(i)));
|
||||
}
|
||||
SignalDevicesChange();
|
||||
}
|
||||
void SetVideoCaptureDevices(const std::vector<std::string>& devices) {
|
||||
vidcap_devices_.clear();
|
||||
for (size_t i = 0; i < devices.size(); ++i) {
|
||||
vidcap_devices_.push_back(Device(devices[i],
|
||||
static_cast<int>(i)));
|
||||
}
|
||||
SignalDevicesChange();
|
||||
}
|
||||
virtual bool GetVideoCaptureDevice(const std::string& name,
|
||||
Device* out) {
|
||||
if (vidcap_devices_.empty())
|
||||
return false;
|
||||
|
||||
// If the name is empty, return the default device.
|
||||
if (name.empty() || name == kDefaultDeviceName) {
|
||||
*out = vidcap_devices_[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
return FindDeviceByName(vidcap_devices_, name, out);
|
||||
}
|
||||
bool GetAudioDevice(bool is_input, const std::string& name,
|
||||
Device* out) {
|
||||
// If the name is empty, return the default device.
|
||||
if (name.empty() || name == kDefaultDeviceName) {
|
||||
*out = Device(name, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return FindDeviceByName((is_input ? input_devices_ : output_devices_),
|
||||
name, out);
|
||||
}
|
||||
static bool FindDeviceByName(const std::vector<Device>& devices,
|
||||
const std::string& name,
|
||||
Device* out) {
|
||||
for (std::vector<Device>::const_iterator it = devices.begin();
|
||||
it != devices.end(); ++it) {
|
||||
if (name == it->name) {
|
||||
*out = *it;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Device> input_devices_;
|
||||
std::vector<Device> output_devices_;
|
||||
std::vector<Device> vidcap_devices_;
|
||||
std::map<std::string, VideoFormat> max_formats_;
|
||||
std::unique_ptr<
|
||||
ScreenCapturerFactory> screen_capturer_factory_;
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // WEBRTC_MEDIA_DEVICES_FAKEDEVICEMANAGER_H_
|
||||
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/media/devices/deviceinfo.h"
|
||||
|
||||
#include "webrtc/base/common.h" // for ASSERT
|
||||
#include "webrtc/media/devices/libudevsymboltable.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class ScopedLibUdev {
|
||||
public:
|
||||
static ScopedLibUdev* Create() {
|
||||
ScopedLibUdev* ret_val = new ScopedLibUdev();
|
||||
if (!ret_val->Init()) {
|
||||
delete ret_val;
|
||||
return NULL;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
~ScopedLibUdev() {
|
||||
libudev_.Unload();
|
||||
}
|
||||
|
||||
LibUDevSymbolTable* instance() { return &libudev_; }
|
||||
|
||||
private:
|
||||
ScopedLibUdev() {}
|
||||
|
||||
bool Init() {
|
||||
return libudev_.Load() &&
|
||||
!IsWrongLibUDevAbiVersion(libudev_.GetDllHandle());
|
||||
}
|
||||
|
||||
LibUDevSymbolTable libudev_;
|
||||
};
|
||||
|
||||
class ScopedUdev {
|
||||
public:
|
||||
explicit ScopedUdev(LibUDevSymbolTable* libudev) : libudev_(libudev) {
|
||||
udev_ = libudev_->udev_new()();
|
||||
}
|
||||
~ScopedUdev() {
|
||||
if (udev_) libudev_->udev_unref()(udev_);
|
||||
}
|
||||
|
||||
udev* instance() { return udev_; }
|
||||
|
||||
private:
|
||||
LibUDevSymbolTable* libudev_;
|
||||
udev* udev_;
|
||||
};
|
||||
|
||||
class ScopedUdevEnumerate {
|
||||
public:
|
||||
ScopedUdevEnumerate(LibUDevSymbolTable* libudev, udev* udev)
|
||||
: libudev_(libudev) {
|
||||
enumerate_ = libudev_->udev_enumerate_new()(udev);
|
||||
}
|
||||
~ScopedUdevEnumerate() {
|
||||
if (enumerate_) libudev_->udev_enumerate_unref()(enumerate_);
|
||||
}
|
||||
|
||||
udev_enumerate* instance() { return enumerate_; }
|
||||
|
||||
private:
|
||||
LibUDevSymbolTable* libudev_;
|
||||
udev_enumerate* enumerate_;
|
||||
};
|
||||
|
||||
bool GetUsbProperty(const Device& device, const char* property_name,
|
||||
std::string* property) {
|
||||
std::unique_ptr<ScopedLibUdev> libudev_context(ScopedLibUdev::Create());
|
||||
if (!libudev_context) {
|
||||
return false;
|
||||
}
|
||||
ScopedUdev udev_context(libudev_context->instance());
|
||||
if (!udev_context.instance()) {
|
||||
return false;
|
||||
}
|
||||
ScopedUdevEnumerate enumerate_context(libudev_context->instance(),
|
||||
udev_context.instance());
|
||||
if (!enumerate_context.instance()) {
|
||||
return false;
|
||||
}
|
||||
libudev_context->instance()->udev_enumerate_add_match_subsystem()(
|
||||
enumerate_context.instance(), "video4linux");
|
||||
libudev_context->instance()->udev_enumerate_scan_devices()(
|
||||
enumerate_context.instance());
|
||||
udev_list_entry* devices =
|
||||
libudev_context->instance()->udev_enumerate_get_list_entry()(
|
||||
enumerate_context.instance());
|
||||
if (!devices) {
|
||||
return false;
|
||||
}
|
||||
udev_list_entry* dev_list_entry = NULL;
|
||||
const char* property_value = NULL;
|
||||
// Macro that expands to a for-loop over the devices.
|
||||
for (dev_list_entry = devices; dev_list_entry != NULL;
|
||||
dev_list_entry = libudev_context->instance()->
|
||||
udev_list_entry_get_next()(dev_list_entry)) {
|
||||
const char* path = libudev_context->instance()->udev_list_entry_get_name()(
|
||||
dev_list_entry);
|
||||
if (!path) continue;
|
||||
udev_device* dev =
|
||||
libudev_context->instance()->udev_device_new_from_syspath()(
|
||||
udev_context.instance(), path);
|
||||
if (!dev) continue;
|
||||
const char* device_node =
|
||||
libudev_context->instance()->udev_device_get_devnode()(dev);
|
||||
if (!device_node || device.id.compare(device_node) != 0) {
|
||||
continue;
|
||||
}
|
||||
dev = libudev_context->instance()->
|
||||
udev_device_get_parent_with_subsystem_devtype()(
|
||||
dev, "usb", "usb_device");
|
||||
if (!dev) continue;
|
||||
property_value = libudev_context->instance()->
|
||||
udev_device_get_sysattr_value()(
|
||||
dev, property_name);
|
||||
break;
|
||||
}
|
||||
if (!property_value) {
|
||||
return false;
|
||||
}
|
||||
property->assign(property_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetUsbId(const Device& device, std::string* usb_id) {
|
||||
std::string id_vendor;
|
||||
std::string id_product;
|
||||
if (!GetUsbProperty(device, "idVendor", &id_vendor)) {
|
||||
return false;
|
||||
}
|
||||
if (!GetUsbProperty(device, "idProduct", &id_product)) {
|
||||
return false;
|
||||
}
|
||||
usb_id->clear();
|
||||
usb_id->append(id_vendor);
|
||||
usb_id->append(":");
|
||||
usb_id->append(id_product);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetUsbVersion(const Device& device, std::string* usb_version) {
|
||||
return GetUsbProperty(device, "version", usb_version);
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
@ -1,396 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/media/devices/linuxdevicemanager.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/base/fileutils.h"
|
||||
#include "webrtc/base/linux.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/pathutils.h"
|
||||
#include "webrtc/base/physicalsocketserver.h"
|
||||
#include "webrtc/base/stream.h"
|
||||
#include "webrtc/base/stringutils.h"
|
||||
#include "webrtc/base/thread.h"
|
||||
#include "webrtc/media/base/mediacommon.h"
|
||||
#include "webrtc/media/devices/libudevsymboltable.h"
|
||||
#include "webrtc/media/devices/v4llookup.h"
|
||||
#include "webrtc/sound/platformsoundsystem.h"
|
||||
#include "webrtc/sound/platformsoundsystemfactory.h"
|
||||
#include "webrtc/sound/sounddevicelocator.h"
|
||||
#include "webrtc/sound/soundsysteminterface.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
DeviceManagerInterface* DeviceManagerFactory::Create() {
|
||||
return new LinuxDeviceManager();
|
||||
}
|
||||
|
||||
class LinuxDeviceWatcher
|
||||
: public DeviceWatcher,
|
||||
private rtc::Dispatcher {
|
||||
public:
|
||||
explicit LinuxDeviceWatcher(DeviceManagerInterface* dm);
|
||||
virtual ~LinuxDeviceWatcher();
|
||||
virtual bool Start();
|
||||
virtual void Stop();
|
||||
|
||||
private:
|
||||
virtual uint32_t GetRequestedEvents();
|
||||
virtual void OnPreEvent(uint32_t ff);
|
||||
virtual void OnEvent(uint32_t ff, int err);
|
||||
virtual int GetDescriptor();
|
||||
virtual bool IsDescriptorClosed();
|
||||
|
||||
DeviceManagerInterface* manager_;
|
||||
LibUDevSymbolTable libudev_;
|
||||
struct udev* udev_;
|
||||
struct udev_monitor* udev_monitor_;
|
||||
bool registered_;
|
||||
};
|
||||
|
||||
static const char* const kFilteredAudioDevicesName[] = {
|
||||
#if defined(CHROMEOS)
|
||||
"surround40:",
|
||||
"surround41:",
|
||||
"surround50:",
|
||||
"surround51:",
|
||||
"surround71:",
|
||||
"iec958:", // S/PDIF
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
static const char* kFilteredVideoDevicesName[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
LinuxDeviceManager::LinuxDeviceManager()
|
||||
: sound_system_(new rtc::PlatformSoundSystemFactory()) {
|
||||
set_watcher(new LinuxDeviceWatcher(this));
|
||||
}
|
||||
|
||||
LinuxDeviceManager::~LinuxDeviceManager() {
|
||||
}
|
||||
|
||||
bool LinuxDeviceManager::GetAudioDevices(bool input,
|
||||
std::vector<Device>* devs) {
|
||||
devs->clear();
|
||||
if (!sound_system_.get()) {
|
||||
return false;
|
||||
}
|
||||
rtc::SoundSystemInterface::SoundDeviceLocatorList list;
|
||||
bool success;
|
||||
if (input) {
|
||||
success = sound_system_->EnumerateCaptureDevices(&list);
|
||||
} else {
|
||||
success = sound_system_->EnumeratePlaybackDevices(&list);
|
||||
}
|
||||
if (!success) {
|
||||
LOG(LS_ERROR) << "Can't enumerate devices";
|
||||
sound_system_.release();
|
||||
return false;
|
||||
}
|
||||
// We have to start the index at 1 because webrtc VoiceEngine puts the default
|
||||
// device at index 0, but Enumerate(Capture|Playback)Devices does not include
|
||||
// a locator for the default device.
|
||||
int index = 1;
|
||||
for (rtc::SoundSystemInterface::SoundDeviceLocatorList::iterator i = list.begin();
|
||||
i != list.end();
|
||||
++i, ++index) {
|
||||
devs->push_back(Device((*i)->name(), index));
|
||||
}
|
||||
rtc::SoundSystemInterface::ClearSoundDeviceLocatorList(&list);
|
||||
sound_system_.release();
|
||||
return FilterDevices(devs, kFilteredAudioDevicesName);
|
||||
}
|
||||
|
||||
static const std::string kVideoMetaPathK2_4("/proc/video/dev/");
|
||||
static const std::string kVideoMetaPathK2_6("/sys/class/video4linux/");
|
||||
|
||||
enum MetaType { M2_4, M2_6, NONE };
|
||||
|
||||
static void ScanDeviceDirectory(const std::string& devdir,
|
||||
std::vector<Device>* devices) {
|
||||
std::unique_ptr<rtc::DirectoryIterator> directoryIterator(
|
||||
rtc::Filesystem::IterateDirectory());
|
||||
|
||||
if (directoryIterator->Iterate(rtc::Pathname(devdir))) {
|
||||
do {
|
||||
std::string filename = directoryIterator->Name();
|
||||
std::string device_name = devdir + filename;
|
||||
if (!directoryIterator->IsDots()) {
|
||||
if (filename.find("video") == 0 &&
|
||||
V4LLookup::IsV4L2Device(device_name)) {
|
||||
devices->push_back(Device(device_name, device_name));
|
||||
}
|
||||
}
|
||||
} while (directoryIterator->Next());
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GetVideoDeviceNameK2_6(const std::string& device_meta_path) {
|
||||
std::string device_name;
|
||||
|
||||
std::unique_ptr<rtc::FileStream> device_meta_stream(
|
||||
rtc::Filesystem::OpenFile(device_meta_path, "r"));
|
||||
|
||||
if (device_meta_stream) {
|
||||
if (device_meta_stream->ReadLine(&device_name) != rtc::SR_SUCCESS) {
|
||||
LOG(LS_ERROR) << "Failed to read V4L2 device meta " << device_meta_path;
|
||||
}
|
||||
device_meta_stream->Close();
|
||||
}
|
||||
|
||||
return device_name;
|
||||
}
|
||||
|
||||
static std::string Trim(const std::string& s, const std::string& drop = " \t") {
|
||||
std::string::size_type first = s.find_first_not_of(drop);
|
||||
std::string::size_type last = s.find_last_not_of(drop);
|
||||
|
||||
if (first == std::string::npos || last == std::string::npos)
|
||||
return std::string("");
|
||||
|
||||
return s.substr(first, last - first + 1);
|
||||
}
|
||||
|
||||
static std::string GetVideoDeviceNameK2_4(const std::string& device_meta_path) {
|
||||
rtc::ConfigParser::MapVector all_values;
|
||||
|
||||
rtc::ConfigParser config_parser;
|
||||
rtc::FileStream* file_stream =
|
||||
rtc::Filesystem::OpenFile(device_meta_path, "r");
|
||||
|
||||
if (file_stream == NULL) return "";
|
||||
|
||||
config_parser.Attach(file_stream);
|
||||
config_parser.Parse(&all_values);
|
||||
|
||||
for (rtc::ConfigParser::MapVector::iterator i = all_values.begin();
|
||||
i != all_values.end(); ++i) {
|
||||
rtc::ConfigParser::SimpleMap::iterator device_name_i =
|
||||
i->find("name");
|
||||
|
||||
if (device_name_i != i->end()) {
|
||||
return device_name_i->second;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string GetVideoDeviceName(MetaType meta,
|
||||
const std::string& device_file_name) {
|
||||
std::string device_meta_path;
|
||||
std::string device_name;
|
||||
std::string meta_file_path;
|
||||
|
||||
if (meta == M2_6) {
|
||||
meta_file_path = kVideoMetaPathK2_6 + device_file_name + "/name";
|
||||
|
||||
LOG(LS_INFO) << "Trying " + meta_file_path;
|
||||
device_name = GetVideoDeviceNameK2_6(meta_file_path);
|
||||
|
||||
if (device_name.empty()) {
|
||||
meta_file_path = kVideoMetaPathK2_6 + device_file_name + "/model";
|
||||
|
||||
LOG(LS_INFO) << "Trying " << meta_file_path;
|
||||
device_name = GetVideoDeviceNameK2_6(meta_file_path);
|
||||
}
|
||||
} else {
|
||||
meta_file_path = kVideoMetaPathK2_4 + device_file_name;
|
||||
LOG(LS_INFO) << "Trying " << meta_file_path;
|
||||
device_name = GetVideoDeviceNameK2_4(meta_file_path);
|
||||
}
|
||||
|
||||
if (device_name.empty()) {
|
||||
device_name = "/dev/" + device_file_name;
|
||||
LOG(LS_ERROR)
|
||||
<< "Device name not found, defaulting to device path " << device_name;
|
||||
}
|
||||
|
||||
LOG(LS_INFO) << "Name for " << device_file_name << " is " << device_name;
|
||||
|
||||
return Trim(device_name);
|
||||
}
|
||||
|
||||
static void ScanV4L2Devices(std::vector<Device>* devices) {
|
||||
LOG(LS_INFO) << ("Enumerating V4L2 devices");
|
||||
|
||||
MetaType meta;
|
||||
std::string metadata_dir;
|
||||
|
||||
std::unique_ptr<rtc::DirectoryIterator> directoryIterator(
|
||||
rtc::Filesystem::IterateDirectory());
|
||||
|
||||
// Try and guess kernel version
|
||||
if (directoryIterator->Iterate(kVideoMetaPathK2_6)) {
|
||||
meta = M2_6;
|
||||
metadata_dir = kVideoMetaPathK2_6;
|
||||
} else if (directoryIterator->Iterate(kVideoMetaPathK2_4)) {
|
||||
meta = M2_4;
|
||||
metadata_dir = kVideoMetaPathK2_4;
|
||||
} else {
|
||||
meta = NONE;
|
||||
}
|
||||
|
||||
if (meta != NONE) {
|
||||
LOG(LS_INFO) << "V4L2 device metadata found at " << metadata_dir;
|
||||
|
||||
do {
|
||||
std::string filename = directoryIterator->Name();
|
||||
|
||||
if (filename.find("video") == 0) {
|
||||
std::string device_path = "/dev/" + filename;
|
||||
|
||||
if (V4LLookup::IsV4L2Device(device_path)) {
|
||||
devices->push_back(
|
||||
Device(GetVideoDeviceName(meta, filename), device_path));
|
||||
}
|
||||
}
|
||||
} while (directoryIterator->Next());
|
||||
} else {
|
||||
LOG(LS_ERROR) << "Unable to detect v4l2 metadata directory";
|
||||
}
|
||||
|
||||
if (devices->size() == 0) {
|
||||
LOG(LS_INFO) << "Plan B. Scanning all video devices in /dev directory";
|
||||
ScanDeviceDirectory("/dev/", devices);
|
||||
}
|
||||
|
||||
LOG(LS_INFO) << "Total V4L2 devices found : " << devices->size();
|
||||
}
|
||||
|
||||
bool LinuxDeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
|
||||
devices->clear();
|
||||
ScanV4L2Devices(devices);
|
||||
return FilterDevices(devices, kFilteredVideoDevicesName);
|
||||
}
|
||||
|
||||
LinuxDeviceWatcher::LinuxDeviceWatcher(DeviceManagerInterface* dm)
|
||||
: DeviceWatcher(dm),
|
||||
manager_(dm),
|
||||
udev_(NULL),
|
||||
udev_monitor_(NULL),
|
||||
registered_(false) {
|
||||
}
|
||||
|
||||
LinuxDeviceWatcher::~LinuxDeviceWatcher() {
|
||||
}
|
||||
|
||||
static rtc::PhysicalSocketServer* CurrentSocketServer() {
|
||||
rtc::SocketServer* ss =
|
||||
rtc::ThreadManager::Instance()->WrapCurrentThread()->socketserver();
|
||||
return reinterpret_cast<rtc::PhysicalSocketServer*>(ss);
|
||||
}
|
||||
|
||||
bool LinuxDeviceWatcher::Start() {
|
||||
// We deliberately return true in the failure paths here because libudev is
|
||||
// not a critical component of a Linux system so it may not be present/usable,
|
||||
// and we don't want to halt LinuxDeviceManager initialization in such a case.
|
||||
if (!libudev_.Load() || IsWrongLibUDevAbiVersion(libudev_.GetDllHandle())) {
|
||||
LOG(LS_WARNING)
|
||||
<< "libudev not present/usable; LinuxDeviceWatcher disabled";
|
||||
return true;
|
||||
}
|
||||
udev_ = libudev_.udev_new()();
|
||||
if (!udev_) {
|
||||
LOG_ERR(LS_ERROR) << "udev_new()";
|
||||
return true;
|
||||
}
|
||||
// The second argument here is the event source. It can be either "kernel" or
|
||||
// "udev", but "udev" is the only correct choice. Apps listen on udev and the
|
||||
// udev daemon in turn listens on the kernel.
|
||||
udev_monitor_ = libudev_.udev_monitor_new_from_netlink()(udev_, "udev");
|
||||
if (!udev_monitor_) {
|
||||
LOG_ERR(LS_ERROR) << "udev_monitor_new_from_netlink()";
|
||||
return true;
|
||||
}
|
||||
// We only listen for changes in the video devices. Audio devices are more or
|
||||
// less unimportant because receiving device change notifications really only
|
||||
// matters for broadcasting updated send/recv capabilities based on whether
|
||||
// there is at least one device available, and almost all computers have at
|
||||
// least one audio device. Also, PulseAudio device notifications don't come
|
||||
// from the udev daemon, they come from the PulseAudio daemon, so we'd only
|
||||
// want to listen for audio device changes from udev if using ALSA. For
|
||||
// simplicity, we don't bother with any audio stuff at all.
|
||||
if (libudev_.udev_monitor_filter_add_match_subsystem_devtype()(
|
||||
udev_monitor_, "video4linux", NULL) < 0) {
|
||||
LOG_ERR(LS_ERROR) << "udev_monitor_filter_add_match_subsystem_devtype()";
|
||||
return true;
|
||||
}
|
||||
if (libudev_.udev_monitor_enable_receiving()(udev_monitor_) < 0) {
|
||||
LOG_ERR(LS_ERROR) << "udev_monitor_enable_receiving()";
|
||||
return true;
|
||||
}
|
||||
CurrentSocketServer()->Add(this);
|
||||
registered_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinuxDeviceWatcher::Stop() {
|
||||
if (registered_) {
|
||||
CurrentSocketServer()->Remove(this);
|
||||
registered_ = false;
|
||||
}
|
||||
if (udev_monitor_) {
|
||||
libudev_.udev_monitor_unref()(udev_monitor_);
|
||||
udev_monitor_ = NULL;
|
||||
}
|
||||
if (udev_) {
|
||||
libudev_.udev_unref()(udev_);
|
||||
udev_ = NULL;
|
||||
}
|
||||
libudev_.Unload();
|
||||
}
|
||||
|
||||
uint32_t LinuxDeviceWatcher::GetRequestedEvents() {
|
||||
return rtc::DE_READ;
|
||||
}
|
||||
|
||||
void LinuxDeviceWatcher::OnPreEvent(uint32_t ff) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
void LinuxDeviceWatcher::OnEvent(uint32_t ff, int err) {
|
||||
udev_device* device = libudev_.udev_monitor_receive_device()(udev_monitor_);
|
||||
if (!device) {
|
||||
// Probably the socket connection to the udev daemon was terminated (perhaps
|
||||
// the daemon crashed or is being restarted?).
|
||||
LOG_ERR(LS_WARNING) << "udev_monitor_receive_device()";
|
||||
// Stop listening to avoid potential livelock (an fd with EOF in it is
|
||||
// always considered readable).
|
||||
CurrentSocketServer()->Remove(this);
|
||||
registered_ = false;
|
||||
return;
|
||||
}
|
||||
// Else we read the device successfully.
|
||||
|
||||
// Since we already have our own filesystem-based device enumeration code, we
|
||||
// simply re-enumerate rather than inspecting the device event.
|
||||
libudev_.udev_device_unref()(device);
|
||||
manager_->SignalDevicesChange();
|
||||
}
|
||||
|
||||
int LinuxDeviceWatcher::GetDescriptor() {
|
||||
return libudev_.udev_monitor_get_fd()(udev_monitor_);
|
||||
}
|
||||
|
||||
bool LinuxDeviceWatcher::IsDescriptorClosed() {
|
||||
// If it is closed then we will just get an error in
|
||||
// udev_monitor_receive_device and unregister, so we don't need to check for
|
||||
// it separately.
|
||||
return false;
|
||||
}
|
||||
|
||||
}; // namespace cricket
|
||||
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MEDIA_DEVICES_LINUXDEVICEMANAGER_H_
|
||||
#define WEBRTC_MEDIA_DEVICES_LINUXDEVICEMANAGER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/sigslot.h"
|
||||
#include "webrtc/base/stringencode.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
#include "webrtc/sound/soundsystemfactory.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class LinuxDeviceManager : public DeviceManager {
|
||||
public:
|
||||
LinuxDeviceManager();
|
||||
virtual ~LinuxDeviceManager();
|
||||
|
||||
virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
|
||||
|
||||
private:
|
||||
virtual bool GetAudioDevices(bool input, std::vector<Device>* devs);
|
||||
rtc::SoundSystemHandle sound_system_;
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // WEBRTC_MEDIA_DEVICES_LINUXDEVICEMANAGER_H_
|
||||
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/media/devices/deviceinfo.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
bool GetUsbId(const Device& device, std::string* usb_id) {
|
||||
// Both PID and VID are 4 characters.
|
||||
const int id_size = 4;
|
||||
if (device.id.size() < 2 * id_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The last characters of device id is a concatenation of VID and then PID.
|
||||
const size_t vid_location = device.id.size() - 2 * id_size;
|
||||
std::string id_vendor = device.id.substr(vid_location, id_size);
|
||||
const size_t pid_location = device.id.size() - id_size;
|
||||
std::string id_product = device.id.substr(pid_location, id_size);
|
||||
|
||||
usb_id->clear();
|
||||
usb_id->append(id_vendor);
|
||||
usb_id->append(":");
|
||||
usb_id->append(id_product);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetUsbVersion(const Device& device, std::string* usb_version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/media/devices/macdevicemanager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <QuickTime/QuickTime.h>
|
||||
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/stringutils.h"
|
||||
#include "webrtc/base/thread.h"
|
||||
#include "webrtc/media/base/mediacommon.h"
|
||||
|
||||
class DeviceWatcherImpl;
|
||||
|
||||
namespace cricket {
|
||||
|
||||
DeviceManagerInterface* DeviceManagerFactory::Create() {
|
||||
return new MacDeviceManager();
|
||||
}
|
||||
|
||||
class MacDeviceWatcher : public DeviceWatcher {
|
||||
public:
|
||||
explicit MacDeviceWatcher(DeviceManagerInterface* dm);
|
||||
virtual ~MacDeviceWatcher();
|
||||
virtual bool Start();
|
||||
virtual void Stop();
|
||||
|
||||
private:
|
||||
DeviceManagerInterface* manager_;
|
||||
DeviceWatcherImpl* impl_;
|
||||
};
|
||||
|
||||
static const char* kFilteredAudioDevicesName[] = {
|
||||
NULL,
|
||||
};
|
||||
// TODO(tommyw): Try to get hold of a copy of Final Cut to understand why we
|
||||
// crash while scanning their components on OS X.
|
||||
static const char* const kFilteredVideoDevicesName[] = {
|
||||
"DVCPRO HD", // Final cut
|
||||
"Sonix SN9C201p", // Crashes in OpenAComponent and CloseComponent
|
||||
NULL,
|
||||
};
|
||||
static const UInt32 kAudioDeviceNameLength = 64;
|
||||
// Obj-C functions defined in macdevicemanagermm.mm
|
||||
// TODO(ronghuawu): have a shared header for these function defines.
|
||||
extern DeviceWatcherImpl* CreateDeviceWatcherCallback(
|
||||
DeviceManagerInterface* dm);
|
||||
extern void ReleaseDeviceWatcherCallback(DeviceWatcherImpl* impl);
|
||||
extern bool GetAVFoundationVideoDevices(std::vector<Device>* out);
|
||||
static bool GetAudioDeviceIDs(bool inputs, std::vector<AudioDeviceID>* out);
|
||||
static bool GetAudioDeviceName(AudioDeviceID id, bool input, std::string* out);
|
||||
|
||||
MacDeviceManager::MacDeviceManager() {
|
||||
set_watcher(new MacDeviceWatcher(this));
|
||||
}
|
||||
|
||||
MacDeviceManager::~MacDeviceManager() {
|
||||
}
|
||||
|
||||
bool MacDeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
|
||||
devices->clear();
|
||||
if (!GetAVFoundationVideoDevices(devices)) {
|
||||
return false;
|
||||
}
|
||||
return FilterDevices(devices, kFilteredVideoDevicesName);
|
||||
}
|
||||
|
||||
bool MacDeviceManager::GetAudioDevices(bool input,
|
||||
std::vector<Device>* devs) {
|
||||
devs->clear();
|
||||
std::vector<AudioDeviceID> dev_ids;
|
||||
bool ret = GetAudioDeviceIDs(input, &dev_ids);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < dev_ids.size(); ++i) {
|
||||
std::string name;
|
||||
if (GetAudioDeviceName(dev_ids[i], input, &name)) {
|
||||
devs->push_back(Device(name, dev_ids[i]));
|
||||
}
|
||||
}
|
||||
return FilterDevices(devs, kFilteredAudioDevicesName);
|
||||
}
|
||||
|
||||
static bool GetAudioDeviceIDs(bool input,
|
||||
std::vector<AudioDeviceID>* out_dev_ids) {
|
||||
UInt32 propsize;
|
||||
OSErr err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
|
||||
&propsize, NULL);
|
||||
if (0 != err) {
|
||||
LOG(LS_ERROR) << "Couldn't get information about property, "
|
||||
<< "so no device list acquired.";
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t num_devices = propsize / sizeof(AudioDeviceID);
|
||||
std::unique_ptr<AudioDeviceID[]> device_ids(
|
||||
new AudioDeviceID[num_devices]);
|
||||
|
||||
err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
|
||||
&propsize, device_ids.get());
|
||||
if (0 != err) {
|
||||
LOG(LS_ERROR) << "Failed to get device ids, "
|
||||
<< "so no device listing acquired.";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_devices; ++i) {
|
||||
AudioDeviceID an_id = device_ids[i];
|
||||
// find out the number of channels for this direction
|
||||
// (input/output) on this device -
|
||||
// we'll ignore anything with no channels.
|
||||
err = AudioDeviceGetPropertyInfo(an_id, 0, input,
|
||||
kAudioDevicePropertyStreams,
|
||||
&propsize, NULL);
|
||||
if (0 == err) {
|
||||
unsigned num_channels = propsize / sizeof(AudioStreamID);
|
||||
if (0 < num_channels) {
|
||||
out_dev_ids->push_back(an_id);
|
||||
}
|
||||
} else {
|
||||
LOG(LS_ERROR) << "No property info for stream property for device id "
|
||||
<< an_id << "(is_input == " << input
|
||||
<< "), so not including it in the list.";
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetAudioDeviceName(AudioDeviceID id,
|
||||
bool input,
|
||||
std::string* out_name) {
|
||||
UInt32 nameLength = kAudioDeviceNameLength;
|
||||
char name[kAudioDeviceNameLength + 1];
|
||||
OSErr err = AudioDeviceGetProperty(id, 0, input,
|
||||
kAudioDevicePropertyDeviceName,
|
||||
&nameLength, name);
|
||||
if (0 != err) {
|
||||
LOG(LS_ERROR) << "No name acquired for device id " << id;
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_name = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
MacDeviceWatcher::MacDeviceWatcher(DeviceManagerInterface* manager)
|
||||
: DeviceWatcher(manager),
|
||||
manager_(manager),
|
||||
impl_(NULL) {
|
||||
}
|
||||
|
||||
MacDeviceWatcher::~MacDeviceWatcher() {
|
||||
}
|
||||
|
||||
bool MacDeviceWatcher::Start() {
|
||||
if (!impl_) {
|
||||
impl_ = CreateDeviceWatcherCallback(manager_);
|
||||
}
|
||||
return impl_ != NULL;
|
||||
}
|
||||
|
||||
void MacDeviceWatcher::Stop() {
|
||||
if (impl_) {
|
||||
ReleaseDeviceWatcherCallback(impl_);
|
||||
impl_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace cricket
|
||||
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MEDIA_DEVICES_MACDEVICEMANAGER_H_
|
||||
#define WEBRTC_MEDIA_DEVICES_MACDEVICEMANAGER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/sigslot.h"
|
||||
#include "webrtc/base/stringencode.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class DeviceWatcher;
|
||||
|
||||
class MacDeviceManager : public DeviceManager {
|
||||
public:
|
||||
MacDeviceManager();
|
||||
virtual ~MacDeviceManager();
|
||||
|
||||
virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
|
||||
|
||||
private:
|
||||
virtual bool GetAudioDevices(bool input, std::vector<Device>* devs);
|
||||
bool FilterDevice(const Device& d);
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // WEBRTC_MEDIA_DEVICES_MACDEVICEMANAGER_H_
|
||||
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// support GCC compiler
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
#import <assert.h>
|
||||
#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#endif
|
||||
#endif
|
||||
#import <QTKit/QTKit.h>
|
||||
|
||||
#include "webrtc/base/logging.h"
|
||||
|
||||
@interface DeviceWatcherImpl : NSObject {
|
||||
@private
|
||||
cricket::DeviceManagerInterface* manager_;
|
||||
}
|
||||
- (id)init:(cricket::DeviceManagerInterface*)manager;
|
||||
- (void)onDevicesChanged:(NSNotification*)notification;
|
||||
@end
|
||||
|
||||
@implementation DeviceWatcherImpl
|
||||
- (id)init:(cricket::DeviceManagerInterface*)manager {
|
||||
if ((self = [super init])) {
|
||||
assert(manager != NULL);
|
||||
manager_ = manager;
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(onDevicesChanged:)
|
||||
name:QTCaptureDeviceWasConnectedNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(onDevicesChanged:)
|
||||
name:QTCaptureDeviceWasDisconnectedNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
#if !__has_feature(objc_arc)
|
||||
[super dealloc];
|
||||
#endif
|
||||
}
|
||||
- (void)onDevicesChanged:(NSNotification*)notification {
|
||||
manager_->SignalDevicesChange();
|
||||
}
|
||||
@end
|
||||
|
||||
namespace cricket {
|
||||
|
||||
DeviceWatcherImpl* CreateDeviceWatcherCallback(
|
||||
DeviceManagerInterface* manager) {
|
||||
DeviceWatcherImpl* impl;
|
||||
#if !__has_feature(objc_arc)
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
#else
|
||||
@autoreleasepool
|
||||
#endif
|
||||
{ impl = [[DeviceWatcherImpl alloc] init:manager]; }
|
||||
#if !__has_feature(objc_arc)
|
||||
[pool drain];
|
||||
#endif
|
||||
return impl;
|
||||
}
|
||||
|
||||
void ReleaseDeviceWatcherCallback(DeviceWatcherImpl* watcher) {
|
||||
#if !__has_feature(objc_arc)
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
[watcher release];
|
||||
[pool drain];
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GetQTKitVideoDevices(std::vector<Device>* devices) {
|
||||
#if !__has_feature(objc_arc)
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
#else
|
||||
@autoreleasepool
|
||||
#endif
|
||||
{
|
||||
NSArray* qt_capture_devices =
|
||||
[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
|
||||
NSUInteger count = [qt_capture_devices count];
|
||||
LOG(LS_INFO) << count << " capture device(s) found:";
|
||||
for (QTCaptureDevice* qt_capture_device in qt_capture_devices) {
|
||||
static NSString* const kFormat = @"localizedDisplayName: \"%@\", "
|
||||
@"modelUniqueID: \"%@\", uniqueID \"%@\", isConnected: %d, "
|
||||
@"isOpen: %d, isInUseByAnotherApplication: %d";
|
||||
NSString* info = [NSString
|
||||
stringWithFormat:kFormat,
|
||||
[qt_capture_device localizedDisplayName],
|
||||
[qt_capture_device modelUniqueID],
|
||||
[qt_capture_device uniqueID],
|
||||
[qt_capture_device isConnected],
|
||||
[qt_capture_device isOpen],
|
||||
[qt_capture_device isInUseByAnotherApplication]];
|
||||
LOG(LS_INFO) << [info UTF8String];
|
||||
|
||||
std::string name([[qt_capture_device localizedDisplayName] UTF8String]);
|
||||
devices->push_back(
|
||||
Device(name, [[qt_capture_device uniqueID] UTF8String]));
|
||||
}
|
||||
}
|
||||
#if !__has_feature(objc_arc)
|
||||
[pool drain];
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetAVFoundationVideoDevices(std::vector<Device>* devices) {
|
||||
#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >=1070
|
||||
if (![AVCaptureDevice class]) {
|
||||
// Fallback to using QTKit if AVFoundation is not available
|
||||
return GetQTKitVideoDevices(devices);
|
||||
}
|
||||
#if !__has_feature(objc_arc)
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
#else
|
||||
@autoreleasepool
|
||||
#endif
|
||||
{
|
||||
NSArray* capture_devices = [AVCaptureDevice devices];
|
||||
LOG(LS_INFO) << [capture_devices count] << " capture device(s) found:";
|
||||
for (AVCaptureDevice* capture_device in capture_devices) {
|
||||
if ([capture_device hasMediaType:AVMediaTypeVideo] ||
|
||||
[capture_device hasMediaType:AVMediaTypeMuxed]) {
|
||||
static NSString* const kFormat = @"localizedName: \"%@\", "
|
||||
@"modelID: \"%@\", uniqueID \"%@\", isConnected: %d, "
|
||||
@"isInUseByAnotherApplication: %d";
|
||||
NSString* info = [NSString
|
||||
stringWithFormat:kFormat,
|
||||
[capture_device localizedName],
|
||||
[capture_device modelID],
|
||||
[capture_device uniqueID],
|
||||
[capture_device isConnected],
|
||||
[capture_device isInUseByAnotherApplication]];
|
||||
LOG(LS_INFO) << [info UTF8String];
|
||||
|
||||
std::string name([[capture_device localizedName] UTF8String]);
|
||||
devices->push_back(
|
||||
Device(name, [[capture_device uniqueID] UTF8String]));
|
||||
}
|
||||
}
|
||||
}
|
||||
#if !__has_feature(objc_arc)
|
||||
[pool drain];
|
||||
#endif
|
||||
return true;
|
||||
#else // __MAC_OS_X_VERSION_MAX_ALLOWED >=1070
|
||||
return GetQTKitVideoDevices(devices);
|
||||
#endif // __MAC_OS_X_VERSION_MAX_ALLOWED >=1070
|
||||
#else // __MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
return GetQTKitVideoDevices(devices);
|
||||
#endif // __MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/base/arraysize.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
#include "webrtc/modules/video_capture/video_capture_factory.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class MobileDeviceManager : public DeviceManager {
|
||||
public:
|
||||
MobileDeviceManager();
|
||||
virtual ~MobileDeviceManager();
|
||||
virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
|
||||
};
|
||||
|
||||
MobileDeviceManager::MobileDeviceManager() {
|
||||
// We don't expect available devices to change on Android/iOS, so use a
|
||||
// do-nothing watcher.
|
||||
set_watcher(new DeviceWatcher(this));
|
||||
}
|
||||
|
||||
MobileDeviceManager::~MobileDeviceManager() {}
|
||||
|
||||
bool MobileDeviceManager::GetVideoCaptureDevices(std::vector<Device>* devs) {
|
||||
devs->clear();
|
||||
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
|
||||
webrtc::VideoCaptureFactory::CreateDeviceInfo(0));
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
uint32_t num_cams = info->NumberOfDevices();
|
||||
char id[256];
|
||||
char name[256];
|
||||
for (uint32_t i = 0; i < num_cams; ++i) {
|
||||
if (info->GetDeviceName(i, name, arraysize(name), id, arraysize(id)))
|
||||
continue;
|
||||
devs->push_back(Device(name, id));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DeviceManagerInterface* DeviceManagerFactory::Create() {
|
||||
return new MobileDeviceManager();
|
||||
}
|
||||
|
||||
bool GetUsbId(const Device& device, std::string* usb_id) { return false; }
|
||||
|
||||
bool GetUsbVersion(const Device& device, std::string* usb_version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/media/devices/deviceinfo.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
bool GetUsbId(const Device& device, std::string* usb_id) {
|
||||
// Both PID and VID are 4 characters.
|
||||
const int id_size = 4;
|
||||
const char vid[] = "vid_"; // Also contains '\0'.
|
||||
const size_t vid_location = device.id.find(vid);
|
||||
if (vid_location == std::string::npos ||
|
||||
vid_location + sizeof(vid) - 1 + id_size > device.id.size()) {
|
||||
return false;
|
||||
}
|
||||
const char pid[] = "pid_";
|
||||
const size_t pid_location = device.id.find(pid);
|
||||
if (pid_location == std::string::npos ||
|
||||
pid_location + sizeof(pid) - 1 + id_size > device.id.size()) {
|
||||
return false;
|
||||
}
|
||||
std::string id_vendor = device.id.substr(vid_location + sizeof(vid) - 1,
|
||||
id_size);
|
||||
std::string id_product = device.id.substr(pid_location + sizeof(pid) -1,
|
||||
id_size);
|
||||
usb_id->clear();
|
||||
usb_id->append(id_vendor);
|
||||
usb_id->append(":");
|
||||
usb_id->append(id_product);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetUsbVersion(const Device& device, std::string* usb_version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
@ -1,398 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/media/devices/win32devicemanager.h"
|
||||
|
||||
#include <atlbase.h>
|
||||
#include <dbt.h>
|
||||
#include <strmif.h> // must come before ks.h
|
||||
#include <ks.h>
|
||||
#include <ksmedia.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <mmsystem.h>
|
||||
#include <functiondiscoverykeys_devpkey.h>
|
||||
#include <uuids.h>
|
||||
|
||||
// PKEY_AudioEndpoint_GUID isn't included in uuid.lib and we don't want
|
||||
// to define INITGUID in order to define all the uuids in this object file
|
||||
// as it will conflict with uuid.lib (multiply defined symbols).
|
||||
// So our workaround is to define this one missing symbol here manually.
|
||||
// See: https://code.google.com/p/webrtc/issues/detail?id=3996
|
||||
EXTERN_C const PROPERTYKEY PKEY_AudioEndpoint_GUID = { {
|
||||
0x1da5d803, 0xd492, 0x4edd, {
|
||||
0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e
|
||||
} }, 4
|
||||
};
|
||||
|
||||
#include "webrtc/base/arraysize.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/stringutils.h"
|
||||
#include "webrtc/base/thread.h"
|
||||
#include "webrtc/base/win32.h" // ToUtf8
|
||||
#include "webrtc/base/win32window.h"
|
||||
#include "webrtc/media/base/mediacommon.h"
|
||||
#ifdef HAVE_LOGITECH_HEADERS
|
||||
#include "third_party/logitech/files/logitechquickcam.h"
|
||||
#endif
|
||||
|
||||
namespace cricket {
|
||||
|
||||
DeviceManagerInterface* DeviceManagerFactory::Create() {
|
||||
return new Win32DeviceManager();
|
||||
}
|
||||
|
||||
class Win32DeviceWatcher
|
||||
: public DeviceWatcher,
|
||||
public rtc::Win32Window {
|
||||
public:
|
||||
explicit Win32DeviceWatcher(Win32DeviceManager* dm);
|
||||
virtual ~Win32DeviceWatcher();
|
||||
virtual bool Start();
|
||||
virtual void Stop();
|
||||
|
||||
private:
|
||||
HDEVNOTIFY Register(REFGUID guid);
|
||||
void Unregister(HDEVNOTIFY notify);
|
||||
virtual bool OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT& result);
|
||||
|
||||
Win32DeviceManager* manager_;
|
||||
HDEVNOTIFY audio_notify_;
|
||||
HDEVNOTIFY video_notify_;
|
||||
};
|
||||
|
||||
static const char* kFilteredAudioDevicesName[] = {
|
||||
NULL,
|
||||
};
|
||||
static const char* const kFilteredVideoDevicesName[] = {
|
||||
"Asus virtual Camera", // Bad Asus desktop virtual cam
|
||||
"Bluetooth Video", // Bad Sony viao bluetooth sharing driver
|
||||
NULL,
|
||||
};
|
||||
static const wchar_t kFriendlyName[] = L"FriendlyName";
|
||||
static const wchar_t kDevicePath[] = L"DevicePath";
|
||||
static const char kUsbDevicePathPrefix[] = "\\\\?\\usb";
|
||||
static bool GetDevices(const CLSID& catid, std::vector<Device>* out);
|
||||
static bool GetCoreAudioDevices(bool input, std::vector<Device>* devs);
|
||||
static bool GetWaveDevices(bool input, std::vector<Device>* devs);
|
||||
|
||||
Win32DeviceManager::Win32DeviceManager()
|
||||
: need_couninitialize_(false) {
|
||||
set_watcher(new Win32DeviceWatcher(this));
|
||||
}
|
||||
|
||||
Win32DeviceManager::~Win32DeviceManager() {
|
||||
if (initialized()) {
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool Win32DeviceManager::Init() {
|
||||
if (!initialized()) {
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
need_couninitialize_ = SUCCEEDED(hr);
|
||||
if (FAILED(hr)) {
|
||||
LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
|
||||
if (hr != RPC_E_CHANGED_MODE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!watcher()->Start()) {
|
||||
return false;
|
||||
}
|
||||
set_initialized(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Win32DeviceManager::Terminate() {
|
||||
if (initialized()) {
|
||||
watcher()->Stop();
|
||||
if (need_couninitialize_) {
|
||||
CoUninitialize();
|
||||
need_couninitialize_ = false;
|
||||
}
|
||||
set_initialized(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool Win32DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
|
||||
bool ret = false;
|
||||
// If there are multiple capture devices, we want the first USB one.
|
||||
// This avoids issues with defaulting to virtual cameras or grabber cards.
|
||||
std::vector<Device> devices;
|
||||
ret = (GetVideoCaptureDevices(&devices) && !devices.empty());
|
||||
if (ret) {
|
||||
*device = devices[0];
|
||||
for (size_t i = 0; i < devices.size(); ++i) {
|
||||
if (strnicmp(devices[i].id.c_str(), kUsbDevicePathPrefix,
|
||||
arraysize(kUsbDevicePathPrefix) - 1) == 0) {
|
||||
*device = devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Win32DeviceManager::GetAudioDevices(bool input,
|
||||
std::vector<Device>* devs) {
|
||||
devs->clear();
|
||||
|
||||
if (rtc::IsWindowsVistaOrLater()) {
|
||||
if (!GetCoreAudioDevices(input, devs))
|
||||
return false;
|
||||
} else {
|
||||
if (!GetWaveDevices(input, devs))
|
||||
return false;
|
||||
}
|
||||
return FilterDevices(devs, kFilteredAudioDevicesName);
|
||||
}
|
||||
|
||||
bool Win32DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
|
||||
devices->clear();
|
||||
if (!GetDevices(CLSID_VideoInputDeviceCategory, devices)) {
|
||||
return false;
|
||||
}
|
||||
return FilterDevices(devices, kFilteredVideoDevicesName);
|
||||
}
|
||||
|
||||
bool GetDevices(const CLSID& catid, std::vector<Device>* devices) {
|
||||
HRESULT hr;
|
||||
|
||||
// CComPtr is a scoped pointer that will be auto released when going
|
||||
// out of scope. CoUninitialize must not be called before the
|
||||
// release.
|
||||
CComPtr<ICreateDevEnum> sys_dev_enum;
|
||||
CComPtr<IEnumMoniker> cam_enum;
|
||||
if (FAILED(hr = sys_dev_enum.CoCreateInstance(CLSID_SystemDeviceEnum)) ||
|
||||
FAILED(hr = sys_dev_enum->CreateClassEnumerator(catid, &cam_enum, 0))) {
|
||||
LOG(LS_ERROR) << "Failed to create device enumerator, hr=" << hr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only enum devices if CreateClassEnumerator returns S_OK. If there are no
|
||||
// devices available, S_FALSE will be returned, but enumMk will be NULL.
|
||||
if (hr == S_OK) {
|
||||
CComPtr<IMoniker> mk;
|
||||
while (cam_enum->Next(1, &mk, NULL) == S_OK) {
|
||||
#ifdef HAVE_LOGITECH_HEADERS
|
||||
// Initialize Logitech device if applicable
|
||||
MaybeLogitechDeviceReset(mk);
|
||||
#endif
|
||||
CComPtr<IPropertyBag> bag;
|
||||
if (SUCCEEDED(mk->BindToStorage(NULL, NULL,
|
||||
__uuidof(bag), reinterpret_cast<void**>(&bag)))) {
|
||||
CComVariant name, path;
|
||||
std::string name_str, path_str;
|
||||
if (SUCCEEDED(bag->Read(kFriendlyName, &name, 0)) &&
|
||||
name.vt == VT_BSTR) {
|
||||
name_str = rtc::ToUtf8(name.bstrVal);
|
||||
// Get the device id if one exists.
|
||||
if (SUCCEEDED(bag->Read(kDevicePath, &path, 0)) &&
|
||||
path.vt == VT_BSTR) {
|
||||
path_str = rtc::ToUtf8(path.bstrVal);
|
||||
}
|
||||
|
||||
devices->push_back(Device(name_str, path_str));
|
||||
}
|
||||
}
|
||||
mk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT GetStringProp(IPropertyStore* bag, PROPERTYKEY key, std::string* out) {
|
||||
out->clear();
|
||||
PROPVARIANT var;
|
||||
PropVariantInit(&var);
|
||||
|
||||
HRESULT hr = bag->GetValue(key, &var);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (var.pwszVal)
|
||||
*out = rtc::ToUtf8(var.pwszVal);
|
||||
else
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
PropVariantClear(&var);
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Adapted from http://msdn.microsoft.com/en-us/library/dd370812(v=VS.85).aspx
|
||||
HRESULT CricketDeviceFromImmDevice(IMMDevice* device, Device* out) {
|
||||
CComPtr<IPropertyStore> props;
|
||||
|
||||
HRESULT hr = device->OpenPropertyStore(STGM_READ, &props);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Get the endpoint's name and id.
|
||||
std::string name, guid;
|
||||
hr = GetStringProp(props, PKEY_Device_FriendlyName, &name);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = GetStringProp(props, PKEY_AudioEndpoint_GUID, &guid);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
out->name = name;
|
||||
out->id = guid;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool GetCoreAudioDevices(
|
||||
bool input, std::vector<Device>* devs) {
|
||||
HRESULT hr = S_OK;
|
||||
CComPtr<IMMDeviceEnumerator> enumerator;
|
||||
|
||||
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
|
||||
__uuidof(IMMDeviceEnumerator), reinterpret_cast<void**>(&enumerator));
|
||||
if (SUCCEEDED(hr)) {
|
||||
CComPtr<IMMDeviceCollection> devices;
|
||||
hr = enumerator->EnumAudioEndpoints((input ? eCapture : eRender),
|
||||
DEVICE_STATE_ACTIVE, &devices);
|
||||
if (SUCCEEDED(hr)) {
|
||||
unsigned int count;
|
||||
hr = devices->GetCount(&count);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
CComPtr<IMMDevice> device;
|
||||
|
||||
// Get pointer to endpoint number i.
|
||||
hr = devices->Item(i, &device);
|
||||
if (FAILED(hr)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Device dev;
|
||||
hr = CricketDeviceFromImmDevice(device, &dev);
|
||||
if (SUCCEEDED(hr)) {
|
||||
devs->push_back(dev);
|
||||
} else {
|
||||
LOG(LS_WARNING) << "Unable to query IMM Device, skipping. HR="
|
||||
<< hr;
|
||||
hr = S_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
LOG(LS_WARNING) << "GetCoreAudioDevices failed with hr " << hr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetWaveDevices(bool input, std::vector<Device>* devs) {
|
||||
// Note, we don't use the System Device Enumerator interface here since it
|
||||
// adds lots of pseudo-devices to the list, such as DirectSound and Wave
|
||||
// variants of the same device.
|
||||
if (input) {
|
||||
int num_devs = waveInGetNumDevs();
|
||||
for (int i = 0; i < num_devs; ++i) {
|
||||
WAVEINCAPS caps;
|
||||
if (waveInGetDevCaps(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR &&
|
||||
caps.wChannels > 0) {
|
||||
devs->push_back(Device(rtc::ToUtf8(caps.szPname),
|
||||
rtc::ToString(i)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int num_devs = waveOutGetNumDevs();
|
||||
for (int i = 0; i < num_devs; ++i) {
|
||||
WAVEOUTCAPS caps;
|
||||
if (waveOutGetDevCaps(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR &&
|
||||
caps.wChannels > 0) {
|
||||
devs->push_back(Device(rtc::ToUtf8(caps.szPname), i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Win32DeviceWatcher::Win32DeviceWatcher(Win32DeviceManager* manager)
|
||||
: DeviceWatcher(manager),
|
||||
manager_(manager),
|
||||
audio_notify_(NULL),
|
||||
video_notify_(NULL) {
|
||||
}
|
||||
|
||||
Win32DeviceWatcher::~Win32DeviceWatcher() {
|
||||
}
|
||||
|
||||
bool Win32DeviceWatcher::Start() {
|
||||
if (!Create(NULL, _T("libjingle Win32DeviceWatcher Window"),
|
||||
0, 0, 0, 0, 0, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
audio_notify_ = Register(KSCATEGORY_AUDIO);
|
||||
if (!audio_notify_) {
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
video_notify_ = Register(KSCATEGORY_VIDEO);
|
||||
if (!video_notify_) {
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Win32DeviceWatcher::Stop() {
|
||||
UnregisterDeviceNotification(video_notify_);
|
||||
video_notify_ = NULL;
|
||||
UnregisterDeviceNotification(audio_notify_);
|
||||
audio_notify_ = NULL;
|
||||
Destroy();
|
||||
}
|
||||
|
||||
HDEVNOTIFY Win32DeviceWatcher::Register(REFGUID guid) {
|
||||
DEV_BROADCAST_DEVICEINTERFACE dbdi;
|
||||
dbdi.dbcc_size = sizeof(dbdi);
|
||||
dbdi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||
dbdi.dbcc_classguid = guid;
|
||||
dbdi.dbcc_name[0] = '\0';
|
||||
return RegisterDeviceNotification(handle(), &dbdi,
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
}
|
||||
|
||||
void Win32DeviceWatcher::Unregister(HDEVNOTIFY handle) {
|
||||
UnregisterDeviceNotification(handle);
|
||||
}
|
||||
|
||||
bool Win32DeviceWatcher::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
|
||||
LRESULT& result) {
|
||||
if (uMsg == WM_DEVICECHANGE) {
|
||||
if (wParam == DBT_DEVICEARRIVAL ||
|
||||
wParam == DBT_DEVICEREMOVECOMPLETE) {
|
||||
DEV_BROADCAST_DEVICEINTERFACE* dbdi =
|
||||
reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(lParam);
|
||||
if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO ||
|
||||
dbdi->dbcc_classguid == KSCATEGORY_VIDEO) {
|
||||
manager_->SignalDevicesChange();
|
||||
}
|
||||
}
|
||||
result = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}; // namespace cricket
|
||||
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MEDIA_DEVICES_WIN32DEVICEMANAGER_H_
|
||||
#define WEBRTC_MEDIA_DEVICES_WIN32DEVICEMANAGER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/sigslot.h"
|
||||
#include "webrtc/base/stringencode.h"
|
||||
#include "webrtc/media/devices/devicemanager.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class Win32DeviceManager : public DeviceManager {
|
||||
public:
|
||||
Win32DeviceManager();
|
||||
virtual ~Win32DeviceManager();
|
||||
|
||||
// Initialization
|
||||
virtual bool Init();
|
||||
virtual void Terminate();
|
||||
|
||||
virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
|
||||
|
||||
private:
|
||||
virtual bool GetAudioDevices(bool input, std::vector<Device>* devs);
|
||||
virtual bool GetDefaultVideoCaptureDevice(Device* device);
|
||||
|
||||
bool need_couninitialize_;
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // WEBRTC_MEDIA_DEVICES_WIN32DEVICEMANAGER_H_
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/media/engine/fakewebrtcdeviceinfo.h"
|
||||
#include "webrtc/media/engine/fakewebrtcvideocapturemodule.h"
|
||||
#include "webrtc/media/engine/webrtcvideocapturer.h"
|
||||
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/media/base/testutils.h"
|
||||
#include "webrtc/media/engine/fakewebrtcdeviceinfo.h"
|
||||
#include "webrtc/media/engine/webrtcvideocapturer.h"
|
||||
|
||||
class FakeWebRtcVcmFactory;
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "webrtc/base/asyncinvoker.h"
|
||||
#include "webrtc/base/messagehandler.h"
|
||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
||||
#include "webrtc/media/base/device.h"
|
||||
#include "webrtc/media/base/videocapturer.h"
|
||||
#include "webrtc/media/engine/webrtcvideoframe.h"
|
||||
#include "webrtc/modules/video_capture/video_capture.h"
|
||||
|
||||
@ -61,7 +61,7 @@ const int kElevatedTraceFilter = kDefaultTraceFilter | webrtc::kTraceStateInfo |
|
||||
// -1 or 0 to select the default device.
|
||||
#ifdef WIN32
|
||||
const int kDefaultAudioDeviceId = -1;
|
||||
#else
|
||||
#elif !defined(WEBRTC_IOS)
|
||||
const int kDefaultAudioDeviceId = 0;
|
||||
#endif
|
||||
|
||||
|
||||
@ -78,7 +78,6 @@
|
||||
'base/videosourcebase.h',
|
||||
'base/yuvframegenerator.cc',
|
||||
'base/yuvframegenerator.h',
|
||||
'devices/deviceinfo.h',
|
||||
'devices/videorendererfactory.h',
|
||||
'engine/nullwebrtcvideoengine.h',
|
||||
'engine/simulcast.cc',
|
||||
@ -123,17 +122,6 @@
|
||||
4389, # signed/unsigned mismatch.
|
||||
],
|
||||
'conditions': [
|
||||
['include_internal_device_management==1', {
|
||||
'sources': [
|
||||
'devices/devicemanager.cc',
|
||||
'devices/devicemanager.h',
|
||||
],
|
||||
}, {
|
||||
'sources': [
|
||||
'devices/dummydevicemanager.cc',
|
||||
'devices/dummydevicemanager.h',
|
||||
],
|
||||
}],
|
||||
['build_libyuv==1', {
|
||||
'dependencies': ['<(DEPTH)/third_party/libyuv/libyuv.gyp:libyuv',],
|
||||
}],
|
||||
@ -172,9 +160,6 @@
|
||||
'sources': [
|
||||
'devices/libudevsymboltable.cc',
|
||||
'devices/libudevsymboltable.h',
|
||||
'devices/linuxdeviceinfo.cc',
|
||||
'devices/linuxdevicemanager.cc',
|
||||
'devices/linuxdevicemanager.h',
|
||||
'devices/v4llookup.cc',
|
||||
'devices/v4llookup.h',
|
||||
],
|
||||
@ -209,51 +194,6 @@
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS=="win" and include_internal_device_management==1', {
|
||||
'sources': [
|
||||
'devices/win32deviceinfo.cc',
|
||||
'devices/win32devicemanager.cc',
|
||||
'devices/win32devicemanager.h',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCLibrarianTool': {
|
||||
'AdditionalDependencies': [
|
||||
'winmm.lib',
|
||||
],
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS=="mac" and include_internal_device_management==1', {
|
||||
'sources': [
|
||||
'devices/macdeviceinfo.cc',
|
||||
'devices/macdevicemanager.cc',
|
||||
'devices/macdevicemanager.h',
|
||||
'devices/macdevicemanagermm.mm',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'WARNING_CFLAGS': [
|
||||
# TODO(perkj): Update macdevicemanager.cc to stop using
|
||||
# deprecated functions and remove this flag.
|
||||
'-Wno-deprecated-declarations',
|
||||
],
|
||||
# Disable partial availability warning to prevent errors
|
||||
# in macdevicemanagermm.mm using AVFoundation.
|
||||
# https://code.google.com/p/webrtc/issues/detail?id=4695
|
||||
'WARNING_CFLAGS!': ['-Wpartial-availability'],
|
||||
},
|
||||
'link_settings': {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'-weak_framework AVFoundation',
|
||||
'-framework Cocoa',
|
||||
'-framework CoreAudio',
|
||||
'-framework CoreVideo',
|
||||
'-framework OpenGL',
|
||||
'-framework QTKit',
|
||||
],
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS=="mac" and target_arch=="ia32"', {
|
||||
'sources': [
|
||||
'devices/carbonvideorenderer.cc',
|
||||
@ -267,36 +207,11 @@
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS=="ios" and include_internal_device_management==1', {
|
||||
'sources': [
|
||||
'devices/mobiledevicemanager.cc',
|
||||
],
|
||||
'include_dirs': [
|
||||
# TODO(sjlee) Remove when vp8 is building for iOS. vp8 pulls in
|
||||
# libjpeg which pulls in libyuv which currently disabled.
|
||||
'../../third_party/libyuv/include',
|
||||
],
|
||||
# TODO(kjellander): Make the code compile without disabling these.
|
||||
# See https://bugs.chromium.org/p/webrtc/issues/detail?id=3307
|
||||
'cflags': [
|
||||
'-Wno-unused-const-variable',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'WARNING_CFLAGS': [
|
||||
'-Wno-unused-const-variable',
|
||||
],
|
||||
},
|
||||
}],
|
||||
['OS=="ios" or (OS=="mac" and target_arch!="ia32")', {
|
||||
'defines': [
|
||||
'CARBON_DEPRECATED=YES',
|
||||
],
|
||||
}],
|
||||
['OS=="android" and include_internal_device_management==1', {
|
||||
'sources': [
|
||||
'devices/mobiledevicemanager.cc',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}, # target rtc_media
|
||||
], # targets.
|
||||
|
||||
@ -51,7 +51,6 @@
|
||||
'base/fakevideorenderer.h',
|
||||
'base/testutils.cc',
|
||||
'base/testutils.h',
|
||||
'devices/fakedevicemanager.h',
|
||||
'engine/fakewebrtccall.cc',
|
||||
'engine/fakewebrtccall.h',
|
||||
'engine/fakewebrtccommon.h',
|
||||
@ -88,16 +87,12 @@
|
||||
'base/videocommon_unittest.cc',
|
||||
'base/videoengine_unittest.h',
|
||||
'base/videoframe_unittest.h',
|
||||
'devices/dummydevicemanager_unittest.cc',
|
||||
'engine/nullwebrtcvideoengine_unittest.cc',
|
||||
'engine/simulcast_unittest.cc',
|
||||
'engine/webrtcmediaengine_unittest.cc',
|
||||
'engine/webrtcvideocapturer_unittest.cc',
|
||||
'engine/webrtcvideoframe_unittest.cc',
|
||||
'engine/webrtcvideoframefactory_unittest.cc',
|
||||
# Disabled because some tests fail.
|
||||
# TODO(ronghuawu): Reenable these tests.
|
||||
# 'devices/devicemanager_unittest.cc',
|
||||
'engine/webrtcvideoengine2_unittest.cc',
|
||||
'engine/webrtcvoiceengine_unittest.cc',
|
||||
'sctp/sctpdataengine_unittest.cc',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user