Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle the case where VLA-provided frame rate is less than the onstage preferred frame rate. #2268

Merged
merged 1 commit into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ class Av1DDRtpLayerDesc(
* {@inheritDoc}
*/
override fun toString(): String {
return "subjective_quality=" + index +
",DT=" + dt
return "subjective_quality=$index,DT=$dt,height=$height,frameRate=$frameRate"
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ constructor(
* {@inheritDoc}
*/
override fun toString(): String {
return "subjective_quality=$index,temporal_id=$tid,spatial_id=$sid,height=$height"
return "subjective_quality=$index,temporal_id=$tid,spatial_id=$sid,height=$height,frameRate=$frameRate"
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,26 @@ class VlaReaderNode(
vla.forEachIndexed { streamIdx, stream ->
val rtpEncoding = sourceDesc?.rtpEncodings?.get(streamIdx)
stream.spatialLayers.forEach { spatialLayer ->
val maxTl = spatialLayer.targetBitratesKbps.size - 1

spatialLayer.targetBitratesKbps.forEachIndexed { tlIdx, targetBitrateKbps ->
rtpEncoding?.layers?.find {
// With VP8 simulcast all layers have sid -1
(it.sid == spatialLayer.id || it.sid == -1) && it.tid == tlIdx
}?.let { layer ->
logger.debug(
logger.debug {
"Setting target bitrate for rtpEncoding=$rtpEncoding layer=$layer to " +
"${targetBitrateKbps.kbps} (res=${spatialLayer.res})"
)
}
layer.targetBitrate = targetBitrateKbps.kbps
spatialLayer.res?.let { res ->
if (layer.height > 0 && layer.height != res.height) {
logger.warn("Updating layer height from ${layer.height} to ${res.height}")
}
layer.height = res.height
layer.frameRate = res.maxFramerate.toDouble()
/* Presume 2:1 frame rate ratios for temporal layers */
val framerateFraction = 1.0 / (1 shl (maxTl - tlIdx))
layer.frameRate = res.maxFramerate.toDouble() * framerateFraction
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ internal class BandwidthAllocator<T : MediaSourceContainer>(

logger.trace {
"Allocating: sortedSources=${sortedSources.map { it.sourceName }}, " +
" effectiveConstraints=${newEffectiveConstraints.map { "${it.key.sourceName}=${it.value}" }}"
"effectiveConstraints=${newEffectiveConstraints.map { "${it.key.sourceName}=${it.value}" }}"
}

// Compute the bandwidth allocation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.jitsi.utils.event.SyncEventEmitter
import org.jitsi.utils.logging.DiagnosticContext
import org.jitsi.utils.logging.TimeSeriesLogger
import org.jitsi.utils.logging2.Logger
import org.jitsi.utils.logging2.createChildLogger
import org.jitsi.utils.secs
import org.jitsi.videobridge.cc.config.BitrateControllerConfig.Companion.config
import org.jitsi.videobridge.message.ReceiverVideoConstraintsMessage
Expand Down Expand Up @@ -53,6 +54,8 @@ class BitrateController<T : MediaSourceContainer> @JvmOverloads constructor(
) {
val eventEmitter = SyncEventEmitter<EventHandler>()

private val logger = createChildLogger(parentLogger)

private val bitrateAllocatorEventHandler = BitrateAllocatorEventHandler()

/**
Expand Down Expand Up @@ -133,6 +136,9 @@ class BitrateController<T : MediaSourceContainer> @JvmOverloads constructor(
fun accept(packetInfo: PacketInfo): Boolean {
if (packetInfo.layeringChanged) {
// This needs to be done synchronously, so it's complete before the accept, below.
logger.debug {
"Layering information changed for packet from ${packetInfo.endpointId}, updating bandwidth allocation"
}
bandwidthAllocator.update()
}
return packetHandler.accept(packetInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.jitsi.utils.logging2.LoggerImpl
import org.jitsi.videobridge.cc.config.BitrateControllerConfig.Companion.config
import java.lang.Integer.max
import java.time.Clock
import kotlin.math.min

/**
* A bitrate allocation that pertains to a specific source. This is the internal representation used in the allocation
Expand Down Expand Up @@ -68,6 +69,7 @@ internal class SingleSourceAllocation(
}
timeSeriesLogger.trace(ratesTimeSeriesPoint)
}
logger.addContext(mapOf("remote_endpoint_id" to endpointId))
}

fun isOnStage() = onStage
Expand Down Expand Up @@ -294,9 +296,15 @@ internal class SingleSourceAllocation(
* oversending.
*/
private fun selectLayersForCamera(layers: List<LayerSnapshot>, constraints: VideoConstraints): Layers {
val minHeight = layers.map { it.layer.height }.minOrNull() ?: return Layers.noLayers
val minHeight = layers.minOfOrNull { it.layer.height } ?: return Layers.noLayers
val maxFps = layers.maxOfOrNull { it.layer.frameRate } ?: return Layers.noLayers
val noActiveLayers = layers.none { (_, bitrate) -> bitrate > 0 }
val (preferredHeight, preferredFps) = getPreferred(constraints)
val effectivePreferredFps = if (maxFps > 0) {
min(maxFps, preferredFps)
} else {
preferredFps
}

val ratesList: MutableList<LayerSnapshot> = ArrayList()
// Initialize the list of layers to be considered. These are the layers that satisfy the constraints, with
Expand All @@ -306,7 +314,7 @@ internal class SingleSourceAllocation(
val lessThanPreferredHeight = layer.height < preferredHeight
val lessThanOrEqualMaxHeight = layer.height <= constraints.maxHeight || !constraints.heightIsLimited()
// If frame rate is unknown, consider it to be sufficient.
val atLeastPreferredFps = layer.frameRate < 0 || layer.frameRate >= preferredFps
val atLeastPreferredFps = layer.frameRate < 0 || layer.frameRate >= effectivePreferredFps
if (lessThanPreferredHeight ||
(lessThanOrEqualMaxHeight && atLeastPreferredFps) ||
layer.height == minHeight
Expand All @@ -321,6 +329,11 @@ internal class SingleSourceAllocation(

val effectivePreferredHeight = max(preferredHeight, minHeight)
val preferredIndex = ratesList.lastIndexWhich { it.layer.height <= effectivePreferredHeight }
logger.trace {
"Selected rates list $ratesList, preferred index $preferredIndex " +
"from layers $layers with constraints $constraints"
}

return Layers(ratesList, preferredIndex, -1)
}

Expand Down
Loading