Skip to content

Commit

Permalink
Add media source selection
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsvanvelzen committed May 11, 2024
1 parent d48c1e6 commit 45d0d18
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.jellyfin.playback.core.mediastream.PlayableMediaStream
import org.jellyfin.playback.core.queue.QueueEntry
import org.jellyfin.playback.core.support.PlaySupportReport
import org.jellyfin.playback.jellyfin.queue.baseItem
import org.jellyfin.playback.jellyfin.queue.mediaSourceId
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.audioApi
import org.jellyfin.sdk.api.client.extensions.dynamicHlsApi
Expand Down Expand Up @@ -54,7 +55,7 @@ class AudioMediaStreamResolver(
val baseItem = queueEntry.baseItem
if (baseItem == null || baseItem.mediaType != MediaType.Audio) return null

val mediaInfo = getPlaybackInfo(baseItem)
val mediaInfo = getPlaybackInfo(baseItem, queueEntry.mediaSourceId)

// Test for direct play support
val directPlayStream = mediaInfo.getDirectPlayStream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.mediaInfoApi
import org.jellyfin.sdk.model.api.BaseItemDto
import org.jellyfin.sdk.model.api.DeviceProfile
import org.jellyfin.sdk.model.api.MediaProtocol
import org.jellyfin.sdk.model.api.MediaSourceInfo
import org.jellyfin.sdk.model.api.PlaybackInfoDto

Expand All @@ -19,41 +20,41 @@ abstract class JellyfinStreamResolver(

protected suspend fun getPlaybackInfo(
item: BaseItemDto,
mediaSource: MediaSourceInfo? = null,
mediaSourceId: String? = null,
): MediaInfo {
val response by api.mediaInfoApi.getPostedPlaybackInfo(
itemId = item.id,
data = PlaybackInfoDto(
userId = api.userId,
maxStreamingBitrate = profile.maxStreamingBitrate,
mediaSourceId = mediaSource?.id,
liveStreamId = mediaSource?.liveStreamId,
mediaSourceId = mediaSourceId,
deviceProfile = profile,
enableDirectPlay = true,
enableDirectStream = true,
enableTranscoding = true,
allowVideoStreamCopy = true,
allowAudioStreamCopy = true,
autoOpenLiveStream = true,
autoOpenLiveStream = false,
)
)

if (response.errorCode != null) {
error("Failed to get media info for item ${item.id} source ${mediaSource?.id}: ${response.errorCode}")
error("Failed to get media info for item ${item.id} source ${mediaSourceId}: ${response.errorCode}")
}

val responseMediaSource = when (mediaSource) {
null -> response.mediaSources.firstOrNull()
else -> response.mediaSources.firstOrNull { it.id === mediaSource.id }
}
val mediaSource = response.mediaSources
// Filter out invalid streams (like strm files)
.filter { it.protocol == MediaProtocol.FILE && !it.isRemote }
// Select first media source
.firstOrNull { mediaSourceId == null || it.id == mediaSourceId }

requireNotNull(responseMediaSource) {
"Failed to get media info for item ${item.id} source ${mediaSource?.id}: media source missing in response"
requireNotNull(mediaSource) {
"Failed to get media info for item ${item.id} source ${mediaSourceId}: media source missing in response"
}

return MediaInfo(
playSessionId = response.playSessionId.orEmpty(),
mediaSource = responseMediaSource
mediaSource = mediaSource
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.jellyfin.playback.core.mediastream.PlayableMediaStream
import org.jellyfin.playback.core.queue.QueueEntry
import org.jellyfin.playback.core.support.PlaySupportReport
import org.jellyfin.playback.jellyfin.queue.baseItem
import org.jellyfin.playback.jellyfin.queue.mediaSourceId
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.universalAudioApi
import org.jellyfin.sdk.model.api.BaseItemKind
Expand All @@ -22,7 +23,7 @@ class UniversalAudioMediaStreamResolver(
val baseItem = queueEntry.baseItem
if (baseItem == null || baseItem.type != BaseItemKind.AUDIO) return null

val mediaInfo = getPlaybackInfo(baseItem)
val mediaInfo = getPlaybackInfo(baseItem, queueEntry.mediaSourceId)

val url = api.universalAudioApi.getUniversalAudioStreamUrl(
itemId = baseItem.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.jellyfin.playback.core.mediastream.PlayableMediaStream
import org.jellyfin.playback.core.queue.QueueEntry
import org.jellyfin.playback.core.support.PlaySupportReport
import org.jellyfin.playback.jellyfin.queue.baseItem
import org.jellyfin.playback.jellyfin.queue.mediaSourceId
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.dynamicHlsApi
import org.jellyfin.sdk.api.client.extensions.videosApi
Expand Down Expand Up @@ -54,7 +55,7 @@ class VideoMediaStreamResolver(
val baseItem = queueEntry.baseItem
if (baseItem == null || baseItem.mediaType != MediaType.Video) return null

val mediaInfo = getPlaybackInfo(baseItem)
val mediaInfo = getPlaybackInfo(baseItem, queueEntry.mediaSourceId)

// Test for direct play support
val directPlayStream = mediaInfo.getDirectPlayStream()
Expand Down
13 changes: 13 additions & 0 deletions playback/jellyfin/src/main/kotlin/queue/mediaSourceIdElement.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.jellyfin.playback.jellyfin.queue

import org.jellyfin.playback.core.element.ElementKey
import org.jellyfin.playback.core.element.element
import org.jellyfin.playback.core.queue.QueueEntry

private val mediaSourceIdKey = ElementKey<String>("MediaSource")

/**
* Get or set the id of the MediaSource to use during playback. Or null for the default selection
* behavior.
*/
var QueueEntry.mediaSourceId by element(mediaSourceIdKey)

0 comments on commit 45d0d18

Please sign in to comment.