Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/midi/midi_manager_winrt.h" | 5 #include "media/midi/midi_manager_winrt.h" |
| 6 | 6 |
| 7 #include <comdef.h> | 7 #include <comdef.h> |
| 8 #include <robuffer.h> | 8 #include <robuffer.h> |
| 9 #include <windows.devices.enumeration.h> | 9 #include <windows.devices.enumeration.h> |
| 10 #include <windows.devices.midi.h> | 10 #include <windows.devices.midi.h> |
| 11 #include <wrl/event.h> | 11 #include <wrl/event.h> |
| 12 | 12 |
| 13 #include <iomanip> | 13 #include <iomanip> |
| 14 #include <unordered_map> | 14 #include <unordered_map> |
| 15 #include <unordered_set> | 15 #include <unordered_set> |
| 16 | 16 |
| 17 #include "base/bind.h" | 17 #include "base/bind.h" |
| 18 #include "base/lazy_instance.h" | |
| 18 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
| 19 #include "base/threading/thread_checker.h" | 20 #include "base/threading/thread_checker.h" |
| 20 #include "base/threading/thread_task_runner_handle.h" | 21 #include "base/threading/thread_task_runner_handle.h" |
| 21 #include "base/timer/timer.h" | 22 #include "base/timer/timer.h" |
| 22 #include "base/win/scoped_comptr.h" | 23 #include "base/win/scoped_comptr.h" |
| 23 #include "base/win/windows_version.h" | 24 #include "base/win/windows_version.h" |
| 24 #include "media/midi/midi_scheduler.h" | 25 #include "media/midi/midi_scheduler.h" |
| 25 | 26 |
| 26 namespace media { | 27 namespace media { |
| 27 namespace midi { | 28 namespace midi { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 43 }; | 44 }; |
| 44 | 45 |
| 45 std::ostream& operator<<(std::ostream& os, const PrintHr& phr) { | 46 std::ostream& operator<<(std::ostream& os, const PrintHr& phr) { |
| 46 std::ios_base::fmtflags ff = os.flags(); | 47 std::ios_base::fmtflags ff = os.flags(); |
| 47 os << _com_error(phr.hr).ErrorMessage() << " (0x" << std::hex | 48 os << _com_error(phr.hr).ErrorMessage() << " (0x" << std::hex |
| 48 << std::uppercase << std::setfill('0') << std::setw(8) << phr.hr << ")"; | 49 << std::uppercase << std::setfill('0') << std::setw(8) << phr.hr << ")"; |
| 49 os.flags(ff); | 50 os.flags(ff); |
| 50 return os; | 51 return os; |
| 51 } | 52 } |
| 52 | 53 |
| 54 class CombaseFunctions { | |
| 55 public: | |
| 56 CombaseFunctions() = default; | |
| 57 | |
| 58 ~CombaseFunctions() { | |
| 59 if (combase_dll_) | |
| 60 ::FreeLibrary(combase_dll_); | |
| 61 } | |
| 62 | |
| 63 bool LoadFunctions() { | |
| 64 combase_dll_ = ::LoadLibrary(L"combase.dll"); | |
| 65 if (!combase_dll_) | |
| 66 return false; | |
| 67 | |
| 68 get_factory_func_ = reinterpret_cast<decltype(&::RoGetActivationFactory)>( | |
| 69 ::GetProcAddress(combase_dll_, "RoGetActivationFactory")); | |
| 70 if (!get_factory_func_) | |
| 71 return false; | |
| 72 | |
| 73 create_string_func_ = reinterpret_cast<decltype(&::WindowsCreateString)>( | |
| 74 ::GetProcAddress(combase_dll_, "WindowsCreateString")); | |
| 75 if (!create_string_func_) | |
| 76 return false; | |
| 77 | |
| 78 delete_string_func_ = reinterpret_cast<decltype(&::WindowsDeleteString)>( | |
| 79 ::GetProcAddress(combase_dll_, "WindowsDeleteString")); | |
| 80 if (!delete_string_func_) | |
| 81 return false; | |
| 82 | |
| 83 get_string_raw_buffer_func_ = | |
| 84 reinterpret_cast<decltype(&::WindowsGetStringRawBuffer)>( | |
| 85 ::GetProcAddress(combase_dll_, "WindowsGetStringRawBuffer")); | |
| 86 if (!get_string_raw_buffer_func_) | |
| 87 return false; | |
| 88 | |
| 89 return true; | |
| 90 } | |
| 91 | |
| 92 HRESULT RoGetActivationFactory(HSTRING class_id, | |
| 93 const IID& iid, | |
| 94 void** out_factory) { | |
| 95 DCHECK(get_factory_func_); | |
| 96 return get_factory_func_(class_id, iid, out_factory); | |
| 97 } | |
| 98 | |
| 99 HRESULT WindowsCreateString(const base::char16* src, | |
| 100 uint32_t len, | |
| 101 HSTRING* out_hstr) { | |
| 102 DCHECK(create_string_func_); | |
| 103 return create_string_func_(src, len, out_hstr); | |
| 104 } | |
| 105 | |
| 106 HRESULT WindowsDeleteString(HSTRING hstr) { | |
| 107 DCHECK(delete_string_func_); | |
| 108 return delete_string_func_(hstr); | |
| 109 } | |
| 110 | |
| 111 const base::char16* WindowsGetStringRawBuffer(HSTRING hstr, | |
| 112 uint32_t* out_len) { | |
| 113 DCHECK(get_string_raw_buffer_func_); | |
| 114 return get_string_raw_buffer_func_(hstr, out_len); | |
| 115 } | |
| 116 | |
| 117 private: | |
| 118 HMODULE combase_dll_ = nullptr; | |
| 119 | |
| 120 decltype(&::RoGetActivationFactory) get_factory_func_ = nullptr; | |
| 121 decltype(&::WindowsCreateString) create_string_func_ = nullptr; | |
| 122 decltype(&::WindowsDeleteString) delete_string_func_ = nullptr; | |
| 123 decltype(&::WindowsGetStringRawBuffer) get_string_raw_buffer_func_ = nullptr; | |
| 124 }; | |
| 125 | |
| 126 base::LazyInstance<CombaseFunctions> g_combase_functions = | |
| 127 LAZY_INSTANCE_INITIALIZER; | |
| 128 | |
| 129 // Minimalist HSTRING wrapper class to properly maintain HSTRING lifetime. | |
|
Takashi Toyoshima
2016/08/31 10:10:29
Can you use base/scoped_generic.h infra to impleme
Shao-Chuan Lee
2016/09/01 03:06:44
Done.
| |
| 130 class HStringWrapper { | |
| 131 public: | |
| 132 HStringWrapper() = default; | |
| 133 ~HStringWrapper() { Release(); } | |
| 134 | |
| 135 HSTRING Get() { return hstring_; } | |
| 136 | |
| 137 HRESULT Set(const base::char16* str) { | |
| 138 Release(); | |
| 139 return g_combase_functions.Get().WindowsCreateString( | |
| 140 str, static_cast<uint32_t>(wcslen(str)), &hstring_); | |
| 141 } | |
| 142 | |
| 143 private: | |
| 144 void Release() { | |
| 145 if (hstring_) | |
| 146 g_combase_functions.Get().WindowsDeleteString(hstring_); | |
| 147 hstring_ = nullptr; | |
| 148 } | |
| 149 | |
| 150 HSTRING hstring_ = nullptr; | |
| 151 | |
| 152 DISALLOW_COPY_AND_ASSIGN(HStringWrapper); | |
| 153 }; | |
| 154 | |
| 53 // Factory functions that activate and create WinRT components. The caller takes | 155 // Factory functions that activate and create WinRT components. The caller takes |
| 54 // ownership of the returning ComPtr. | 156 // ownership of the returning ComPtr. |
| 55 template <typename InterfaceType, base::char16 const* runtime_class_id> | 157 template <typename InterfaceType, base::char16 const* runtime_class_id> |
| 56 ScopedComPtr<InterfaceType> WrlStaticsFactory() { | 158 ScopedComPtr<InterfaceType> WrlStaticsFactory() { |
| 57 ScopedComPtr<InterfaceType> com_ptr; | 159 ScopedComPtr<InterfaceType> com_ptr; |
| 58 | 160 |
| 59 HRESULT hr = GetActivationFactory( | 161 HStringWrapper class_id_hstring; |
| 60 WRL::Wrappers::HStringReference(runtime_class_id).Get(), | 162 HRESULT hr = class_id_hstring.Set(runtime_class_id); |
|
Shao-Chuan Lee
2016/08/31 09:52:13
Here we create new HSTRINGs with WindowsCreateStri
| |
| 61 com_ptr.Receive()); | |
| 62 if (FAILED(hr)) { | 163 if (FAILED(hr)) { |
| 63 VLOG(1) << "GetActivationFactory failed: " << PrintHr(hr); | 164 VLOG(1) << "WindowsCreateString failed: " << PrintHr(hr); |
| 165 com_ptr = nullptr; | |
| 166 return com_ptr; | |
| 167 } | |
| 168 | |
| 169 hr = g_combase_functions.Get().RoGetActivationFactory( | |
| 170 class_id_hstring.Get(), __uuidof(InterfaceType), com_ptr.ReceiveVoid()); | |
| 171 if (FAILED(hr)) { | |
| 172 VLOG(1) << "RoGetActivationFactory failed: " << PrintHr(hr); | |
| 64 com_ptr = nullptr; | 173 com_ptr = nullptr; |
| 65 } | 174 } |
| 66 | 175 |
| 67 return com_ptr; | 176 return com_ptr; |
| 68 } | 177 } |
| 69 | 178 |
| 70 template <typename T, HRESULT (T::*method)(HSTRING*)> | 179 template <typename T, HRESULT (T::*method)(HSTRING*)> |
| 71 std::string GetStringFromObjectMethod(T* obj) { | 180 std::string GetStringFromObjectMethod(T* obj) { |
| 72 HSTRING result; | 181 HSTRING result; |
| 73 HRESULT hr = (obj->*method)(&result); | 182 HRESULT hr = (obj->*method)(&result); |
| 74 if (FAILED(hr)) { | 183 if (FAILED(hr)) { |
| 75 VLOG(1) << "GetStringFromObjectMethod failed: " << PrintHr(hr); | 184 VLOG(1) << "GetStringFromObjectMethod failed: " << PrintHr(hr); |
| 76 return std::string(); | 185 return std::string(); |
| 77 } | 186 } |
| 78 | 187 |
| 79 // Note: empty HSTRINGs are represent as nullptr, and instantiating | 188 // Note: empty HSTRINGs are represent as nullptr, and instantiating |
| 80 // std::string with nullptr (in base::WideToUTF8) is undefined behavior. | 189 // std::string with nullptr (in base::WideToUTF8) is undefined behavior. |
| 81 const base::char16* buffer = WindowsGetStringRawBuffer(result, nullptr); | 190 const base::char16* buffer = |
| 191 g_combase_functions.Get().WindowsGetStringRawBuffer(result, nullptr); | |
| 82 if (buffer) | 192 if (buffer) |
| 83 return base::WideToUTF8(buffer); | 193 return base::WideToUTF8(buffer); |
| 84 return std::string(); | 194 return std::string(); |
| 85 } | 195 } |
| 86 | 196 |
| 87 template <typename T> | 197 template <typename T> |
| 88 std::string GetIdString(T* obj) { | 198 std::string GetIdString(T* obj) { |
| 89 return GetStringFromObjectMethod<T, &T::get_Id>(obj); | 199 return GetStringFromObjectMethod<T, &T::get_Id>(obj); |
| 90 } | 200 } |
| 91 | 201 |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 // DeviceWatcher callbacks: | 464 // DeviceWatcher callbacks: |
| 355 void OnAdded(std::string dev_id, std::string dev_name) { | 465 void OnAdded(std::string dev_id, std::string dev_name) { |
| 356 DCHECK(thread_checker_.CalledOnValidThread()); | 466 DCHECK(thread_checker_.CalledOnValidThread()); |
| 357 CHECK(is_initialized_); | 467 CHECK(is_initialized_); |
| 358 | 468 |
| 359 // TODO(shaochuan): Disable Microsoft GS Wavetable Synth due to security | 469 // TODO(shaochuan): Disable Microsoft GS Wavetable Synth due to security |
| 360 // reasons. http://crbug.com/499279 | 470 // reasons. http://crbug.com/499279 |
| 361 | 471 |
| 362 port_names_[dev_id] = dev_name; | 472 port_names_[dev_id] = dev_name; |
| 363 | 473 |
| 364 WRL::Wrappers::HString dev_id_hstring; | 474 HStringWrapper dev_id_hstring; |
| 365 HRESULT hr = dev_id_hstring.Set(base::UTF8ToWide(dev_id).c_str()); | 475 HRESULT hr = dev_id_hstring.Set(base::UTF8ToWide(dev_id).c_str()); |
| 366 if (FAILED(hr)) { | 476 if (FAILED(hr)) { |
| 367 VLOG(1) << "Set failed: " << PrintHr(hr); | 477 VLOG(1) << "Set failed: " << PrintHr(hr); |
| 368 return; | 478 return; |
| 369 } | 479 } |
| 370 | 480 |
| 371 IAsyncOperation<RuntimeType*>* async_op; | 481 IAsyncOperation<RuntimeType*>* async_op; |
| 372 | 482 |
| 373 hr = midi_port_statics_->FromIdAsync(dev_id_hstring.Get(), &async_op); | 483 hr = midi_port_statics_->FromIdAsync(dev_id_hstring.Get(), &async_op); |
| 374 if (FAILED(hr)) { | 484 if (FAILED(hr)) { |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 684 CHECK(!scheduler_); | 794 CHECK(!scheduler_); |
| 685 } | 795 } |
| 686 | 796 |
| 687 void MidiManagerWinrt::StartInitialization() { | 797 void MidiManagerWinrt::StartInitialization() { |
| 688 if (base::win::GetVersion() < base::win::VERSION_WIN10) { | 798 if (base::win::GetVersion() < base::win::VERSION_WIN10) { |
| 689 VLOG(1) << "WinRT MIDI backend is only supported on Windows 10 or later."; | 799 VLOG(1) << "WinRT MIDI backend is only supported on Windows 10 or later."; |
| 690 CompleteInitialization(Result::INITIALIZATION_ERROR); | 800 CompleteInitialization(Result::INITIALIZATION_ERROR); |
| 691 return; | 801 return; |
| 692 } | 802 } |
| 693 | 803 |
| 804 if (!g_combase_functions.Get().LoadFunctions()) { | |
| 805 VLOG(1) << "Failed loading functions from Combase.dll: " | |
| 806 << PrintHr(HRESULT_FROM_WIN32(GetLastError())); | |
| 807 CompleteInitialization(Result::INITIALIZATION_ERROR); | |
| 808 return; | |
| 809 } | |
| 810 | |
| 694 com_thread_.init_com_with_mta(true); | 811 com_thread_.init_com_with_mta(true); |
| 695 com_thread_.Start(); | 812 com_thread_.Start(); |
| 696 | 813 |
| 697 com_thread_.task_runner()->PostTask( | 814 com_thread_.task_runner()->PostTask( |
| 698 FROM_HERE, base::Bind(&MidiManagerWinrt::InitializeOnComThread, | 815 FROM_HERE, base::Bind(&MidiManagerWinrt::InitializeOnComThread, |
| 699 base::Unretained(this))); | 816 base::Unretained(this))); |
| 700 } | 817 } |
| 701 | 818 |
| 702 void MidiManagerWinrt::Finalize() { | 819 void MidiManagerWinrt::Finalize() { |
| 703 com_thread_.task_runner()->PostTask( | 820 com_thread_.task_runner()->PostTask( |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 805 if (++port_manager_ready_count_ == 2) | 922 if (++port_manager_ready_count_ == 2) |
| 806 CompleteInitialization(Result::OK); | 923 CompleteInitialization(Result::OK); |
| 807 } | 924 } |
| 808 | 925 |
| 809 MidiManager* MidiManager::Create() { | 926 MidiManager* MidiManager::Create() { |
| 810 return new MidiManagerWinrt(); | 927 return new MidiManagerWinrt(); |
| 811 } | 928 } |
| 812 | 929 |
| 813 } // namespace midi | 930 } // namespace midi |
| 814 } // namespace media | 931 } // namespace media |
| OLD | NEW |