davidliu
Committed by GitHub

Allow setting of degradation preference (#420)

* Allow setting of degradation preference

* fix tests

* spotless
... ... @@ -465,7 +465,6 @@ internal fun isSVCCodec(codec: String?): Boolean {
/**
* @suppress
*/
@VisibleForTesting
data class TrackBitrateInfo(
val codec: String,
val maxBitrate: Long,
... ... @@ -474,7 +473,6 @@ data class TrackBitrateInfo(
/**
* @suppress
*/
@VisibleForTesting
sealed class TrackBitrateInfoKey {
data class Cid(val value: String) : TrackBitrateInfoKey()
data class Transceiver(val value: RtpTransceiver) : TrackBitrateInfoKey()
... ...
... ... @@ -31,7 +31,19 @@ import io.livekit.android.room.DefaultsManager
import io.livekit.android.room.RTCEngine
import io.livekit.android.room.TrackBitrateInfo
import io.livekit.android.room.isSVCCodec
import io.livekit.android.room.track.*
import io.livekit.android.room.track.DataPublishReliability
import io.livekit.android.room.track.LocalAudioTrack
import io.livekit.android.room.track.LocalAudioTrackOptions
import io.livekit.android.room.track.LocalScreencastVideoTrack
import io.livekit.android.room.track.LocalTrackPublication
import io.livekit.android.room.track.LocalVideoTrack
import io.livekit.android.room.track.LocalVideoTrackOptions
import io.livekit.android.room.track.Track
import io.livekit.android.room.track.TrackException
import io.livekit.android.room.track.TrackPublication
import io.livekit.android.room.track.VideoCaptureParameter
import io.livekit.android.room.track.VideoCodec
import io.livekit.android.room.track.VideoEncoding
import io.livekit.android.room.util.EncodingUtils
import io.livekit.android.util.LKLog
import io.livekit.android.webrtc.sortVideoCodecPreferences
... ... @@ -41,8 +53,14 @@ import livekit.LivekitModels
import livekit.LivekitRtc
import livekit.LivekitRtc.AddTrackRequest
import livekit.LivekitRtc.SimulcastCodec
import livekit.org.webrtc.*
import livekit.org.webrtc.EglBase
import livekit.org.webrtc.PeerConnectionFactory
import livekit.org.webrtc.RtpParameters
import livekit.org.webrtc.RtpTransceiver
import livekit.org.webrtc.RtpTransceiver.RtpTransceiverInit
import livekit.org.webrtc.SurfaceTextureHelper
import livekit.org.webrtc.VideoCapturer
import livekit.org.webrtc.VideoProcessor
import javax.inject.Named
import kotlin.math.max
... ... @@ -412,10 +430,14 @@ internal constructor(
}
}
// Set preferred video codec order
if (options is VideoTrackPublishOptions) {
// Set preferred video codec order
transceiver.sortVideoCodecPreferences(options.videoCodec, capabilitiesGetter)
(track as LocalVideoTrack).codec = options.videoCodec
val rtpParameters = transceiver.sender.parameters
rtpParameters.degradationPreference = options.degradationPreference
transceiver.sender.parameters = rtpParameters
}
val publication = LocalTrackPublication(
... ... @@ -877,6 +899,14 @@ abstract class BaseVideoTrackPublishOptions {
* will automatically publish a secondary track encoded with the backup codec.
*/
abstract val backupCodec: BackupVideoCodec?
/**
* When bandwidth is constrained, this preference indicates which is preferred
* between degrading resolution vs. framerate.
*
* null value indicates default value (maintain framerate).
*/
abstract val degradationPreference: RtpParameters.DegradationPreference?
}
data class VideoTrackPublishDefaults(
... ... @@ -885,6 +915,7 @@ data class VideoTrackPublishDefaults(
override val videoCodec: String = VideoCodec.VP8.codecName,
override val scalabilityMode: String? = null,
override val backupCodec: BackupVideoCodec? = null,
override val degradationPreference: RtpParameters.DegradationPreference? = null,
) : BaseVideoTrackPublishOptions()
data class VideoTrackPublishOptions(
... ... @@ -896,6 +927,7 @@ data class VideoTrackPublishOptions(
override val backupCodec: BackupVideoCodec? = null,
override val source: Track.Source? = null,
override val stream: String? = null,
override val degradationPreference: RtpParameters.DegradationPreference? = null,
) : BaseVideoTrackPublishOptions(), TrackPublishOptions {
constructor(
name: String? = null,
... ... @@ -911,6 +943,7 @@ data class VideoTrackPublishOptions(
backupCodec = base.backupCodec,
source = source,
stream = stream,
degradationPreference = base.degradationPreference,
)
fun createBackupOptions(): VideoTrackPublishOptions? {
... ...
... ... @@ -16,11 +16,30 @@
package io.livekit.android.test.mock
import livekit.org.webrtc.MockRtpParameters
import livekit.org.webrtc.RtpParameters
import livekit.org.webrtc.RtpSender
import org.mockito.Mockito
import org.mockito.kotlin.any
import org.mockito.kotlin.whenever
import java.util.UUID
object MockRtpSender {
fun create(): RtpSender {
return Mockito.mock(RtpSender::class.java)
var rtpParameters: RtpParameters = MockRtpParameters(
transactionId = UUID.randomUUID().toString(),
degradationPreference = null,
rtcp = MockRtpParameters.MockRtcp("", false),
headerExtensions = mutableListOf(),
encodings = mutableListOf(),
codecs = mutableListOf(),
)
return Mockito.mock(RtpSender::class.java).apply {
whenever(this.parameters).thenAnswer { rtpParameters }
whenever(this.setParameters(any())).thenAnswer {
rtpParameters = it.getArgument(0)
true
}
}
}
}
... ...
/*
* Copyright 2024 LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package livekit.org.webrtc
class MockRtpParameters(
transactionId: String?,
degradationPreference: DegradationPreference?,
rtcp: Rtcp?,
headerExtensions: MutableList<HeaderExtension>?,
encodings: MutableList<Encoding>?,
codecs: MutableList<Codec>?,
) : RtpParameters(transactionId, degradationPreference, rtcp, headerExtensions, encodings, codecs) {
class MockRtcp(cname: String?, reducedSize: Boolean) : Rtcp(cname, reducedSize)
class MockHeaderExtension(uri: String?, id: Int, encrypted: Boolean) : HeaderExtension(uri, id, encrypted)
class MockCodec(payloadType: Int, name: String?, kind: MediaStreamTrack.MediaType?, clockRate: Int?, numChannels: Int?, parameters: MutableMap<String, String>?) :
Codec(payloadType, name, kind, clockRate, numChannels, parameters)
}
... ...
... ... @@ -40,6 +40,7 @@ import livekit.LivekitModels
import livekit.LivekitRtc
import livekit.LivekitRtc.SubscribedCodec
import livekit.LivekitRtc.SubscribedQuality
import livekit.org.webrtc.RtpParameters
import livekit.org.webrtc.VideoSource
import org.junit.Assert.*
import org.junit.Test
... ... @@ -333,4 +334,18 @@ class LocalParticipantMockE2ETest : MockE2ETest() {
},
)
}
@Test
fun publishDegradationPreferences() = runTest {
val preference = RtpParameters.DegradationPreference.DISABLED
room.videoTrackPublishDefaults = room.videoTrackPublishDefaults.copy(degradationPreference = preference)
connect()
room.localParticipant.publishVideoTrack(track = createLocalTrack())
val peerConnection = getPublisherPeerConnection()
val transceiver = peerConnection.transceivers.first()
assertEquals(preference, transceiver.sender.parameters.degradationPreference)
}
}
... ...