From 496d7f10c917f3c3d1a5d66ff2451a1864cf25f9 Mon Sep 17 00:00:00 2001 From: ziad-halabi9 Date: Mon, 15 Sep 2025 14:45:30 +0100 Subject: [PATCH 1/5] Making streaming-api depend on tidalapi This required changing it to an android library and switching libs.androidx.annotations compileOnly to implementation. --- player/streaming-api/build.gradle.kts | 7 +++++-- player/streaming-api/src/main/AndroidManifest.xml | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 player/streaming-api/src/main/AndroidManifest.xml diff --git a/player/streaming-api/build.gradle.kts b/player/streaming-api/build.gradle.kts index bbd77701..f195526a 100644 --- a/player/streaming-api/build.gradle.kts +++ b/player/streaming-api/build.gradle.kts @@ -1,12 +1,14 @@ plugins { - alias(libs.plugins.tidal.kotlin.jvm) + alias(libs.plugins.tidal.android.library) alias(libs.plugins.google.devtools.ksp) } +android { namespace = "com.tidal.sdk.player.streamingapi" } + dependencies { ksp(libs.dagger.compiler) - compileOnly(libs.androidx.annotations) + implementation(libs.androidx.annotations) implementation(libs.dagger) implementation(libs.gson) @@ -15,6 +17,7 @@ dependencies { implementation(libs.retrofit.converter.gson) api(libs.retrofit) implementation(project(":player:common")) + implementation(project(":tidalapi")) testImplementation(libs.kotlin.reflect) testImplementation(libs.kotlinxCoroutinesCore) diff --git a/player/streaming-api/src/main/AndroidManifest.xml b/player/streaming-api/src/main/AndroidManifest.xml new file mode 100644 index 00000000..bd1f5b21 --- /dev/null +++ b/player/streaming-api/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + From f8a15b7f77e751d94fd3043b95c727fdf5f358b0 Mon Sep 17 00:00:00 2001 From: ziad-halabi9 Date: Tue, 16 Sep 2025 09:56:01 +0100 Subject: [PATCH 2/5] Providing TidalApiClient in StreamingApiModule This depends on CredentialsProvider. --- .../kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt | 3 +++ .../sdk/player/streamingapi/StreamingApiModuleRoot.kt | 3 +++ .../sdk/player/streamingapi/di/StreamingApiComponent.kt | 2 ++ .../tidal/sdk/player/streamingapi/di/StreamingApiModule.kt | 7 +++++++ .../sdk/player/streamingapi/StreamingApiDefaultTest.kt | 6 ++++++ 5 files changed, 21 insertions(+) diff --git a/player/src/main/kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt b/player/src/main/kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt index 8c2c5045..f188edac 100644 --- a/player/src/main/kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt +++ b/player/src/main/kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt @@ -1,6 +1,7 @@ package com.tidal.sdk.player.di import com.google.gson.Gson +import com.tidal.sdk.auth.CredentialsProvider import com.tidal.sdk.player.common.model.ApiError import com.tidal.sdk.player.offlineplay.OfflinePlayProvider import com.tidal.sdk.player.streamingapi.StreamingApiModuleRoot @@ -24,6 +25,7 @@ internal object StreamingApiModule { gson: Gson, apiErrorFactory: ApiError.Factory, offlinePlayProvider: OfflinePlayProvider?, + credentialsProvider: CredentialsProvider, ) = StreamingApiModuleRoot( okHttpClient, @@ -31,6 +33,7 @@ internal object StreamingApiModule { gson, apiErrorFactory, offlinePlayProvider?.offlinePlaybackInfoProvider, + credentialsProvider, ) .streamingApi } diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiModuleRoot.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiModuleRoot.kt index 2850c197..1d42bec9 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiModuleRoot.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiModuleRoot.kt @@ -1,6 +1,7 @@ package com.tidal.sdk.player.streamingapi import com.google.gson.Gson +import com.tidal.sdk.auth.CredentialsProvider import com.tidal.sdk.player.common.model.ApiError import com.tidal.sdk.player.streamingapi.di.DaggerStreamingApiComponent import com.tidal.sdk.player.streamingapi.playbackinfo.offline.OfflinePlaybackInfoProvider @@ -12,6 +13,7 @@ class StreamingApiModuleRoot( gson: Gson, apiErrorFactory: ApiError.Factory, offlinePlaybackInfoProvider: OfflinePlaybackInfoProvider?, + credentialsProvider: CredentialsProvider, ) { val streamingApi = @@ -22,6 +24,7 @@ class StreamingApiModuleRoot( gson, apiErrorFactory, offlinePlaybackInfoProvider, + credentialsProvider, ) .streamingApi } diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiComponent.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiComponent.kt index 765fa0f8..b60572aa 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiComponent.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiComponent.kt @@ -1,6 +1,7 @@ package com.tidal.sdk.player.streamingapi.di import com.google.gson.Gson +import com.tidal.sdk.auth.CredentialsProvider import com.tidal.sdk.player.common.model.ApiError import com.tidal.sdk.player.streamingapi.StreamingApi import com.tidal.sdk.player.streamingapi.StreamingApiTimeoutConfig @@ -34,6 +35,7 @@ interface StreamingApiComponent { @BindsInstance gson: Gson, @BindsInstance apiErrorFactory: ApiError.Factory, @BindsInstance offlinePlaybackInfoProvider: OfflinePlaybackInfoProvider?, + @BindsInstance credentialsProvider: CredentialsProvider, ): StreamingApiComponent } diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt index 1b382358..3caee28b 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt @@ -1,6 +1,7 @@ package com.tidal.sdk.player.streamingapi.di import com.google.gson.Gson +import com.tidal.sdk.auth.CredentialsProvider import com.tidal.sdk.player.common.model.ApiError import com.tidal.sdk.player.streamingapi.StreamingApi import com.tidal.sdk.player.streamingapi.StreamingApiDefault @@ -8,6 +9,7 @@ import com.tidal.sdk.player.streamingapi.drm.repository.DrmLicenseRepository import com.tidal.sdk.player.streamingapi.playbackinfo.mapper.ApiErrorMapper import com.tidal.sdk.player.streamingapi.playbackinfo.model.ManifestMimeType import com.tidal.sdk.player.streamingapi.playbackinfo.repository.PlaybackInfoRepository +import com.tidal.sdk.tidalapi.generated.TidalApiClient import dagger.Module import dagger.Provides import dagger.Reusable @@ -40,6 +42,11 @@ internal object StreamingApiModule { @Reusable fun provideApiErrorMapper(apiErrorFactory: ApiError.Factory) = ApiErrorMapper(apiErrorFactory) + @Provides + @Reusable + fun provideTidalApiClient(credentialsProvider: CredentialsProvider): TidalApiClient = + TidalApiClient(credentialsProvider) + @Provides @Reusable fun streamingApiDefault( diff --git a/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefaultTest.kt b/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefaultTest.kt index 5c39c6f6..194bd2ac 100644 --- a/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefaultTest.kt +++ b/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefaultTest.kt @@ -6,6 +6,7 @@ import assertk.assertions.isEqualTo import assertk.assertions.isEqualToIgnoringGivenProperties import com.google.gson.Gson import com.google.gson.JsonParseException +import com.tidal.sdk.auth.CredentialsProvider import com.tidal.sdk.player.MockWebServerExtensions.enqueueResponse import com.tidal.sdk.player.common.model.ApiError import com.tidal.sdk.player.common.model.AudioQuality @@ -26,6 +27,7 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.kotlin.mock /** * Test that the [StreamingApi] returns correct in various situations, using real @@ -36,10 +38,13 @@ internal class StreamingApiDefaultTest { @get:ExtendWith val server = MockWebServer() private lateinit var streamingApi: StreamingApi + private lateinit var credentialsProviderMock: CredentialsProvider @BeforeEach fun setUp() { val gson = Gson() + credentialsProviderMock = mock() + streamingApi = DaggerStreamingApiComponent.factory() .create( @@ -59,6 +64,7 @@ internal class StreamingApiDefaultTest { streamingApiTimeoutConfig = StreamingApiTimeoutConfig(), gson = gson, offlinePlaybackInfoProvider = OfflinePlaybackInfoProviderStub(), + credentialsProvider = credentialsProviderMock, ) .streamingApi } From 8d7bb86b1bc64ef436d98a071083287cd73b5710 Mon Sep 17 00:00:00 2001 From: ziad-halabi9 Date: Tue, 16 Sep 2025 10:12:31 +0100 Subject: [PATCH 3/5] Providing TrackManifests to PlaybackInfoRepositoryDefault --- .../tidal/sdk/player/streamingapi/di/PlaybackInfoModule.kt | 3 +++ .../tidal/sdk/player/streamingapi/di/StreamingApiModule.kt | 6 ++++++ .../repository/PlaybackInfoRepositoryDefault.kt | 2 ++ .../repository/PlaybackInfoRepositoryDefaultTest.kt | 3 +++ 4 files changed, 14 insertions(+) diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/PlaybackInfoModule.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/PlaybackInfoModule.kt index 5afb8cb6..01862b96 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/PlaybackInfoModule.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/PlaybackInfoModule.kt @@ -5,6 +5,7 @@ import com.tidal.sdk.player.streamingapi.playbackinfo.mapper.ApiErrorMapper import com.tidal.sdk.player.streamingapi.playbackinfo.offline.OfflinePlaybackInfoProvider import com.tidal.sdk.player.streamingapi.playbackinfo.repository.PlaybackInfoRepository import com.tidal.sdk.player.streamingapi.playbackinfo.repository.PlaybackInfoRepositoryDefault +import com.tidal.sdk.tidalapi.generated.apis.TrackManifests import dagger.Lazy import dagger.Module import dagger.Provides @@ -18,12 +19,14 @@ internal object PlaybackInfoModule { fun providePlaybackInfoRepository( offlinePlaybackInfoProvider: OfflinePlaybackInfoProvider?, playbackInfoService: PlaybackInfoService, + trackManifests: TrackManifests, apiErrorMapperLazy: Lazy, ): PlaybackInfoRepository { return PlaybackInfoRepositoryDefault( offlinePlaybackInfoProvider, playbackInfoService, apiErrorMapperLazy, + trackManifests, ) } } diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt index 3caee28b..a185311e 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt @@ -10,6 +10,7 @@ import com.tidal.sdk.player.streamingapi.playbackinfo.mapper.ApiErrorMapper import com.tidal.sdk.player.streamingapi.playbackinfo.model.ManifestMimeType import com.tidal.sdk.player.streamingapi.playbackinfo.repository.PlaybackInfoRepository import com.tidal.sdk.tidalapi.generated.TidalApiClient +import com.tidal.sdk.tidalapi.generated.apis.TrackManifests import dagger.Module import dagger.Provides import dagger.Reusable @@ -47,6 +48,11 @@ internal object StreamingApiModule { fun provideTidalApiClient(credentialsProvider: CredentialsProvider): TidalApiClient = TidalApiClient(credentialsProvider) + @Provides + @Reusable + fun provideTrackManifests(tidalApiClient: TidalApiClient): TrackManifests = + tidalApiClient.createTrackManifests() + @Provides @Reusable fun streamingApiDefault( diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefault.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefault.kt index 4049a84c..ca85a12a 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefault.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefault.kt @@ -9,6 +9,7 @@ import com.tidal.sdk.player.streamingapi.playbackinfo.model.ManifestMimeType import com.tidal.sdk.player.streamingapi.playbackinfo.model.PlaybackInfo import com.tidal.sdk.player.streamingapi.playbackinfo.model.PlaybackMode import com.tidal.sdk.player.streamingapi.playbackinfo.offline.OfflinePlaybackInfoProvider +import com.tidal.sdk.tidalapi.generated.apis.TrackManifests import dagger.Lazy import retrofit2.HttpException @@ -24,6 +25,7 @@ internal class PlaybackInfoRepositoryDefault( private val offlinePlaybackInfoProvider: OfflinePlaybackInfoProvider?, private val playbackInfoService: PlaybackInfoService, private val apiErrorMapperLazy: Lazy, + private val trackManifests: TrackManifests, ) : PlaybackInfoRepository { override suspend fun getTrackPlaybackInfo( diff --git a/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefaultTest.kt b/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefaultTest.kt index ba9f4138..ef15925d 100644 --- a/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefaultTest.kt +++ b/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefaultTest.kt @@ -16,6 +16,7 @@ import com.tidal.sdk.player.streamingapi.playbackinfo.api.PlaybackInfoServiceStu import com.tidal.sdk.player.streamingapi.playbackinfo.mapper.ApiErrorMapper import com.tidal.sdk.player.streamingapi.playbackinfo.model.PlaybackInfo import com.tidal.sdk.player.streamingapi.playbackinfo.model.PlaybackMode +import com.tidal.sdk.tidalapi.generated.apis.TrackManifests import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.Test import org.mockito.kotlin.mock @@ -26,11 +27,13 @@ internal class PlaybackInfoRepositoryDefaultTest { private val offlinePlaybackInfoProvider = OfflinePlaybackInfoProviderStub() private val playbackInfoService = PlaybackInfoServiceStub() private val apiErrorMapperLazy = { mock() } + private val trackManifests = mock() private val playbackInfoRepository = PlaybackInfoRepositoryDefault( offlinePlaybackInfoProvider, playbackInfoService, apiErrorMapperLazy, + trackManifests, ) @Test From 0733d46eb38bf31a53379fa784acf62d89815a05 Mon Sep 17 00:00:00 2001 From: ziad-halabi9 Date: Tue, 16 Sep 2025 10:20:02 +0100 Subject: [PATCH 4/5] Adding getTrackPlaybackInfoTop --- .../repository/PlaybackInfoRepository.kt | 20 ++++++ .../PlaybackInfoRepositoryDefault.kt | 70 +++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepository.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepository.kt index cee1b794..5cfd3982 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepository.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepository.kt @@ -28,6 +28,26 @@ internal interface PlaybackInfoRepository { playlistUuid: String?, ): PlaybackInfo + /** + * Returns a [PlaybackInfo] which we can use for playback of a track from Top. + * + * @param[trackId] The requested track id as [String]. + * @param[audioQuality] The requested audio quality as [AudioQuality]. + * @param[playbackMode] The requested playback mode as [PlaybackMode]. + * @param[immersiveAudio] The requested option to include immersive audio or not. + * @param[streamingSessionId] The streaming session uuid as [String], created by the client, for + * this streaming session. + * @param[playlistUuid] The playlistUuid this play originates from as [String]. May be null. + */ + suspend fun getTrackPlaybackInfoTop( + trackId: String, + audioQuality: AudioQuality, + playbackMode: PlaybackMode, + immersiveAudio: Boolean, + streamingSessionId: String, + playlistUuid: String?, + ): PlaybackInfo + /** * Returns a [PlaybackInfo] which we can use for playback of a video. * diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefault.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefault.kt index ca85a12a..b7252cb6 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefault.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/playbackinfo/repository/PlaybackInfoRepositoryDefault.kt @@ -1,6 +1,7 @@ package com.tidal.sdk.player.streamingapi.playbackinfo.repository import com.tidal.sdk.player.common.model.AssetPresentation +import com.tidal.sdk.player.common.model.AudioMode import com.tidal.sdk.player.common.model.AudioQuality import com.tidal.sdk.player.common.model.VideoQuality import com.tidal.sdk.player.streamingapi.playbackinfo.api.PlaybackInfoService @@ -50,6 +51,67 @@ internal class PlaybackInfoRepositoryDefault( throw apiErrorMapperLazy.get().map(e) } + override suspend fun getTrackPlaybackInfoTop( + trackId: String, + audioQuality: AudioQuality, + playbackMode: PlaybackMode, + immersiveAudio: Boolean, + streamingSessionId: String, + playlistUuid: String?, + ) = + try { + val data = + trackManifests + .trackManifestsIdGet( + trackId, + MANIFEST_TYPE, + audioQuality.toFormats(), + DATA_URI_SCHEME, + if (playbackMode == PlaybackMode.STREAM) PLAYBACK_USAGE else DOWNLOAD_USAGE, + "false", + ) + .body() + ?.data + PlaybackInfo.Track( + data?.id?.toInt() ?: -1, + AudioQuality.HI_RES_LOSSLESS, + if (data?.attributes?.trackPresentation?.name == TRACK_PREVIEW_PRESENTATION) + AssetPresentation.PREVIEW + else AssetPresentation.FULL, + AudioMode.STEREO, + null, + null, + data?.attributes?.hash.orEmpty(), + streamingSessionId, + ManifestMimeType.DASH, + extractManifest(data?.attributes?.uri.orEmpty()), + data?.attributes?.drmData?.licenseUrl, + data?.attributes?.albumAudioNormalizationData?.replayGain ?: -1f, + data?.attributes?.albumAudioNormalizationData?.peakAmplitude ?: -1f, + data?.attributes?.trackAudioNormalizationData?.replayGain ?: -1f, + data?.attributes?.trackAudioNormalizationData?.peakAmplitude ?: -1f, + -1, + -1, + ) + } catch (e: HttpException) { + throw apiErrorMapperLazy.get().map(e) + } + + private fun AudioQuality.toFormats(): String { + return when (this) { + AudioQuality.LOW -> "HEAACV1" + AudioQuality.HIGH -> "HEAACV1,AACLC" + AudioQuality.LOSSLESS -> "HEAACV1,AACLC,FLAC" + AudioQuality.HI_RES_LOSSLESS -> "HEAACV1,AACLC,FLAC,FLAC_HIRES" + } + } + + private fun extractManifest(dataUrl: String): String { + val commaIndex = dataUrl.indexOf(',') + require(commaIndex >= 0) { "Invalid manifest" } + return dataUrl.substring(commaIndex + 1) + } + override suspend fun getVideoPlaybackInfo( videoId: String, videoQuality: VideoQuality, @@ -106,4 +168,12 @@ internal class PlaybackInfoRepositoryDefault( override suspend fun getOfflineVideoPlaybackInfo(videoId: String, streamingSessionId: String) = offlinePlaybackInfoProvider?.getOfflineVideoPlaybackInfo(videoId, streamingSessionId) ?: throw NullPointerException("No OfflinePlaybackInfoProvider provided") + + private companion object { + const val MANIFEST_TYPE = "MPEG_DASH" + const val DATA_URI_SCHEME = "DATA" + const val PLAYBACK_USAGE = "PLAYBACK" + const val DOWNLOAD_USAGE = "DOWNLOAD" + const val TRACK_PREVIEW_PRESENTATION = "PREVIEW" + } } From 19e4b6993413f7ae17a815a6d221d30ef484616b Mon Sep 17 00:00:00 2001 From: ziad-halabi9 Date: Tue, 16 Sep 2025 11:00:13 +0100 Subject: [PATCH 5/5] Enabling getTrackPlaybackInfoTop behind feature flag --- .../ExoPlayerPlaybackEngineLooperTest.kt | 1 + .../PlaybackEngineModuleRoot.kt | 2 ++ .../di/ExoPlayerPlaybackEngineComponent.kt | 1 + .../kotlin/com/tidal/sdk/player/Player.kt | 2 ++ .../sdk/player/di/PlaybackEngineModule.kt | 2 ++ .../tidal/sdk/player/di/PlayerComponent.kt | 1 + .../tidal/sdk/player/di/StreamingApiModule.kt | 3 ++ .../streamingapi/StreamingApiDefault.kt | 28 +++++++++++++------ .../streamingapi/StreamingApiModuleRoot.kt | 2 ++ .../streamingapi/di/StreamingApiComponent.kt | 2 ++ .../streamingapi/di/StreamingApiModule.kt | 5 +++- .../streamingapi/StreamingApiDefaultTest.kt | 1 + 12 files changed, 41 insertions(+), 9 deletions(-) diff --git a/player/playback-engine/src/androidTest/kotlin/com/tidal/sdk/player/playbackengine/ExoPlayerPlaybackEngineLooperTest.kt b/player/playback-engine/src/androidTest/kotlin/com/tidal/sdk/player/playbackengine/ExoPlayerPlaybackEngineLooperTest.kt index 9836e370..225bf348 100644 --- a/player/playback-engine/src/androidTest/kotlin/com/tidal/sdk/player/playbackengine/ExoPlayerPlaybackEngineLooperTest.kt +++ b/player/playback-engine/src/androidTest/kotlin/com/tidal/sdk/player/playbackengine/ExoPlayerPlaybackEngineLooperTest.kt @@ -25,6 +25,7 @@ internal class ExoPlayerPlaybackEngineLooperTest { InstrumentationRegistry.getInstrumentation().targetContext, mock(), true, + false, MutableSharedFlow(), BufferConfiguration(), AssetTimeoutConfig(), diff --git a/player/playback-engine/src/main/kotlin/com/tidal/sdk/player/playbackengine/PlaybackEngineModuleRoot.kt b/player/playback-engine/src/main/kotlin/com/tidal/sdk/player/playbackengine/PlaybackEngineModuleRoot.kt index 066a24dd..74aad7b4 100644 --- a/player/playback-engine/src/main/kotlin/com/tidal/sdk/player/playbackengine/PlaybackEngineModuleRoot.kt +++ b/player/playback-engine/src/main/kotlin/com/tidal/sdk/player/playbackengine/PlaybackEngineModuleRoot.kt @@ -28,6 +28,7 @@ class PlaybackEngineModuleRoot( context: Context, connectivityManager: ConnectivityManager, useLibflacAudioRenderer: Boolean, + useTopPlaybackInfo: Boolean, events: MutableSharedFlow, bufferConfiguration: BufferConfiguration, assetTimeoutConfig: AssetTimeoutConfig, @@ -61,6 +62,7 @@ class PlaybackEngineModuleRoot( cacheProvider, configuration, useLibflacAudioRenderer, + useTopPlaybackInfo, appSpecificCacheDir, streamingApi, okHttpClient, diff --git a/player/playback-engine/src/main/kotlin/com/tidal/sdk/player/playbackengine/di/ExoPlayerPlaybackEngineComponent.kt b/player/playback-engine/src/main/kotlin/com/tidal/sdk/player/playbackengine/di/ExoPlayerPlaybackEngineComponent.kt index 923569eb..b8c1cfc8 100644 --- a/player/playback-engine/src/main/kotlin/com/tidal/sdk/player/playbackengine/di/ExoPlayerPlaybackEngineComponent.kt +++ b/player/playback-engine/src/main/kotlin/com/tidal/sdk/player/playbackengine/di/ExoPlayerPlaybackEngineComponent.kt @@ -47,6 +47,7 @@ interface ExoPlayerPlaybackEngineComponent { @BindsInstance cacheProvider: CacheProvider, @BindsInstance configuration: Configuration, @BindsInstance @Named("useLibflacAudioRenderer") useLibflacAudioRenderer: Boolean, + @BindsInstance @Named("useTopPlaybackInfo") useTopPlaybackInfo: Boolean, @BindsInstance appSpecificCacheDir: File, @BindsInstance streamingApi: StreamingApi, @BindsInstance @Local okHttpClient: OkHttpClient, diff --git a/player/src/main/kotlin/com/tidal/sdk/player/Player.kt b/player/src/main/kotlin/com/tidal/sdk/player/Player.kt index c5cf8686..39fe2c25 100644 --- a/player/src/main/kotlin/com/tidal/sdk/player/Player.kt +++ b/player/src/main/kotlin/com/tidal/sdk/player/Player.kt @@ -45,6 +45,7 @@ class Player( credentialsProvider: CredentialsProvider, eventSender: EventSender, useLibflacAudioRenderer: Boolean = true, + useTopPlaybackInfo: Boolean = false, userClientIdSupplier: (() -> Int)? = null, bufferConfiguration: BufferConfiguration = BufferConfiguration(), assetTimeoutConfig: AssetTimeoutConfig = AssetTimeoutConfig(), @@ -67,6 +68,7 @@ class Player( credentialsProvider, eventSender, useLibflacAudioRenderer, + useTopPlaybackInfo, userClientIdSupplier, version, bufferConfiguration, diff --git a/player/src/main/kotlin/com/tidal/sdk/player/di/PlaybackEngineModule.kt b/player/src/main/kotlin/com/tidal/sdk/player/di/PlaybackEngineModule.kt index b6fdaacd..0e8ad777 100644 --- a/player/src/main/kotlin/com/tidal/sdk/player/di/PlaybackEngineModule.kt +++ b/player/src/main/kotlin/com/tidal/sdk/player/di/PlaybackEngineModule.kt @@ -42,6 +42,7 @@ internal object PlaybackEngineModule { context: Context, connectivityManager: ConnectivityManager, @Named("useLibflacAudioRenderer") useLibflacAudioRenderer: Boolean, + @Named("useTopPlaybackInfo") useTopPlaybackInfo: Boolean, events: MutableSharedFlow, bufferConfiguration: BufferConfiguration, assetTimeoutConfig: AssetTimeoutConfig, @@ -66,6 +67,7 @@ internal object PlaybackEngineModule { context, connectivityManager, useLibflacAudioRenderer, + useTopPlaybackInfo, events, bufferConfiguration, assetTimeoutConfig, diff --git a/player/src/main/kotlin/com/tidal/sdk/player/di/PlayerComponent.kt b/player/src/main/kotlin/com/tidal/sdk/player/di/PlayerComponent.kt index 6e1ac599..19dd6370 100644 --- a/player/src/main/kotlin/com/tidal/sdk/player/di/PlayerComponent.kt +++ b/player/src/main/kotlin/com/tidal/sdk/player/di/PlayerComponent.kt @@ -45,6 +45,7 @@ internal interface PlayerComponent { @BindsInstance credentialsProvider: CredentialsProvider, @BindsInstance eventSender: EventSender, @BindsInstance @Named("useLibflacAudioRenderer") useLibflacAudioRenderer: Boolean, + @BindsInstance @Named("useTopPlaybackInfo") useTopPlaybackInfo: Boolean, @BindsInstance userClientIdSupplier: (() -> Int)?, @BindsInstance version: String, @BindsInstance bufferConfiguration: BufferConfiguration, diff --git a/player/src/main/kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt b/player/src/main/kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt index f188edac..deb27438 100644 --- a/player/src/main/kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt +++ b/player/src/main/kotlin/com/tidal/sdk/player/di/StreamingApiModule.kt @@ -9,6 +9,7 @@ import com.tidal.sdk.player.streamingapi.StreamingApiTimeoutConfig import dagger.Module import dagger.Provides import dagger.Reusable +import javax.inject.Named import javax.inject.Singleton import okhttp3.OkHttpClient @@ -26,6 +27,7 @@ internal object StreamingApiModule { apiErrorFactory: ApiError.Factory, offlinePlayProvider: OfflinePlayProvider?, credentialsProvider: CredentialsProvider, + @Named("useTopPlaybackInfo") useTopPlaybackInfo: Boolean, ) = StreamingApiModuleRoot( okHttpClient, @@ -34,6 +36,7 @@ internal object StreamingApiModule { apiErrorFactory, offlinePlayProvider?.offlinePlaybackInfoProvider, credentialsProvider, + useTopPlaybackInfo, ) .streamingApi } diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefault.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefault.kt index 3bacd437..5ca31056 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefault.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefault.kt @@ -17,6 +17,7 @@ import com.tidal.sdk.player.streamingapi.playbackinfo.repository.PlaybackInfoRep internal class StreamingApiDefault( private val playbackInfoRepository: PlaybackInfoRepository, private val drmLicenseRepository: DrmLicenseRepository, + private val useTopPlaybackInfo: Boolean, ) : StreamingApi { override suspend fun getTrackPlaybackInfo( @@ -27,14 +28,25 @@ internal class StreamingApiDefault( streamingSessionId: String, playlistUuid: String?, ) = - playbackInfoRepository.getTrackPlaybackInfo( - trackId, - audioQuality, - playbackMode, - immersiveAudio, - streamingSessionId, - playlistUuid, - ) + if (useTopPlaybackInfo) { + playbackInfoRepository.getTrackPlaybackInfoTop( + trackId, + audioQuality, + playbackMode, + immersiveAudio, + streamingSessionId, + playlistUuid, + ) + } else { + playbackInfoRepository.getTrackPlaybackInfo( + trackId, + audioQuality, + playbackMode, + immersiveAudio, + streamingSessionId, + playlistUuid, + ) + } override suspend fun getVideoPlaybackInfo( videoId: String, diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiModuleRoot.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiModuleRoot.kt index 1d42bec9..e9d22cc7 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiModuleRoot.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiModuleRoot.kt @@ -14,6 +14,7 @@ class StreamingApiModuleRoot( apiErrorFactory: ApiError.Factory, offlinePlaybackInfoProvider: OfflinePlaybackInfoProvider?, credentialsProvider: CredentialsProvider, + useTopPlaybackInfo: Boolean, ) { val streamingApi = @@ -25,6 +26,7 @@ class StreamingApiModuleRoot( apiErrorFactory, offlinePlaybackInfoProvider, credentialsProvider, + useTopPlaybackInfo, ) .streamingApi } diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiComponent.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiComponent.kt index b60572aa..bae34d8e 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiComponent.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiComponent.kt @@ -8,6 +8,7 @@ import com.tidal.sdk.player.streamingapi.StreamingApiTimeoutConfig import com.tidal.sdk.player.streamingapi.playbackinfo.offline.OfflinePlaybackInfoProvider import dagger.BindsInstance import dagger.Component +import javax.inject.Named import javax.inject.Qualifier import javax.inject.Singleton import okhttp3.OkHttpClient @@ -36,6 +37,7 @@ interface StreamingApiComponent { @BindsInstance apiErrorFactory: ApiError.Factory, @BindsInstance offlinePlaybackInfoProvider: OfflinePlaybackInfoProvider?, @BindsInstance credentialsProvider: CredentialsProvider, + @BindsInstance @Named("useTopPlaybackInfo") useTopPlaybackInfo: Boolean, ): StreamingApiComponent } diff --git a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt index a185311e..dcea6fb2 100644 --- a/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt +++ b/player/streaming-api/src/main/kotlin/com/tidal/sdk/player/streamingapi/di/StreamingApiModule.kt @@ -14,6 +14,7 @@ import com.tidal.sdk.tidalapi.generated.apis.TrackManifests import dagger.Module import dagger.Provides import dagger.Reusable +import javax.inject.Named import retrofit2.Converter import retrofit2.converter.gson.GsonConverterFactory @@ -58,5 +59,7 @@ internal object StreamingApiModule { fun streamingApiDefault( playbackInfoRepository: PlaybackInfoRepository, drmLicenseRepository: DrmLicenseRepository, - ): StreamingApi = StreamingApiDefault(playbackInfoRepository, drmLicenseRepository) + @Named("useTopPlaybackInfo") useTopPlaybackInfo: Boolean, + ): StreamingApi = + StreamingApiDefault(playbackInfoRepository, drmLicenseRepository, useTopPlaybackInfo) } diff --git a/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefaultTest.kt b/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefaultTest.kt index 194bd2ac..2dc9d8ba 100644 --- a/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefaultTest.kt +++ b/player/streaming-api/src/test/kotlin/com/tidal/sdk/player/streamingapi/StreamingApiDefaultTest.kt @@ -65,6 +65,7 @@ internal class StreamingApiDefaultTest { gson = gson, offlinePlaybackInfoProvider = OfflinePlaybackInfoProviderStub(), credentialsProvider = credentialsProviderMock, + useTopPlaybackInfo = false, ) .streamingApi }