Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions iOS/Pulsar/Sources/Pulsar/Composers/PatternComposer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class PatternComposer: NSObject {
}

private func parse(hapticsData: PatternData, audioEvent: CHHapticEvent?) {
releasePlayers()
discreteLine.reset()
continuousLine.reset()
hasSound = audioEvent != nil
Expand Down Expand Up @@ -162,6 +163,15 @@ public class PatternComposer: NSObject {
}
}

private func releasePlayers() {
if let id = continuousPlayerId { engine.removePlayer(id: id) }
if let id = discretePlayerId { engine.removePlayer(id: id) }
continuousPlayerId = nil
discretePlayerId = nil
continuousPattern = nil
discretePattern = nil
}

private func releaseAudio() {
if let id = audioResourceID {
engine.unregisterAudioResource(id)
Expand Down Expand Up @@ -202,12 +212,7 @@ public class PatternComposer: NSObject {

@objc public func dispose() {
stop()
if let id = continuousPlayerId { engine.removePlayer(id: id) }
if let id = discretePlayerId { engine.removePlayer(id: id) }
continuousPlayerId = nil
discretePlayerId = nil
continuousPattern = nil
discretePattern = nil
releasePlayers()
audioBuffer = nil
hasSound = false
releaseAudio()
Expand Down
9 changes: 7 additions & 2 deletions iOS/Pulsar/Sources/Pulsar/HapticEngineWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ public extension HapticEngineWrapper {
func stopPlayer(id: Int) {
guard let player = playerRegistry[id] else { return }
stopPlayer(player, errorPrefix: "Error stopping player")
unregisterPlayer(id)
}

func removePlayer(id: Int) {
if let player = playerRegistry[id] {
try? player.stop(atTime: 0)
}

playerRegistry.removeValue(forKey: id)
playerCreationOrder.removeAll { $0 == id }
unregisterPlayer(id)
}
}

Expand Down Expand Up @@ -350,6 +350,11 @@ private extension HapticEngineWrapper {
playerCreationOrder.append(id)
}

func unregisterPlayer(_ id: Int) {
playerRegistry.removeValue(forKey: id)
playerCreationOrder.removeAll { $0 == id }
}

func evictOldestPlayerIfNeeded() {
guard playerRegistry.count >= playerLimit else { return }

Expand Down
18 changes: 18 additions & 0 deletions iOS/Pulsar/Tests/PulsarTests/CoreHapticsMockTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ struct CoreHapticsMockTests {
#expect(HapticMockRecorder.shared.playerStops >= 1)
}

@Test func playingAfterAStopBuildsAFreshPlayer() {
CoreHapticsMock.install()
defer { CoreHapticsMock.uninstall() }

let engine = activeEngine()
let pattern = makePattern()
let created = engine.createPlayer(pattern: pattern)
#expect(created != nil)
guard let id = created else { return }

engine.playPlayer(id: id, pattern: pattern)
engine.stopPlayer(id: id)
engine.playPlayer(id: id, pattern: pattern)

#expect(HapticMockRecorder.shared.playersCreated == 2)
#expect(HapticMockRecorder.shared.playerStarts == 2)
}

@Test func stopHapticsStopsEveryRegisteredPlayer() {
CoreHapticsMock.install()
defer { CoreHapticsMock.uninstall() }
Expand Down
Loading