// Copyright 2017 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/gamepad/abstract_haptic_gamepad.h" namespace device { AbstractHapticGamepad::AbstractHapticGamepad() : is_shut_down_(false), sequence_id_(0) {} AbstractHapticGamepad::~AbstractHapticGamepad() { // Shutdown() must be called to allow the device a chance to stop vibration // and release held resources. DCHECK(is_shut_down_); } void AbstractHapticGamepad::Shutdown() { if (playing_effect_callback_) { sequence_id_++; SetZeroVibration(); RunCallbackOnMojoThread( mojom::GamepadHapticsResult::GamepadHapticsResultPreempted); } DoShutdown(); is_shut_down_ = true; } void AbstractHapticGamepad::SetZeroVibration() { SetVibration(0.0, 0.0); } base::TimeDelta AbstractHapticGamepad::TaskDelayFromMilliseconds( double delay_millis) { return base::TimeDelta::FromMillisecondsD(delay_millis); } void AbstractHapticGamepad::PlayEffect( mojom::GamepadHapticEffectType type, mojom::GamepadEffectParametersPtr params, mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) { DCHECK(!is_shut_down_); if (type != mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble) { // Only dual-rumble effects are supported. std::move(callback).Run( mojom::GamepadHapticsResult::GamepadHapticsResultNotSupported); return; } int sequence_id = ++sequence_id_; if (playing_effect_callback_) { if (params->start_delay > 0.0) SetZeroVibration(); RunCallbackOnMojoThread( mojom::GamepadHapticsResult::GamepadHapticsResultPreempted); } playing_effect_task_runner_ = base::ThreadTaskRunnerHandle::Get(); playing_effect_callback_ = std::move(callback); PlayDualRumbleEffect(sequence_id, params->duration, params->start_delay, params->strong_magnitude, params->weak_magnitude); } void AbstractHapticGamepad::ResetVibration( mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback) { DCHECK(!is_shut_down_); sequence_id_++; if (playing_effect_callback_) { SetZeroVibration(); RunCallbackOnMojoThread( mojom::GamepadHapticsResult::GamepadHapticsResultPreempted); } std::move(callback).Run( mojom::GamepadHapticsResult::GamepadHapticsResultComplete); } void AbstractHapticGamepad::PlayDualRumbleEffect(int sequence_id, double duration, double start_delay, double strong_magnitude, double weak_magnitude) { base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::BindOnce(&AbstractHapticGamepad::StartVibration, base::Unretained(this), sequence_id_, duration, strong_magnitude, weak_magnitude), TaskDelayFromMilliseconds(start_delay)); } void AbstractHapticGamepad::StartVibration(int sequence_id, double duration, double strong_magnitude, double weak_magnitude) { if (is_shut_down_ || sequence_id != sequence_id_) return; SetVibration(strong_magnitude, weak_magnitude); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::BindOnce(&AbstractHapticGamepad::StopVibration, base::Unretained(this), sequence_id), TaskDelayFromMilliseconds(duration)); } void AbstractHapticGamepad::StopVibration(int sequence_id) { if (is_shut_down_ || sequence_id != sequence_id_) return; SetZeroVibration(); RunCallbackOnMojoThread( mojom::GamepadHapticsResult::GamepadHapticsResultComplete); } void AbstractHapticGamepad::RunCallbackOnMojoThread( mojom::GamepadHapticsResult result) { if (playing_effect_task_runner_->RunsTasksInCurrentSequence()) { DoRunCallback(std::move(playing_effect_callback_), result); return; } playing_effect_task_runner_->PostTask( FROM_HERE, base::BindOnce(&AbstractHapticGamepad::DoRunCallback, std::move(playing_effect_callback_), result)); } // static void AbstractHapticGamepad::DoRunCallback( mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback, mojom::GamepadHapticsResult result) { std::move(callback).Run(result); } } // namespace device