From 9f0a5201b7bd216425338c6e8c1bf8c604ac90a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Muller?= Date: Wed, 31 Jul 2024 09:23:55 +0200 Subject: [PATCH] Remove old QoS models --- .../srgssr/pillarbox/player/qos/QoSError.kt | 42 ----- .../srgssr/pillarbox/player/qos/QoSEvent.kt | 28 --- .../srgssr/pillarbox/player/qos/QoSMessage.kt | 20 -- .../srgssr/pillarbox/player/qos/QoSSession.kt | 123 ------------ .../pillarbox/player/qos/QoSSessionTimings.kt | 35 ---- .../pillarbox/player/qos/QoSErrorTest.kt | 56 ------ .../pillarbox/player/qos/QoSSessionTest.kt | 178 ------------------ .../player/qos/QoSSessionTimingsTest.kt | 20 -- 8 files changed, 502 deletions(-) delete mode 100644 pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSError.kt delete mode 100644 pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSEvent.kt delete mode 100644 pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSMessage.kt delete mode 100644 pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSSession.kt delete mode 100644 pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSSessionTimings.kt delete mode 100644 pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSErrorTest.kt delete mode 100644 pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSSessionTest.kt delete mode 100644 pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSSessionTimingsTest.kt diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSError.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSError.kt deleted file mode 100644 index 1030b4e27..000000000 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSError.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.player.qos - -/** - * Represents a [Player][androidx.media3.common.Player] error to send to a QoS server. - * - * @property log The log associated with the error. - * @property message The error message. - * @property name The name of the error. - * @property playerPosition The position of the player when the error occurred, in milliseconds, or `null` if not available. - * @property severity The severity of the error, either [FATAL][Severity.FATAL] or [WARNING][Severity.WARNING]. - */ -data class QoSError( - val log: String, - val message: String, - val name: String, - val playerPosition: Long?, - val severity: Severity, -) { - /** - * Represents a [Player][androidx.media3.common.Player] error severity. - */ - enum class Severity { - FATAL, - WARNING, - } - - constructor( - throwable: Throwable, - playerPosition: Long?, - severity: Severity, - ) : this( - log = throwable.stackTraceToString(), - message = throwable.message.orEmpty(), - name = throwable::class.simpleName.orEmpty(), - playerPosition = playerPosition, - severity = severity, - ) -} diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSEvent.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSEvent.kt deleted file mode 100644 index 628bf9d38..000000000 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSEvent.kt +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.player.qos - -/** - * Represents a generic event, which contains metrics about the current media stream. - * - * @property bandwidth The device-measured network bandwidth, in bytes per second. - * @property bitrate The bitrate of the current stream, in bytes per second. - * @property bufferDuration The forward duration of the buffer, in milliseconds. - * @property playbackDuration The duration of the playback, in milliseconds. - * @property playerPosition The position of the player, in milliseconds. - * @property stallCount The number of stalls that have occurred, not as a result of a seek. - * @property stallDuration The total duration of the stalls, in milliseconds. - * @property url The URL of the stream. - */ -data class QoSEvent( - val bandwidth: Long, - val bitrate: Int, - val bufferDuration: Long, - val playbackDuration: Long, - val playerPosition: Long, - val stallCount: Int, - val stallDuration: Long, - val url: String, -) diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSMessage.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSMessage.kt deleted file mode 100644 index 92dd12605..000000000 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSMessage.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.player.qos - -/** - * Represents a QoS message. - * - * @property data The data associated with the message. - * @property eventName The name of the event. - * @property sessionId The session id. - * @property timestamp The current timestamp. - */ -data class QoSMessage( - val data: Any, - val eventName: String, - val sessionId: String, - val timestamp: Long = System.currentTimeMillis(), -) diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSSession.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSSession.kt deleted file mode 100644 index 1405c01e6..000000000 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSSession.kt +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.player.qos - -import android.content.Context -import android.content.res.Configuration -import android.graphics.Rect -import android.os.Build -import android.view.WindowManager -import ch.srgssr.pillarbox.player.BuildConfig - -/** - * Represents a QoS session, which contains information about the device, current media, and player. - * - * @property deviceId The unique identifier of the device. - * @property deviceModel The model of the device. - * @property deviceType The type of device. - * @property mediaId The identifier of the media being played. - * @property mediaSource The source URL of the media being played. - * @property operatingSystemName The name of the operating system. - * @property operatingSystemVersion The version of the operating system. - * @property origin The origin of the player. - * @property playerName The name of the player. - * @property playerPlatform The platform of the player. - * @property playerVersion The version of the player. - * @property screenHeight The height of the screen in pixels. - * @property screenWidth The width of the screen in pixels. - * @property timings The timing until the current media started to play. - */ -data class QoSSession( - val deviceId: String, - val deviceModel: String = getDeviceModel(), - val deviceType: DeviceType, - val mediaId: String, - val mediaSource: String, - val operatingSystemName: String = PLATFORM_NAME, - val operatingSystemVersion: String = OPERATING_SYSTEM_VERSION, - val origin: String, - val playerName: String = PLAYER_NAME, - val playerPlatform: String = PLATFORM_NAME, - val playerVersion: String = PLAYER_VERSION, - val screenHeight: Int, - val screenWidth: Int, - val timings: QoSSessionTimings = QoSSessionTimings.Empty, -) { - /** - * The type of device. - */ - enum class DeviceType { - CAR, - PHONE, - TABLET, - TV, - } - - constructor( - context: Context, - mediaId: String, - mediaSource: String, - timings: QoSSessionTimings - ) : this( - deviceId = getDeviceId(), - deviceType = context.getDeviceType(), - mediaId = mediaId, - mediaSource = mediaSource, - origin = context.packageName, - screenHeight = context.getWindowBounds().height(), - screenWidth = context.getWindowBounds().width(), - timings = timings - ) - - private companion object { - private val OPERATING_SYSTEM_VERSION = Build.VERSION.RELEASE - private const val PHONE_TABLET_WIDTH_THRESHOLD = 600 - private const val PLATFORM_NAME = "android" - private const val PLAYER_NAME = "pillarbox" - private const val PLAYER_VERSION = BuildConfig.VERSION_NAME - - @Suppress("FunctionOnlyReturningConstant") - private fun getDeviceId(): String { - // TODO Define this somehow (maybe use TCPredefinedVariables.getInstance().uniqueIdentifier) - return "" - } - - private fun getDeviceModel(): String { - return Build.MANUFACTURER + " " + Build.MODEL - } - - private fun Context.getDeviceType(): DeviceType { - val configuration = resources.configuration - return when (configuration.uiMode and Configuration.UI_MODE_TYPE_MASK) { - Configuration.UI_MODE_TYPE_CAR -> DeviceType.CAR - Configuration.UI_MODE_TYPE_NORMAL -> { - val smallestWidthDp = configuration.smallestScreenWidthDp - - if (smallestWidthDp >= PHONE_TABLET_WIDTH_THRESHOLD) { - DeviceType.TABLET - } else { - DeviceType.PHONE - } - } - - Configuration.UI_MODE_TYPE_TELEVISION -> DeviceType.TV - else -> DeviceType.PHONE // TODO Do we assume PHONE by default? Or do we throw an exception? - } - } - - private fun Context.getWindowBounds(): Rect { - val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager - - return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { - Rect().also { - @Suppress("DEPRECATION") - windowManager.defaultDisplay.getRectSize(it) - } - } else { - windowManager.maximumWindowMetrics.bounds - } - } - } -} diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSSessionTimings.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSSessionTimings.kt deleted file mode 100644 index 2128a86e8..000000000 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/qos/QoSSessionTimings.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.player.qos - -import kotlin.time.Duration - -/** - * Represents the timings until the current media started to play. - * - * @property asset The time spent to load the asset. - * @property currentToStart The time spent to load from the moment the [MediaItem][androidx.media3.common.MediaItem] became the current item until it - * started to play. - * @property drm The time spent to load the DRM. - * @property mediaSource The time spent to load the media source. - */ -data class QoSSessionTimings( - val asset: Duration? = null, - val currentToStart: Duration? = null, - val drm: Duration? = null, - val mediaSource: Duration? = null, -) { - companion object { - /** - * Default [QoSSessionTimings] where all fields are set to `null`. - */ - val Empty = QoSSessionTimings( - asset = null, - currentToStart = null, - drm = null, - mediaSource = null, - ) - } -} diff --git a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSErrorTest.kt b/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSErrorTest.kt deleted file mode 100644 index f99a7aaed..000000000 --- a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSErrorTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.player.qos - -import java.lang.RuntimeException -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.minutes -import kotlin.time.Duration.Companion.seconds - -class QoSErrorTest { - @Test - fun `throwableConstructor with empty exception`() { - val throwable = IllegalStateException() - val qosError = QoSError( - throwable = throwable, - playerPosition = 5.minutes.inWholeMilliseconds, - severity = QoSError.Severity.WARNING, - ) - - val logLines = qosError.log.lineSequence() - - assertTrue(logLines.count() > 1, "Expected log to contain the stacktrace") - assertEquals("java.lang.IllegalStateException", logLines.first()) - assertTrue(logLines.none { it.startsWith("Caused by: ") }, "Expected log to not contain a cause") - assertEquals("", qosError.message) - assertEquals("IllegalStateException", qosError.name) - assertEquals(QoSError.Severity.WARNING, qosError.severity) - } - - @Test - fun `throwableConstructor with detailed exception`() { - val cause = NullPointerException("Expected 'foo' to be not null") - val throwable = RuntimeException("Something bad happened", cause) - val qosError = QoSError( - throwable = throwable, - playerPosition = 30.seconds.inWholeMilliseconds, - severity = QoSError.Severity.FATAL, - ) - - val logLines = qosError.log.lineSequence() - - assertTrue(logLines.count() > 1, "Expected log to contain the stacktrace") - assertEquals("java.lang.RuntimeException: ${throwable.message}", logLines.first()) - assertTrue( - logLines.any { it == "Caused by: java.lang.NullPointerException: ${cause.message}" }, - "Expected log to contain a cause", - ) - assertEquals(throwable.message, qosError.message) - assertEquals("RuntimeException", qosError.name) - assertEquals(QoSError.Severity.FATAL, qosError.severity) - } -} diff --git a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSSessionTest.kt b/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSSessionTest.kt deleted file mode 100644 index 966ec0db6..000000000 --- a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSSessionTest.kt +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.player.qos - -import android.content.Context -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.junit.runner.RunWith -import org.robolectric.annotation.Config -import kotlin.test.Test -import kotlin.test.assertEquals - -@RunWith(AndroidJUnit4::class) -class QoSSessionTest { - @Test - fun `contextConstructor provides correct default values`() { - val qosSession = createQoSSession() - - assertEquals("", qosSession.deviceId) - assertEquals("unknown robolectric", qosSession.deviceModel) - assertEquals(QoSSession.DeviceType.PHONE, qosSession.deviceType) - assertEquals("android", qosSession.operatingSystemName) - assertEquals("5.0.2", qosSession.operatingSystemVersion) - assertEquals("ch.srgssr.pillarbox.player.test", qosSession.origin) - assertEquals("pillarbox", qosSession.playerName) - assertEquals("android", qosSession.playerPlatform) - assertEquals("Local", qosSession.playerVersion) - assertEquals(470, qosSession.screenHeight) - assertEquals(320, qosSession.screenWidth) - assertEquals(QoSSessionTimings.Empty, qosSession.timings) - } - - @Test - @Config(sdk = [30]) - fun `contextConstructor provides correct default values (API 30)`() { - val qosSession = createQoSSession() - - assertEquals("", qosSession.deviceId) - assertEquals("robolectric robolectric", qosSession.deviceModel) - assertEquals(QoSSession.DeviceType.PHONE, qosSession.deviceType) - assertEquals("android", qosSession.operatingSystemName) - assertEquals("11", qosSession.operatingSystemVersion) - assertEquals("ch.srgssr.pillarbox.player.test", qosSession.origin) - assertEquals("pillarbox", qosSession.playerName) - assertEquals("android", qosSession.playerPlatform) - assertEquals("Local", qosSession.playerVersion) - assertEquals(470, qosSession.screenHeight) - assertEquals(320, qosSession.screenWidth) - assertEquals(QoSSessionTimings.Empty, qosSession.timings) - } - - @Test - @Config(qualifiers = "car") - fun `contextConstructor provides correct default values for car`() { - val qosSession = createQoSSession() - - assertEquals("", qosSession.deviceId) - assertEquals("unknown robolectric", qosSession.deviceModel) - assertEquals(QoSSession.DeviceType.CAR, qosSession.deviceType) - assertEquals("android", qosSession.operatingSystemName) - assertEquals("5.0.2", qosSession.operatingSystemVersion) - assertEquals("ch.srgssr.pillarbox.player.test", qosSession.origin) - assertEquals("pillarbox", qosSession.playerName) - assertEquals("android", qosSession.playerPlatform) - assertEquals("Local", qosSession.playerVersion) - assertEquals(470, qosSession.screenHeight) - assertEquals(320, qosSession.screenWidth) - assertEquals(QoSSessionTimings.Empty, qosSession.timings) - } - - @Test - @Config(qualifiers = "sw320dp") - fun `contextConstructor provides correct default values for phone (sw320dp)`() { - val qosSession = createQoSSession() - - assertEquals("", qosSession.deviceId) - assertEquals("unknown robolectric", qosSession.deviceModel) - assertEquals(QoSSession.DeviceType.PHONE, qosSession.deviceType) - assertEquals("android", qosSession.operatingSystemName) - assertEquals("5.0.2", qosSession.operatingSystemVersion) - assertEquals("ch.srgssr.pillarbox.player.test", qosSession.origin) - assertEquals("pillarbox", qosSession.playerName) - assertEquals("android", qosSession.playerPlatform) - assertEquals("Local", qosSession.playerVersion) - assertEquals(470, qosSession.screenHeight) - assertEquals(320, qosSession.screenWidth) - assertEquals(QoSSessionTimings.Empty, qosSession.timings) - } - - @Test - @Config(qualifiers = "sw600dp") - fun `contextConstructor provides correct default values for tablet (sw600dp)`() { - val qosSession = createQoSSession() - - assertEquals("", qosSession.deviceId) - assertEquals("unknown robolectric", qosSession.deviceModel) - assertEquals(QoSSession.DeviceType.TABLET, qosSession.deviceType) - assertEquals("android", qosSession.operatingSystemName) - assertEquals("5.0.2", qosSession.operatingSystemVersion) - assertEquals("ch.srgssr.pillarbox.player.test", qosSession.origin) - assertEquals("pillarbox", qosSession.playerName) - assertEquals("android", qosSession.playerPlatform) - assertEquals("Local", qosSession.playerVersion) - assertEquals(470, qosSession.screenHeight) - assertEquals(320, qosSession.screenWidth) - assertEquals(QoSSessionTimings.Empty, qosSession.timings) - } - - @Test - @Config(qualifiers = "sw720dp") - fun `contextConstructor provides correct default values for tablet (sw720dp)`() { - val qosSession = createQoSSession() - - assertEquals("", qosSession.deviceId) - assertEquals("unknown robolectric", qosSession.deviceModel) - assertEquals(QoSSession.DeviceType.TABLET, qosSession.deviceType) - assertEquals("android", qosSession.operatingSystemName) - assertEquals("5.0.2", qosSession.operatingSystemVersion) - assertEquals("ch.srgssr.pillarbox.player.test", qosSession.origin) - assertEquals("pillarbox", qosSession.playerName) - assertEquals("android", qosSession.playerPlatform) - assertEquals("Local", qosSession.playerVersion) - assertEquals(470, qosSession.screenHeight) - assertEquals(320, qosSession.screenWidth) - assertEquals(QoSSessionTimings.Empty, qosSession.timings) - } - - @Test - @Config(qualifiers = "television") - fun `contextConstructor provides correct default values for TV`() { - val qosSession = createQoSSession() - - assertEquals("", qosSession.deviceId) - assertEquals("unknown robolectric", qosSession.deviceModel) - assertEquals(QoSSession.DeviceType.TV, qosSession.deviceType) - assertEquals("android", qosSession.operatingSystemName) - assertEquals("5.0.2", qosSession.operatingSystemVersion) - assertEquals("ch.srgssr.pillarbox.player.test", qosSession.origin) - assertEquals("pillarbox", qosSession.playerName) - assertEquals("android", qosSession.playerPlatform) - assertEquals("Local", qosSession.playerVersion) - assertEquals(470, qosSession.screenHeight) - assertEquals(320, qosSession.screenWidth) - assertEquals(QoSSessionTimings.Empty, qosSession.timings) - } - - @Test - @Config(qualifiers = "watch") - fun `contextConstructor provides correct default values for watch`() { - val qosSession = createQoSSession() - - assertEquals("", qosSession.deviceId) - assertEquals("unknown robolectric", qosSession.deviceModel) - assertEquals(QoSSession.DeviceType.PHONE, qosSession.deviceType) - assertEquals("android", qosSession.operatingSystemName) - assertEquals("5.0.2", qosSession.operatingSystemVersion) - assertEquals("ch.srgssr.pillarbox.player.test", qosSession.origin) - assertEquals("pillarbox", qosSession.playerName) - assertEquals("android", qosSession.playerPlatform) - assertEquals("Local", qosSession.playerVersion) - assertEquals(470, qosSession.screenHeight) - assertEquals(320, qosSession.screenWidth) - assertEquals(QoSSessionTimings.Empty, qosSession.timings) - } - - private fun createQoSSession(): QoSSession { - val context = ApplicationProvider.getApplicationContext() - - return QoSSession( - context = context, - mediaId = "urn:rts:video:12345", - mediaSource = "https://il-stage.srgssr.ch/integrationlayer/2.1/mediaComposition/byUrn/urn:rts:video:12345?vector=APPPLAY", - timings = QoSSessionTimings.Empty, - ) - } -} diff --git a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSSessionTimingsTest.kt b/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSSessionTimingsTest.kt deleted file mode 100644 index 37e499a39..000000000 --- a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/qos/QoSSessionTimingsTest.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.player.qos - -import kotlin.test.Test -import kotlin.test.assertNull - -class QoSSessionTimingsTest { - @Test - fun `zero timings`() { - val timings = QoSSessionTimings.Empty - - assertNull(timings.asset) - assertNull(timings.currentToStart) - assertNull(timings.drm) - assertNull(timings.mediaSource) - } -}