Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add track and application information to monitoring data #1161

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions Sources/Monitoring/MetricsTracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ public extension MetricsTracker {
private extension MetricsTracker {
func startData(from events: [MetricEvent]) -> MetricStartData {
MetricStartData(
application: .init(
id: Self.applicationId,
version: Self.applicationVersion
),
device: .init(
id: Self.deviceId,
model: Self.deviceModel,
Expand All @@ -134,8 +138,7 @@ private extension MetricsTracker {
media: .init(
assetUrl: metadata?.assetUrl,
id: configuration.identifier,
metadataUrl: metadata?.metadataUrl,
origin: Bundle.main.bundleIdentifier
metadataUrl: metadata?.metadataUrl
),
qoeTimings: .init(events: events),
qosTimings: .init(events: events)
Expand All @@ -145,10 +148,12 @@ private extension MetricsTracker {
func errorData(from error: Error) -> MetricErrorData {
let error = error as NSError
return MetricErrorData(
audio: Self.languageCode(from: properties, for: .audible),
message: error.localizedDescription,
name: "\(error.domain)(\(error.code))",
position: Self.position(from: properties),
positionTimestamp: Self.positionTimestamp(from: properties),
subtitles: Self.languageCode(from: properties, for: .legible),
url: URL(string: properties?.metrics?.uri),
vpn: Self.isUsingVirtualPrivateNetwork()
)
Expand All @@ -158,6 +163,7 @@ private extension MetricsTracker {
let metrics = properties.metrics
return MetricStatusData(
airplay: properties.isExternalPlaybackActive,
audio: Self.languageCode(from: properties, for: .audible),
bandwidth: metrics?.observedBitrate,
bitrate: metrics?.indicatedBitrate,
bufferedDuration: Self.bufferedDuration(from: properties),
Expand All @@ -171,6 +177,7 @@ private extension MetricsTracker {
duration: stallDuration.toMilliseconds
),
streamType: Self.streamType(from: properties),
subtitles: Self.languageCode(from: properties, for: .legible),
url: metrics?.uri
)
}
Expand Down Expand Up @@ -220,6 +227,16 @@ private extension MetricsTracker {
}
}

private extension MetricsTracker {
static let applicationId: String? = {
Bundle.main.bundleIdentifier
}()

static let applicationVersion: String? = {
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
}()
}

private extension MetricsTracker {
func startHeartbeat() {
Timer.publish(every: configuration.heartbeatInterval, on: .main, in: .common)
Expand Down Expand Up @@ -307,6 +324,15 @@ private extension MetricsTracker {
properties.seekableTimeRange.duration.toMilliseconds
}

static func languageCode(from properties: TrackerProperties?, for characteristic: AVMediaCharacteristic) -> String? {
if case let .on(option) = properties?.currentMediaOption(for: characteristic) {
return languageCode(from: option)
}
else {
return nil
}
}

static func isUsingVirtualPrivateNetwork() -> Bool {
// Source: https://blog.tarkalabs.com/the-ultimate-vpn-detection-guide-for-ios-and-android-313b521186cb
guard let proxySettings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as? [String: Any],
Expand All @@ -317,4 +343,8 @@ private extension MetricsTracker {
key == "tap" || key == "ppp" || key.contains("tun") || key.contains("ipsec")
}
}

private static func languageCode(from option: AVMediaSelectionOption?) -> String? {
option?.locale?.language.languageCode?.identifier
}
}
2 changes: 2 additions & 0 deletions Sources/Monitoring/Types/MetricErrorData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import Foundation

struct MetricErrorData: Encodable {
let audio: String?
let message: String
let name: String
let position: Int?
let positionTimestamp: Int?
let subtitles: String?
let url: URL?
let vpn: Bool
}
7 changes: 6 additions & 1 deletion Sources/Monitoring/Types/MetricStartData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Foundation
import PillarboxPlayer

struct MetricStartData: Encodable {
let application: Application
let device: Device
let os: OperatingSystem
let screen: Screen
Expand All @@ -18,6 +19,11 @@ struct MetricStartData: Encodable {
}

extension MetricStartData {
struct Application: Encodable {
let id: String?
let version: String?
}

struct Device: Encodable {
let id: String?
let model: String
Expand All @@ -28,7 +34,6 @@ extension MetricStartData {
let assetUrl: URL?
let id: String?
let metadataUrl: URL?
let origin: String?
}

struct OperatingSystem: Encodable {
Expand Down
2 changes: 2 additions & 0 deletions Sources/Monitoring/Types/MetricStatusData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

struct MetricStatusData: Encodable {
let airplay: Bool
let audio: String?
let bandwidth: Double?
let bitrate: Double?
let bufferedDuration: Int?
Expand All @@ -16,6 +17,7 @@ struct MetricStatusData: Encodable {
let positionTimestamp: Int?
let stall: Stall
let streamType: String?
let subtitles: String?
let url: String?
}

Expand Down
5 changes: 4 additions & 1 deletion Tests/MonitoringTests/MetricsTrackerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ final class MetricsTrackerTests: MonitoringTestCase {

let data = payload.data

let application = data.application
expect(application.id).notTo(beNil())
expect(application.version).notTo(beNil())

let device = data.device
expect(device.id).notTo(beNil())
expect(device.model).notTo(beNil())
Expand All @@ -188,7 +192,6 @@ final class MetricsTrackerTests: MonitoringTestCase {
expect(media.assetUrl).to(equal(URL(string: "https://localhost/asset.m3u8")))
expect(media.id).to(equal("identifier"))
expect(media.metadataUrl).to(equal(URL(string: "https://localhost/metadata.json")))
expect(media.origin).notTo(beNil())

let os = data.os
expect(os.name).notTo(beNil())
Expand Down