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" | |
| 19 #include "base/scoped_generic.h" | |
| 18 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
| 19 #include "base/threading/thread_checker.h" | 21 #include "base/threading/thread_checker.h" |
| 20 #include "base/threading/thread_task_runner_handle.h" | 22 #include "base/threading/thread_task_runner_handle.h" |
| 21 #include "base/timer/timer.h" | 23 #include "base/timer/timer.h" |
| 22 #include "base/win/scoped_comptr.h" | 24 #include "base/win/scoped_comptr.h" |
| 23 #include "base/win/windows_version.h" | 25 #include "base/win/windows_version.h" |
| 24 #include "media/midi/midi_scheduler.h" | 26 #include "media/midi/midi_scheduler.h" |
| 25 | 27 |
| 26 namespace media { | 28 namespace media { |
| 27 namespace midi { | 29 namespace midi { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 43 }; | 45 }; |
| 44 | 46 |
| 45 std::ostream& operator<<(std::ostream& os, const PrintHr& phr) { | 47 std::ostream& operator<<(std::ostream& os, const PrintHr& phr) { |
| 46 std::ios_base::fmtflags ff = os.flags(); | 48 std::ios_base::fmtflags ff = os.flags(); |
| 47 os << _com_error(phr.hr).ErrorMessage() << " (0x" << std::hex | 49 os << _com_error(phr.hr).ErrorMessage() << " (0x" << std::hex |
| 48 << std::uppercase << std::setfill('0') << std::setw(8) << phr.hr << ")"; | 50 << std::uppercase << std::setfill('0') << std::setw(8) << phr.hr << ")"; |
| 49 os.flags(ff); | 51 os.flags(ff); |
| 50 return os; | 52 return os; |
| 51 } | 53 } |
| 52 | 54 |
| 55 // Provides access to functions in combase.dll which may not be available on | |
| 56 // Windows 7. Loads functions dynamically at runtime to prevent library | |
| 57 // dependencies. Use this class through the global LazyInstance | |
| 58 // |g_combase_functions|. | |
| 59 class CombaseFunctions { | |
| 60 public: | |
| 61 CombaseFunctions() = default; | |
| 62 | |
| 63 ~CombaseFunctions() { | |
| 64 if (combase_dll_) | |
| 65 ::FreeLibrary(combase_dll_); | |
| 66 } | |
| 67 | |
| 68 bool LoadFunctions() { | |
| 69 combase_dll_ = ::LoadLibrary(L"combase.dll"); | |
| 70 if (!combase_dll_) | |
| 71 return false; | |
| 72 | |
| 73 get_factory_func_ = reinterpret_cast<decltype(&::RoGetActivationFactory)>( | |
| 74 ::GetProcAddress(combase_dll_, "RoGetActivationFactory")); | |
| 75 if (!get_factory_func_) | |
| 76 return false; | |
| 77 | |
| 78 create_string_func_ = reinterpret_cast<decltype(&::WindowsCreateString)>( | |
| 79 ::GetProcAddress(combase_dll_, "WindowsCreateString")); | |
| 80 if (!create_string_func_) | |
| 81 return false; | |
| 82 | |
| 83 delete_string_func_ = reinterpret_cast<decltype(&::WindowsDeleteString)>( | |
| 84 ::GetProcAddress(combase_dll_, "WindowsDeleteString")); | |
| 85 if (!delete_string_func_) | |
| 86 return false; | |
| 87 | |
| 88 get_string_raw_buffer_func_ = | |
| 89 reinterpret_cast<decltype(&::WindowsGetStringRawBuffer)>( | |
| 90 ::GetProcAddress(combase_dll_, "WindowsGetStringRawBuffer")); | |
| 91 if (!get_string_raw_buffer_func_) | |
| 92 return false; | |
| 93 | |
| 94 return true; | |
| 95 } | |
| 96 | |
| 97 HRESULT RoGetActivationFactory(HSTRING class_id, | |
| 98 const IID& iid, | |
| 99 void** out_factory) { | |
| 100 DCHECK(get_factory_func_); | |
| 101 return get_factory_func_(class_id, iid, out_factory); | |
| 102 } | |
| 103 | |
| 104 HRESULT WindowsCreateString(const base::char16* src, | |
| 105 uint32_t len, | |
| 106 HSTRING* out_hstr) { | |
| 107 DCHECK(create_string_func_); | |
| 108 return create_string_func_(src, len, out_hstr); | |
| 109 } | |
| 110 | |
| 111 HRESULT WindowsDeleteString(HSTRING hstr) { | |
| 112 DCHECK(delete_string_func_); | |
| 113 return delete_string_func_(hstr); | |
| 114 } | |
| 115 | |
| 116 const base::char16* WindowsGetStringRawBuffer(HSTRING hstr, | |
| 117 uint32_t* out_len) { | |
| 118 DCHECK(get_string_raw_buffer_func_); | |
| 119 return get_string_raw_buffer_func_(hstr, out_len); | |
| 120 } | |
| 121 | |
| 122 private: | |
| 123 HMODULE combase_dll_ = nullptr; | |
| 124 | |
| 125 decltype(&::RoGetActivationFactory) get_factory_func_ = nullptr; | |
| 126 decltype(&::WindowsCreateString) create_string_func_ = nullptr; | |
| 127 decltype(&::WindowsDeleteString) delete_string_func_ = nullptr; | |
| 128 decltype(&::WindowsGetStringRawBuffer) get_string_raw_buffer_func_ = nullptr; | |
| 129 }; | |
| 130 | |
| 131 base::LazyInstance<CombaseFunctions> g_combase_functions = | |
| 132 LAZY_INSTANCE_INITIALIZER; | |
| 133 | |
| 134 // Scoped HSTRING class to maintain lifetime of HSTRINGs allocated with | |
| 135 // WindowsCreateString(). | |
| 136 class ScopedHStringTraits { | |
| 137 public: | |
| 138 static HSTRING InvalidValue() { return nullptr; } | |
| 139 | |
| 140 static void Free(HSTRING hstr) { | |
| 141 g_combase_functions.Get().WindowsDeleteString(hstr); | |
| 142 } | |
| 143 }; | |
| 144 | |
| 145 class ScopedHString : public base::ScopedGeneric<HSTRING, ScopedHStringTraits> { | |
| 146 public: | |
| 147 explicit ScopedHString(const base::char16* str) : ScopedGeneric(nullptr) { | |
| 148 HSTRING hstr; | |
| 149 HRESULT hr = g_combase_functions.Get().WindowsCreateString( | |
| 150 str, static_cast<uint32_t>(wcslen(str)), &hstr); | |
| 151 if (FAILED(hr)) | |
| 152 VLOG(1) << "WindowsCreateString failed: " << PrintHr(hr); | |
| 153 else | |
| 154 reset(hstr); | |
| 155 } | |
| 156 }; | |
| 157 | |
| 53 // Factory functions that activate and create WinRT components. The caller takes | 158 // Factory functions that activate and create WinRT components. The caller takes |
| 54 // ownership of the returning ComPtr. | 159 // ownership of the returning ComPtr. |
| 55 template <typename InterfaceType, base::char16 const* runtime_class_id> | 160 template <typename InterfaceType, base::char16 const* runtime_class_id> |
| 56 ScopedComPtr<InterfaceType> WrlStaticsFactory() { | 161 ScopedComPtr<InterfaceType> WrlStaticsFactory() { |
| 57 ScopedComPtr<InterfaceType> com_ptr; | 162 ScopedComPtr<InterfaceType> com_ptr; |
| 58 | 163 |
| 59 HRESULT hr = GetActivationFactory( | 164 ScopedHString class_id_hstring(runtime_class_id); |
| 60 WRL::Wrappers::HStringReference(runtime_class_id).Get(), | 165 if (!class_id_hstring.is_valid()) { |
| 61 com_ptr.Receive()); | 166 com_ptr = nullptr; |
| 167 return com_ptr; | |
| 168 } | |
| 169 | |
| 170 HRESULT hr = g_combase_functions.Get().RoGetActivationFactory( | |
| 171 class_id_hstring.get(), __uuidof(InterfaceType), com_ptr.ReceiveVoid()); | |
| 62 if (FAILED(hr)) { | 172 if (FAILED(hr)) { |
| 63 VLOG(1) << "GetActivationFactory failed: " << PrintHr(hr); | 173 VLOG(1) << "RoGetActivationFactory failed: " << PrintHr(hr); |
| 64 com_ptr = nullptr; | 174 com_ptr = nullptr; |
| 65 } | 175 } |
| 66 | 176 |
| 67 return com_ptr; | 177 return com_ptr; |
| 68 } | 178 } |
| 69 | 179 |
| 70 template <typename T, HRESULT (T::*method)(HSTRING*)> | 180 template <typename T, HRESULT (T::*method)(HSTRING*)> |
| 71 std::string GetStringFromObjectMethod(T* obj) { | 181 std::string GetStringFromObjectMethod(T* obj) { |
| 72 HSTRING result; | 182 HSTRING result; |
| 73 HRESULT hr = (obj->*method)(&result); | 183 HRESULT hr = (obj->*method)(&result); |
| 74 if (FAILED(hr)) { | 184 if (FAILED(hr)) { |
| 75 VLOG(1) << "GetStringFromObjectMethod failed: " << PrintHr(hr); | 185 VLOG(1) << "GetStringFromObjectMethod failed: " << PrintHr(hr); |
| 76 return std::string(); | 186 return std::string(); |
| 77 } | 187 } |
| 78 | 188 |
| 79 // Note: empty HSTRINGs are represent as nullptr, and instantiating | 189 // Note: empty HSTRINGs are represent as nullptr, and instantiating |
| 80 // std::string with nullptr (in base::WideToUTF8) is undefined behavior. | 190 // std::string with nullptr (in base::WideToUTF8) is undefined behavior. |
| 81 const base::char16* buffer = WindowsGetStringRawBuffer(result, nullptr); | 191 const base::char16* buffer = |
| 192 g_combase_functions.Get().WindowsGetStringRawBuffer(result, nullptr); | |
| 82 if (buffer) | 193 if (buffer) |
| 83 return base::WideToUTF8(buffer); | 194 return base::WideToUTF8(buffer); |
| 84 return std::string(); | 195 return std::string(); |
| 85 } | 196 } |
| 86 | 197 |
| 87 template <typename T> | 198 template <typename T> |
| 88 std::string GetIdString(T* obj) { | 199 std::string GetIdString(T* obj) { |
| 89 return GetStringFromObjectMethod<T, &T::get_Id>(obj); | 200 return GetStringFromObjectMethod<T, &T::get_Id>(obj); |
| 90 } | 201 } |
| 91 | 202 |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 368 base::ThreadChecker thread_checker_; | 479 base::ThreadChecker thread_checker_; |
| 369 | 480 |
| 370 private: | 481 private: |
| 371 // DeviceWatcher callbacks: | 482 // DeviceWatcher callbacks: |
| 372 void OnAdded(std::string dev_id, std::string dev_name) { | 483 void OnAdded(std::string dev_id, std::string dev_name) { |
| 373 DCHECK(thread_checker_.CalledOnValidThread()); | 484 DCHECK(thread_checker_.CalledOnValidThread()); |
| 374 CHECK(is_initialized_); | 485 CHECK(is_initialized_); |
| 375 | 486 |
| 376 port_names_[dev_id] = dev_name; | 487 port_names_[dev_id] = dev_name; |
| 377 | 488 |
| 378 WRL::Wrappers::HString dev_id_hstring; | 489 ScopedHString dev_id_hstring(base::UTF8ToWide(dev_id).c_str()); |
| 379 HRESULT hr = dev_id_hstring.Set(base::UTF8ToWide(dev_id).c_str()); | 490 if (!dev_id_hstring.is_valid()) |
| 380 if (FAILED(hr)) { | |
| 381 VLOG(1) << "Set failed: " << PrintHr(hr); | |
| 382 return; | 491 return; |
| 383 } | |
| 384 | 492 |
| 385 IAsyncOperation<RuntimeType*>* async_op; | 493 IAsyncOperation<RuntimeType*>* async_op; |
| 386 | 494 |
| 387 hr = midi_port_statics_->FromIdAsync(dev_id_hstring.Get(), &async_op); | 495 HRESULT hr = |
| 496 midi_port_statics_->FromIdAsync(dev_id_hstring.get(), &async_op); | |
| 388 if (FAILED(hr)) { | 497 if (FAILED(hr)) { |
| 389 VLOG(1) << "FromIdAsync failed: " << PrintHr(hr); | 498 VLOG(1) << "FromIdAsync failed: " << PrintHr(hr); |
| 390 return; | 499 return; |
| 391 } | 500 } |
| 392 | 501 |
| 393 base::WeakPtr<MidiPortManager> weak_ptr = GetWeakPtrFromFactory(); | 502 base::WeakPtr<MidiPortManager> weak_ptr = GetWeakPtrFromFactory(); |
| 394 scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_; | 503 scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_; |
| 395 | 504 |
| 396 hr = async_op->put_Completed( | 505 hr = async_op->put_Completed( |
| 397 WRL::Callback<IAsyncOperationCompletedHandler<RuntimeType*>>( | 506 WRL::Callback<IAsyncOperationCompletedHandler<RuntimeType*>>( |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 735 client, data.size(), timestamp, | 844 client, data.size(), timestamp, |
| 736 base::Bind(&MidiManagerWinrt::SendOnComThread, base::Unretained(this), | 845 base::Bind(&MidiManagerWinrt::SendOnComThread, base::Unretained(this), |
| 737 port_index, data)); | 846 port_index, data)); |
| 738 } | 847 } |
| 739 | 848 |
| 740 void MidiManagerWinrt::InitializeOnComThread() { | 849 void MidiManagerWinrt::InitializeOnComThread() { |
| 741 base::AutoLock auto_lock(lazy_init_member_lock_); | 850 base::AutoLock auto_lock(lazy_init_member_lock_); |
| 742 | 851 |
| 743 com_thread_checker_.reset(new base::ThreadChecker); | 852 com_thread_checker_.reset(new base::ThreadChecker); |
| 744 | 853 |
| 854 if (!g_combase_functions.Get().LoadFunctions()) { | |
| 855 VLOG(1) << "Failed loading functions from combase.dll: " | |
| 856 << PrintHr(HRESULT_FROM_WIN32(GetLastError())); | |
| 857 CompleteInitialization(Result::INITIALIZATION_ERROR); | |
| 858 return; | |
| 859 } | |
| 860 | |
| 745 port_manager_in_.reset(new MidiInPortManager(this)); | 861 port_manager_in_.reset(new MidiInPortManager(this)); |
| 746 port_manager_out_.reset(new MidiOutPortManager(this)); | 862 port_manager_out_.reset(new MidiOutPortManager(this)); |
| 747 | 863 |
| 748 scheduler_.reset(new MidiScheduler(this)); | 864 scheduler_.reset(new MidiScheduler(this)); |
| 749 | 865 |
| 750 if (!(port_manager_in_->StartWatcher() && | 866 if (!(port_manager_in_->StartWatcher() && |
| 751 port_manager_out_->StartWatcher())) { | 867 port_manager_out_->StartWatcher())) { |
| 752 port_manager_in_->StopWatcher(); | 868 port_manager_in_->StopWatcher(); |
| 753 port_manager_out_->StopWatcher(); | 869 port_manager_out_->StopWatcher(); |
| 754 CompleteInitialization(Result::INITIALIZATION_ERROR); | 870 CompleteInitialization(Result::INITIALIZATION_ERROR); |
| 755 } | 871 } |
| 756 } | 872 } |
| 757 | 873 |
| 758 void MidiManagerWinrt::FinalizeOnComThread() { | 874 void MidiManagerWinrt::FinalizeOnComThread() { |
| 759 base::AutoLock auto_lock(lazy_init_member_lock_); | 875 base::AutoLock auto_lock(lazy_init_member_lock_); |
| 760 | 876 |
| 761 DCHECK(com_thread_checker_->CalledOnValidThread()); | 877 DCHECK(com_thread_checker_->CalledOnValidThread()); |
| 762 | 878 |
| 763 scheduler_.reset(); | 879 scheduler_.reset(); |
| 764 | 880 |
| 765 port_manager_in_->StopWatcher(); | 881 if (port_manager_in_) { |
|
Shao-Chuan Lee
2016/09/01 06:11:35
Additional checks in case InitializeOnComThread()
| |
| 766 port_manager_in_.reset(); | 882 port_manager_in_->StopWatcher(); |
| 767 port_manager_out_->StopWatcher(); | 883 port_manager_in_.reset(); |
| 768 port_manager_out_.reset(); | 884 } |
| 885 | |
| 886 if (port_manager_out_) { | |
|
Shao-Chuan Lee
2016/09/01 06:11:35
ditto
| |
| 887 port_manager_out_->StopWatcher(); | |
| 888 port_manager_out_.reset(); | |
| 889 } | |
| 769 | 890 |
| 770 com_thread_checker_.reset(); | 891 com_thread_checker_.reset(); |
| 771 } | 892 } |
| 772 | 893 |
| 773 void MidiManagerWinrt::SendOnComThread(uint32_t port_index, | 894 void MidiManagerWinrt::SendOnComThread(uint32_t port_index, |
| 774 const std::vector<uint8_t>& data) { | 895 const std::vector<uint8_t>& data) { |
| 775 DCHECK(com_thread_checker_->CalledOnValidThread()); | 896 DCHECK(com_thread_checker_->CalledOnValidThread()); |
| 776 | 897 |
| 777 MidiPort<IMidiOutPort>* port = port_manager_out_->GetPortByIndex(port_index); | 898 MidiPort<IMidiOutPort>* port = port_manager_out_->GetPortByIndex(port_index); |
| 778 if (!(port && port->handle)) { | 899 if (!(port && port->handle)) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 821 if (++port_manager_ready_count_ == 2) | 942 if (++port_manager_ready_count_ == 2) |
| 822 CompleteInitialization(Result::OK); | 943 CompleteInitialization(Result::OK); |
| 823 } | 944 } |
| 824 | 945 |
| 825 MidiManager* MidiManager::Create() { | 946 MidiManager* MidiManager::Create() { |
| 826 return new MidiManagerWinrt(); | 947 return new MidiManagerWinrt(); |
| 827 } | 948 } |
| 828 | 949 |
| 829 } // namespace midi | 950 } // namespace midi |
| 830 } // namespace media | 951 } // namespace media |
| OLD | NEW |