Skip to content

Commit

Permalink
Use common generic name for item and asset configurations (#1152)
Browse files Browse the repository at this point in the history
  • Loading branch information
defagos authored Feb 28, 2025
1 parent 8637b57 commit 14b3471
Show file tree
Hide file tree
Showing 11 changed files with 41 additions and 41 deletions.
2 changes: 1 addition & 1 deletion Demo/Sources/Model/Media.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ struct Media: Hashable {
configuration: .init(position: at(startTime))
)
case let .unbufferedUrl(url):
let configuration = PlayerItemConfiguration(
let configuration = PlaybackConfiguration(
position: at(startTime),
automaticallyPreservesTimeOffsetFromLive: true,
preferredForwardBufferDuration: 1
Expand Down
4 changes: 2 additions & 2 deletions Sources/CoreBusiness/Extensions/Asset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Foundation
import PillarboxPlayer

extension Asset {
static func tokenProtected(url: URL, metadata: M, configuration: PlayerItemConfiguration) -> Self {
static func tokenProtected(url: URL, metadata: M, configuration: PlaybackConfiguration) -> Self {
let id = UUID()
return .custom(
url: AkamaiURLCoding.encodeUrl(url, id: id),
Expand All @@ -18,7 +18,7 @@ extension Asset {
)
}

static func encrypted(url: URL, certificateUrl: URL, metadata: M, configuration: PlayerItemConfiguration) -> Self {
static func encrypted(url: URL, certificateUrl: URL, metadata: M, configuration: PlaybackConfiguration) -> Self {
.encrypted(
url: url,
delegate: ContentKeySessionDelegate(certificateUrl: certificateUrl),
Expand Down
14 changes: 7 additions & 7 deletions Sources/CoreBusiness/Extensions/PlayerItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public extension PlayerItem {
_ urn: String,
server: Server = .production,
trackerAdapters: [TrackerAdapter<MediaMetadata>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
publisher: publisher(forUrn: urn, server: server, configuration: configuration),
Expand Down Expand Up @@ -62,7 +62,7 @@ public extension PlayerItem {
url: URL,
metadata: M,
trackerAdapters: [TrackerAdapter<M>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self where M: AssetMetadata {
.init(
asset: .tokenProtected(url: url, metadata: metadata, configuration: configuration),
Expand All @@ -86,7 +86,7 @@ public extension PlayerItem {
certificateUrl: URL,
metadata: M,
trackerAdapters: [TrackerAdapter<M>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self where M: AssetMetadata {
.init(
asset: .encrypted(url: url, certificateUrl: certificateUrl, metadata: metadata, configuration: configuration),
Expand All @@ -96,7 +96,7 @@ public extension PlayerItem {
}

private extension PlayerItem {
static func publisher(forUrn urn: String, server: Server, configuration: PlayerItemConfiguration) -> AnyPublisher<Asset<MediaMetadata>, Error> {
static func publisher(forUrn urn: String, server: Server, configuration: PlaybackConfiguration) -> AnyPublisher<Asset<MediaMetadata>, Error> {
let dataProvider = DataProvider(server: server)
return dataProvider.mediaCompositionPublisher(forUrn: urn)
.tryMap { response in
Expand All @@ -106,7 +106,7 @@ private extension PlayerItem {
.eraseToAnyPublisher()
}

private static func asset(metadata: MediaMetadata, configuration: PlayerItemConfiguration, dataProvider: DataProvider) -> Asset<MediaMetadata> {
private static func asset(metadata: MediaMetadata, configuration: PlaybackConfiguration, dataProvider: DataProvider) -> Asset<MediaMetadata> {
if let blockingReason = metadata.blockingReason {
return .unavailable(with: DataError.blocked(withMessage: blockingReason.description), metadata: metadata)
}
Expand All @@ -129,8 +129,8 @@ private extension PlayerItem {

private static func assetConfiguration(
for resource: MediaComposition.Resource,
configuration: PlayerItemConfiguration
) -> PlayerItemConfiguration {
configuration: PlaybackConfiguration
) -> PlaybackConfiguration {
// Limit buffering and force the player to return to the live edge when re-buffering. This ensures
// livestreams cannot be paused and resumed in the past, as requested by business people.
guard resource.streamType == .live else { return configuration }
Expand Down
26 changes: 13 additions & 13 deletions Sources/Player/Asset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ import AVFoundation
public struct Asset<M> {
let resource: Resource
let metadata: M
let configuration: PlayerItemConfiguration
let configuration: PlaybackConfiguration

/// Returns a simple asset playable from a URL.
///
/// - Parameters:
/// - url: The URL to be played.
/// - metadata: The metadata associated with the asset.
/// - configuration: The configuration to apply to the player item.
/// - configuration: The configuration to apply to the asset.
/// - Returns: The asset.
public static func simple(url: URL, metadata: M, configuration: PlayerItemConfiguration = .default) -> Self {
public static func simple(url: URL, metadata: M, configuration: PlaybackConfiguration = .default) -> Self {
.init(resource: .simple(url: url), metadata: metadata, configuration: configuration)
}

Expand All @@ -35,15 +35,15 @@ public struct Asset<M> {
/// - url: The URL to be played.
/// - delegate: The custom resource loader to use.
/// - metadata: The metadata associated with the asset.
/// - configuration: The configuration to apply to the player item.
/// - configuration: The configuration to apply to the asset.
/// - Returns: The asset.
///
/// The scheme of the URL to be played has to be recognized by the associated resource loader delegate.
public static func custom(
url: URL,
delegate: AVAssetResourceLoaderDelegate,
metadata: M,
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
resource: .custom(url: url, delegate: delegate),
Expand All @@ -58,13 +58,13 @@ public struct Asset<M> {
/// - url: The URL to be played.
/// - delegate: The content key session delegate to use.
/// - metadata: The metadata associated with the asset.
/// - configuration: The configuration to apply to the player item.
/// - configuration: The configuration to apply to the asset.
/// - Returns: The asset.
public static func encrypted(
url: URL,
delegate: AVContentKeySessionDelegate,
metadata: M,
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
resource: .encrypted(url: url, delegate: delegate),
Expand Down Expand Up @@ -99,11 +99,11 @@ public extension Asset where M == Void {
///
/// - Parameters:
/// - url: The URL to be played.
/// - configuration: The configuration to apply to the player item.
/// - configuration: The configuration to apply to the asset.
/// - Returns: The asset.
static func simple(
url: URL,
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
resource: .simple(url: url),
Expand All @@ -117,14 +117,14 @@ public extension Asset where M == Void {
/// - Parameters:
/// - url: The URL to be played.
/// - delegate: The custom resource loader to use.
/// - configuration: The configuration to apply to the player item.
/// - configuration: The configuration to apply to the asset.
/// - Returns: The asset.
///
/// The scheme of the URL to be played has to be recognized by the associated resource loader delegate.
static func custom(
url: URL,
delegate: AVAssetResourceLoaderDelegate,
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
resource: .custom(url: url, delegate: delegate),
Expand All @@ -138,12 +138,12 @@ public extension Asset where M == Void {
/// - Parameters:
/// - url: The URL to be played.
/// - delegate: The content key session delegate to use.
/// - configuration: The configuration to apply to the player item.
/// - configuration: The configuration to apply to the asset.
/// - Returns: The asset.
static func encrypted(
url: URL,
delegate: AVContentKeySessionDelegate,
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
resource: .encrypted(url: url, delegate: delegate),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ An empty ``Player`` instance is lightweight, but once loaded with content, it in
To minimize resource usage, aim to keep the number of ``Player`` instances loaded with content as low as possible. Consider these strategies:

- **Implement a Player Pool:** Instead of creating a new player instance for every need, maintain a pool of reusable players. Borrow a player from the pool when needed and return it when done.
- **Clear Unused Players:** Use ``Player/removeAllItems()`` to empty a player's item queue without destroying the player instance. When reloading previously played content, use ``PlayerItemConfiguration/position`` to resume playback from where it was last interrupted.
- **Clear Unused Players:** Use ``Player/removeAllItems()`` to empty a player's item queue without destroying the player instance. When reloading previously played content, use ``PlaybackConfiguration/position`` to resume playback from where it was last interrupted.
- **Leverage Thumbnails:** Display thumbnails representing the first frame or video content to create the illusion of instant playback without loading the actual video. This approach is especially effective in scrollable lists with autoplay functionality.
- **Limit Buffering:** Control the player's buffering behavior by setting ``PlayerItemConfiguration/preferredForwardBufferDuration`` in a ``PlayerItem`` configuration. While the default buffering can be quite aggressive, reducing the buffer duration lowers memory usage but increases the likelihood of playback stalling and re-buffering. Use this setting judiciously to balance resource usage and playback stability.
- **Limit Buffering:** Control the player's buffering behavior by setting ``PlaybackConfiguration/preferredForwardBufferDuration`` in a ``PlayerItem`` configuration. While the default buffering can be quite aggressive, reducing the buffer duration lowers memory usage but increases the likelihood of playback stalling and re-buffering. Use this setting judiciously to balance resource usage and playback stability.

## Implement autoplay wisely

Expand Down
4 changes: 2 additions & 2 deletions Sources/Player/Player.docc/PillarboxPlayer.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,14 @@ The PillarboxPlayer framework seamlessly integrates with SwiftUI, leveraging its
- ``PictureInPicturePersistable``
- ``RoutePickerView``

### Asset Resource Loading
### Content Loading

- <doc:fairplay-streaming-article>
- <doc:asset-resource-loading-article>

- ``Asset``
- ``PlaybackConfiguration``
- ``PlayerItem``
- ``PlayerItemConfiguration``

### Tracking

Expand Down
12 changes: 6 additions & 6 deletions Sources/Player/PlayerItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public extension PlayerItem {
url: URL,
metadata: M,
trackerAdapters: [TrackerAdapter<M>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self where M: AssetMetadata {
.init(
asset: .simple(url: url, metadata: metadata, configuration: configuration),
Expand All @@ -185,7 +185,7 @@ public extension PlayerItem {
delegate: AVAssetResourceLoaderDelegate,
metadata: M,
trackerAdapters: [TrackerAdapter<M>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self where M: AssetMetadata {
.init(
asset: .custom(url: url, delegate: delegate, metadata: metadata, configuration: configuration),
Expand All @@ -207,7 +207,7 @@ public extension PlayerItem {
delegate: AVContentKeySessionDelegate,
metadata: M,
trackerAdapters: [TrackerAdapter<M>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self where M: AssetMetadata {
.init(
asset: .encrypted(url: url, delegate: delegate, metadata: metadata, configuration: configuration),
Expand All @@ -227,7 +227,7 @@ public extension PlayerItem {
static func simple(
url: URL,
trackerAdapters: [TrackerAdapter<Void>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
asset: .simple(url: url, configuration: configuration),
Expand All @@ -249,7 +249,7 @@ public extension PlayerItem {
url: URL,
delegate: AVAssetResourceLoaderDelegate,
trackerAdapters: [TrackerAdapter<Void>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
asset: .custom(url: url, delegate: delegate, configuration: configuration),
Expand All @@ -269,7 +269,7 @@ public extension PlayerItem {
url: URL,
delegate: AVContentKeySessionDelegate,
trackerAdapters: [TrackerAdapter<Void>] = [],
configuration: PlayerItemConfiguration = .default
configuration: PlaybackConfiguration = .default
) -> Self {
.init(
asset: .encrypted(url: url, delegate: delegate, configuration: configuration),
Expand Down
2 changes: 1 addition & 1 deletion Sources/Player/Types/AssetContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct AssetContent {
let id: UUID
let resource: Resource
let metadata: PlayerMetadata
let configuration: PlayerItemConfiguration
let configuration: PlaybackConfiguration
let dateInterval: DateInterval?

static func loading(id: UUID) -> Self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import AVFoundation

/// A player item configuration.
public struct PlayerItemConfiguration {
/// A playback configuration.
public struct PlaybackConfiguration {
/// The default configuration.
public static let `default` = Self()

Expand All @@ -29,7 +29,7 @@ public struct PlayerItemConfiguration {
/// disruption.
public let preferredForwardBufferDuration: TimeInterval

/// Creates a player item configuration.
/// Creates a playback configuration.
public init(
position: Position = at(.zero),
automaticallyPreservesTimeOffsetFromLive: Bool = false,
Expand Down
4 changes: 2 additions & 2 deletions Tests/PlayerTests/Player/BlockedTimeRangeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ final class BlockedTimeRangeTests: TestCase {
}

func testBlockedTimeRangeTraversal() {
let configuration = PlayerItemConfiguration(position: at(.init(value: 29, timescale: 1)))
let configuration = PlaybackConfiguration(position: at(.init(value: 29, timescale: 1)))
let player = Player(item: .simple(url: Stream.onDemand.url, metadata: MetadataWithBlockedTimeRange(), configuration: configuration))
player.play()
expect(player.time()).toEventually(beGreaterThan(kBlockedTimeRange.end))
}

func testOnDemandStartInBlockedTimeRange() {
let configuration = PlayerItemConfiguration(position: at(.init(value: 30, timescale: 1)))
let configuration = PlaybackConfiguration(position: at(.init(value: 30, timescale: 1)))
let player = Player(item: .simple(url: Stream.onDemand.url, metadata: MetadataWithBlockedTimeRange(), configuration: configuration))
expect(player.time()).toEventually(equal(kBlockedTimeRange.end))
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/PlayerTests/Player/SeekTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ final class SeekTests: TestCase {
}

func testOnDemandStartAtTime() {
let configuration = PlayerItemConfiguration(position: at(.init(value: 10, timescale: 1)))
let configuration = PlaybackConfiguration(position: at(.init(value: 10, timescale: 1)))
let player = Player(item: .simple(url: Stream.onDemand.url, configuration: configuration))
expect(player.time().seconds).toEventually(equal(10))
}

func testDvrStartAtTime() {
let configuration = PlayerItemConfiguration(position: at(.init(value: 10, timescale: 1)))
let configuration = PlaybackConfiguration(position: at(.init(value: 10, timescale: 1)))
let player = Player(item: .simple(url: Stream.dvr.url, configuration: configuration))
expect(player.time().seconds).toEventually(equal(10))
}
Expand Down

0 comments on commit 14b3471

Please sign in to comment.