Events

Vesper SDK surfaces every significant player, ads, system, and UI interaction through the VesperSDK event layer. You can subscribe to these events by implementing Output protocols you already pass into createPlayerManager.

final class PlayerViewController: UIViewController {
    private var playerManager: PlayerManager?

    func attachPlayer() {
        vesperSDKManager.createPlayerManager(
            playerOutput: self,
            userInterfaceConfig: .default(output: self)
        ) { [weak self] result in
            guard case .success(let manager) = result else { return }
            self?.playerManager = manager
        }
    }
}

extension PlayerViewController: DorisPlayerOutputProtocol, DorisViewOutputProtocol {
    func onPlayerEvent(_ event: DorisPlayerEvent) {  }
    func onPlayerStateChanged(old: DorisPlayerState, new: DorisPlayerState) {  }
    func onAdvertisementEvent(_ event: DorisAdsEvent) {  }
    func onRemoteCommandEvent(_ event: DorisRemoteCommandEvent) {  }
    func onSystemEvent(_ event: DorisSystemEvent) {  }
    func onViewTapEvent(_ event: DorisViewTapEvent) {  }
    func onViewUniversalEvent(_ event: DorisViewUniversalEvent) {  }
}

Below is a full reference of every event enum exposed by VesperSDK.


System lifecycle (DorisSystemEvent)

Case Fired when
didEnterBackground The hosting app moved to the background.
willEnterForeground The app is transitioning back to foreground.
willResignActive The app is about to become inactive (incoming call, Control Center, etc.).
didBecomeActive The app became active again after being inactive/backgrounded.

Use these events to pause analytics, throttle UI updates, or prepare for PiP transitions.


Player pipeline (DorisPlayerEvent)

Case Fired when
didCurrentItemChange(old:new:) The underlying AVPlayerItem changed.
playerItemFailed(logs:error:) Vesper failed to load or play the current item. Includes diagnostics and a DorisPlayerError.
playbackStalled Playback stalled because of buffering/network issues.
didTimeControlStatusChange(status:) AVPlayer.timeControlStatus changed (e.g. waiting, paused, playing).
loadInitiated A new ResolvableSource has been handed over to the player.
willLoadAfterDelay(delay:initialSeek:) Loading is queued—typically awaiting stream to become available prerequisites—optionally with an initial seek.
willLoadNow(initialSeek:) Loading will start immediately with optional initial seek instructions.
metadataChanged(metadata:) Fresh DorisSourceMetadata became available (title, artwork, etc.).
willSeek(info:) User, code or the UI initiated a seek; includes seek ID and target. Can be canceled
didSeek(info:) Seek finished (success or cancellation).
finishedPlaying(endTime:) Playback reached the end of stream/content.
currentTimeChanged(contentPosition:streamPosition:date:) Periodic time updates (content position excludes SSAI, stream includes).
itemDurationChanged(contentDuration:streamDuration:) Asset duration changed (e.g. DVR window updates).
streamTypeRecognized(streamType:) The SDK determined the stream type (LIVE, VOD).
seekableTimeRangesChanged(contentSeekableRanges:streamSeekableRanges:) Seekable window changed.
loadedTimeRangesChanged(contentLoadedRanges:streamLoadedRanges:) Buffered ranges changed.
queueItemsChanged(items:) Playlist/queue contents changed.
availableMediaTracksChanged(tracks:) Audio or text track list changed.
playbackReceiverChanged(old:new:) Output switched (AirPlay, Chromecast, default).
playbackLogsUpdated(logs:) Diagnostic log payload updated.
readyToPlay The current AVPlayerItem reached .readyToPlay.
pipWillStart Player is about to enter Picture in Picture mode.
pipDidStop PiP session ended and control returned to the in-app player.
trackChanged(track:autoSet:) Active audio/text track changed (either automatically or by the user).
presentationSizeChanged(size:) The video’s presentation size changed. (Player layer’s video frame bounds)
bitrateChanged(bitrate:policy:) Adaptive bitrate switched quality, including the policy that caused it.
volumeChanged(volume:) Player volume changed.
didUnload The player fully unloaded its item (e.g. after unload()).

Ads (DorisAdsEvent)

Case Fired when
daiStreamStarted SSAI stream initialization completed.
adTagParametersRequired The SDK requests additional ad tag parameters (client can provide dynamic values).
adRangesChanged The list of available ad breaks updated.
adProgressChanged The current ad’s progress changed (quartiles, countdown).
adBreakEnded An ad break finished.
adBreakStarted(adBreak:pendingSeekPosition:) A break started; includes pending seek info if playback will resume elsewhere.
adRequested A client-side ad request kicked off with the optional tag URL.
adLoaded A client-side ad payload loaded.
adStarted A specific ad creative started playing within active adBreak.
adFirstQuartile / adMidpoint / adThirdQuartile Standard quartile beacons for the active ad.
adEnded The ad creative finished.
adPaused / adResumed Ad playback paused/resumed.
adSkipped User skipped the ad.
shouldSeekTo(position:willPlayAdBreak:) SDK instructs the player to jump to content position (e.g. after SSAI break).
errorOccured Ad subsystem hit an error (see DorisAdsError).

Remote commands (DorisRemoteCommandEvent)

Emitted when the system’s remote-command center (lock screen, Control Center, external accessories) interacts with playback.

Case Fired when
play, pause, playPause, stop Corresponding transport commands were invoked.
skipBackward(_:), skipForward(_:) User activated skip controls (value is seconds).
previousTrack, nextTrack Previous/next commands triggered.
changePosition(_:) User scrubbed via the system slider (value is seconds).

Configure availability through DorisRemoteCommandsConfig.


View tap events (DorisViewTapEvent)

Fine-grained tap/gesture signals from the default UI.

  • playPauseButtonTap
  • seekBackButtonTap
  • seekForwardButtonTap
  • viewLeftTap / viewRightTap
  • seekBarLeftTap / seekBarRightTap
  • seekBarRemoteTap
  • seekBarVoiceOverDecrement / seekBarVoiceOverIncrement
  • favouritesButtonTap
  • watchlistButtonTap
  • statsButtonTap
  • scheduleButtonTap
  • moreRelatedVideosTap
  • backButtonTap
  • restartButtonTap
  • liveBadgeTapped
  • retryButtonTap
  • fullScreenButtonTap
  • overlayOpenButtonTap
  • menuButtonTapped
  • infoButtonTapped
  • tracksButtonTapped
  • episodesButtonTapped
  • settingsButtonTapped
  • castButtonTapped
  • overlayCloseButtonTap
  • shareButtonTap
  • tapOnView
  • longPressedLeftOnView / longPressedRightOnView
  • nextEpisodeButtonTap(_:)
  • prevEpisodeButtonTap(_:)
  • currentPlaybackTimeLabelTapped(_:)
  • annotationsButtonTap
  • adsLearnMoreTap
  • adsSkipTap
  • skipMarkerButtonTap(_:)
  • watchFromStartButtonButtonTap
  • adChoicesTapped
  • whyThisAdCloseTapped

View lifecycle & gestures (DorisViewUniversalEvent)

Higher-level view state transitions and gestures from the default UI.

  • viewLoaded, viewDidAppear, viewDidDisappear
  • viewRotated(isExternalOverlayForbidden:)
  • subtitleSelected(_:), audioTrackSelected(_:)
  • bandwidthPolicyModeSelected(_:)
  • seekBarAnnotationTapped(value:)
  • seekBarPanned(state:offsetPercent:isRemote:)
  • progressiveSeekDidUpdate(interval:)
  • relatedVideoSelected(_:)
  • pinched(_:)
  • playbackRateChanged(value:)
  • userInteractionEnded
  • playlistAnimationStateChanged(_:), playlistAnimationStateWillChange
  • viewPanned(state:offsetPercent:isRemote:)
  • bottomContainerFocusRemoved, bottomContainerFocusSet
  • episodesScrolled
  • annotationFocused(_:)
  • nextEpisodeViewProgressAnimationCompleted(_:)
  • errorOccured
  • readyForDisplayChanged(_:)
  • adChoicesTapped
  • layoutTypeChanged(_:)
  • voiceOverStatusChanged(_:)
  • voiceOverFocusChanged

Use these events to add custom logic if needed.


For player and default UI state diagrams, see the States reference.