Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9d66fc5

Browse files
update
1 parent 923f3f4 commit 9d66fc5

File tree

8 files changed

+108
-13
lines changed

8 files changed

+108
-13
lines changed

‎README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ video_main.m3u8
243243
| `error(VPErrors)` | Represents an occurrence of an error within the player. The event provides a `VPErrors` enum value indicating the specific type of error encountered. |
244244
| `volumeChanged` | Happens when the player's volume level is adjusted. This event provides the new volume level, which ranges from 0.0 (muted) to 1.0 (maximum volume). |
245245
| `boundsChanged(CGRect)` | Triggered when the bounds of the main layer change, allowing the developer to recalculate and update all vector layers within the CompositeLayer. |
246+
| `startedPiP` | Event triggered when Picture-in-Picture (PiP) mode starts. |
247+
| `stoppedPiP` | Event triggered when Picture-in-Picture (PiP) mode stops. |
248+
| `itemStatusChanged(AVPlayerItem.Status)` | Indicates that the AVPlayerItem's status has changed. Possible statuses: `.unknown`, `.readyToPlay`, `.failed`. |
249+
| `duration(CMTime)` | Provides the duration of the AVPlayerItem when it is ready to play. The duration is given in `CMTime`. |
246250

247251

248252
### Additional Notes on Adding and Removing Vector Graphics

‎Sources/swiftui-loop-videoplayer/enum/PlayerEvent.swift‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ public enum PlayerEvent: Equatable {
6969

7070
/// Event triggered when Picture-in-Picture (PiP) mode stops.
7171
case stoppedPiP
72+
73+
/// Indicates that the AVPlayerItem's status has changed.
74+
/// - Parameter status: The new status of the AVPlayerItem.
75+
case itemStatusChanged(AVPlayerItem.Status)
76+
77+
/// Provides the duration of the AVPlayerItem when it is ready to play.
78+
/// - Parameter duration: The total duration of the media item in `CMTime`.
79+
case duration(CMTime)
7280
}
7381

7482
extension PlayerEvent: CustomStringConvertible {
@@ -96,6 +104,18 @@ extension PlayerEvent: CustomStringConvertible {
96104
return "Started PiP"
97105
case .stoppedPiP:
98106
return "Stopped PiP"
107+
case .itemStatusChanged(let status):
108+
switch status {
109+
case .unknown:
110+
return "Status: Unknown"
111+
case .readyToPlay:
112+
return "Status: ReadyToPlay"
113+
case .failed:
114+
return "Status: FailedToLoad"
115+
}
116+
case .duration(let value):
117+
let roundedString = String(format: "%.0f", value.seconds)
118+
return "Duration \(roundedString) sec"
99119
}
100120
}
101121
}

‎Sources/swiftui-loop-videoplayer/enum/VPErrors.swift‎

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Foundation
99

1010
@available(iOS 14.0, macOS 11.0, tvOS 14.0, *)
1111
/// An enumeration of possible errors that can occur in the video player.
12-
public enum VPErrors: Error, CustomStringConvertible, Sendable{
12+
public enum VPErrors: Error, CustomStringConvertible, Sendable{
1313

1414
/// Error case for when there is an error with remote video playback.
1515
/// - Parameter error: The error that occurred during remote video playback.
@@ -25,25 +25,26 @@ public enum VPErrors: Error, CustomStringConvertible, Sendable{
2525
/// Picture-in-Picture (PiP) is not supported
2626
case notSupportedPiP
2727

28+
/// Failed to load
29+
case failedToLoad
30+
2831
/// A description of the error, suitable for display.
2932
public var description: String {
3033
switch self {
31-
/// Returns a description indicating that the specified file was not found.
32-
/// - Parameter name: The name of the file that was not found.
3334
case .sourceNotFound(let name):
3435
return "Source not found: \(name)"
3536

3637
case .notSupportedPiP:
3738
return "Picture-in-Picture (PiP) is not supported on this device."
3839

39-
/// Returns a description indicating that the settings are not unique.
4040
case .settingsNotUnique:
4141
return "Settings are not unique"
4242

43-
/// Returns a description indicating a playback error with the remote video.
44-
/// - Parameter error: The error that occurred during remote video playback.
4543
case .remoteVideoError(let error):
4644
return "Playback error: \(String(describing: error?.localizedDescription))"
45+
46+
case .failedToLoad:
47+
return "Failed to load the video."
4748
}
4849
}
4950
}
@@ -52,10 +53,6 @@ public enum VPErrors: Error, CustomStringConvertible, Sendable{
5253
extension VPErrors: Equatable {
5354

5455
/// Compares two `VPErrors` instances for equality based on specific error conditions.
55-
/// - Parameters:
56-
/// - lhs: The left-hand side `VPErrors` instance to compare.
57-
/// - rhs: The right-hand side `VPErrors` instance to compare.
58-
/// - Returns: A Boolean value indicating whether the two `VPErrors` instances are considered equal.
5956
public static func ==(lhs: VPErrors, rhs: VPErrors) -> Bool {
6057
switch (lhs, rhs) {
6158
case (.remoteVideoError(let a), .remoteVideoError(let b)):
@@ -64,9 +61,10 @@ extension VPErrors: Equatable {
6461
return a == b
6562
case (.settingsNotUnique, .settingsNotUnique):
6663
return true
64+
case (.failedToLoad, .failedToLoad):
65+
return true
6766
default:
6867
return false
6968
}
7069
}
7170
}
72-

‎Sources/swiftui-loop-videoplayer/protocol/helpers/PlayerDelegateProtocol.swift‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,19 @@ public protocol PlayerDelegateProtocol: AnyObject{
7373

7474
func boundsDidChange(to bounds: CGRect)
7575

76+
/// Called when the AVPlayerItem's status changes.
77+
/// - Parameter status: The new status of the AVPlayerItem.
78+
/// - `.unknown`: The item is still loading or its status is not yet determined.
79+
/// - `.readyToPlay`: The item is fully loaded and ready to play.
80+
/// - `.failed`: The item failed to load due to an error.
81+
func itemStatusChanged(_ status: AVPlayerItem.Status)
82+
83+
/// Called when the duration of the AVPlayerItem is available.
84+
/// - Parameter time: The total duration of the media item in `CMTime`.
85+
/// - This method is only called when the item reaches `.readyToPlay`,
86+
/// ensuring that the duration value is valid.
87+
func duration(_ time: CMTime)
88+
7689
#if os(iOS)
7790
func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController)
7891

‎Sources/swiftui-loop-videoplayer/protocol/player/ExtPlayerProtocol.swift‎

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public protocol ExtPlayerProtocol: AbstractPlayer, LayerMakerProtocol{
4444

4545
/// An optional observer for monitoring changes to the player's `currentItem` property.
4646
var currentItemObserver: NSKeyValueObservation? { get set }
47+
48+
/// Item status observer
49+
var itemStatusObserver: NSKeyValueObservation? { get set }
4750

4851
/// An optional observer for monitoring changes to the player's `volume` property.
4952
var volumeObserver: NSKeyValueObservation? { get set }
@@ -182,6 +185,7 @@ internal extension ExtPlayerProtocol {
182185
return
183186
}
184187

188+
observeItemStatus(newItem)
185189
insert(newItem)
186190

187191
if settings.loop{
@@ -198,6 +202,37 @@ internal extension ExtPlayerProtocol {
198202
func onError(_ error : VPErrors){
199203
delegate?.didReceiveError(error)
200204
}
205+
206+
/// Observes the status of an AVPlayerItem and notifies the delegate when the status changes.
207+
/// - Parameter item: The AVPlayerItem whose status should be observed.
208+
private func observeItemStatus(_ item: AVPlayerItem) {
209+
210+
removeItemObserver()
211+
212+
itemStatusObserver = item.observe(\.status, options: [.new, .initial]) { [weak self] item, _ in
213+
Task { @MainActor in
214+
self?.delegate?.itemStatusChanged(item.status)
215+
}
216+
217+
switch item.status {
218+
case .unknown: break
219+
case .readyToPlay:
220+
Task { @MainActor in
221+
self?.delegate?.duration(item.duration)
222+
}
223+
case .failed:
224+
Task { @MainActor in
225+
self?.onError(.failedToLoad)
226+
}
227+
}
228+
}
229+
}
230+
231+
/// Removes the current AVPlayerItem observer, if any, to prevent memory leaks.
232+
private func removeItemObserver() {
233+
itemStatusObserver?.invalidate()
234+
itemStatusObserver = nil
235+
}
201236

202237
/// Sets up observers on the player item and the player to track their status and error states.
203238
///
@@ -234,7 +269,7 @@ internal extension ExtPlayerProtocol {
234269
}
235270
}
236271

237-
currentItemObserver = player.observe(\.currentItem, options: [.new, .old]) { [weak self] player, change in
272+
currentItemObserver = player.observe(\.currentItem, options: [.new, .old,.initial]) { [weak self] player, change in
238273
// Detecting when the current item is changed
239274
if let newItem = change.newValue as? AVPlayerItem {
240275
Task { @MainActor in
@@ -259,6 +294,8 @@ internal extension ExtPlayerProtocol {
259294
/// Clear observers
260295
func clearObservers(){
261296

297+
removeItemObserver()
298+
262299
errorObserver?.invalidate()
263300
errorObserver = nil
264301

‎Sources/swiftui-loop-videoplayer/view/helpers/PlayerCoordinator.swift‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,26 @@ internal class PlayerCoordinator: NSObject, PlayerDelegateProtocol {
118118
/// Notifies that the bounds have changed.
119119
///
120120
/// - Parameter bounds: The new bounds of the main layer where we keep the video player and all vector layers. This allows a developer to recalculate and update all vector layers that lie in the CompositeLayer.
121-
122121
func boundsDidChange(to bounds: CGRect) {
123122
eventPublisher.send(.boundsChanged(bounds))
124123
}
124+
125+
/// Called when the AVPlayerItem's status changes.
126+
/// - Parameter status: The new status of the AVPlayerItem.
127+
/// - `.unknown`: The item is still loading or its status is not yet determined.
128+
/// - `.readyToPlay`: The item is fully loaded and ready to play.
129+
/// - `.failed`: The item failed to load due to an error.
130+
func itemStatusChanged(_ status: AVPlayerItem.Status) {
131+
eventPublisher.send(.itemStatusChanged(status))
132+
}
133+
134+
/// Called when the duration of the AVPlayerItem is available.
135+
/// - Parameter time: The total duration of the media item in `CMTime`.
136+
/// - This method is only called when the item reaches `.readyToPlay`,
137+
/// ensuring that the duration value is valid.
138+
func duration(_ time: CMTime) {
139+
eventPublisher.send(.duration(time))
140+
}
125141

126142
}
127143

‎Sources/swiftui-loop-videoplayer/view/player/ios/ExtPlayerUIView.swift‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ internal class ExtPlayerUIView: UIView, ExtPlayerProtocol{
5353
/// An optional observer for monitoring changes to the player's `currentItem` property.
5454
internal var currentItemObserver: NSKeyValueObservation?
5555

56+
/// Item status observer
57+
internal var itemStatusObserver: NSKeyValueObservation?
58+
5659
/// An optional observer for monitoring changes to the player's `volume` property.
5760
///
5861
/// This property holds an instance of `NSKeyValueObservation`, which observes the `volume`
@@ -62,6 +65,7 @@ internal class ExtPlayerUIView: UIView, ExtPlayerProtocol{
6265
/// The delegate to be notified about errors encountered by the player.
6366
weak var delegate: PlayerDelegateProtocol?
6467

68+
/// The Picture-in-Picture (PiP) controller for managing PiP functionality.
6569
internal var pipController: AVPictureInPictureController?
6670

6771
/// Initializes a new player view with a video asset and custom settings.

‎Sources/swiftui-loop-videoplayer/view/player/mac/ExtPlayerNSView.swift‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ internal class ExtPlayerNSView: NSView, ExtPlayerProtocol {
5555
/// An optional observer for monitoring changes to the player's `currentItem` property.
5656
internal var currentItemObserver: NSKeyValueObservation?
5757

58+
/// Item status observer
59+
internal var itemStatusObserver: NSKeyValueObservation?
60+
5861
/// An optional observer for monitoring changes to the player's `volume` property.
5962
///
6063
/// This property holds an instance of `NSKeyValueObservation`, which observes the `volume`

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /