From 1b3b8b164fbcd3ce8da5bc793b4b76711e132c17 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Wed, 7 Aug 2024 15:16:38 +0200 Subject: [PATCH 01/31] Implement UplynkPrelayResponseEvent --- .../uplynk/internal/events/UplynkEvent.kt | 12 +++++++++++ .../uplynk/internal/events/UplynkEventImpl.kt | 21 +++++++++++++++++++ .../events/UplynkPreplayResponseEventImpl.kt | 12 +++++++++++ .../uplynk/network/PreplayResponse.kt | 2 +- 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt new file mode 100644 index 00000000..9b31bcc7 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt @@ -0,0 +1,12 @@ +package com.theoplayer.android.connector.uplynk.internal.events + +import com.theoplayer.android.api.event.Event + +/** + * The base Uplynk Event. + */ +interface UplynkEvent> : Event + +interface UplynkPreplayResponseEvent: UplynkEvent + +interface UplynkAssetInfoResponseEvent: UplynkEvent \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt new file mode 100644 index 00000000..1eac7ba3 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt @@ -0,0 +1,21 @@ +package com.theoplayer.android.connector.uplynk.internal.events + +import com.theoplayer.android.api.event.EventType +import java.util.Date + +abstract class UplynkEventImpl> internal constructor( + private val type: EventType, + private val date: Date +) : UplynkEvent { + + override fun getDate() = date + + override fun getType() = type + + override fun toString(): String { + return "UplynkEvent{" + + "type=" + type + + ", date=" + date + + '}' + } +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt new file mode 100644 index 00000000..4591bd04 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt @@ -0,0 +1,12 @@ +package com.theoplayer.android.connector.uplynk.internal.events + +import com.theoplayer.android.api.event.EventType +import com.theoplayer.android.connector.uplynk.network.PreplayResponse +import java.util.Date + +class UplynkPreplayResponseEventImpl( + type: EventType, + date: Date, + val response: PreplayResponse +) : + UplynkEventImpl(type, date) \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt index d7d39865..78b7c926 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt @@ -3,4 +3,4 @@ package com.theoplayer.android.connector.uplynk.network import kotlinx.serialization.Serializable @Serializable -internal class PreplayResponse(val playURL: String) +class PreplayResponse(val playURL: String) From db5bf3c54347c5ea24a2a01c29e229c02b0c7f3c Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Thu, 8 Aug 2024 14:33:05 +0200 Subject: [PATCH 02/31] Implement UplynkPreplayResponseEvent --- .../android/connector/MainActivity.kt | 4 +++ .../connector/uplynk/UplynkAdIntegration.kt | 0 .../connector/uplynk/UplynkConnector.kt | 2 ++ .../uplynk/UplynkEventDispatcherImpl.kt | 31 +++++++++++++++++++ .../uplynk/internal/UplynkAdIntegration.kt | 5 +++ .../uplynk/internal/events/UplynkEvent.kt | 5 ++- .../internal/events/UplynkEventTypeImpl.kt | 11 +++++++ .../internal/events/UplynkEventTypes.kt | 5 +++ .../events/UplynkPreplayResponseEventImpl.kt | 9 +++--- .../uplynk/network/PreplayResponse.kt | 2 +- 10 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkAdIntegration.kt create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcherImpl.kt create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt diff --git a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt index a13282b8..208d0d2e 100644 --- a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt +++ b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt @@ -23,6 +23,7 @@ import com.theoplayer.android.connector.analytics.conviva.ConvivaConfiguration import com.theoplayer.android.connector.analytics.conviva.ConvivaConnector import com.theoplayer.android.connector.analytics.nielsen.NielsenConnector import com.theoplayer.android.connector.uplynk.UplynkConnector +import com.theoplayer.android.connector.uplynk.internal.events.UplynkEventTypes import com.theoplayer.android.connector.yospace.YospaceConnector const val TAG = "MainActivity" @@ -148,6 +149,9 @@ class MainActivity : AppCompatActivity() { private fun setupUplynk() { uplynkConnector = UplynkConnector(theoplayerView) + uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.PREPLAY_RESPONSE) { + Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE ${it.getResponse()} - $it") + } } private fun setupListeners() { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkAdIntegration.kt new file mode 100644 index 00000000..e69de29b diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt index 5cbd3e46..2f059dc4 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt @@ -21,6 +21,7 @@ class UplynkConnector( private val theoplayerView: THEOplayerView, ) { private lateinit var integration: UplynkAdIntegration + val eventDispatcher = UplynkEventDispatcherImpl() init { theoplayerView.player.ads.registerServerSideIntegration(INTEGRATION_ID, this::setupIntegration) @@ -30,6 +31,7 @@ class UplynkConnector( val integration = UplynkAdIntegration( theoplayerView, controller, + eventDispatcher, UplynkSsaiDescriptionConverter() ) this.integration = integration diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcherImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcherImpl.kt new file mode 100644 index 00000000..93e21f8c --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcherImpl.kt @@ -0,0 +1,31 @@ +package com.theoplayer.android.connector.uplynk + +import android.os.Handler +import android.os.Looper +import com.theoplayer.android.api.event.EventDispatcher +import com.theoplayer.android.api.event.EventListener +import com.theoplayer.android.api.event.EventType +import com.theoplayer.android.connector.uplynk.internal.events.UplynkEvent + + +class UplynkEventDispatcherImpl : EventDispatcher> { + private val eventMap: HashMap, ArrayList>>> = HashMap() + private val handler = Handler(Looper.getMainLooper()) + override fun > addEventListener( + type: EventType, + listener: EventListener + ) { + eventMap.getOrPut(type) { ArrayList(1) }.add(listener as EventListener>) + } + + override fun > removeEventListener( + type: EventType, + listener: EventListener + ) { + eventMap[type]?.remove(listener) + } + + fun dispatchEvent(event: UplynkEvent<*>) = handler.post { + eventMap[event.type]?.forEach { it.handleEvent(event) } + } +} diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 7eb2414a..ab0a4605 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -5,12 +5,16 @@ import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.ads.ServerSideAdIntegrationHandler import com.theoplayer.android.api.player.Player import com.theoplayer.android.api.source.SourceDescription +import com.theoplayer.android.connector.uplynk.UplynkEventDispatcherImpl import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription +import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl import com.theoplayer.android.connector.uplynk.network.UplynkApi +import java.util.Date internal class UplynkAdIntegration( val theoplayerView: THEOplayerView, val controller: ServerSideAdIntegrationController, + val eventDispatcher: UplynkEventDispatcherImpl, val uplynkDescriptionConverter: UplynkSsaiDescriptionConverter ) : ServerSideAdIntegrationHandler { @@ -23,6 +27,7 @@ internal class UplynkAdIntegration( val uplynkSource = source.sources.find { it.ssai is UplynkSsaiDescription } ?: return source val ssaiDescription = uplynkSource.ssai as? UplynkSsaiDescription ?: return source val response = uplynkApi.preplay(uplynkDescriptionConverter.buildPreplayUrl(ssaiDescription)) + eventDispatcher.dispatchEvent(UplynkPreplayResponseEventImpl(Date(), response)) val newSource = source.replaceSources(source.sources.toMutableList().apply { remove(uplynkSource) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt index 9b31bcc7..283ac24d 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt @@ -1,12 +1,15 @@ package com.theoplayer.android.connector.uplynk.internal.events import com.theoplayer.android.api.event.Event +import com.theoplayer.android.connector.uplynk.network.PreplayResponse /** * The base Uplynk Event. */ interface UplynkEvent> : Event -interface UplynkPreplayResponseEvent: UplynkEvent +interface UplynkPreplayResponseEvent: UplynkEvent { + fun getResponse(): PreplayResponse +} interface UplynkAssetInfoResponseEvent: UplynkEvent \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt new file mode 100644 index 00000000..0d0691e0 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt @@ -0,0 +1,11 @@ +package com.theoplayer.android.connector.uplynk.internal.events + +import com.theoplayer.android.api.event.EventType + +class UplynkEventTypeImpl>(private val name: String) : EventType { + override fun getName() = this.name + + override fun toString(): String { + return this.name + } +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt new file mode 100644 index 00000000..d201c8aa --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt @@ -0,0 +1,5 @@ +package com.theoplayer.android.connector.uplynk.internal.events + +object UplynkEventTypes { + val PREPLAY_RESPONSE = UplynkEventTypeImpl("PREPLAY_RESPONSE") +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt index 4591bd04..cc990495 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt @@ -1,12 +1,13 @@ package com.theoplayer.android.connector.uplynk.internal.events -import com.theoplayer.android.api.event.EventType import com.theoplayer.android.connector.uplynk.network.PreplayResponse import java.util.Date class UplynkPreplayResponseEventImpl( - type: EventType, date: Date, - val response: PreplayResponse + private val response: PreplayResponse ) : - UplynkEventImpl(type, date) \ No newline at end of file + UplynkEventImpl(UplynkEventTypes.PREPLAY_RESPONSE, date), + UplynkPreplayResponseEvent { + override fun getResponse(): PreplayResponse = response + } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt index 78b7c926..581d8eb9 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt @@ -3,4 +3,4 @@ package com.theoplayer.android.connector.uplynk.network import kotlinx.serialization.Serializable @Serializable -class PreplayResponse(val playURL: String) +data class PreplayResponse(val playURL: String) From 32fc9939bd1abef4e6de626ea9273ba4828fade4 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 9 Aug 2024 12:02:10 +0200 Subject: [PATCH 03/31] Implement UplynkAssetInfoResponseEvent --- .../android/connector/MainActivity.kt | 4 ++ .../theoplayer/android/connector/Sources.kt | 1 + connectors/uplynk/build.gradle | 1 + .../connector/uplynk/UplynkSsaiDescription.kt | 11 +++- .../uplynk/internal/UplynkAdIntegration.kt | 21 ++++++++ .../UplynkSsaiDescriptionConverter.kt | 16 ++++++ .../UplynkAssetInfoResponseEventImpl.kt | 12 +++++ .../uplynk/internal/events/UplynkEvent.kt | 4 +- .../internal/events/UplynkEventTypes.kt | 1 + .../uplynk/network/PreplayResponse.kt | 4 +- .../connector/uplynk/network/UplynkApi.kt | 4 ++ .../UplynkSsaiDescriptionConverterTest.kt | 50 +++++++++++++++++++ 12 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt diff --git a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt index 208d0d2e..940c3e78 100644 --- a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt +++ b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt @@ -152,6 +152,10 @@ class MainActivity : AppCompatActivity() { uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.PREPLAY_RESPONSE) { Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE ${it.getResponse()} - $it") } + + uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.ASSET_INFO_RESPONSE) { + Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE ${it.getResponse()} - $it") + } } private fun setupListeners() { diff --git a/app/src/main/java/com/theoplayer/android/connector/Sources.kt b/app/src/main/java/com/theoplayer/android/connector/Sources.kt index 8bb50e3e..23384daf 100644 --- a/app/src/main/java/com/theoplayer/android/connector/Sources.kt +++ b/app/src/main/java/com/theoplayer/android/connector/Sources.kt @@ -110,6 +110,7 @@ val sources: List by lazy { UplynkSsaiDescription .Builder() .prefix("https://content.uplynk.com") + .assetInfo(true) .assetIds(listOf( "41afc04d34ad4cbd855db52402ef210e", "c6b61470c27d44c4842346980ec2c7bd", diff --git a/connectors/uplynk/build.gradle b/connectors/uplynk/build.gradle index 4488d153..59062f15 100644 --- a/connectors/uplynk/build.gradle +++ b/connectors/uplynk/build.gradle @@ -44,6 +44,7 @@ dependencies { testImplementation "com.theoplayer.theoplayer-sdk-android:core:$sdkVersion" testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" + testImplementation "org.jetbrains.kotlin:kotlin-test-junit:1.8.10" } tasks.withType(AbstractDokkaLeafTask.class).configureEach { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkSsaiDescription.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkSsaiDescription.kt index 3eb00eb1..0259a65f 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkSsaiDescription.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkSsaiDescription.kt @@ -12,7 +12,8 @@ data class UplynkSsaiDescription( val assetIds: List = listOf(), val externalId: List = listOf(), val userId: String? = null, - val preplayParameters: LinkedHashMap = linkedMapOf() + val preplayParameters: LinkedHashMap = linkedMapOf(), + val assetInfo: Boolean ): CustomSsaiDescription() { override val customIntegration: String @@ -73,6 +74,11 @@ data class UplynkSsaiDescription( */ fun preplayParameters(parameters: LinkedHashMap) = apply { this.preplayParameters = parameters } + private var assetInfo: Boolean = false + /** + * Sets flat to request asset info + */ + fun assetInfo(shouldRequest: Boolean) = apply { this.assetInfo = shouldRequest } /** * Builds the [UplynkSsaiDescription]. */ @@ -81,6 +87,7 @@ data class UplynkSsaiDescription( assetIds = assetIds, externalId = externalIds, userId = userId, - preplayParameters = preplayParameters) + preplayParameters = preplayParameters, + assetInfo = assetInfo) } } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index ab0a4605..4a2e45f3 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -1,5 +1,7 @@ package com.theoplayer.android.connector.uplynk.internal +import android.os.Handler +import android.os.Looper import com.theoplayer.android.api.THEOplayerView import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.ads.ServerSideAdIntegrationHandler @@ -7,8 +9,12 @@ import com.theoplayer.android.api.player.Player import com.theoplayer.android.api.source.SourceDescription import com.theoplayer.android.connector.uplynk.UplynkEventDispatcherImpl import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription +import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl import com.theoplayer.android.connector.uplynk.network.UplynkApi +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async import java.util.Date internal class UplynkAdIntegration( @@ -22,6 +28,8 @@ internal class UplynkAdIntegration( get() = theoplayerView.player private val uplynkApi = UplynkApi() + private val mainThreadHandler = Handler(Looper.getMainLooper()) + private val ioScope = CoroutineScope(Dispatchers.IO) override suspend fun setSource(source: SourceDescription): SourceDescription { val uplynkSource = source.sources.find { it.ssai is UplynkSsaiDescription } ?: return source @@ -33,6 +41,19 @@ internal class UplynkAdIntegration( remove(uplynkSource) add(0, uplynkSource.replaceSrc(response.playURL)) }) + if (ssaiDescription.assetInfo) { + uplynkDescriptionConverter + .buildAssetInfoUrls(ssaiDescription, response.sid) + .map { url -> + ioScope.async { + val assetInfo = uplynkApi.assetInfo(url) + mainThreadHandler.post { + eventDispatcher.dispatchEvent(UplynkAssetInfoResponseEventImpl(Date(), assetInfo)) + } + } + } + } + return newSource } } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt index afc9d6ce..737f0bb9 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt @@ -16,4 +16,20 @@ internal class UplynkSsaiDescriptionConverter { val parameters = preplayParameters.map{ "${it.key}=${it.value}" }.joinToString("&") return "$prefix/preplay/$assetIds?v=2&$parameters" } + + fun buildAssetInfoUrls(ssaiDescription: UplynkSsaiDescription, sessionId: String): List = with(ssaiDescription) { + val urlList = when { + assetIds.isNotEmpty() -> assetIds.map { + "$prefix/player/assetinfo/$it.json" + } + externalId.isNotEmpty() -> externalId.map { + "$prefix/player/assetinfo/ext/$userId/$it.json" + } + else -> listOf() + } + return when { + sessionId.isBlank() -> urlList + else -> urlList.map { "$it?pbs=$sessionId" } + } + } } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt new file mode 100644 index 00000000..e0fc5ec4 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt @@ -0,0 +1,12 @@ +package com.theoplayer.android.connector.uplynk.internal.events + +import java.util.Date + +class UplynkAssetInfoResponseEventImpl( + date: Date, + private val response: String +) : + UplynkEventImpl(UplynkEventTypes.ASSET_INFO_RESPONSE, date), + UplynkAssetInfoResponseEvent { + override fun getResponse(): String = response + } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt index 283ac24d..1796dd91 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt @@ -12,4 +12,6 @@ interface UplynkPreplayResponseEvent: UplynkEvent { fun getResponse(): PreplayResponse } -interface UplynkAssetInfoResponseEvent: UplynkEvent \ No newline at end of file +interface UplynkAssetInfoResponseEvent: UplynkEvent { + fun getResponse(): String +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt index d201c8aa..6cc19ecb 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt @@ -2,4 +2,5 @@ package com.theoplayer.android.connector.uplynk.internal.events object UplynkEventTypes { val PREPLAY_RESPONSE = UplynkEventTypeImpl("PREPLAY_RESPONSE") + val ASSET_INFO_RESPONSE = UplynkEventTypeImpl("ASSET_INFO_RESPONSE") } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt index 581d8eb9..38f3d7d9 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt @@ -3,4 +3,6 @@ package com.theoplayer.android.connector.uplynk.network import kotlinx.serialization.Serializable @Serializable -data class PreplayResponse(val playURL: String) +data class PreplayResponse( + val playURL: String, + val sid: String) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt index f383a9dc..ed8ad2c1 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt @@ -10,4 +10,8 @@ internal class UplynkApi { val body = network.get(srcURL) return json.decodeFromString(body) } + + suspend fun assetInfo(url: String): String { + return network.get(url) + } } diff --git a/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt b/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt index d0d4606a..8971eed5 100644 --- a/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt +++ b/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt @@ -8,6 +8,7 @@ import org.junit.Test import org.mockito.Mock import org.mockito.MockitoAnnotations import org.mockito.kotlin.whenever +import kotlin.test.assertContains class UplynkSsaiDescriptionConverterTest { private lateinit var ssaiDescription: UplynkSsaiDescription @@ -92,4 +93,53 @@ class UplynkSsaiDescriptionConverterTest { assertEquals("multiple.json", items[3]) assertEquals("v=2&p1=v1&p2=v2&p3=v3", items[4]) } + + @Test + fun buildAssetInfoUrls_withoutSid_doesNotContainPbsParameter() { + val result = converter.buildAssetInfoUrls(ssaiDescription, "") + + assertTrue(result.none { it.contains("pbs=") }) + } + + @Test + fun buildAssetInfoUrls_withSid_hasPbsParameter() { + val result = converter.buildAssetInfoUrls(ssaiDescription, "sessionId") + + assertTrue(result.all { it.contains("pbs=sessionId") }) + } + + @Test + fun buildAssetInfoUrls_whenAssetIdIsEmptyAndExternalIdIsEmpty_returnsEmptyUrl() { + whenever(ssaiDescription.assetIds).thenReturn(listOf()) + whenever(ssaiDescription.externalId).thenReturn(listOf()) + + val result = converter.buildAssetInfoUrls(ssaiDescription, "") + + assertEquals(0, result.size) + } + + @Test + fun buildAssetInfoUrls_whenAssetIdHasValues_returnsAssetInfoUrls() { + val result = converter.buildAssetInfoUrls(ssaiDescription, "") + + assertEquals(3, result.size) + + assertContains(result, "urlprefix/player/assetinfo/asset1.json") + assertContains(result, "urlprefix/player/assetinfo/asset2.json") + assertContains(result, "urlprefix/player/assetinfo/asset3.json") + } + + @Test + fun buildAssetInfoUrls_whenAssetIdIsEmpty_returnsAssetInfoUrlsUsingExternalId() { + whenever(ssaiDescription.assetIds).thenReturn(listOf()) + whenever(ssaiDescription.externalId).thenReturn(listOf("extId1", "extId2")) + whenever(ssaiDescription.userId).thenReturn("userId") + + val result = converter.buildAssetInfoUrls(ssaiDescription, "") + + assertEquals(2, result.size) + + assertContains(result, "urlprefix/player/assetinfo/ext/userId/extId1.json") + assertContains(result, "urlprefix/player/assetinfo/ext/userId/extId2.json") + } } \ No newline at end of file From 3f05e3cefd064eb84da3f0767513268f48f3f9b4 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 9 Aug 2024 12:27:34 +0200 Subject: [PATCH 04/31] Deserialize AssetInfoResponse --- .../UplynkAssetInfoResponseEventImpl.kt | 5 +- .../uplynk/internal/events/UplynkEvent.kt | 3 +- .../uplynk/network/AssetInfoResponse.kt | 264 ++++++++++++++++++ .../connector/uplynk/network/UplynkApi.kt | 9 +- 4 files changed, 275 insertions(+), 6 deletions(-) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoResponse.kt diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt index e0fc5ec4..7470244a 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt @@ -1,12 +1,13 @@ package com.theoplayer.android.connector.uplynk.internal.events +import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import java.util.Date class UplynkAssetInfoResponseEventImpl( date: Date, - private val response: String + private val response: AssetInfoResponse ) : UplynkEventImpl(UplynkEventTypes.ASSET_INFO_RESPONSE, date), UplynkAssetInfoResponseEvent { - override fun getResponse(): String = response + override fun getResponse(): AssetInfoResponse = response } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt index 1796dd91..44a5d2bc 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt @@ -1,6 +1,7 @@ package com.theoplayer.android.connector.uplynk.internal.events import com.theoplayer.android.api.event.Event +import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import com.theoplayer.android.connector.uplynk.network.PreplayResponse /** @@ -13,5 +14,5 @@ interface UplynkPreplayResponseEvent: UplynkEvent { } interface UplynkAssetInfoResponseEvent: UplynkEvent { - fun getResponse(): String + fun getResponse(): AssetInfoResponse } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoResponse.kt new file mode 100644 index 00000000..5ff35558 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoResponse.kt @@ -0,0 +1,264 @@ +package com.theoplayer.android.connector.uplynk.network + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Represents the details of an asset retrieved from the AssetInfo request. + * + * This data class encapsulates various properties and metadata about an asset, + * such as its ratings, duration, thumbnail information, and more. + * + * For further details, please refer to the Uplynk Documentation: + * [AssetInfo Documentation](https://docs.edgecast.com/video/#Develop/AssetInfo.htm%3FTocPath%3DDevelop%7CClient%2520(Media%2520Player)%7C_____1) + */ +@Serializable +data class AssetInfoResponse( + /** + * Returns whether the asset is audio only. + * + *
    + *
  • 1 if it is audio. + *
+ */ + @SerialName("audio_only") + val audioOnly: Int, + /** + * List of objects which contain information for the boundaries for the asset. + * + *
    + *
  • Will contain instances of the subclasses of {@link BoundaryDetail}. + *
+ * + * @return List of objects which contain information for the {@link BoundaryDetail}s for the asset. (Nullable) + */ + @SerialName("boundary_details") + val boundaryDetails: List? = null, + /** + * Returns whether an error occurred. + * + *
    + *
  • Zero if error + *
  • One otherwise. + *
+ */ + @SerialName("error") + val error: Int, + /** + * The tv-rating of the asset. + * + *
    + *
  • -1: Not Available + *
  • 0: Not Rated + *
  • 1: TV-Y + *
  • 2: TV-Y7 + *
  • 3: TV-G + *
  • 4: TV-PG + *
  • 5: TV-14 + *
  • 6: TV-MA + *
  • 7: Not Rated + *
+ * + * @return The {@link VerizonMediaAssetTvRating}. (NonNull) + */ + @SerialName("tv_rating") + val tvRating: Int, + /** + * The number of slices available for the asset. + */ + @SerialName("max_slice") + val maxSlice: Int, + /** + * The prefix URL to the thumbnails. + * + */ + @SerialName("thumb_prefix") + val thumbPrefix: String, + + /** + * The average slice duration. + */ + @SerialName("slice_dur") + val sliceDur: Double, + /** + * The movie rating of the asset. + * + *
    + *
  • -1: Not Available + *
  • 0: Not Applicable + *
  • 1: G + *
  • 2: PG + *
  • 3: PG-13 + *
  • 4: R + *
  • 5: NC-17 + *
  • 6: X + *
  • 7: Not Rated + *
+ * + */ + @SerialName("movie_rating") + val movieRating: Int, + /** + * The identifier of the owner. + * + *

Example:

+ *
    + *
  • "fb3a4cb996THEOOWNERa101477ffad8fb" + *
+ */ + @SerialName("owner") + val owner: String, + /** + * The metadata attached to the asset. + * + *
    + *
  • Metadata may be added via the CMS. + *
+ * + * NonNull + */ + @SerialName("meta") + val meta: Map, + /** + * The available bitrates of the asset. + * + * NonNull + */ + @SerialName("rates") + val rates: List, + /** + * List of thumbnail resolutions of the asset. + * + * NonNull + */ + @SerialName("thumbs") + val thumbs: List, + /** + * The poster URL of the asset. + * + * NonNull + */ + @SerialName("poster_url") + val posterUrl: String, + /** + * The duration of the asset. + * + * NonNull + */ + @SerialName("duration") + val duration: Double, + /** + * The default poster URL created for the asset. + * + * NonNull + */ + @SerialName("default_poster_url") + val defaultPosterUrl: String, + /** + * The description of the asset. + * + * NonNull + */ + @SerialName("desc") + val desc: String, + /** + * The ratings for the asset, as bitwise flags. + * + * These available flags are the following: + *
    + *
  • D: Drug-related themes are present + *
  • V: Violence is present + *
  • S: Sexual situations are present + *
  • L: Adult Language is present + *
+ * + * This number is a bitwise number to indicate if one or more of these values are present. + *
    + *
  • [D][V][S][L] - 0: No rating flag. + *
  • [D][V][S][L] - 1: Language flag. + *
  • [D][V][S][L] - 2: Sex flag. + *
  • [D][V][S][L] - 4: Violence flag. + *
  • [D][V][S][L] - 8: Drugs flag. + *
  • [D][V][S][L] - 15: All flags are on. + *
+ * + */ + @SerialName("rating_flags") + val ratingFlags: Int, + /** + * The identifier of the external source. + * + * NonNull + */ + @SerialName("external_id") + val externalId: String, + /** + * Returns whether the asset is an ad. + * + *
    + *
  • Zero if it is not an ad + *
  • One otherwise + *
+ */ + @SerialName("is_ad") + val isAd: Int, + /** + * The identifier of the asset. + * + *

Example:

+ *
    + *
  • "5a3THEO272d44THEOc810d5849aeTHEO" + *
+ * NonNull + */ + @SerialName("asset") + val asset: String +) + +/** + * Data class representing the details of a boundary. + * + * @property offset Indicates the offset, in seconds, of the boundary. + * @property duration Indicates the duration, in seconds, of the boundary. + */ +@Serializable +data class BoundaryDetail( + val offset: Int, + val duration: Int +) + +/** + * Data class representing a thumbnail resolution. + * + */ +@Serializable +data class Thumbnail( + /** + * The height of the thumbnail, in pixels. (Nullable) + */ + val height: Int?, + /** + * The width of the thumbnail, in pixels. (Nullable) + */ + val width: Int?, + /** + * The prefix of the thumbnail. (NonNull) + */ + val prefix: String, + /** + * The requested width, in pixels. + * + *
    + *
  • This can differ from the actual width because images are not stretched. + *
+ */ + val bw: Int, + /** + * The requested height, in pixels. + * + *
    + *
  • This can differ from the actual width because images are not stretched. + *
+ */ + val bh: Int, +) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt index ed8ad2c1..a493754e 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt @@ -3,7 +3,9 @@ package com.theoplayer.android.connector.uplynk.network import kotlinx.serialization.json.Json internal class UplynkApi { - private val json = Json{ ignoreUnknownKeys = true } + private val json = Json{ + ignoreUnknownKeys = true + } private val network = HttpsConnection() suspend fun preplay(srcURL: String): PreplayResponse { @@ -11,7 +13,8 @@ internal class UplynkApi { return json.decodeFromString(body) } - suspend fun assetInfo(url: String): String { - return network.get(url) + suspend fun assetInfo(url: String): AssetInfoResponse { + val body = network.get(url) + return json.decodeFromString(body) } } From 7e28652002549d0460bcb88b4e21a998e35d12b1 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 9 Aug 2024 12:42:56 +0200 Subject: [PATCH 05/31] Add properties to PreplayResponse --- .../uplynk/network/AssetInfoResponse.kt | 2 +- .../uplynk/network/PreplayResponse.kt | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoResponse.kt index 5ff35558..4b59d438 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoResponse.kt @@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable /** * Represents the details of an asset retrieved from the AssetInfo request. * - * This data class encapsulates various properties and metadata about an asset, + * This class encapsulates various properties and metadata about an asset, * such as its ratings, duration, thumbnail information, and more. * * For further details, please refer to the Uplynk Documentation: diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt index 38f3d7d9..bbeba90a 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayResponse.kt @@ -2,7 +2,36 @@ package com.theoplayer.android.connector.uplynk.network import kotlinx.serialization.Serializable +/** + * The Uplynk Preplay Base Response API. + * + * For further details, please refer to the Uplynk Documentation: + * [Preplay API (Version 2) Documentation](https://docs.edgecast.com/video/#Develop/Preplayv2.htm%3FTocPath%3DDevelop%7CClient%2520(Media%2520Player)%7C_____2) + */ @Serializable data class PreplayResponse( + + /** + * The manifest's URL. (**NonNull**) + */ val playURL: String, - val sid: String) + + /** + * The identifier of the viewer's session. (**NonNull**) + */ + val sid: String, + + /** + * The zone prefix for the viewer's session. (**NonNull**) + * + * + * * Use this prefix when submitting playback or API requests for this session. + * + * + * + * Example: + * + * * Possible return value: 'https://content-ause2.uplynk.com/' + * + */ + val prefix: String) From c5a3425128807f7a83f79d7412c37a09acf50e9b Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 9 Aug 2024 14:11:47 +0200 Subject: [PATCH 06/31] Implement error responses --- .../android/connector/MainActivity.kt | 8 ++++ .../uplynk/internal/UplynkAdIntegration.kt | 31 +++++++++++++-- .../UplynkAssetInfoErrorResponseEventImpl.kt | 18 +++++++++ .../uplynk/internal/events/UplynkEvent.kt | 10 +++++ .../internal/events/UplynkEventTypes.kt | 2 + .../UplynkPreplayErrorResponseEventImpl.kt | 15 +++++++ .../network/AssetInfoInternalResponse.kt | 23 +++++++++++ .../uplynk/network/PreplayInternalResponse.kt | 39 +++++++++++++++++++ .../connector/uplynk/network/UplynkApi.kt | 11 ++---- 9 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoInternalResponse.kt create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayInternalResponse.kt diff --git a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt index 940c3e78..3e2fa420 100644 --- a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt +++ b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt @@ -156,6 +156,14 @@ class MainActivity : AppCompatActivity() { uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.ASSET_INFO_RESPONSE) { Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE ${it.getResponse()} - $it") } + + uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.PREPLAY_RESPONSE_ERROR) { + Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE_ERROR ${it.getBody()} - ${it.getException()}") + } + + uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.ASSET_INFO_RESPONSE_ERROR) { + Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE_ERROR ${it.getBody()} - ${it.getException()}") + } } private fun setupListeners() { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 4a2e45f3..44411ef1 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -9,7 +9,9 @@ import com.theoplayer.android.api.player.Player import com.theoplayer.android.api.source.SourceDescription import com.theoplayer.android.connector.uplynk.UplynkEventDispatcherImpl import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription +import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoErrorResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl +import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayErrorResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl import com.theoplayer.android.connector.uplynk.network.UplynkApi import kotlinx.coroutines.CoroutineScope @@ -35,20 +37,41 @@ internal class UplynkAdIntegration( val uplynkSource = source.sources.find { it.ssai is UplynkSsaiDescription } ?: return source val ssaiDescription = uplynkSource.ssai as? UplynkSsaiDescription ?: return source val response = uplynkApi.preplay(uplynkDescriptionConverter.buildPreplayUrl(ssaiDescription)) - eventDispatcher.dispatchEvent(UplynkPreplayResponseEventImpl(Date(), response)) + if (response.externalResponse != null) { + eventDispatcher.dispatchEvent(UplynkPreplayResponseEventImpl(Date(), response.externalResponse!!)) + } else { + eventDispatcher.dispatchEvent(UplynkPreplayErrorResponseEventImpl(Date(), response.body, response.error)) + } + val newSource = source.replaceSources(source.sources.toMutableList().apply { remove(uplynkSource) - add(0, uplynkSource.replaceSrc(response.playURL)) + add(0, uplynkSource.replaceSrc(response.internalResponse.playURL)) }) if (ssaiDescription.assetInfo) { uplynkDescriptionConverter - .buildAssetInfoUrls(ssaiDescription, response.sid) + .buildAssetInfoUrls(ssaiDescription, response.internalResponse.sid) .map { url -> ioScope.async { val assetInfo = uplynkApi.assetInfo(url) mainThreadHandler.post { - eventDispatcher.dispatchEvent(UplynkAssetInfoResponseEventImpl(Date(), assetInfo)) + if (assetInfo.externalResponse != null) { + eventDispatcher.dispatchEvent( + UplynkAssetInfoResponseEventImpl( + Date(), + assetInfo.externalResponse!! + ) + ) + } else { + eventDispatcher.dispatchEvent( + UplynkAssetInfoErrorResponseEventImpl( + Date(), + assetInfo.body, + assetInfo.error + ) + ) + } + } } } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt new file mode 100644 index 00000000..654c2eca --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt @@ -0,0 +1,18 @@ +package com.theoplayer.android.connector.uplynk.internal.events + +import java.util.Date + +class UplynkAssetInfoErrorResponseEventImpl( + date: Date, + private val body: String, + private val exception: Exception? +) : + UplynkEventImpl( + UplynkEventTypes.ASSET_INFO_RESPONSE_ERROR, + date + ), + UplynkAssetInfoResponseErrorEvent { + override fun getException() = exception + + override fun getBody() = body +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt index 44a5d2bc..9de53dca 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt @@ -13,6 +13,16 @@ interface UplynkPreplayResponseEvent: UplynkEvent { fun getResponse(): PreplayResponse } +interface UplynkPreplayErrorResponseEvent: UplynkEvent { + fun getException(): Exception? + fun getBody(): String +} + interface UplynkAssetInfoResponseEvent: UplynkEvent { fun getResponse(): AssetInfoResponse +} + +interface UplynkAssetInfoResponseErrorEvent: UplynkEvent { + fun getException(): Exception? + fun getBody(): String } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt index 6cc19ecb..3bd48e2a 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt @@ -2,5 +2,7 @@ package com.theoplayer.android.connector.uplynk.internal.events object UplynkEventTypes { val PREPLAY_RESPONSE = UplynkEventTypeImpl("PREPLAY_RESPONSE") + val PREPLAY_RESPONSE_ERROR = UplynkEventTypeImpl("PREPLAY_RESPONSE_ERROR") val ASSET_INFO_RESPONSE = UplynkEventTypeImpl("ASSET_INFO_RESPONSE") + val ASSET_INFO_RESPONSE_ERROR = UplynkEventTypeImpl("ASSET_INFO_RESPONSE_ERROR") } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt new file mode 100644 index 00000000..a06a1ba5 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt @@ -0,0 +1,15 @@ +package com.theoplayer.android.connector.uplynk.internal.events + +import java.util.Date + +class UplynkPreplayErrorResponseEventImpl( + date: Date, + private val body: String, + private val exception: Exception? +) : + UplynkEventImpl(UplynkEventTypes.PREPLAY_RESPONSE_ERROR, date), + UplynkPreplayErrorResponseEvent { + override fun getException() = exception + + override fun getBody() = body +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoInternalResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoInternalResponse.kt new file mode 100644 index 00000000..80cc6737 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoInternalResponse.kt @@ -0,0 +1,23 @@ +package com.theoplayer.android.connector.uplynk.network + +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json + +private val json = Json { + ignoreUnknownKeys = true +} + +internal class AssetInfoInternalResponse(val body: String) { + var error: Exception? = null + val externalResponse: AssetInfoResponse? by lazy { + try { + json.decodeFromString(body) + } catch (se: SerializationException) { + error = se + null + } catch (ie: IllegalArgumentException) { + error = ie + null + } + } +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayInternalResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayInternalResponse.kt new file mode 100644 index 00000000..39b79779 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayInternalResponse.kt @@ -0,0 +1,39 @@ +package com.theoplayer.android.connector.uplynk.network + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json + +private val json = Json{ + ignoreUnknownKeys = true +} + +@Serializable +internal data class MinimalPreplayResponse( + + /** + * The manifest's URL. (**NonNull**) + */ + val playURL: String, + + /** + * The identifier of the viewer's session. (**NonNull**) + */ + val sid: String) + + +internal class PreplayInternalResponse(val body: String) { + val internalResponse: MinimalPreplayResponse = json.decodeFromString(body) + var error: Exception? = null + val externalResponse: PreplayResponse? by lazy { + try { + json.decodeFromString(body) + } catch (se: SerializationException) { + error = se + null + } catch (ie: IllegalArgumentException) { + error = ie + null + } + } +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt index a493754e..42504bee 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt @@ -3,18 +3,15 @@ package com.theoplayer.android.connector.uplynk.network import kotlinx.serialization.json.Json internal class UplynkApi { - private val json = Json{ - ignoreUnknownKeys = true - } private val network = HttpsConnection() - suspend fun preplay(srcURL: String): PreplayResponse { + suspend fun preplay(srcURL: String): PreplayInternalResponse { val body = network.get(srcURL) - return json.decodeFromString(body) + return PreplayInternalResponse(body) } - suspend fun assetInfo(url: String): AssetInfoResponse { + suspend fun assetInfo(url: String): AssetInfoInternalResponse { val body = network.get(url) - return json.decodeFromString(body) + return AssetInfoInternalResponse(body) } } From f2fa9e5083dda4afd5b01cc8dc2d826a7d6e4bf2 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 09:41:23 +0200 Subject: [PATCH 07/31] Docs for preplay and assetInfo error events --- .../uplynk/internal/events/UplynkEvent.kt | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt index 9de53dca..f45dcf06 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt @@ -9,20 +9,70 @@ import com.theoplayer.android.connector.uplynk.network.PreplayResponse */ interface UplynkEvent> : Event -interface UplynkPreplayResponseEvent: UplynkEvent { +/** + * Represents a response event for a Uplynk preplay request. + * This event carries the response payload from the preplay request. + */ +interface UplynkPreplayResponseEvent : UplynkEvent { + /** + * Retrieves the preplay response. + * + * @return the response from the preplay request + */ fun getResponse(): PreplayResponse } -interface UplynkPreplayErrorResponseEvent: UplynkEvent { +/** + * Represents an error response event for a Uplynk preplay request. + * This event captures any exception that occurred and the response body. + */ +interface UplynkPreplayErrorResponseEvent : UplynkEvent { + /** + * Retrieves the exception that occurred during the preplay request + * or during parsing the response from preplay request. + * + * @return the exception + */ fun getException(): Exception? + + /** + * Retrieves the response body from the preplay request. + * + * @return the response body as a string + */ fun getBody(): String } -interface UplynkAssetInfoResponseEvent: UplynkEvent { +/** + * Represents a response event for a Uplynk asset information request. + * This event carries the response payload from the asset information request. + */ +interface UplynkAssetInfoResponseEvent : UplynkEvent { + /** + * Retrieves the asset information response. + * + * @return the response from the asset information request + */ fun getResponse(): AssetInfoResponse } -interface UplynkAssetInfoResponseErrorEvent: UplynkEvent { +/** + * Represents an error response event for a Uplynk asset information request. + * This event captures any exception that occurred and the raw response body. + */ +interface UplynkAssetInfoResponseErrorEvent : UplynkEvent { + /** + * Retrieves the exception that occurred during the asset info request + * or during parsing the asset info request + * + * @return the exception + */ fun getException(): Exception? + + /** + * Retrieves the response body from the asset information request. + * + * @return the response body as a string + */ fun getBody(): String -} \ No newline at end of file +} From 805a2175f27cde89004c6edec7aba9b5e84fe348 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 11:21:11 +0200 Subject: [PATCH 08/31] Rename UplynkEventDispatcher --- .../theoplayer/android/connector/uplynk/UplynkConnector.kt | 2 +- ...{UplynkEventDispatcherImpl.kt => UplynkEventDispatcher.kt} | 2 +- .../android/connector/uplynk/internal/UplynkAdIntegration.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/{UplynkEventDispatcherImpl.kt => UplynkEventDispatcher.kt} (93%) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt index 2f059dc4..6ccf1e97 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt @@ -21,7 +21,7 @@ class UplynkConnector( private val theoplayerView: THEOplayerView, ) { private lateinit var integration: UplynkAdIntegration - val eventDispatcher = UplynkEventDispatcherImpl() + val eventDispatcher = UplynkEventDispatcher() init { theoplayerView.player.ads.registerServerSideIntegration(INTEGRATION_ID, this::setupIntegration) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcherImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt similarity index 93% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcherImpl.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt index 93e21f8c..2c56e36e 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcherImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt @@ -8,7 +8,7 @@ import com.theoplayer.android.api.event.EventType import com.theoplayer.android.connector.uplynk.internal.events.UplynkEvent -class UplynkEventDispatcherImpl : EventDispatcher> { +class UplynkEventDispatcher : EventDispatcher> { private val eventMap: HashMap, ArrayList>>> = HashMap() private val handler = Handler(Looper.getMainLooper()) override fun > addEventListener( diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 44411ef1..b1e59ca9 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -7,7 +7,7 @@ import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.ads.ServerSideAdIntegrationHandler import com.theoplayer.android.api.player.Player import com.theoplayer.android.api.source.SourceDescription -import com.theoplayer.android.connector.uplynk.UplynkEventDispatcherImpl +import com.theoplayer.android.connector.uplynk.UplynkEventDispatcher import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoErrorResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl @@ -22,7 +22,7 @@ import java.util.Date internal class UplynkAdIntegration( val theoplayerView: THEOplayerView, val controller: ServerSideAdIntegrationController, - val eventDispatcher: UplynkEventDispatcherImpl, + val eventDispatcher: UplynkEventDispatcher, val uplynkDescriptionConverter: UplynkSsaiDescriptionConverter ) : ServerSideAdIntegrationHandler { From 7ff53ada0fa1880da806d7d386e372cf8150555c Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 11:23:59 +0200 Subject: [PATCH 09/31] Move internal classes to internal package --- .../{ => internal}/network/AssetInfoInternalResponse.kt | 4 +++- .../uplynk/{ => internal}/network/HttpsConnection.kt | 2 +- .../uplynk/{ => internal}/network/PreplayInternalResponse.kt | 3 ++- .../theoplayer/android/connector/uplynk/network/UplynkApi.kt | 4 +++- 4 files changed, 9 insertions(+), 4 deletions(-) rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/{ => internal}/network/AssetInfoInternalResponse.kt (79%) rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/{ => internal}/network/HttpsConnection.kt (95%) rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/{ => internal}/network/PreplayInternalResponse.kt (86%) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoInternalResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/AssetInfoInternalResponse.kt similarity index 79% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoInternalResponse.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/AssetInfoInternalResponse.kt index 80cc6737..d5744731 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/AssetInfoInternalResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/AssetInfoInternalResponse.kt @@ -1,5 +1,6 @@ -package com.theoplayer.android.connector.uplynk.network +package com.theoplayer.android.connector.uplynk.internal.network +import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json @@ -7,6 +8,7 @@ private val json = Json { ignoreUnknownKeys = true } + internal class AssetInfoInternalResponse(val body: String) { var error: Exception? = null val externalResponse: AssetInfoResponse? by lazy { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/HttpsConnection.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt similarity index 95% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/HttpsConnection.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt index 34163e92..c8ac99bb 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/HttpsConnection.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt @@ -1,4 +1,4 @@ -package com.theoplayer.android.connector.uplynk.network +package com.theoplayer.android.connector.uplynk.internal.network import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayInternalResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt similarity index 86% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayInternalResponse.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt index 39b79779..35a3df33 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/PreplayInternalResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt @@ -1,5 +1,6 @@ -package com.theoplayer.android.connector.uplynk.network +package com.theoplayer.android.connector.uplynk.internal.network +import com.theoplayer.android.connector.uplynk.network.PreplayResponse import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt index 42504bee..dd30b004 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt @@ -1,6 +1,8 @@ package com.theoplayer.android.connector.uplynk.network -import kotlinx.serialization.json.Json +import com.theoplayer.android.connector.uplynk.internal.network.AssetInfoInternalResponse +import com.theoplayer.android.connector.uplynk.internal.network.HttpsConnection +import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse internal class UplynkApi { private val network = HttpsConnection() From 0e2766ecc5eb4fb9b7f542dc8565ea03168ff804 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 11:25:56 +0200 Subject: [PATCH 10/31] Move user available events to events package --- .../com/theoplayer/android/connector/MainActivity.kt | 2 +- .../android/connector/uplynk/UplynkEventDispatcher.kt | 2 +- .../uplynk/{internal => }/events/UplynkEvent.kt | 2 +- .../connector/uplynk/events/UplynkEventTypes.kt | 11 +++++++++++ .../events/UplynkAssetInfoErrorResponseEventImpl.kt | 4 +++- .../events/UplynkAssetInfoResponseEventImpl.kt | 4 +++- .../uplynk/internal/events/UplynkEventImpl.kt | 3 ++- .../uplynk/internal/events/UplynkEventTypeImpl.kt | 3 ++- .../uplynk/internal/events/UplynkEventTypes.kt | 8 -------- .../events/UplynkPreplayErrorResponseEventImpl.kt | 4 +++- .../internal/events/UplynkPreplayResponseEventImpl.kt | 4 +++- 11 files changed, 30 insertions(+), 17 deletions(-) rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/{internal => }/events/UplynkEvent.kt (97%) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt diff --git a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt index 3e2fa420..4cb2a942 100644 --- a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt +++ b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt @@ -23,7 +23,7 @@ import com.theoplayer.android.connector.analytics.conviva.ConvivaConfiguration import com.theoplayer.android.connector.analytics.conviva.ConvivaConnector import com.theoplayer.android.connector.analytics.nielsen.NielsenConnector import com.theoplayer.android.connector.uplynk.UplynkConnector -import com.theoplayer.android.connector.uplynk.internal.events.UplynkEventTypes +import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes import com.theoplayer.android.connector.yospace.YospaceConnector const val TAG = "MainActivity" diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt index 2c56e36e..484f3c8b 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt @@ -5,7 +5,7 @@ import android.os.Looper import com.theoplayer.android.api.event.EventDispatcher import com.theoplayer.android.api.event.EventListener import com.theoplayer.android.api.event.EventType -import com.theoplayer.android.connector.uplynk.internal.events.UplynkEvent +import com.theoplayer.android.connector.uplynk.events.UplynkEvent class UplynkEventDispatcher : EventDispatcher> { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt similarity index 97% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt index f45dcf06..0a978790 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEvent.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt @@ -1,4 +1,4 @@ -package com.theoplayer.android.connector.uplynk.internal.events +package com.theoplayer.android.connector.uplynk.events import com.theoplayer.android.api.event.Event import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt new file mode 100644 index 00000000..939279b9 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt @@ -0,0 +1,11 @@ +package com.theoplayer.android.connector.uplynk.events + +import com.theoplayer.android.api.event.EventType +import com.theoplayer.android.connector.uplynk.internal.events.UplynkEventTypeImpl + +object UplynkEventTypes { + val PREPLAY_RESPONSE: EventType = UplynkEventTypeImpl("PREPLAY_RESPONSE") + val PREPLAY_RESPONSE_ERROR: EventType = UplynkEventTypeImpl("PREPLAY_RESPONSE_ERROR") + val ASSET_INFO_RESPONSE: EventType = UplynkEventTypeImpl("ASSET_INFO_RESPONSE") + val ASSET_INFO_RESPONSE_ERROR: EventType = UplynkEventTypeImpl("ASSET_INFO_RESPONSE_ERROR") +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt index 654c2eca..a2d7c924 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt @@ -1,8 +1,10 @@ package com.theoplayer.android.connector.uplynk.internal.events +import com.theoplayer.android.connector.uplynk.events.UplynkAssetInfoResponseErrorEvent +import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes import java.util.Date -class UplynkAssetInfoErrorResponseEventImpl( +internal class UplynkAssetInfoErrorResponseEventImpl( date: Date, private val body: String, private val exception: Exception? diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt index 7470244a..d52ba37a 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt @@ -1,9 +1,11 @@ package com.theoplayer.android.connector.uplynk.internal.events +import com.theoplayer.android.connector.uplynk.events.UplynkAssetInfoResponseEvent +import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import java.util.Date -class UplynkAssetInfoResponseEventImpl( +internal class UplynkAssetInfoResponseEventImpl( date: Date, private val response: AssetInfoResponse ) : diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt index 1eac7ba3..db946363 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt @@ -1,9 +1,10 @@ package com.theoplayer.android.connector.uplynk.internal.events import com.theoplayer.android.api.event.EventType +import com.theoplayer.android.connector.uplynk.events.UplynkEvent import java.util.Date -abstract class UplynkEventImpl> internal constructor( +internal abstract class UplynkEventImpl> internal constructor( private val type: EventType, private val date: Date ) : UplynkEvent { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt index 0d0691e0..42bd8baa 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt @@ -1,8 +1,9 @@ package com.theoplayer.android.connector.uplynk.internal.events import com.theoplayer.android.api.event.EventType +import com.theoplayer.android.connector.uplynk.events.UplynkEvent -class UplynkEventTypeImpl>(private val name: String) : EventType { +internal class UplynkEventTypeImpl>(private val name: String) : EventType { override fun getName() = this.name override fun toString(): String { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt deleted file mode 100644 index 3bd48e2a..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypes.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.events - -object UplynkEventTypes { - val PREPLAY_RESPONSE = UplynkEventTypeImpl("PREPLAY_RESPONSE") - val PREPLAY_RESPONSE_ERROR = UplynkEventTypeImpl("PREPLAY_RESPONSE_ERROR") - val ASSET_INFO_RESPONSE = UplynkEventTypeImpl("ASSET_INFO_RESPONSE") - val ASSET_INFO_RESPONSE_ERROR = UplynkEventTypeImpl("ASSET_INFO_RESPONSE_ERROR") -} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt index a06a1ba5..73887aa8 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt @@ -1,8 +1,10 @@ package com.theoplayer.android.connector.uplynk.internal.events +import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes +import com.theoplayer.android.connector.uplynk.events.UplynkPreplayErrorResponseEvent import java.util.Date -class UplynkPreplayErrorResponseEventImpl( +internal class UplynkPreplayErrorResponseEventImpl( date: Date, private val body: String, private val exception: Exception? diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt index cc990495..4a5f4324 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt @@ -1,9 +1,11 @@ package com.theoplayer.android.connector.uplynk.internal.events +import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes +import com.theoplayer.android.connector.uplynk.events.UplynkPreplayResponseEvent import com.theoplayer.android.connector.uplynk.network.PreplayResponse import java.util.Date -class UplynkPreplayResponseEventImpl( +internal class UplynkPreplayResponseEventImpl( date: Date, private val response: PreplayResponse ) : From 2adbcd42534278b87fdda4f7bbc75cae1391b822 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 11:45:41 +0200 Subject: [PATCH 11/31] Move dispatching events in separate methods --- .../uplynk/internal/UplynkAdIntegration.kt | 82 ++++++++++++------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index b1e59ca9..8ab975a1 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -13,6 +13,8 @@ import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoEr import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayErrorResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl +import com.theoplayer.android.connector.uplynk.internal.network.AssetInfoInternalResponse +import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse import com.theoplayer.android.connector.uplynk.network.UplynkApi import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -31,17 +33,14 @@ internal class UplynkAdIntegration( private val uplynkApi = UplynkApi() private val mainThreadHandler = Handler(Looper.getMainLooper()) - private val ioScope = CoroutineScope(Dispatchers.IO) override suspend fun setSource(source: SourceDescription): SourceDescription { val uplynkSource = source.sources.find { it.ssai is UplynkSsaiDescription } ?: return source val ssaiDescription = uplynkSource.ssai as? UplynkSsaiDescription ?: return source - val response = uplynkApi.preplay(uplynkDescriptionConverter.buildPreplayUrl(ssaiDescription)) - if (response.externalResponse != null) { - eventDispatcher.dispatchEvent(UplynkPreplayResponseEventImpl(Date(), response.externalResponse!!)) - } else { - eventDispatcher.dispatchEvent(UplynkPreplayErrorResponseEventImpl(Date(), response.body, response.error)) - } + val response = uplynkDescriptionConverter + .buildPreplayUrl(ssaiDescription) + .let { uplynkApi.preplay(it) } + .also { dispatchPreplayEvents(it) } val newSource = source.replaceSources(source.sources.toMutableList().apply { @@ -51,32 +50,53 @@ internal class UplynkAdIntegration( if (ssaiDescription.assetInfo) { uplynkDescriptionConverter .buildAssetInfoUrls(ssaiDescription, response.internalResponse.sid) - .map { url -> - ioScope.async { - val assetInfo = uplynkApi.assetInfo(url) - mainThreadHandler.post { - if (assetInfo.externalResponse != null) { - eventDispatcher.dispatchEvent( - UplynkAssetInfoResponseEventImpl( - Date(), - assetInfo.externalResponse!! - ) - ) - } else { - eventDispatcher.dispatchEvent( - UplynkAssetInfoErrorResponseEventImpl( - Date(), - assetInfo.body, - assetInfo.error - ) - ) - } - - } - } - } + .map { uplynkApi.assetInfo(it) } + .forEach { dispatchAssetInfoEvents(it) } } return newSource } + + private fun dispatchPreplayEvents(response: PreplayInternalResponse) { + if (response.externalResponse != null) { + eventDispatcher.dispatchEvent( + UplynkPreplayResponseEventImpl( + Date(), + response.externalResponse!! + ) + ) + } else { + eventDispatcher.dispatchEvent( + UplynkPreplayErrorResponseEventImpl( + Date(), + response.body, + response.error + ) + ) + } + } + + private fun dispatchAssetInfoEvents(assetInfo: AssetInfoInternalResponse) = + CoroutineScope(Dispatchers.IO).async { + mainThreadHandler.post { + if (assetInfo.externalResponse != null) { + eventDispatcher.dispatchEvent( + UplynkAssetInfoResponseEventImpl( + Date(), + assetInfo.externalResponse!! + ) + ) + } else { + eventDispatcher.dispatchEvent( + UplynkAssetInfoErrorResponseEventImpl( + Date(), + assetInfo.body, + assetInfo.error + ) + ) + } + + } + } + } From d39573b97e47e922ecdb61545b6dc84208dbf572 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 12:01:33 +0200 Subject: [PATCH 12/31] Make sure that there is a single Uplynk source. Uplynk connector could only work with a single source at a moment so we'll fail fast rather than ignore other Uplynk sources. --- .../connector/uplynk/internal/UplynkAdIntegration.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 8ab975a1..8cca7857 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -35,8 +35,10 @@ internal class UplynkAdIntegration( private val mainThreadHandler = Handler(Looper.getMainLooper()) override suspend fun setSource(source: SourceDescription): SourceDescription { - val uplynkSource = source.sources.find { it.ssai is UplynkSsaiDescription } ?: return source - val ssaiDescription = uplynkSource.ssai as? UplynkSsaiDescription ?: return source + + val uplynkSource = source.sources.singleOrNull { it.ssai is UplynkSsaiDescription } + val ssaiDescription = uplynkSource?.ssai as? UplynkSsaiDescription ?: return source + val response = uplynkDescriptionConverter .buildPreplayUrl(ssaiDescription) .let { uplynkApi.preplay(it) } From 939e024627969128545bc499e4a28bb199e87240 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 12:22:31 +0200 Subject: [PATCH 13/31] Move HttpsConnection and EventDispatcher to common package --- .../connector/uplynk/UplynkConnector.kt | 1 + .../uplynk/common/HttpsConnection.kt | 44 +++++++++++++++++++ .../{ => common}/UplynkEventDispatcher.kt | 2 +- .../uplynk/internal/UplynkAdIntegration.kt | 2 +- .../internal/network/HttpsConnection.kt | 39 ---------------- .../connector/uplynk/network/UplynkApi.kt | 2 +- 6 files changed, 48 insertions(+), 42 deletions(-) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/{ => common}/UplynkEventDispatcher.kt (95%) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt index 6ccf1e97..91dc5439 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt @@ -6,6 +6,7 @@ import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.source.ssai.CustomSsaiDescriptionRegistry import com.theoplayer.android.connector.uplynk.internal.UplynkAdIntegration import com.theoplayer.android.connector.uplynk.internal.UplynkSsaiDescriptionConverter +import com.theoplayer.android.connector.uplynk.common.UplynkEventDispatcher internal const val TAG = "UplynkConnector" diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt new file mode 100644 index 00000000..0d203aa3 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt @@ -0,0 +1,44 @@ +package com.theoplayer.android.connector.uplynk.common + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runInterruptible +import java.net.URL +import javax.net.ssl.HttpsURLConnection + +internal const val CONNECT_TIMEOUT_IN_MS = 30000 +internal const val READ_TIMEOUT_IN_MS = 30000 + +internal class HttpsConnection { + suspend fun get(urlString: String): String = runInterruptible(context = Dispatchers.IO) { + var result: String + var connection: HttpsURLConnection? = null + try { + connection = (URL(urlString).openConnection() as HttpsURLConnection) + .apply { + requestMethod = "GET" + connectTimeout = CONNECT_TIMEOUT_IN_MS + readTimeout = READ_TIMEOUT_IN_MS + doInput = true + } + + connection.connect() + + val responseCode: Int = connection.getResponseCode() + result = when (responseCode) { + HttpsURLConnection.HTTP_OK -> + connection + .inputStream + .bufferedReader() + .use { it.readText() } + + else -> "Error: $responseCode" + } + } catch (e: Exception) { + result = e.message ?: "" + } finally { + connection?.disconnect() + } + + result + } +} diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/UplynkEventDispatcher.kt similarity index 95% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/UplynkEventDispatcher.kt index 484f3c8b..9d058746 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/UplynkEventDispatcher.kt @@ -1,4 +1,4 @@ -package com.theoplayer.android.connector.uplynk +package com.theoplayer.android.connector.uplynk.common import android.os.Handler import android.os.Looper diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 8cca7857..33bd3119 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -7,7 +7,7 @@ import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.ads.ServerSideAdIntegrationHandler import com.theoplayer.android.api.player.Player import com.theoplayer.android.api.source.SourceDescription -import com.theoplayer.android.connector.uplynk.UplynkEventDispatcher +import com.theoplayer.android.connector.uplynk.common.UplynkEventDispatcher import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoErrorResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt index c8ac99bb..e69de29b 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt @@ -1,39 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.network - -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runInterruptible -import java.io.IOException -import java.net.URL -import javax.net.ssl.HttpsURLConnection - -internal const val CONNECT_TIMEOUT_IN_MS = 30000 -internal const val READ_TIMEOUT_IN_MS = 30000 - -internal class HttpsConnection { - suspend fun get(urlString: String): String = runInterruptible(context = Dispatchers.IO) { - var connection: HttpsURLConnection? = null - try { - connection = (URL(urlString).openConnection() as HttpsURLConnection) - .apply { - requestMethod = "GET" - connectTimeout = CONNECT_TIMEOUT_IN_MS - readTimeout = READ_TIMEOUT_IN_MS - doInput = true - } - - connection.connect() - - when (val responseCode: Int = connection.responseCode) { - HttpsURLConnection.HTTP_OK -> - return@runInterruptible connection - .inputStream - .bufferedReader() - .use { it.readText() } - - else -> throw IOException("HTTP response $responseCode for URL: $urlString") - } - } finally { - connection?.disconnect() - } - } -} diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt index dd30b004..4d1567a4 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt @@ -1,7 +1,7 @@ package com.theoplayer.android.connector.uplynk.network import com.theoplayer.android.connector.uplynk.internal.network.AssetInfoInternalResponse -import com.theoplayer.android.connector.uplynk.internal.network.HttpsConnection +import com.theoplayer.android.connector.uplynk.common.HttpsConnection import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse internal class UplynkApi { From ec686f5b1dafeb35dfcd5d2b8c2f00fe6af05428 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 12:23:19 +0200 Subject: [PATCH 14/31] Rename EventDispatcherImpl --- .../theoplayer/android/connector/uplynk/UplynkConnector.kt | 4 ++-- .../{UplynkEventDispatcher.kt => EventDispatcherImpl.kt} | 2 +- .../android/connector/uplynk/internal/UplynkAdIntegration.kt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/{UplynkEventDispatcher.kt => EventDispatcherImpl.kt} (94%) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt index 91dc5439..72588212 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt @@ -6,7 +6,7 @@ import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.source.ssai.CustomSsaiDescriptionRegistry import com.theoplayer.android.connector.uplynk.internal.UplynkAdIntegration import com.theoplayer.android.connector.uplynk.internal.UplynkSsaiDescriptionConverter -import com.theoplayer.android.connector.uplynk.common.UplynkEventDispatcher +import com.theoplayer.android.connector.uplynk.common.EventDispatcherImpl internal const val TAG = "UplynkConnector" @@ -22,7 +22,7 @@ class UplynkConnector( private val theoplayerView: THEOplayerView, ) { private lateinit var integration: UplynkAdIntegration - val eventDispatcher = UplynkEventDispatcher() + val eventDispatcher = EventDispatcherImpl() init { theoplayerView.player.ads.registerServerSideIntegration(INTEGRATION_ID, this::setupIntegration) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/EventDispatcherImpl.kt similarity index 94% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/UplynkEventDispatcher.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/EventDispatcherImpl.kt index 9d058746..df787c95 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/EventDispatcherImpl.kt @@ -8,7 +8,7 @@ import com.theoplayer.android.api.event.EventType import com.theoplayer.android.connector.uplynk.events.UplynkEvent -class UplynkEventDispatcher : EventDispatcher> { +class EventDispatcherImpl : EventDispatcher> { private val eventMap: HashMap, ArrayList>>> = HashMap() private val handler = Handler(Looper.getMainLooper()) override fun > addEventListener( diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 33bd3119..2c89ab9f 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -7,7 +7,7 @@ import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.ads.ServerSideAdIntegrationHandler import com.theoplayer.android.api.player.Player import com.theoplayer.android.api.source.SourceDescription -import com.theoplayer.android.connector.uplynk.common.UplynkEventDispatcher +import com.theoplayer.android.connector.uplynk.common.EventDispatcherImpl import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoErrorResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl @@ -24,7 +24,7 @@ import java.util.Date internal class UplynkAdIntegration( val theoplayerView: THEOplayerView, val controller: ServerSideAdIntegrationController, - val eventDispatcher: UplynkEventDispatcher, + val eventDispatcher: EventDispatcherImpl, val uplynkDescriptionConverter: UplynkSsaiDescriptionConverter ) : ServerSideAdIntegrationHandler { From 1fab01ae752bec29e21ca637bf31536511ec72af Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 12:27:09 +0200 Subject: [PATCH 15/31] Remove unnecessary post to main thread --- .../uplynk/internal/UplynkAdIntegration.kt | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 2c89ab9f..be8ed7fb 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -32,7 +32,6 @@ internal class UplynkAdIntegration( get() = theoplayerView.player private val uplynkApi = UplynkApi() - private val mainThreadHandler = Handler(Looper.getMainLooper()) override suspend fun setSource(source: SourceDescription): SourceDescription { @@ -80,24 +79,21 @@ internal class UplynkAdIntegration( private fun dispatchAssetInfoEvents(assetInfo: AssetInfoInternalResponse) = CoroutineScope(Dispatchers.IO).async { - mainThreadHandler.post { - if (assetInfo.externalResponse != null) { - eventDispatcher.dispatchEvent( - UplynkAssetInfoResponseEventImpl( - Date(), - assetInfo.externalResponse!! - ) + if (assetInfo.externalResponse != null) { + eventDispatcher.dispatchEvent( + UplynkAssetInfoResponseEventImpl( + Date(), + assetInfo.externalResponse!! ) - } else { - eventDispatcher.dispatchEvent( - UplynkAssetInfoErrorResponseEventImpl( - Date(), - assetInfo.body, - assetInfo.error - ) + ) + } else { + eventDispatcher.dispatchEvent( + UplynkAssetInfoErrorResponseEventImpl( + Date(), + assetInfo.body, + assetInfo.error ) - } - + ) } } From e66e3db0463219792d203818f08bf0e18ec3a7f9 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 12 Aug 2024 12:39:59 +0200 Subject: [PATCH 16/31] Extract UplynkEventDispatcher --- .../connector/uplynk/UplynkConnector.kt | 7 +- .../uplynk/internal/UplynkAdIntegration.kt | 64 ++----------------- .../uplynk/internal/UplynkEventDispatcher.kt | 55 ++++++++++++++++ 3 files changed, 65 insertions(+), 61 deletions(-) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt index 72588212..f853b42d 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt @@ -7,6 +7,8 @@ import com.theoplayer.android.api.source.ssai.CustomSsaiDescriptionRegistry import com.theoplayer.android.connector.uplynk.internal.UplynkAdIntegration import com.theoplayer.android.connector.uplynk.internal.UplynkSsaiDescriptionConverter import com.theoplayer.android.connector.uplynk.common.EventDispatcherImpl +import com.theoplayer.android.connector.uplynk.internal.UplynkEventDispatcher +import com.theoplayer.android.connector.uplynk.network.UplynkApi internal const val TAG = "UplynkConnector" @@ -32,8 +34,9 @@ class UplynkConnector( val integration = UplynkAdIntegration( theoplayerView, controller, - eventDispatcher, - UplynkSsaiDescriptionConverter() + UplynkEventDispatcher(eventDispatcher), + UplynkSsaiDescriptionConverter(), + UplynkApi() ) this.integration = integration return integration diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index be8ed7fb..3c7b948f 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -1,38 +1,24 @@ package com.theoplayer.android.connector.uplynk.internal -import android.os.Handler -import android.os.Looper import com.theoplayer.android.api.THEOplayerView import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.ads.ServerSideAdIntegrationHandler import com.theoplayer.android.api.player.Player import com.theoplayer.android.api.source.SourceDescription -import com.theoplayer.android.connector.uplynk.common.EventDispatcherImpl import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription -import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoErrorResponseEventImpl -import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl -import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayErrorResponseEventImpl -import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl -import com.theoplayer.android.connector.uplynk.internal.network.AssetInfoInternalResponse -import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse import com.theoplayer.android.connector.uplynk.network.UplynkApi -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import java.util.Date internal class UplynkAdIntegration( val theoplayerView: THEOplayerView, val controller: ServerSideAdIntegrationController, - val eventDispatcher: EventDispatcherImpl, - val uplynkDescriptionConverter: UplynkSsaiDescriptionConverter + val eventDispatcher: UplynkEventDispatcher, + val uplynkDescriptionConverter: UplynkSsaiDescriptionConverter, + private val uplynkApi: UplynkApi ) : ServerSideAdIntegrationHandler { private val player: Player get() = theoplayerView.player - private val uplynkApi = UplynkApi() - override suspend fun setSource(source: SourceDescription): SourceDescription { val uplynkSource = source.sources.singleOrNull { it.ssai is UplynkSsaiDescription } @@ -41,7 +27,7 @@ internal class UplynkAdIntegration( val response = uplynkDescriptionConverter .buildPreplayUrl(ssaiDescription) .let { uplynkApi.preplay(it) } - .also { dispatchPreplayEvents(it) } + .also { eventDispatcher.dispatchPreplayEvents(it) } val newSource = source.replaceSources(source.sources.toMutableList().apply { @@ -52,49 +38,9 @@ internal class UplynkAdIntegration( uplynkDescriptionConverter .buildAssetInfoUrls(ssaiDescription, response.internalResponse.sid) .map { uplynkApi.assetInfo(it) } - .forEach { dispatchAssetInfoEvents(it) } + .forEach { eventDispatcher.dispatchAssetInfoEvents(it) } } return newSource } - - private fun dispatchPreplayEvents(response: PreplayInternalResponse) { - if (response.externalResponse != null) { - eventDispatcher.dispatchEvent( - UplynkPreplayResponseEventImpl( - Date(), - response.externalResponse!! - ) - ) - } else { - eventDispatcher.dispatchEvent( - UplynkPreplayErrorResponseEventImpl( - Date(), - response.body, - response.error - ) - ) - } - } - - private fun dispatchAssetInfoEvents(assetInfo: AssetInfoInternalResponse) = - CoroutineScope(Dispatchers.IO).async { - if (assetInfo.externalResponse != null) { - eventDispatcher.dispatchEvent( - UplynkAssetInfoResponseEventImpl( - Date(), - assetInfo.externalResponse!! - ) - ) - } else { - eventDispatcher.dispatchEvent( - UplynkAssetInfoErrorResponseEventImpl( - Date(), - assetInfo.body, - assetInfo.error - ) - ) - } - } - } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt new file mode 100644 index 00000000..bd3e26b5 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt @@ -0,0 +1,55 @@ +package com.theoplayer.android.connector.uplynk.internal + +import com.theoplayer.android.connector.uplynk.common.EventDispatcherImpl +import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoErrorResponseEventImpl +import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl +import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayErrorResponseEventImpl +import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl +import com.theoplayer.android.connector.uplynk.internal.network.AssetInfoInternalResponse +import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import java.util.Date + +internal class UplynkEventDispatcher(val eventDispatcher: EventDispatcherImpl) { + + fun dispatchPreplayEvents(response: PreplayInternalResponse) { + if (response.externalResponse != null) { + eventDispatcher.dispatchEvent( + UplynkPreplayResponseEventImpl( + Date(), + response.externalResponse!! + ) + ) + } else { + eventDispatcher.dispatchEvent( + UplynkPreplayErrorResponseEventImpl( + Date(), + response.body, + response.error + ) + ) + } + } + + fun dispatchAssetInfoEvents(assetInfo: AssetInfoInternalResponse) = + CoroutineScope(Dispatchers.IO).async { + if (assetInfo.externalResponse != null) { + eventDispatcher.dispatchEvent( + UplynkAssetInfoResponseEventImpl( + Date(), + assetInfo.externalResponse!! + ) + ) + } else { + eventDispatcher.dispatchEvent( + UplynkAssetInfoErrorResponseEventImpl( + Date(), + assetInfo.body, + assetInfo.error + ) + ) + } + } +} From bab43c368ad2772a476b1b5f429bac89631ddde1 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Tue, 13 Aug 2024 16:29:42 +0200 Subject: [PATCH 17/31] Make non fatal exceptions in Uplink flow send Ad Error events rather than Player Error. --- .../android/connector/MainActivity.kt | 8 ++++ .../uplynk/internal/UplynkAdIntegration.kt | 22 +++++++-- .../uplynk/internal/UplynkEventDispatcher.kt | 47 +++++-------------- .../network/AssetInfoInternalResponse.kt | 25 ---------- .../network/PreplayInternalResponse.kt | 16 +------ .../connector/uplynk/network/UplynkApi.kt | 10 ++-- 6 files changed, 48 insertions(+), 80 deletions(-) delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/AssetInfoInternalResponse.kt diff --git a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt index 4cb2a942..3a238f2f 100644 --- a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt +++ b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt @@ -15,6 +15,7 @@ import com.theoplayer.android.api.ads.ima.GoogleImaIntegrationFactory import com.theoplayer.android.api.event.ads.AdBreakEvent import com.theoplayer.android.api.event.ads.AdsEventTypes import com.theoplayer.android.api.event.ads.SingleAdEvent +import com.theoplayer.android.api.event.player.PlayerEventTypes import com.theoplayer.android.connector.analytics.comscore.ComscoreConfiguration import com.theoplayer.android.connector.analytics.comscore.ComscoreConnector import com.theoplayer.android.connector.analytics.comscore.ComscoreMediaType @@ -164,6 +165,13 @@ class MainActivity : AppCompatActivity() { uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.ASSET_INFO_RESPONSE_ERROR) { Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE_ERROR ${it.getBody()} - ${it.getException()}") } + theoplayerView.player.ads.addEventListener(AdsEventTypes.AD_ERROR) { + Log.d("UplynkConnectorEvents", "AD_ERROR " + it.error) + } + + theoplayerView.player.addEventListener(PlayerEventTypes.ERROR) { + Log.d("UplynkConnectorEvents", "ERROR " + it.errorObject) + } } private fun setupListeners() { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 3c7b948f..b3bb218c 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -27,17 +27,31 @@ internal class UplynkAdIntegration( val response = uplynkDescriptionConverter .buildPreplayUrl(ssaiDescription) .let { uplynkApi.preplay(it) } - .also { eventDispatcher.dispatchPreplayEvents(it) } + .also { + try { + eventDispatcher.dispatchPreplayEvents(it) + } catch (e: Exception) { + controller.error(e) + } + } + val internalResponse = response.parseMinimalResponse() val newSource = source.replaceSources(source.sources.toMutableList().apply { remove(uplynkSource) - add(0, uplynkSource.replaceSrc(response.internalResponse.playURL)) + add(0, uplynkSource.replaceSrc(internalResponse.playURL)) }) if (ssaiDescription.assetInfo) { uplynkDescriptionConverter - .buildAssetInfoUrls(ssaiDescription, response.internalResponse.sid) - .map { uplynkApi.assetInfo(it) } + .buildAssetInfoUrls(ssaiDescription, internalResponse.sid) + .mapNotNull { + try { + uplynkApi.assetInfo(it) + } catch (e: Exception) { + controller.error(e) + null + } + } .forEach { eventDispatcher.dispatchAssetInfoEvents(it) } } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt index bd3e26b5..7bffa6f1 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt @@ -1,12 +1,10 @@ package com.theoplayer.android.connector.uplynk.internal import com.theoplayer.android.connector.uplynk.common.EventDispatcherImpl -import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoErrorResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl -import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayErrorResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl -import com.theoplayer.android.connector.uplynk.internal.network.AssetInfoInternalResponse import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse +import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async @@ -15,41 +13,22 @@ import java.util.Date internal class UplynkEventDispatcher(val eventDispatcher: EventDispatcherImpl) { fun dispatchPreplayEvents(response: PreplayInternalResponse) { - if (response.externalResponse != null) { - eventDispatcher.dispatchEvent( - UplynkPreplayResponseEventImpl( - Date(), - response.externalResponse!! - ) - ) - } else { - eventDispatcher.dispatchEvent( - UplynkPreplayErrorResponseEventImpl( - Date(), - response.body, - response.error - ) + val preplayResponse = response.parseExternalResponse() + eventDispatcher.dispatchEvent( + UplynkPreplayResponseEventImpl( + Date(), + preplayResponse ) - } + ) } - fun dispatchAssetInfoEvents(assetInfo: AssetInfoInternalResponse) = + fun dispatchAssetInfoEvents(assetInfo: AssetInfoResponse) = CoroutineScope(Dispatchers.IO).async { - if (assetInfo.externalResponse != null) { - eventDispatcher.dispatchEvent( - UplynkAssetInfoResponseEventImpl( - Date(), - assetInfo.externalResponse!! - ) - ) - } else { - eventDispatcher.dispatchEvent( - UplynkAssetInfoErrorResponseEventImpl( - Date(), - assetInfo.body, - assetInfo.error - ) + eventDispatcher.dispatchEvent( + UplynkAssetInfoResponseEventImpl( + Date(), + assetInfo ) - } + ) } } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/AssetInfoInternalResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/AssetInfoInternalResponse.kt deleted file mode 100644 index d5744731..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/AssetInfoInternalResponse.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.network - -import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse -import kotlinx.serialization.SerializationException -import kotlinx.serialization.json.Json - -private val json = Json { - ignoreUnknownKeys = true -} - - -internal class AssetInfoInternalResponse(val body: String) { - var error: Exception? = null - val externalResponse: AssetInfoResponse? by lazy { - try { - json.decodeFromString(body) - } catch (se: SerializationException) { - error = se - null - } catch (ie: IllegalArgumentException) { - error = ie - null - } - } -} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt index 35a3df33..eb6a8303 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt @@ -2,7 +2,6 @@ package com.theoplayer.android.connector.uplynk.internal.network import com.theoplayer.android.connector.uplynk.network.PreplayResponse import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json private val json = Json{ @@ -24,17 +23,6 @@ internal data class MinimalPreplayResponse( internal class PreplayInternalResponse(val body: String) { - val internalResponse: MinimalPreplayResponse = json.decodeFromString(body) - var error: Exception? = null - val externalResponse: PreplayResponse? by lazy { - try { - json.decodeFromString(body) - } catch (se: SerializationException) { - error = se - null - } catch (ie: IllegalArgumentException) { - error = ie - null - } - } + fun parseMinimalResponse(): MinimalPreplayResponse = json.decodeFromString(body) + fun parseExternalResponse(): PreplayResponse = json.decodeFromString(body) } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt index 4d1567a4..9b8670d0 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt @@ -1,8 +1,12 @@ package com.theoplayer.android.connector.uplynk.network -import com.theoplayer.android.connector.uplynk.internal.network.AssetInfoInternalResponse import com.theoplayer.android.connector.uplynk.common.HttpsConnection import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse +import kotlinx.serialization.json.Json + +private val json = Json { + ignoreUnknownKeys = true +} internal class UplynkApi { private val network = HttpsConnection() @@ -12,8 +16,8 @@ internal class UplynkApi { return PreplayInternalResponse(body) } - suspend fun assetInfo(url: String): AssetInfoInternalResponse { + suspend fun assetInfo(url: String): AssetInfoResponse { val body = network.get(url) - return AssetInfoInternalResponse(body) + return json.decodeFromString(body) } } From 925082aa0d670ef4e772d893198e007419d3fbff Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Tue, 13 Aug 2024 16:31:04 +0200 Subject: [PATCH 18/31] Move parseExternalResponse out of event dispatcher --- .../connector/uplynk/internal/UplynkAdIntegration.kt | 2 +- .../connector/uplynk/internal/UplynkEventDispatcher.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index b3bb218c..2d406e0b 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -29,7 +29,7 @@ internal class UplynkAdIntegration( .let { uplynkApi.preplay(it) } .also { try { - eventDispatcher.dispatchPreplayEvents(it) + eventDispatcher.dispatchPreplayEvents(it.parseExternalResponse()) } catch (e: Exception) { controller.error(e) } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt index 7bffa6f1..e9631fb8 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt @@ -5,6 +5,7 @@ import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoRe import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse +import com.theoplayer.android.connector.uplynk.network.PreplayResponse import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async @@ -12,12 +13,11 @@ import java.util.Date internal class UplynkEventDispatcher(val eventDispatcher: EventDispatcherImpl) { - fun dispatchPreplayEvents(response: PreplayInternalResponse) { - val preplayResponse = response.parseExternalResponse() + fun dispatchPreplayEvents(response: PreplayResponse) { eventDispatcher.dispatchEvent( UplynkPreplayResponseEventImpl( Date(), - preplayResponse + response ) ) } From f804cba90659e4d15af55e019e3dcf50e4efe93f Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Tue, 13 Aug 2024 17:22:19 +0200 Subject: [PATCH 19/31] Use val response instead of a getter method. --- .../android/connector/MainActivity.kt | 11 +---- .../connector/uplynk/events/UplynkEvent.kt | 48 ++----------------- .../uplynk/events/UplynkEventTypes.kt | 2 - .../UplynkAssetInfoErrorResponseEventImpl.kt | 20 -------- .../UplynkAssetInfoResponseEventImpl.kt | 6 +-- .../UplynkPreplayErrorResponseEventImpl.kt | 17 ------- .../events/UplynkPreplayResponseEventImpl.kt | 6 +-- 7 files changed, 9 insertions(+), 101 deletions(-) delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt diff --git a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt index 3a238f2f..faf6722a 100644 --- a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt +++ b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt @@ -151,20 +151,13 @@ class MainActivity : AppCompatActivity() { private fun setupUplynk() { uplynkConnector = UplynkConnector(theoplayerView) uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.PREPLAY_RESPONSE) { - Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE ${it.getResponse()} - $it") + Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE ${it.response} - $it") } uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.ASSET_INFO_RESPONSE) { - Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE ${it.getResponse()} - $it") + Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE ${it.response} - $it") } - uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.PREPLAY_RESPONSE_ERROR) { - Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE_ERROR ${it.getBody()} - ${it.getException()}") - } - - uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.ASSET_INFO_RESPONSE_ERROR) { - Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE_ERROR ${it.getBody()} - ${it.getException()}") - } theoplayerView.player.ads.addEventListener(AdsEventTypes.AD_ERROR) { Log.d("UplynkConnectorEvents", "AD_ERROR " + it.error) } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt index 0a978790..30cd75f5 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt @@ -19,28 +19,7 @@ interface UplynkPreplayResponseEvent : UplynkEvent { * * @return the response from the preplay request */ - fun getResponse(): PreplayResponse -} - -/** - * Represents an error response event for a Uplynk preplay request. - * This event captures any exception that occurred and the response body. - */ -interface UplynkPreplayErrorResponseEvent : UplynkEvent { - /** - * Retrieves the exception that occurred during the preplay request - * or during parsing the response from preplay request. - * - * @return the exception - */ - fun getException(): Exception? - - /** - * Retrieves the response body from the preplay request. - * - * @return the response body as a string - */ - fun getBody(): String + val response: PreplayResponse } /** @@ -53,26 +32,5 @@ interface UplynkAssetInfoResponseEvent : UplynkEvent { - /** - * Retrieves the exception that occurred during the asset info request - * or during parsing the asset info request - * - * @return the exception - */ - fun getException(): Exception? - - /** - * Retrieves the response body from the asset information request. - * - * @return the response body as a string - */ - fun getBody(): String -} + val response: AssetInfoResponse +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt index 939279b9..55b6c260 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt @@ -5,7 +5,5 @@ import com.theoplayer.android.connector.uplynk.internal.events.UplynkEventTypeIm object UplynkEventTypes { val PREPLAY_RESPONSE: EventType = UplynkEventTypeImpl("PREPLAY_RESPONSE") - val PREPLAY_RESPONSE_ERROR: EventType = UplynkEventTypeImpl("PREPLAY_RESPONSE_ERROR") val ASSET_INFO_RESPONSE: EventType = UplynkEventTypeImpl("ASSET_INFO_RESPONSE") - val ASSET_INFO_RESPONSE_ERROR: EventType = UplynkEventTypeImpl("ASSET_INFO_RESPONSE_ERROR") } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt deleted file mode 100644 index a2d7c924..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoErrorResponseEventImpl.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.events - -import com.theoplayer.android.connector.uplynk.events.UplynkAssetInfoResponseErrorEvent -import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes -import java.util.Date - -internal class UplynkAssetInfoErrorResponseEventImpl( - date: Date, - private val body: String, - private val exception: Exception? -) : - UplynkEventImpl( - UplynkEventTypes.ASSET_INFO_RESPONSE_ERROR, - date - ), - UplynkAssetInfoResponseErrorEvent { - override fun getException() = exception - - override fun getBody() = body -} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt index d52ba37a..1d9b73c7 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt @@ -7,9 +7,7 @@ import java.util.Date internal class UplynkAssetInfoResponseEventImpl( date: Date, - private val response: AssetInfoResponse + override val response: AssetInfoResponse ) : UplynkEventImpl(UplynkEventTypes.ASSET_INFO_RESPONSE, date), - UplynkAssetInfoResponseEvent { - override fun getResponse(): AssetInfoResponse = response - } \ No newline at end of file + UplynkAssetInfoResponseEvent \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt deleted file mode 100644 index 73887aa8..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayErrorResponseEventImpl.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.events - -import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes -import com.theoplayer.android.connector.uplynk.events.UplynkPreplayErrorResponseEvent -import java.util.Date - -internal class UplynkPreplayErrorResponseEventImpl( - date: Date, - private val body: String, - private val exception: Exception? -) : - UplynkEventImpl(UplynkEventTypes.PREPLAY_RESPONSE_ERROR, date), - UplynkPreplayErrorResponseEvent { - override fun getException() = exception - - override fun getBody() = body -} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt index 4a5f4324..6f48cc06 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt @@ -7,9 +7,7 @@ import java.util.Date internal class UplynkPreplayResponseEventImpl( date: Date, - private val response: PreplayResponse + override val response: PreplayResponse ) : UplynkEventImpl(UplynkEventTypes.PREPLAY_RESPONSE, date), - UplynkPreplayResponseEvent { - override fun getResponse(): PreplayResponse = response - } \ No newline at end of file + UplynkPreplayResponseEvent \ No newline at end of file From 7178e9b9b3f1d37a1f7d3cf9f714151909ae4aa1 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Wed, 14 Aug 2024 08:46:34 +0200 Subject: [PATCH 20/31] Replace uplynk events to UplynkListener --- .../android/connector/MainActivity.kt | 19 +++++---- .../connector/uplynk/UplynkConnector.kt | 9 +++-- .../connector/uplynk/UplynkListener.kt | 10 +++++ .../uplynk/common/EventDispatcherImpl.kt | 31 -------------- .../connector/uplynk/events/UplynkEvent.kt | 36 ----------------- .../uplynk/events/UplynkEventTypes.kt | 9 ----- .../uplynk/internal/UplynkEventDispatcher.kt | 40 +++++++------------ .../UplynkAssetInfoResponseEventImpl.kt | 13 ------ .../uplynk/internal/events/UplynkEventImpl.kt | 22 ---------- .../internal/events/UplynkEventTypeImpl.kt | 12 ------ .../events/UplynkPreplayResponseEventImpl.kt | 13 ------ 11 files changed, 43 insertions(+), 171 deletions(-) create mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/EventDispatcherImpl.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt diff --git a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt index faf6722a..1c2b4518 100644 --- a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt +++ b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt @@ -24,7 +24,9 @@ import com.theoplayer.android.connector.analytics.conviva.ConvivaConfiguration import com.theoplayer.android.connector.analytics.conviva.ConvivaConnector import com.theoplayer.android.connector.analytics.nielsen.NielsenConnector import com.theoplayer.android.connector.uplynk.UplynkConnector -import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes +import com.theoplayer.android.connector.uplynk.UplynkListener +import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse +import com.theoplayer.android.connector.uplynk.network.PreplayResponse import com.theoplayer.android.connector.yospace.YospaceConnector const val TAG = "MainActivity" @@ -150,13 +152,16 @@ class MainActivity : AppCompatActivity() { private fun setupUplynk() { uplynkConnector = UplynkConnector(theoplayerView) - uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.PREPLAY_RESPONSE) { - Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE ${it.response} - $it") - } + uplynkConnector.addListener(object: UplynkListener { + override fun onPreplayResponse(response: PreplayResponse) { + Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE $response") + } - uplynkConnector.eventDispatcher.addEventListener(UplynkEventTypes.ASSET_INFO_RESPONSE) { - Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE ${it.response} - $it") - } + override fun onAssetInfoResponse(response: AssetInfoResponse) { + Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE $response") + } + + }) theoplayerView.player.ads.addEventListener(AdsEventTypes.AD_ERROR) { Log.d("UplynkConnectorEvents", "AD_ERROR " + it.error) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt index f853b42d..3fbd8c42 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt @@ -6,7 +6,6 @@ import com.theoplayer.android.api.ads.ServerSideAdIntegrationController import com.theoplayer.android.api.source.ssai.CustomSsaiDescriptionRegistry import com.theoplayer.android.connector.uplynk.internal.UplynkAdIntegration import com.theoplayer.android.connector.uplynk.internal.UplynkSsaiDescriptionConverter -import com.theoplayer.android.connector.uplynk.common.EventDispatcherImpl import com.theoplayer.android.connector.uplynk.internal.UplynkEventDispatcher import com.theoplayer.android.connector.uplynk.network.UplynkApi @@ -24,7 +23,7 @@ class UplynkConnector( private val theoplayerView: THEOplayerView, ) { private lateinit var integration: UplynkAdIntegration - val eventDispatcher = EventDispatcherImpl() + private val eventDispatcher = UplynkEventDispatcher() init { theoplayerView.player.ads.registerServerSideIntegration(INTEGRATION_ID, this::setupIntegration) @@ -34,7 +33,7 @@ class UplynkConnector( val integration = UplynkAdIntegration( theoplayerView, controller, - UplynkEventDispatcher(eventDispatcher), + eventDispatcher, UplynkSsaiDescriptionConverter(), UplynkApi() ) @@ -42,6 +41,10 @@ class UplynkConnector( return integration } + fun addListener(listener: UplynkListener) = eventDispatcher.addListener(listener) + + fun removeListener(listener: UplynkListener) = eventDispatcher.removeListener(listener) + companion object { /** * The integration identifier for the Uplynk connector. diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt new file mode 100644 index 00000000..6456b307 --- /dev/null +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt @@ -0,0 +1,10 @@ +package com.theoplayer.android.connector.uplynk + +import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse +import com.theoplayer.android.connector.uplynk.network.PreplayResponse + +interface UplynkListener { + fun onPreplayResponse(response: PreplayResponse) + fun onAssetInfoResponse(response: AssetInfoResponse) + +} diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/EventDispatcherImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/EventDispatcherImpl.kt deleted file mode 100644 index df787c95..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/EventDispatcherImpl.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.theoplayer.android.connector.uplynk.common - -import android.os.Handler -import android.os.Looper -import com.theoplayer.android.api.event.EventDispatcher -import com.theoplayer.android.api.event.EventListener -import com.theoplayer.android.api.event.EventType -import com.theoplayer.android.connector.uplynk.events.UplynkEvent - - -class EventDispatcherImpl : EventDispatcher> { - private val eventMap: HashMap, ArrayList>>> = HashMap() - private val handler = Handler(Looper.getMainLooper()) - override fun > addEventListener( - type: EventType, - listener: EventListener - ) { - eventMap.getOrPut(type) { ArrayList(1) }.add(listener as EventListener>) - } - - override fun > removeEventListener( - type: EventType, - listener: EventListener - ) { - eventMap[type]?.remove(listener) - } - - fun dispatchEvent(event: UplynkEvent<*>) = handler.post { - eventMap[event.type]?.forEach { it.handleEvent(event) } - } -} diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt deleted file mode 100644 index 30cd75f5..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEvent.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.theoplayer.android.connector.uplynk.events - -import com.theoplayer.android.api.event.Event -import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse -import com.theoplayer.android.connector.uplynk.network.PreplayResponse - -/** - * The base Uplynk Event. - */ -interface UplynkEvent> : Event - -/** - * Represents a response event for a Uplynk preplay request. - * This event carries the response payload from the preplay request. - */ -interface UplynkPreplayResponseEvent : UplynkEvent { - /** - * Retrieves the preplay response. - * - * @return the response from the preplay request - */ - val response: PreplayResponse -} - -/** - * Represents a response event for a Uplynk asset information request. - * This event carries the response payload from the asset information request. - */ -interface UplynkAssetInfoResponseEvent : UplynkEvent { - /** - * Retrieves the asset information response. - * - * @return the response from the asset information request - */ - val response: AssetInfoResponse -} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt deleted file mode 100644 index 55b6c260..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/events/UplynkEventTypes.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.theoplayer.android.connector.uplynk.events - -import com.theoplayer.android.api.event.EventType -import com.theoplayer.android.connector.uplynk.internal.events.UplynkEventTypeImpl - -object UplynkEventTypes { - val PREPLAY_RESPONSE: EventType = UplynkEventTypeImpl("PREPLAY_RESPONSE") - val ASSET_INFO_RESPONSE: EventType = UplynkEventTypeImpl("ASSET_INFO_RESPONSE") -} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt index e9631fb8..64578c2a 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt @@ -1,34 +1,24 @@ package com.theoplayer.android.connector.uplynk.internal -import com.theoplayer.android.connector.uplynk.common.EventDispatcherImpl -import com.theoplayer.android.connector.uplynk.internal.events.UplynkAssetInfoResponseEventImpl -import com.theoplayer.android.connector.uplynk.internal.events.UplynkPreplayResponseEventImpl -import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse +import android.os.Handler +import android.os.Looper +import com.theoplayer.android.connector.uplynk.UplynkListener import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import com.theoplayer.android.connector.uplynk.network.PreplayResponse -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import java.util.Date +import java.util.concurrent.CopyOnWriteArrayList -internal class UplynkEventDispatcher(val eventDispatcher: EventDispatcherImpl) { +internal class UplynkEventDispatcher(val handler: Handler = Handler(Looper.getMainLooper())) { + private val listeners = CopyOnWriteArrayList() - fun dispatchPreplayEvents(response: PreplayResponse) { - eventDispatcher.dispatchEvent( - UplynkPreplayResponseEventImpl( - Date(), - response - ) - ) + fun dispatchPreplayEvents(response: PreplayResponse) = listeners.forEach { listener -> + handler.post { listener.onPreplayResponse(response) } } - fun dispatchAssetInfoEvents(assetInfo: AssetInfoResponse) = - CoroutineScope(Dispatchers.IO).async { - eventDispatcher.dispatchEvent( - UplynkAssetInfoResponseEventImpl( - Date(), - assetInfo - ) - ) - } + fun dispatchAssetInfoEvents(assetInfo: AssetInfoResponse) = listeners.forEach { listener -> + handler.post { listener.onAssetInfoResponse(assetInfo) } + } + + fun addListener(listener: UplynkListener) = listeners.add(listener) + + fun removeListener(listener: UplynkListener) = listeners.remove(listener) } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt deleted file mode 100644 index 1d9b73c7..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkAssetInfoResponseEventImpl.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.events - -import com.theoplayer.android.connector.uplynk.events.UplynkAssetInfoResponseEvent -import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes -import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse -import java.util.Date - -internal class UplynkAssetInfoResponseEventImpl( - date: Date, - override val response: AssetInfoResponse -) : - UplynkEventImpl(UplynkEventTypes.ASSET_INFO_RESPONSE, date), - UplynkAssetInfoResponseEvent \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt deleted file mode 100644 index db946363..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventImpl.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.events - -import com.theoplayer.android.api.event.EventType -import com.theoplayer.android.connector.uplynk.events.UplynkEvent -import java.util.Date - -internal abstract class UplynkEventImpl> internal constructor( - private val type: EventType, - private val date: Date -) : UplynkEvent { - - override fun getDate() = date - - override fun getType() = type - - override fun toString(): String { - return "UplynkEvent{" + - "type=" + type + - ", date=" + date + - '}' - } -} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt deleted file mode 100644 index 42bd8baa..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkEventTypeImpl.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.events - -import com.theoplayer.android.api.event.EventType -import com.theoplayer.android.connector.uplynk.events.UplynkEvent - -internal class UplynkEventTypeImpl>(private val name: String) : EventType { - override fun getName() = this.name - - override fun toString(): String { - return this.name - } -} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt deleted file mode 100644 index 6f48cc06..00000000 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/events/UplynkPreplayResponseEventImpl.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.theoplayer.android.connector.uplynk.internal.events - -import com.theoplayer.android.connector.uplynk.events.UplynkEventTypes -import com.theoplayer.android.connector.uplynk.events.UplynkPreplayResponseEvent -import com.theoplayer.android.connector.uplynk.network.PreplayResponse -import java.util.Date - -internal class UplynkPreplayResponseEventImpl( - date: Date, - override val response: PreplayResponse -) : - UplynkEventImpl(UplynkEventTypes.PREPLAY_RESPONSE, date), - UplynkPreplayResponseEvent \ No newline at end of file From bf957e1dad01b2c3edcc8c84af78d44d529ee9af Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 16 Aug 2024 13:37:58 +0200 Subject: [PATCH 21/31] Fix unit tests --- .../connector/uplynk/UplynkSsaiDescription.kt | 2 +- .../UplynkSsaiDescriptionConverterTest.kt | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkSsaiDescription.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkSsaiDescription.kt index 0259a65f..4dbadea4 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkSsaiDescription.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkSsaiDescription.kt @@ -13,7 +13,7 @@ data class UplynkSsaiDescription( val externalId: List = listOf(), val userId: String? = null, val preplayParameters: LinkedHashMap = linkedMapOf(), - val assetInfo: Boolean + val assetInfo: Boolean = false ): CustomSsaiDescription() { override val customIntegration: String diff --git a/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt b/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt index 8971eed5..3f7e9cd7 100644 --- a/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt +++ b/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt @@ -5,9 +5,7 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test -import org.mockito.Mock import org.mockito.MockitoAnnotations -import org.mockito.kotlin.whenever import kotlin.test.assertContains class UplynkSsaiDescriptionConverterTest { @@ -110,8 +108,9 @@ class UplynkSsaiDescriptionConverterTest { @Test fun buildAssetInfoUrls_whenAssetIdIsEmptyAndExternalIdIsEmpty_returnsEmptyUrl() { - whenever(ssaiDescription.assetIds).thenReturn(listOf()) - whenever(ssaiDescription.externalId).thenReturn(listOf()) + ssaiDescription = UplynkSsaiDescription( + assetIds = listOf(), externalId = listOf() + ) val result = converter.buildAssetInfoUrls(ssaiDescription, "") @@ -131,9 +130,11 @@ class UplynkSsaiDescriptionConverterTest { @Test fun buildAssetInfoUrls_whenAssetIdIsEmpty_returnsAssetInfoUrlsUsingExternalId() { - whenever(ssaiDescription.assetIds).thenReturn(listOf()) - whenever(ssaiDescription.externalId).thenReturn(listOf("extId1", "extId2")) - whenever(ssaiDescription.userId).thenReturn("userId") + ssaiDescription = ssaiDescription.copy( + assetIds = listOf(), + externalId = listOf("extId1", "extId2"), + userId = "userId" + ) val result = converter.buildAssetInfoUrls(ssaiDescription, "") From cc6bf1f8fb00e5ba007f3a1dc3fdfe0bda25f33c Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 16 Aug 2024 13:38:45 +0200 Subject: [PATCH 22/31] Use default prefix in buildAssetInfoUrls() --- .../internal/UplynkSsaiDescriptionConverter.kt | 1 + .../internal/UplynkSsaiDescriptionConverterTest.kt | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt index 737f0bb9..acb133e4 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt @@ -18,6 +18,7 @@ internal class UplynkSsaiDescriptionConverter { } fun buildAssetInfoUrls(ssaiDescription: UplynkSsaiDescription, sessionId: String): List = with(ssaiDescription) { + val prefix = prefix ?: DEFAULT_PREFIX val urlList = when { assetIds.isNotEmpty() -> assetIds.map { "$prefix/player/assetinfo/$it.json" diff --git a/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt b/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt index 3f7e9cd7..65805888 100644 --- a/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt +++ b/connectors/uplynk/src/test/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverterTest.kt @@ -143,4 +143,16 @@ class UplynkSsaiDescriptionConverterTest { assertContains(result, "urlprefix/player/assetinfo/ext/userId/extId1.json") assertContains(result, "urlprefix/player/assetinfo/ext/userId/extId2.json") } + + + @Test + fun buildAssetInfoUrls_whenPrefixIsNotSet_returnsUrlWithDefaultPrefix() { + ssaiDescription = UplynkSsaiDescription( + assetIds = listOf("assetId1"), + ) + + val result = converter.buildAssetInfoUrls(ssaiDescription, "") + + assertEquals("https://content.uplynk.com/player/assetinfo/assetId1.json", result.first()) + } } \ No newline at end of file From 8f50d3d8af00baea71614d4034111cac37532610 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 19 Aug 2024 12:16:59 +0200 Subject: [PATCH 23/31] Add docs for UplynkListener --- .../connector/uplynk/UplynkListener.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt index 6456b307..e58b04f2 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt @@ -3,8 +3,28 @@ package com.theoplayer.android.connector.uplynk import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import com.theoplayer.android.connector.uplynk.network.PreplayResponse +/** + * A listener interface for receiving events related to Uplynk + * Implementations of this interface can be used to handle responses from Uplynk's API. + */ interface UplynkListener { - fun onPreplayResponse(response: PreplayResponse) - fun onAssetInfoResponse(response: AssetInfoResponse) + + /** + * Called when a preplay response is received from Uplynk. + * + * For more details, refer to the [Preplay API (Version 2) Documentation](https://docs.edgecast.com/video/index.html#Develop/Preplayv2.htm). + * + * @param response the `PreplayResponse` object containing information relevant to the preplay request. + */ + fun onPreplayResponse(response: PreplayResponse) {} + + /** + * Called when an asset information response is received from Uplynk. + * + * For more details, refer to the [Asset Info Documentation](https://docs.edgecast.com/video/index.html#Develop/AssetInfo.htm). + * + * @param response the `AssetInfoResponse` object containing detailed information about the asset. + */ + fun onAssetInfoResponse(response: AssetInfoResponse) {} } From 4b7e849abb7979a1d6e903053e749f0fd974f042 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 19 Aug 2024 13:10:47 +0200 Subject: [PATCH 24/31] Run all listeners in the single post --- .../connector/uplynk/internal/UplynkEventDispatcher.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt index 64578c2a..7db49ccd 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt @@ -10,12 +10,12 @@ import java.util.concurrent.CopyOnWriteArrayList internal class UplynkEventDispatcher(val handler: Handler = Handler(Looper.getMainLooper())) { private val listeners = CopyOnWriteArrayList() - fun dispatchPreplayEvents(response: PreplayResponse) = listeners.forEach { listener -> - handler.post { listener.onPreplayResponse(response) } + fun dispatchPreplayEvents(response: PreplayResponse) = handler.post { + listeners.forEach { it.onPreplayResponse(response) } } - fun dispatchAssetInfoEvents(assetInfo: AssetInfoResponse) = listeners.forEach { listener -> - handler.post { listener.onAssetInfoResponse(assetInfo) } + fun dispatchAssetInfoEvents(assetInfo: AssetInfoResponse) = handler.post { + listeners.forEach { it.onAssetInfoResponse(assetInfo) } } fun addListener(listener: UplynkListener) = listeners.add(listener) From 231371b8add35ae8dc56f4dd8c55438aa4e43a11 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Mon, 19 Aug 2024 13:17:28 +0200 Subject: [PATCH 25/31] Move json to the private field of the UplynkApi --- .../uplynk/internal/network/PreplayInternalResponse.kt | 5 +---- .../android/connector/uplynk/network/UplynkApi.kt | 6 ++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt index eb6a8303..e1aad64a 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/PreplayInternalResponse.kt @@ -4,9 +4,6 @@ import com.theoplayer.android.connector.uplynk.network.PreplayResponse import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json -private val json = Json{ - ignoreUnknownKeys = true -} @Serializable internal data class MinimalPreplayResponse( @@ -22,7 +19,7 @@ internal data class MinimalPreplayResponse( val sid: String) -internal class PreplayInternalResponse(val body: String) { +internal class PreplayInternalResponse(val body: String, private val json: Json) { fun parseMinimalResponse(): MinimalPreplayResponse = json.decodeFromString(body) fun parseExternalResponse(): PreplayResponse = json.decodeFromString(body) } \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt index 9b8670d0..58480858 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt @@ -4,16 +4,14 @@ import com.theoplayer.android.connector.uplynk.common.HttpsConnection import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse import kotlinx.serialization.json.Json -private val json = Json { - ignoreUnknownKeys = true -} internal class UplynkApi { + private val json = Json { ignoreUnknownKeys = true } private val network = HttpsConnection() suspend fun preplay(srcURL: String): PreplayInternalResponse { val body = network.get(srcURL) - return PreplayInternalResponse(body) + return PreplayInternalResponse(body, json) } suspend fun assetInfo(url: String): AssetInfoResponse { From a331da50e5fb3cd41c1c9b5f42f17f9f3735e471 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Tue, 20 Aug 2024 07:44:03 +0200 Subject: [PATCH 26/31] Add onPreplayFailure and onAssetInfoFailure --- .../theoplayer/android/connector/MainActivity.kt | 8 ++++++++ .../android/connector/uplynk/UplynkListener.kt | 13 +++++++++++++ .../uplynk/internal/UplynkAdIntegration.kt | 2 ++ .../uplynk/internal/UplynkEventDispatcher.kt | 8 ++++++++ .../uplynk/internal/network/HttpsConnection.kt | 0 5 files changed, 31 insertions(+) delete mode 100644 connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt diff --git a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt index 1c2b4518..af99e9fe 100644 --- a/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt +++ b/app/src/main/java/com/theoplayer/android/connector/MainActivity.kt @@ -161,6 +161,14 @@ class MainActivity : AppCompatActivity() { Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE $response") } + override fun onPreplayFailure(exception: Exception) { + Log.d("UplynkConnectorEvents", "PREPLAY_RESPONSE_FAILURE $exception") + } + + override fun onAssetInfoFailure(exception: Exception) { + Log.d("UplynkConnectorEvents", "ASSET_INFO_RESPONSE Failure $exception") + } + }) theoplayerView.player.ads.addEventListener(AdsEventTypes.AD_ERROR) { diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt index e58b04f2..3346ec66 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkListener.kt @@ -18,6 +18,13 @@ interface UplynkListener { */ fun onPreplayResponse(response: PreplayResponse) {} + /** + * Called when a preplay response is received from Uplynk and failed to be parsed + * + * @param exception the `Exception` occurred during the response parsing + */ + fun onPreplayFailure(exception: Exception) {} + /** * Called when an asset information response is received from Uplynk. * @@ -27,4 +34,10 @@ interface UplynkListener { */ fun onAssetInfoResponse(response: AssetInfoResponse) {} + /** + * Called when an asset information response is failed + * + * @param exception the `Exception` occurred during the request + */ + fun onAssetInfoFailure(exception: Exception) {} } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 2d406e0b..7fa2fad6 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -31,6 +31,7 @@ internal class UplynkAdIntegration( try { eventDispatcher.dispatchPreplayEvents(it.parseExternalResponse()) } catch (e: Exception) { + eventDispatcher.dispatchPreplayFailure(e) controller.error(e) } } @@ -48,6 +49,7 @@ internal class UplynkAdIntegration( try { uplynkApi.assetInfo(it) } catch (e: Exception) { + eventDispatcher.dispatchAssetInfoFailure(e) controller.error(e) null } diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt index 7db49ccd..57c3281f 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt @@ -18,6 +18,14 @@ internal class UplynkEventDispatcher(val handler: Handler = Handler(Looper.getMa listeners.forEach { it.onAssetInfoResponse(assetInfo) } } + fun dispatchAssetInfoFailure(e: Exception) = handler.post { + listeners.forEach { it.onAssetInfoFailure(e) } + } + + fun dispatchPreplayFailure(e: Exception) = handler.post { + listeners.forEach { it.onPreplayFailure(e) } + } + fun addListener(listener: UplynkListener) = listeners.add(listener) fun removeListener(listener: UplynkListener) = listeners.remove(listener) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt deleted file mode 100644 index e69de29b..00000000 From 9bc0b93b97b8d3d4f87f6c6e15a65b79ebb64ed8 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Wed, 21 Aug 2024 16:31:24 +0200 Subject: [PATCH 27/31] Throw an exception when connection fails --- .../connector/uplynk/common/HttpsConnection.kt | 17 ++++++----------- .../connector/uplynk/network/UplynkApi.kt | 2 +- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt index 0d203aa3..2a980f85 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt @@ -1,7 +1,8 @@ -package com.theoplayer.android.connector.uplynk.common +package com.theoplayer.android.connector.uplynk.internal.network import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible +import java.io.IOException import java.net.URL import javax.net.ssl.HttpsURLConnection @@ -10,7 +11,6 @@ internal const val READ_TIMEOUT_IN_MS = 30000 internal class HttpsConnection { suspend fun get(urlString: String): String = runInterruptible(context = Dispatchers.IO) { - var result: String var connection: HttpsURLConnection? = null try { connection = (URL(urlString).openConnection() as HttpsURLConnection) @@ -23,22 +23,17 @@ internal class HttpsConnection { connection.connect() - val responseCode: Int = connection.getResponseCode() - result = when (responseCode) { + when (val responseCode: Int = connection.responseCode) { HttpsURLConnection.HTTP_OK -> - connection + return@runInterruptible connection .inputStream .bufferedReader() .use { it.readText() } - else -> "Error: $responseCode" + else -> throw IOException("HTTP response $responseCode for URL: $urlString") } - } catch (e: Exception) { - result = e.message ?: "" } finally { connection?.disconnect() } - - result } -} +} \ No newline at end of file diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt index 58480858..7496e7c8 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt @@ -1,6 +1,6 @@ package com.theoplayer.android.connector.uplynk.network -import com.theoplayer.android.connector.uplynk.common.HttpsConnection +import com.theoplayer.android.connector.uplynk.internal.network.HttpsConnection import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse import kotlinx.serialization.json.Json From 65711f733897d4831d45177575a71e5059a6ab0f Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 23 Aug 2024 06:46:50 +0200 Subject: [PATCH 28/31] Move classes to an internal package --- .../theoplayer/android/connector/uplynk/UplynkConnector.kt | 2 +- .../android/connector/uplynk/internal/UplynkAdIntegration.kt | 2 +- .../uplynk/{common => internal/network}/HttpsConnection.kt | 0 .../connector/uplynk/{ => internal}/network/UplynkApi.kt | 5 ++--- 4 files changed, 4 insertions(+), 5 deletions(-) rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/{common => internal/network}/HttpsConnection.kt (100%) rename connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/{ => internal}/network/UplynkApi.kt (68%) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt index 3fbd8c42..c6d9b920 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/UplynkConnector.kt @@ -7,7 +7,7 @@ import com.theoplayer.android.api.source.ssai.CustomSsaiDescriptionRegistry import com.theoplayer.android.connector.uplynk.internal.UplynkAdIntegration import com.theoplayer.android.connector.uplynk.internal.UplynkSsaiDescriptionConverter import com.theoplayer.android.connector.uplynk.internal.UplynkEventDispatcher -import com.theoplayer.android.connector.uplynk.network.UplynkApi +import com.theoplayer.android.connector.uplynk.internal.network.UplynkApi internal const val TAG = "UplynkConnector" diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 7fa2fad6..7b227389 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -6,7 +6,7 @@ import com.theoplayer.android.api.ads.ServerSideAdIntegrationHandler import com.theoplayer.android.api.player.Player import com.theoplayer.android.api.source.SourceDescription import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription -import com.theoplayer.android.connector.uplynk.network.UplynkApi +import com.theoplayer.android.connector.uplynk.internal.network.UplynkApi internal class UplynkAdIntegration( val theoplayerView: THEOplayerView, diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt similarity index 100% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/common/HttpsConnection.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/HttpsConnection.kt diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/UplynkApi.kt similarity index 68% rename from connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt rename to connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/UplynkApi.kt index 7496e7c8..83a88c75 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/network/UplynkApi.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/network/UplynkApi.kt @@ -1,7 +1,6 @@ -package com.theoplayer.android.connector.uplynk.network +package com.theoplayer.android.connector.uplynk.internal.network -import com.theoplayer.android.connector.uplynk.internal.network.HttpsConnection -import com.theoplayer.android.connector.uplynk.internal.network.PreplayInternalResponse +import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import kotlinx.serialization.json.Json From a4da8784e4d3f83d12a4fbb81a1365d0ff7b8725 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 23 Aug 2024 06:53:27 +0200 Subject: [PATCH 29/31] Move handler to a class body --- .../connector/uplynk/internal/UplynkEventDispatcher.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt index 57c3281f..4cb50e48 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkEventDispatcher.kt @@ -7,7 +7,9 @@ import com.theoplayer.android.connector.uplynk.network.AssetInfoResponse import com.theoplayer.android.connector.uplynk.network.PreplayResponse import java.util.concurrent.CopyOnWriteArrayList -internal class UplynkEventDispatcher(val handler: Handler = Handler(Looper.getMainLooper())) { +internal class UplynkEventDispatcher { + private val handler = Handler(Looper.getMainLooper()) + private val listeners = CopyOnWriteArrayList() fun dispatchPreplayEvents(response: PreplayResponse) = handler.post { From 4f82b024dc06fdb878546081d605f0c0bde3fb82 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 23 Aug 2024 06:55:16 +0200 Subject: [PATCH 30/31] Make properties private --- .../connector/uplynk/internal/UplynkAdIntegration.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt index 7b227389..76c6f258 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkAdIntegration.kt @@ -9,10 +9,10 @@ import com.theoplayer.android.connector.uplynk.UplynkSsaiDescription import com.theoplayer.android.connector.uplynk.internal.network.UplynkApi internal class UplynkAdIntegration( - val theoplayerView: THEOplayerView, - val controller: ServerSideAdIntegrationController, - val eventDispatcher: UplynkEventDispatcher, - val uplynkDescriptionConverter: UplynkSsaiDescriptionConverter, + private val theoplayerView: THEOplayerView, + private val controller: ServerSideAdIntegrationController, + private val eventDispatcher: UplynkEventDispatcher, + private val uplynkDescriptionConverter: UplynkSsaiDescriptionConverter, private val uplynkApi: UplynkApi ) : ServerSideAdIntegrationHandler { From 63d8f1828119fd0f1c3b7b4c9c91b259971996d8 Mon Sep 17 00:00:00 2001 From: OlegRyz Date: Fri, 23 Aug 2024 17:01:06 +0200 Subject: [PATCH 31/31] Change when to if --- .../uplynk/internal/UplynkSsaiDescriptionConverter.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt index acb133e4..bb02f072 100644 --- a/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt +++ b/connectors/uplynk/src/main/java/com/theoplayer/android/connector/uplynk/internal/UplynkSsaiDescriptionConverter.kt @@ -28,9 +28,10 @@ internal class UplynkSsaiDescriptionConverter { } else -> listOf() } - return when { - sessionId.isBlank() -> urlList - else -> urlList.map { "$it?pbs=$sessionId" } + return if (sessionId.isBlank()) { + urlList + } else { + urlList.map { "$it?pbs=$sessionId" } } } }