15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/* 25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle 35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2004 Google Inc. 45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without 65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met: 75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 1. Redistributions of source code must retain the above copyright notice, 95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * this list of conditions and the following disclaimer. 105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 2. Redistributions in binary form must reproduce the above copyright notice, 115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * this list of conditions and the following disclaimer in the documentation 125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * and/or other materials provided with the distribution. 135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 3. The name of the author may not be used to endorse or promote products 145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * derived from this software without specific prior written permission. 155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */ 275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/devices/win32devicemanager.h" 295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <atlbase.h> 315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <dbt.h> 325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <strmif.h> // must come before ks.h 335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <ks.h> 345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <ksmedia.h> 355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#define INITGUID // For PKEY_AudioEndpoint_GUID 365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <mmdeviceapi.h> 375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <mmsystem.h> 385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <functiondiscoverykeys_devpkey.h> 395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <uuids.h> 405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/logging.h" 425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/stringutils.h" 435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/thread.h" 445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/win32.h" // ToUtf8 455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/win32window.h" 465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/base/mediacommon.h" 475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef HAVE_LOGITECH_HEADERS 485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "third_party/logitech/files/logitechquickcam.h" 495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif 505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace cricket { 525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgDeviceManagerInterface* DeviceManagerFactory::Create() { 545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return new Win32DeviceManager(); 555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass Win32DeviceWatcher 585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : public DeviceWatcher, 595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public talk_base::Win32Window { 605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public: 615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org explicit Win32DeviceWatcher(Win32DeviceManager* dm); 625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual ~Win32DeviceWatcher(); 635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual bool Start(); 645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void Stop(); 655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private: 675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HDEVNOTIFY Register(REFGUID guid); 685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void Unregister(HDEVNOTIFY notify); 695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual bool OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT& result); 705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Win32DeviceManager* manager_; 725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HDEVNOTIFY audio_notify_; 735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HDEVNOTIFY video_notify_; 745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char* kFilteredAudioDevicesName[] = { 775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org NULL, 785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char* const kFilteredVideoDevicesName[] = { 805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org "Asus virtual Camera", // Bad Asus desktop virtual cam 815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org "Bluetooth Video", // Bad Sony viao bluetooth sharing driver 825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org NULL, 835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const wchar_t kFriendlyName[] = L"FriendlyName"; 855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const wchar_t kDevicePath[] = L"DevicePath"; 865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char kUsbDevicePathPrefix[] = "\\\\?\\usb"; 875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool GetDevices(const CLSID& catid, std::vector<Device>* out); 885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool GetCoreAudioDevices(bool input, std::vector<Device>* devs); 895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool GetWaveDevices(bool input, std::vector<Device>* devs); 905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWin32DeviceManager::Win32DeviceManager() 925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : need_couninitialize_(false) { 935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_watcher(new Win32DeviceWatcher(this)); 945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWin32DeviceManager::~Win32DeviceManager() { 975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (initialized()) { 985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Terminate(); 995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool Win32DeviceManager::Init() { 1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!initialized()) { 1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org need_couninitialize_ = SUCCEEDED(hr); 1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (FAILED(hr)) { 1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr; 1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (hr != RPC_E_CHANGED_MODE) { 1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!watcher()->Start()) { 1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_initialized(true); 1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid Win32DeviceManager::Terminate() { 1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (initialized()) { 1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org watcher()->Stop(); 1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (need_couninitialize_) { 1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CoUninitialize(); 1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org need_couninitialize_ = false; 1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_initialized(false); 1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool Win32DeviceManager::GetDefaultVideoCaptureDevice(Device* device) { 1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org bool ret = false; 1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // If there are multiple capture devices, we want the first USB one. 1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // This avoids issues with defaulting to virtual cameras or grabber cards. 1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::vector<Device> devices; 1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ret = (GetVideoCaptureDevices(&devices) && !devices.empty()); 1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (ret) { 1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *device = devices[0]; 1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org for (size_t i = 0; i < devices.size(); ++i) { 1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (strnicmp(devices[i].id.c_str(), kUsbDevicePathPrefix, 1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ARRAY_SIZE(kUsbDevicePathPrefix) - 1) == 0) { 1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *device = devices[i]; 1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return ret; 1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool Win32DeviceManager::GetAudioDevices(bool input, 1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::vector<Device>* devs) { 1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devs->clear(); 1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (talk_base::IsWindowsVistaOrLater()) { 1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!GetCoreAudioDevices(input, devs)) 1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!GetWaveDevices(input, devs)) 1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return FilterDevices(devs, kFilteredAudioDevicesName); 1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool Win32DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) { 1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devices->clear(); 1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!GetDevices(CLSID_VideoInputDeviceCategory, devices)) { 1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return FilterDevices(devices, kFilteredVideoDevicesName); 1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool GetDevices(const CLSID& catid, std::vector<Device>* devices) { 1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HRESULT hr; 1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // CComPtr is a scoped pointer that will be auto released when going 1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // out of scope. CoUninitialize must not be called before the 1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // release. 1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComPtr<ICreateDevEnum> sys_dev_enum; 1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComPtr<IEnumMoniker> cam_enum; 1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (FAILED(hr = sys_dev_enum.CoCreateInstance(CLSID_SystemDeviceEnum)) || 1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org FAILED(hr = sys_dev_enum->CreateClassEnumerator(catid, &cam_enum, 0))) { 1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "Failed to create device enumerator, hr=" << hr; 1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Only enum devices if CreateClassEnumerator returns S_OK. If there are no 1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // devices available, S_FALSE will be returned, but enumMk will be NULL. 1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (hr == S_OK) { 1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComPtr<IMoniker> mk; 1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org while (cam_enum->Next(1, &mk, NULL) == S_OK) { 1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef HAVE_LOGITECH_HEADERS 1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Initialize Logitech device if applicable 1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org MaybeLogitechDeviceReset(mk); 1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif 1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComPtr<IPropertyBag> bag; 1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(mk->BindToStorage(NULL, NULL, 1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org __uuidof(bag), reinterpret_cast<void**>(&bag)))) { 1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComVariant name, path; 1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::string name_str, path_str; 2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(bag->Read(kFriendlyName, &name, 0)) && 2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org name.vt == VT_BSTR) { 2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org name_str = talk_base::ToUtf8(name.bstrVal); 2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Get the device id if one exists. 2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(bag->Read(kDevicePath, &path, 0)) && 2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org path.vt == VT_BSTR) { 2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org path_str = talk_base::ToUtf8(path.bstrVal); 2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devices->push_back(Device(name_str, path_str)); 2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org mk = NULL; 2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgHRESULT GetStringProp(IPropertyStore* bag, PROPERTYKEY key, std::string* out) { 2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org out->clear(); 2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org PROPVARIANT var; 2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org PropVariantInit(&var); 2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HRESULT hr = bag->GetValue(key, &var); 2255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(hr)) { 2265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (var.pwszVal) 2275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *out = talk_base::ToUtf8(var.pwszVal); 2285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org else 2295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = E_FAIL; 2305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org PropVariantClear(&var); 2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return hr; 2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Adapted from http://msdn.microsoft.com/en-us/library/dd370812(v=VS.85).aspx 2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgHRESULT CricketDeviceFromImmDevice(IMMDevice* device, Device* out) { 2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComPtr<IPropertyStore> props; 2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HRESULT hr = device->OpenPropertyStore(STGM_READ, &props); 2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (FAILED(hr)) { 2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return hr; 2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Get the endpoint's name and id. 2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::string name, guid; 2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = GetStringProp(props, PKEY_Device_FriendlyName, &name); 2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(hr)) { 2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = GetStringProp(props, PKEY_AudioEndpoint_GUID, &guid); 2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(hr)) { 2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org out->name = name; 2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org out->id = guid; 2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return hr; 2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool GetCoreAudioDevices( 2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org bool input, std::vector<Device>* devs) { 2615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HRESULT hr = S_OK; 2625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComPtr<IMMDeviceEnumerator> enumerator; 2635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, 2655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org __uuidof(IMMDeviceEnumerator), reinterpret_cast<void**>(&enumerator)); 2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(hr)) { 2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComPtr<IMMDeviceCollection> devices; 2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = enumerator->EnumAudioEndpoints((input ? eCapture : eRender), 2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DEVICE_STATE_ACTIVE, &devices); 2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(hr)) { 2715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org unsigned int count; 2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = devices->GetCount(&count); 2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(hr)) { 2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org for (unsigned int i = 0; i < count; i++) { 2765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CComPtr<IMMDevice> device; 2775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Get pointer to endpoint number i. 2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = devices->Item(i, &device); 2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (FAILED(hr)) { 2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Device dev; 2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = CricketDeviceFromImmDevice(device, &dev); 2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (SUCCEEDED(hr)) { 2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devs->push_back(dev); 2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_WARNING) << "Unable to query IMM Device, skipping. HR=" 2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << hr; 2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org hr = S_FALSE; 2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (FAILED(hr)) { 2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_WARNING) << "GetCoreAudioDevices failed with hr " << hr; 3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 3015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 3035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool GetWaveDevices(bool input, std::vector<Device>* devs) { 3065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Note, we don't use the System Device Enumerator interface here since it 3075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // adds lots of pseudo-devices to the list, such as DirectSound and Wave 3085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // variants of the same device. 3095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (input) { 3105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int num_devs = waveInGetNumDevs(); 3115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org for (int i = 0; i < num_devs; ++i) { 3125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org WAVEINCAPS caps; 3135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (waveInGetDevCaps(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR && 3145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org caps.wChannels > 0) { 3155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devs->push_back(Device(talk_base::ToUtf8(caps.szPname), 3165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::ToString(i))); 3175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 3205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int num_devs = waveOutGetNumDevs(); 3215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org for (int i = 0; i < num_devs; ++i) { 3225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org WAVEOUTCAPS caps; 3235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (waveOutGetDevCaps(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR && 3245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org caps.wChannels > 0) { 3255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devs->push_back(Device(talk_base::ToUtf8(caps.szPname), i)); 3265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 3305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWin32DeviceWatcher::Win32DeviceWatcher(Win32DeviceManager* manager) 3335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : DeviceWatcher(manager), 3345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org manager_(manager), 3355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org audio_notify_(NULL), 3365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org video_notify_(NULL) { 3375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWin32DeviceWatcher::~Win32DeviceWatcher() { 3405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool Win32DeviceWatcher::Start() { 3435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!Create(NULL, _T("libjingle Win32DeviceWatcher Window"), 3445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 0, 0, 0, 0, 0, 0)) { 3455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 3465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org audio_notify_ = Register(KSCATEGORY_AUDIO); 3495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!audio_notify_) { 3505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Stop(); 3515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 3525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org video_notify_ = Register(KSCATEGORY_VIDEO); 3555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!video_notify_) { 3565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Stop(); 3575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 3585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 3615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid Win32DeviceWatcher::Stop() { 3645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org UnregisterDeviceNotification(video_notify_); 3655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org video_notify_ = NULL; 3665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org UnregisterDeviceNotification(audio_notify_); 3675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org audio_notify_ = NULL; 3685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Destroy(); 3695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgHDEVNOTIFY Win32DeviceWatcher::Register(REFGUID guid) { 3725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DEV_BROADCAST_DEVICEINTERFACE dbdi; 3735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dbdi.dbcc_size = sizeof(dbdi); 3745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dbdi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 3755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dbdi.dbcc_classguid = guid; 3765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dbdi.dbcc_name[0] = '\0'; 3775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return RegisterDeviceNotification(handle(), &dbdi, 3785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DEVICE_NOTIFY_WINDOW_HANDLE); 3795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid Win32DeviceWatcher::Unregister(HDEVNOTIFY handle) { 3825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org UnregisterDeviceNotification(handle); 3835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool Win32DeviceWatcher::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, 3865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LRESULT& result) { 3875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (uMsg == WM_DEVICECHANGE) { 3885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (wParam == DBT_DEVICEARRIVAL || 3895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org wParam == DBT_DEVICEREMOVECOMPLETE) { 3905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DEV_BROADCAST_DEVICEINTERFACE* dbdi = 3915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(lParam); 3925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO || 3935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dbdi->dbcc_classguid == KSCATEGORY_VIDEO) { 3945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org manager_->SignalDevicesChange(); 3955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org result = 0; 3985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 3995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 4025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; // namespace cricket 405