Skip to content

Commit

Permalink
Display event log in metrics debugging view (#942)
Browse files Browse the repository at this point in the history
  • Loading branch information
defagos committed Jul 16, 2024
1 parent 72d60ca commit e685c27
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 26 deletions.
4 changes: 4 additions & 0 deletions Demo/Pillarbox-demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
6F9D879A2BE35A6100DEE9EB /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 6F9D87992BE3587700DEE9EB /* PrivacyInfo.xcprivacy */; };
6FAD51122B331A370078FE08 /* MultiViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FAD51112B331A370078FE08 /* MultiViewModel.swift */; };
6FAD51142B331AAD0078FE08 /* SingleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FAD51132B331AAD0078FE08 /* SingleView.swift */; };
6FB8ED742C417E7E0049171B /* MetricEventCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB8ED732C417E780049171B /* MetricEventCell.swift */; };
6FBCC1F92B2A090E009EA3E3 /* MotionManager~ios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FBCC1F82B2A090E009EA3E3 /* MotionManager~ios.swift */; };
6FBF198F2B1A2E1C00B16BD5 /* OptimizingCustomLayouts2~ios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FBF198D2B1A2E1C00B16BD5 /* OptimizingCustomLayouts2~ios.swift */; };
6FBF19902B1A2E1C00B16BD5 /* OptimizingCustomLayouts1~ios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FBF198E2B1A2E1C00B16BD5 /* OptimizingCustomLayouts1~ios.swift */; };
Expand Down Expand Up @@ -193,6 +194,7 @@
6F9D87992BE3587700DEE9EB /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
6FAD51112B331A370078FE08 /* MultiViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiViewModel.swift; sourceTree = "<group>"; };
6FAD51132B331AAD0078FE08 /* SingleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleView.swift; sourceTree = "<group>"; };
6FB8ED732C417E780049171B /* MetricEventCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetricEventCell.swift; sourceTree = "<group>"; };
6FBCC1F82B2A090E009EA3E3 /* MotionManager~ios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionManager~ios.swift"; sourceTree = "<group>"; };
6FBF198D2B1A2E1C00B16BD5 /* OptimizingCustomLayouts2~ios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OptimizingCustomLayouts2~ios.swift"; sourceTree = "<group>"; };
6FBF198E2B1A2E1C00B16BD5 /* OptimizingCustomLayouts1~ios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OptimizingCustomLayouts1~ios.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -294,6 +296,7 @@
6F56F91D2C1D85E900495E20 /* Metrics */ = {
isa = PBXGroup;
children = (
6FB8ED732C417E780049171B /* MetricEventCell.swift */,
6F7DDB622C20394600B48A67 /* DataVolumeChart.swift */,
6F7DDB602C20388200B48A67 /* FrameDropsChart.swift */,
6F56F9242C1D89F700495E20 /* IndicatedBitrateChart.swift */,
Expand Down Expand Up @@ -719,6 +722,7 @@
6F59E8A429CF31E20093E6FB /* ExamplesViewModel.swift in Sources */,
6F59E89829CF31E20093E6FB /* PlayerConfiguration.swift in Sources */,
6F8459F22A38543400A7B5F2 /* Signal.swift in Sources */,
6FB8ED742C417E7E0049171B /* MetricEventCell.swift in Sources */,
6FDB51CB2A4042B2001F430F /* Router.swift in Sources */,
6F59E88B29CF31E20093E6FB /* PlaylistViewModel.swift in Sources */,
6F56F9232C1D893400495E20 /* ObservedBitrateChart.swift in Sources */,
Expand Down
3 changes: 3 additions & 0 deletions Demo/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
},
"Enabled" : {

},
"Event log" : {

},
"Examples" : {

Expand Down
61 changes: 61 additions & 0 deletions Demo/Sources/Metrics/MetricEventCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// Copyright (c) SRG SSR. All rights reserved.
//
// License information is available from the LICENSE file.
//

import CoreMedia
import PillarboxPlayer
import SwiftUI

struct MetricEventCell: View {
private static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
return formatter
}()

private static let durationFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.zeroFormattingBehavior = .pad
return formatter
}()

let event: MetricEvent

private var time: String {
if let duration = Self.duration(from: event.time) {
return "[\(duration)] \(formattedDate)"
}
else {
return formattedDate
}
}

private var description: String {
event.kind.description
}

private var formattedDate: String {
Self.dateFormatter.string(from: event.date)
}

var body: some View {
VStack(alignment: .leading) {
Text(time)
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(1)
Text(description)
.lineLimit(3)
.multilineTextAlignment(.leading)
}
}

private static func duration(from time: CMTime) -> String? {
guard time.isValid else { return nil }
return durationFormatter.string(from: time.seconds)
}
}
11 changes: 11 additions & 0 deletions Demo/Sources/Metrics/MetricsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ struct MetricsView: View {
stallsChartSection()
frameDropsChartSection()
}
eventLogSection()
}
}

Expand Down Expand Up @@ -229,6 +230,16 @@ struct MetricsView: View {
Text("Frame drops")
}
}

private func eventLogSection() -> some View {
Section {
ForEach(metricsCollector.metricEvents, id: \.self) { event in
MetricEventCell(event: event)
}
} header: {
Text("Event log")
}
}
}

struct MetricsView_Previews: PreviewProvider {
Expand Down
55 changes: 47 additions & 8 deletions Sources/Player/Metrics/MetricEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//

import CoreMedia
import Foundation

/// A metric event.
public struct MetricEvent: Hashable {
Expand Down Expand Up @@ -75,21 +76,59 @@ public struct MetricEvent: Hashable {
}
}

extension MetricEvent: CustomStringConvertible {
extension MetricEvent.Kind: CustomStringConvertible {
public var description: String {
switch kind {
switch self {
case let .assetLoading(dateInterval):
return "assetLoading(\(dateInterval.duration))"
return "Asset loaded in \(Self.duration(from: dateInterval.duration))"
case let .resourceLoading(dateInterval):
return "resourceLoading(\(dateInterval.duration))"
return "Resource loaded in \(Self.duration(from: dateInterval.duration))"
case let .failure(error):
return "failure(\(error.localizedDescription))"
return "[FAILURE] \(error.localizedDescription)"
case let .warning(error):
return "warning(\(error.localizedDescription))"
return "[WARNING] \(error.localizedDescription)"
case .stall:
return "stall"
return "Stall"
case let .resumeAfterStall(dateInterval):
return "resumeAfterStall(\(dateInterval.duration))"
return "Resume after stall for \(Self.duration(from: dateInterval.duration))"
}
}

private static func duration(from interval: TimeInterval) -> String {
String(format: "%.3fs", interval)
}
}

extension MetricEvent: CustomStringConvertible {
private static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
return formatter
}()

private static let durationFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.zeroFormattingBehavior = .pad
return formatter
}()

private var formattedDate: String {
Self.dateFormatter.string(from: date)
}

public var description: String {
if let duration = Self.duration(from: time) {
"[\(duration)] \(formattedDate) - \(kind.description)"
}
else {
"\(formattedDate) - \(kind.description)"
}
}

private static func duration(from time: CMTime) -> String? {
guard time.isValid else { return nil }
return durationFormatter.string(from: time.seconds)
}
}
32 changes: 14 additions & 18 deletions Sources/Player/Publishers/AVPlayerPublishers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,22 @@ extension AVPlayer {
publisher(for: \.currentItem)
.removeDuplicates()
.map { item -> AnyPublisher<ItemState, Never> in
if let item {
if let error = item.error {
let event = MetricEvent(kind: .failure(error), time: item.currentTime())
item.metricLog.appendEvent(event)
return Just(.init(item: item, error: error)).eraseToAnyPublisher()
}
else {
return item.errorPublisher()
.handleEvents(receiveOutput: { error in
// swiftlint:disable:previous trailing_closure
let event = MetricEvent(kind: .failure(error), time: item.currentTime())
item.metricLog.appendEvent(event)
})
.map { .init(item: item, error: $0) }
.prepend(.init(item: item, error: nil))
.eraseToAnyPublisher()
}
guard let item else { return Just(.empty).eraseToAnyPublisher() }
if let error = item.error {
let event = MetricEvent(kind: .failure(error), time: item.currentTime())
item.metricLog.appendEvent(event)
return Just(.init(item: item, error: error)).eraseToAnyPublisher()
}
else {
return Just(.empty).eraseToAnyPublisher()
return item.errorPublisher()
.handleEvents(receiveOutput: { error in
// swiftlint:disable:previous trailing_closure
let event = MetricEvent(kind: .failure(error), time: item.currentTime())
item.metricLog.appendEvent(event)
})
.map { .init(item: item, error: $0) }
.prepend(.init(item: item, error: nil))
.eraseToAnyPublisher()
}
}
.switchToLatest()
Expand Down

0 comments on commit e685c27

Please sign in to comment.