Logging video player errors

commit_hash:28bd6632f7a21cee86275cece1717a0abdfa85fb
This commit is contained in:
denlvovich
2026-02-25 01:11:25 +03:00
parent c73991a290
commit f4d2da5df5
11 changed files with 93 additions and 15 deletions
+1
View File
@@ -24733,6 +24733,7 @@
"test_data/integration_test_data/variable-functions/get_url_value_with_url_fallback.json":"divkit/public/test_data/integration_test_data/variable-functions/get_url_value_with_url_fallback.json",
"test_data/integration_test_data/variable-functions/nested_get_value.json":"divkit/public/test_data/integration_test_data/variable-functions/nested_get_value.json",
"test_data/integration_test_data/variable-functions/nested_get_value_without_variables.json":"divkit/public/test_data/integration_test_data/variable-functions/nested_get_value_without_variables.json",
"test_data/integration_test_data/video/player_error_reporting_ios.json":"divkit/public/test_data/integration_test_data/video/player_error_reporting_ios.json",
"test_data/integration_test_data/wrap_content_constraints_warning.json":"divkit/public/test_data/integration_test_data/wrap_content_constraints_warning.json",
"test_data/interactive_snapshot_test_data/div-action/base.json":"divkit/public/test_data/interactive_snapshot_test_data/div-action/base.json",
"test_data/interactive_snapshot_test_data/div-action/custom-action.json":"divkit/public/test_data/interactive_snapshot_test_data/div-action/custom-action.json",
+13
View File
@@ -157,3 +157,16 @@ struct DivUnknownError: Error, DivError {
DivKitLogger.error(description)
}
}
struct DivUnknownWarning: DivError {
let kind = DivErrorKind.unknown
let message: String
let path: UIElementPath
let level: DivErrorLevel = .warning
init(_ message: String, path: UIElementPath) {
self.message = message
self.path = path
DivKitLogger.warning(description)
}
}
@@ -15,7 +15,7 @@ extension DivVideo: DivBlockModeling {
private func makeBaseBlock(context: DivBlockModelingContext) throws -> Block {
guard let playerFactory = context.playerFactory else {
DivKitLogger.error("There is no player factory in the context")
context.addWarning(message: "There is no player factory in the context")
return EmptyBlock()
}
@@ -57,7 +57,15 @@ extension DivVideo: DivBlockModeling {
endActions: endActions,
fatalActions: fatalActions,
path: context.path,
scale: resolveScale(resolver).scale
scale: resolveScale(resolver).scale,
errorReporter: { [weak errorsStorage = context.errorsStorage, path = context.path] error in
errorsStorage?.add(
DivUnknownWarning(
"Playback encountered an error: \"\(error.errorDescription)\"",
path: path
)
)
}
)
let videoBlock = VideoBlock(
@@ -46,7 +46,8 @@ extension VideoBlockViewModel {
endActions: endActions,
fatalActions: fatalActions,
path: path,
scale: scale
scale: scale,
errorReporter: errorReporter
)
}
}
@@ -166,7 +166,7 @@ final class CorePlayerImpl: CorePlayer {
guard let self = weakSelf, self.player.currentItem == item else { return }
let nserror = notification.userInfo?[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? NSError
self.playbackDidFail(nserror.map(BasePlayerError.init) ?? UnknownPlayerError())
self.playbackDidFail(nserror.map(BasePlayerError.init) ?? CustomPlayerError())
}.dispose(in: itemObservers)
}
@@ -181,7 +181,7 @@ final class CorePlayerImpl: CorePlayer {
let playerError = (player.error as? NSError).map(BasePlayerError.init)
let itemError = (player.currentItem?.error as? NSError).map(BasePlayerError.init)
playbackDidFail((playerError ?? itemError) ?? UnknownPlayerError())
playbackDidFail((playerError ?? itemError) ?? CustomPlayerError())
}
}
@@ -1,17 +1,25 @@
import Foundation
protocol PlayerError: Error {}
public protocol PlayerError: Error {
var errorDescription: String { get }
}
struct BasePlayerError: PlayerError {
let error: NSError
private let error: NSError
var errorDescription: String {
error.localizedDescription
}
init(_ error: NSError) {
self.error = error
}
}
struct UnknownPlayerError: PlayerError {
var description: String {
"Something went wrong"
struct CustomPlayerError: PlayerError {
let errorDescription: String
init(errorDescription: String? = nil) {
self.errorDescription = errorDescription ?? "Something went wrong"
}
}
@@ -23,7 +23,11 @@ final class DefaultPlayer: Player {
func set(data: VideoData, config: PlaybackConfig) {
context = SourceContext(videoData: data, playbackConfig: config)
guard let source = data.getSupportedVideo(player.staticScope.isMIMETypeSupported) else {
eventPipe.send(.fatal)
eventPipe.send(
.fatal(
CustomPlayerError(errorDescription: "Unsupported MIME Type") as PlayerError
)
)
return
}
@@ -99,7 +103,7 @@ final class DefaultPlayer: Player {
player
.playbackDidFail
.addObserver { _ in weakSelf?.eventPipe.send(.fatal) }
.addObserver { error in weakSelf?.eventPipe.send(.fatal(error)) }
.dispose(in: playerObservers)
player
@@ -17,7 +17,7 @@ public enum PlayerEvent {
case buffering
case play
case end
case fatal
case fatal(PlayerError)
case currentTimeUpdate(_ ms: Int)
case durationUpdate(_ ms: Int)
@@ -76,7 +76,8 @@ private final class VideoBlockView: BlockView, VisibleBoundsTrackingContainer {
forPath: self.model.path
)
self.model.pauseActions.perform(sendingFrom: self)
case .fatal:
case let .fatal(error):
self.model.errorReporter?(error)
self.model.fatalActions.perform(sendingFrom: self)
case .play:
self.observer?.elementStateChanged(
@@ -13,6 +13,7 @@ public struct VideoBlockViewModel: Equatable {
public let fatalActions: [UserInterfaceAction]
public let path: UIElementPath
public let scale: VideoScale
public let errorReporter: ((PlayerError) -> Void)?
public init(
videoData: VideoData,
@@ -26,7 +27,8 @@ public struct VideoBlockViewModel: Equatable {
endActions: [UserInterfaceAction] = [],
fatalActions: [UserInterfaceAction] = [],
path: UIElementPath,
scale: VideoScale = .fit
scale: VideoScale = .fit,
errorReporter: ((PlayerError) -> Void)? = nil
) {
self.videoData = videoData
self.playbackConfig = playbackConfig
@@ -40,6 +42,7 @@ public struct VideoBlockViewModel: Equatable {
self.fatalActions = fatalActions
self.path = path
self.scale = scale
self.errorReporter = errorReporter
}
public static func ==(lhs: VideoBlockViewModel, rhs: VideoBlockViewModel) -> Bool {
@@ -0,0 +1,39 @@
{
"description": "Verify runtime video playback errors in the player",
"div_data": {
"card": {
"log_id": "test_card",
"states": [
{
"state_id": 0,
"div": {
"type": "video",
"id": "video",
"autostart": true,
"video_sources": [
{
"type": "video_source",
"mime_type": "video/unsupported",
"url": "https://example.com/video.unsupported"
}
]
}
}
]
}
},
"cases": [
{
"div_actions": [],
"expected": [
{
"type": "error",
"value": "Playback encountered an error: \"Unsupported MIME Type\""
}
],
"platforms": [
"ios"
]
}
]
}