I work with my IOS challenge and attempt to ship haptics to ps4 controller.
CHHapticPatternPlayer and CHHapticAdvancedPatternPlayer good work with iPhone.
On PS4 controller If I take advantage of CHHapticPatternPlayer all work good, but when I take advantage of CHHapticAdvancedPatternPlayer I get error. I need use CHHapticAdvancedPatternPlayer to make use of extra settings. I do not discovered any data the right way to repair it –
CHHapticEngine.mm:624 -[CHHapticEngine finishInit:]_block_invoke: ERROR: Server connection broke with error 'Не удалось завершить операцию. (com.apple.CoreHaptics, ошибка -4811)'
The engine stopped as a result of a system error occurred.
AVHapticClient.mm:1228 -[AVHapticClient getSyncDelegateForMethod:errorHandler:]_block_invoke: ERROR: Sync XPC name for 'loadAndPrepareHapticSequenceFromEvents:reply:' (shopper ID 0x21) failed: Не удалось установить связь с приложением-помощником.
Не удалось создать или воспроизвести паттерн: Error Area=NSCocoaErrorDomain Code=4097 "connection to service with pid 5087 named com.apple.GameController.gamecontrollerd.haptics" UserInfo={NSDebugDescription=connection to service with pid 5087 named com.apple.GameController.gamecontrollerd.haptics}
My Haptic class –
import Basis
import CoreHaptics
import GameController
protocol HapticsControllerDelegate: AnyObject {
func didConnectController()
func didDisconnectController()
func enginePlayerStart(worth: Bool)
}
remaining class HapticsControllerManager {
static let shared = HapticsControllerManager()
personal var isSetup = false
personal var hapticEngine: CHHapticEngine?
personal var hapticPlayer: CHHapticAdvancedPatternPlayer?
weak var delegate: HapticsControllerDelegate? {
didSet {
if delegate != nil {
startObserving()
}
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
personal func startObserving() {
guard !isSetup else { return }
NotificationCenter.default.addObserver(
self,
selector: #selector(controllerDidConnect),
identify: .GCControllerDidConnect,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(controllerDidDisconnect),
identify: .GCControllerDidDisconnect,
object: nil
)
isSetup = true
}
@objc personal func controllerDidConnect(notification: Notification) {
delegate?.didConnectController()
self.createAndStartHapticEngine()
}
@objc personal func controllerDidDisconnect(notification: Notification) {
delegate?.didDisconnectController()
hapticEngine = nil
hapticPlayer = nil
}
personal func createAndStartHapticEngine() {
guard let controller = GCController.controllers().first else {
print("No controller linked")
return
}
guard controller.haptics != nil else {
print("Haptics not supported on this controller")
return
}
hapticEngine = createEngine(for: controller, locality: .default)
hapticEngine?.playsHapticsOnly = true
do {
attempt hapticEngine?.begin()
} catch {
print("Failed to begin haptic suggestions engine: (error)")
}
}
personal func createEngine(for controller: GCController, locality: GCHapticsLocality) -> CHHapticEngine? {
guard let engine = controller.haptics?.createEngine(withLocality: locality) else {
print("Did not create engine.")
return nil
}
print("Efficiently created engine.")
engine.stoppedHandler = { motive in
print("The engine stopped as a result of (motive.message)")
}
engine.resetHandler = {
print("The engine reset --> Restarting now!")
do {
attempt engine.begin()
} catch {
print("Did not restart the engine: (error)")
}
}
return engine
}
func startHapticFeedback(haptics: [CHHapticEvent]) {
do {
let sample = attempt CHHapticPattern(occasions: haptics, parameters: [])
hapticPlayer = attempt hapticEngine?.makeAdvancedPlayer(with: sample)
hapticPlayer?.loopEnabled = true
attempt hapticPlayer?.begin(atTime: 0)
self.delegate?.enginePlayerStart(worth: true)
} catch {
self.delegate?.enginePlayerStart(worth: false)
print("Did not create or play sample: (error)")
}
}
func stopHapticFeedback() {
do {
attempt hapticPlayer?.cease(atTime: 0)
self.delegate?.enginePlayerStart(worth: false)
} catch {
self.delegate?.enginePlayerStart(worth: true)
print("Couldn't cease vibration playback: (error)")
}
}
}
extension CHHapticEngine.StoppedReason {
var message: String {
swap self {
case .audioSessionInterrupt:
return "the audio session was interrupted."
case .applicationSuspended:
return "the applying was suspended."
case .idleTimeout:
return "an idle timeout occurred."
case .systemError:
return "a system error occurred."
case .notifyWhenFinished:
return "playback completed."
case .engineDestroyed:
return "the engine was destroyed."
case .gameControllerDisconnect:
return "the sport controller disconnected."
@unknown default:
return "an unknown error occurred."
}
}
}
customized haptic occasion –
static func changeVibrationPower(energy: HapricPower) -> [CHHapticEvent] {
let continuousEvent = CHHapticEvent(eventType: .hapticContinuous, parameters: [
CHHapticEventParameter(parameterID: .hapticSharpness, value: 1.0),
CHHapticEventParameter(parameterID: .hapticIntensity, value: power.value)
], relativeTime: 0, period: 0.5)
return [continuousEvent]
}