| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "device/vr/vr_device_manager.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/singleton.h" |
| #include "build/build_config.h" |
| #include "device/vr/vr_service_impl.h" |
| |
| #if defined(OS_WIN) |
| #include "device/vr/oculus/oculus_vr_device_provider.h" |
| #include "device/vr/openvr/open_vr_device_provider.h" |
| #endif |
| |
| #if defined(OS_ANDROID) |
| #include "device/vr/android/gvr/gvr_device_provider.h" |
| #endif |
| |
| namespace device { |
| |
| namespace { |
| VRDeviceManager* g_vr_device_manager = nullptr; |
| } |
| |
| VRDeviceManager::VRDeviceManager() |
| : vr_initialized_(false), presenting_service_(nullptr), |
| presenting_device_(nullptr), keep_alive_(false), |
| has_scheduled_poll_(false) { |
| // Register VRDeviceProviders for the current platform |
| #if defined(OS_ANDROID) |
| RegisterProvider(base::WrapUnique(new GvrDeviceProvider())); |
| #endif |
| |
| #if defined(OS_WIN) |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| |
| VRDeviceProvider* oculus_provider_raw_ptr = nullptr; |
| if (!command_line->HasSwitch(kForceOpenVR)) { |
| std::unique_ptr<VRDeviceProvider> oculus_provider( |
| new OculusVRDeviceProvider()); |
| oculus_provider_raw_ptr = oculus_provider.get(); |
| RegisterProvider(std::move(oculus_provider)); |
| } |
| |
| RegisterProvider(base::WrapUnique( |
| new OpenVRDeviceProvider(oculus_provider_raw_ptr))); |
| #endif |
| } |
| |
| VRDeviceManager::VRDeviceManager(std::unique_ptr<VRDeviceProvider> provider) |
| : vr_initialized_(false), presenting_service_(nullptr), |
| presenting_device_(nullptr), keep_alive_(true), |
| has_scheduled_poll_(false) { |
| thread_checker_.DetachFromThread(); |
| RegisterProvider(std::move(provider)); |
| SetInstance(this); |
| } |
| |
| VRDeviceManager::~VRDeviceManager() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| StopSchedulingPollEvents(); |
| g_vr_device_manager = nullptr; |
| } |
| |
| VRDeviceManager* VRDeviceManager::GetInstance() { |
| if (!g_vr_device_manager) { |
| g_vr_device_manager = new VRDeviceManager(); |
| } |
| return g_vr_device_manager; |
| } |
| |
| void VRDeviceManager::SetInstance(VRDeviceManager* instance) { |
| // Unit tests can create multiple instances but only one should exist at any |
| // given time so g_vr_device_manager should only go from nullptr to |
| // non-nullptr and vica versa. |
| CHECK_NE(!!instance, !!g_vr_device_manager); |
| g_vr_device_manager = instance; |
| } |
| |
| bool VRDeviceManager::HasInstance() { |
| // For testing. Checks to see if a VRDeviceManager instance is active. |
| return !!g_vr_device_manager; |
| } |
| |
| void VRDeviceManager::AddService(VRServiceImpl* service) { |
| services_.push_back(service); |
| |
| // Ensure that the device providers are initialized |
| InitializeProviders(); |
| |
| SchedulePollEvents(); |
| } |
| |
| void VRDeviceManager::RemoveService(VRServiceImpl* service) { |
| services_.erase(std::remove(services_.begin(), services_.end(), service), |
| services_.end()); |
| |
| if (services_.empty() && !keep_alive_) { |
| // Delete the device manager when it has no active connections. |
| // delete g_vr_device_manager; |
| } |
| } |
| |
| mojo::Array<VRDisplayPtr> VRDeviceManager::GetVRDevices() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| InitializeProviders(); |
| |
| std::vector<VRDevice*> devices; |
| for (const auto& provider : providers_) |
| provider->GetDevices(&devices); |
| |
| mojo::Array<VRDisplayPtr> out_devices; |
| for (auto* device : devices) { |
| if (device->id() == VR_DEVICE_LAST_ID) |
| continue; |
| |
| if (devices_.find(device->id()) == devices_.end()) { |
| devices_[device->id()] = device; |
| device->SetClient(this); |
| } |
| |
| VRDisplayPtr vr_device_info = device->GetVRDevice(); |
| if (vr_device_info.is_null()) |
| continue; |
| |
| vr_device_info->index = device->id(); |
| out_devices.push_back(std::move(vr_device_info)); |
| } |
| |
| return out_devices; |
| } |
| |
| VRDevice* VRDeviceManager::GetDevice(unsigned int index) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (index == 0) { |
| return NULL; |
| } |
| |
| DeviceMap::iterator iter = devices_.find(index); |
| if (iter == devices_.end()) { |
| return nullptr; |
| } |
| return iter->second; |
| } |
| |
| bool VRDeviceManager::RequestPresent( |
| VRServiceImpl* service, unsigned int index) { |
| // Is anything presenting currently? |
| if (presenting_service_) { |
| // Fail if the currently presenting service is not the one making the |
| // request. |
| if (presenting_service_ != service) |
| return false; |
| |
| // If we are switching presentation from the currently presenting service to |
| // a new device stop presening to the previous one. |
| if (presenting_device_ && presenting_device_->id() != index) { |
| // Tell the device to stop presenting. |
| presenting_device_->ExitPresent(); |
| |
| // Only the presenting service needs to be notified that presentation is |
| // ending on the previous device. |
| presenting_service_->client()->OnExitPresent(presenting_device_->id()); |
| presenting_device_ = nullptr; |
| } |
| |
| presenting_service_ = nullptr; |
| } |
| |
| VRDevice* requested_device = GetDevice(index); |
| // Can't present to a device that doesn't exist. |
| if (!requested_device) |
| return false; |
| |
| // Attempt to begin presenting to this device. This could fail for any number |
| // of device-specific reasons. |
| if (!requested_device->RequestPresent()) |
| return false; |
| |
| // Successfully began presenting! |
| presenting_service_ = service; |
| presenting_device_ = requested_device; |
| |
| return true; |
| } |
| |
| void VRDeviceManager::ExitPresent( |
| VRServiceImpl* service, unsigned int index) { |
| // Don't allow services other than the currently presenting one to exit |
| // presentation. |
| if (presenting_service_ != service) |
| return; |
| |
| // Fail if the specified device is not currently presenting. |
| if (!presenting_device_ || presenting_device_->id() != index) |
| return; |
| |
| // Tell the device to stop presenting. |
| presenting_device_->ExitPresent(); |
| presenting_service_->client()->OnExitPresent(presenting_device_->id()); |
| |
| // Clear the presenting service and device. |
| presenting_service_ = nullptr; |
| presenting_device_ = nullptr; |
| } |
| |
| void VRDeviceManager::SubmitFrame( |
| VRServiceImpl* service, unsigned int index, VRPosePtr pose) { |
| // Don't allow services other than the currently presenting one to submit any |
| // frames. |
| if (presenting_service_ != service) |
| return; |
| |
| // Don't submit frames to devices other than the currently presenting one. |
| if (!presenting_device_ || presenting_device_->id() != index) |
| return; |
| |
| presenting_device_->SubmitFrame(std::move(pose)); |
| } |
| |
| // These dispatchers must use Clone() instead of std::move to ensure that |
| // if there are multiple registered services they all get a copy of the data. |
| void VRDeviceManager::OnDeviceChanged(VRDisplayPtr device) { |
| for (const auto& service : services_) |
| service->client()->OnDisplayChanged(device.Clone()); |
| } |
| |
| void VRDeviceManager::OnDeviceConnect(VRDisplayPtr device) { |
| for (const auto& service : services_) |
| service->client()->OnDisplayConnect(device.Clone()); |
| } |
| |
| void VRDeviceManager::OnDeviceDisconnect(unsigned int index) { |
| for (const auto& service : services_) |
| service->client()->OnDisplayDisconnect(index); |
| } |
| |
| void VRDeviceManager::OnDeviceActivate(VRDisplayPtr device, |
| VRDisplayEventReason reason) { |
| for (const auto& service : services_) |
| service->client()->OnDisplayActivate(device.Clone(), reason); |
| } |
| |
| void VRDeviceManager::OnDeviceDeactivate(VRDisplayPtr device, |
| VRDisplayEventReason reason) { |
| for (const auto& service : services_) |
| service->client()->OnDisplayDeactivate(device.Clone(), reason); |
| } |
| |
| void VRDeviceManager::OnDeviceBlur(VRDisplayPtr device) { |
| for (const auto& service : services_) |
| service->client()->OnDisplayBlur(device.Clone()); |
| } |
| |
| void VRDeviceManager::OnDeviceFocus(VRDisplayPtr device) { |
| for (const auto& service : services_) |
| service->client()->OnDisplayFocus(device.Clone()); |
| } |
| |
| void VRDeviceManager::InitializeProviders() { |
| if (vr_initialized_) { |
| return; |
| } |
| |
| for (const auto& provider : providers_) |
| provider->Initialize(); |
| |
| vr_initialized_ = true; |
| } |
| |
| void VRDeviceManager::RegisterProvider( |
| std::unique_ptr<VRDeviceProvider> provider) { |
| providers_.push_back(make_linked_ptr(provider.release())); |
| } |
| |
| void VRDeviceManager::SchedulePollEvents() { |
| if (has_scheduled_poll_) |
| return; |
| |
| has_scheduled_poll_ = true; |
| |
| timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(500), this, |
| &VRDeviceManager::PollEvents); |
| } |
| |
| void VRDeviceManager::PollEvents() { |
| for (const auto& provider : providers_) |
| provider->PollEvents(); |
| } |
| |
| void VRDeviceManager::StopSchedulingPollEvents() { |
| if (has_scheduled_poll_) |
| timer_.Stop(); |
| } |
| |
| } // namespace device |