Skip to content

Commit c40d8c8

Browse files
committed
feat: Send StartEvent if encoding type changes for an SSRC.
1 parent a2e3ff4 commit c40d8c8

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

jvb/src/main/kotlin/org/jitsi/videobridge/export/ExporterWrapper.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package org.jitsi.videobridge.export
1717

1818
import org.jitsi.mediajson.TranscriptionResultEvent
1919
import org.jitsi.nlj.PacketInfo
20-
import org.jitsi.nlj.format.OpusPayloadType
2120
import org.jitsi.nlj.rtp.AudioRtpPacket
2221
import org.jitsi.utils.logging2.Logger
2322
import org.jitsi.utils.logging2.createChildLogger

jvb/src/main/kotlin/org/jitsi/videobridge/export/MediaJsonSerializer.kt

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import org.jitsi.mediajson.MediaFormat
2323
import org.jitsi.mediajson.Start
2424
import org.jitsi.mediajson.StartEvent
2525
import org.jitsi.nlj.PacketInfo
26-
import org.jitsi.nlj.format.PayloadType
26+
import org.jitsi.nlj.format.PayloadTypeEncoding
2727
import org.jitsi.nlj.rtp.AudioRtpPacket
2828
import org.jitsi.nlj.util.RtpSequenceIndexTracker
2929
import org.jitsi.nlj.util.RtpTimestampIndexTracker
@@ -62,25 +62,47 @@ class MediaJsonSerializer(
6262
val state = ssrcsStarted.computeIfAbsent(p.ssrc) { ssrc ->
6363
SsrcState(
6464
p.timestamp,
65-
(Duration.between(ref, Clock.systemUTC().instant()).toNanos() * 48.0e-6).toLong()
65+
(
66+
Duration.between(ref, Clock.systemUTC().instant())
67+
.toNanos() * (packetInfo.payloadType?.clockRate?.toDouble() ?: 48000.0) * 1e-9
68+
).toLong(),
69+
packetInfo.encoding()
6670
).also {
6771
logger.info("Starting SSRC $ssrc for endpoint $epId ")
68-
handleEvent(createStart(epId, ssrc, packetInfo.payloadType))
72+
handleEvent(createStart(epId, ssrc, it.encoding))
6973
}
7074
}
7175

76+
if ((packetInfo.payloadType?.encoding ?: PayloadTypeEncoding.OPUS) != state.encoding.payloadTypeEncoding) {
77+
if (state.encodingChanges >= MAX_ENCODING_CHANGES) {
78+
logger.warn("SSRC ${p.ssrc} has changed format more than $MAX_ENCODING_CHANGES times, ignoring")
79+
return@synchronized
80+
}
81+
logger.info("SSRC ${p.ssrc} changed format from ${state.encoding} to ${packetInfo.encoding()}")
82+
ssrcsStarted[p.ssrc] = SsrcState(
83+
p.timestamp,
84+
(
85+
Duration.between(ref, Clock.systemUTC().instant())
86+
.toNanos() * (packetInfo.payloadType?.clockRate?.toDouble() ?: 48000.0) * 1e-9
87+
).toLong(),
88+
packetInfo.encoding(),
89+
state.encodingChanges + 1
90+
)
91+
handleEvent(createStart(epId, p.ssrc, state.encoding))
92+
}
93+
7294
handleEvent(encodeMedia(p, state, epId))
7395
}
7496

75-
private fun createStart(epId: String, ssrc: Long, payloadType: PayloadType?) = StartEvent(
97+
private fun createStart(epId: String, ssrc: Long, encoding: Encoding) = StartEvent(
7698
++seq,
7799
Start(
78100
"$epId-$ssrc",
79101
MediaFormat(
80-
payloadType?.encoding?.toString()?.lowercase() ?:"opus",
81-
payloadType?.clockRate ?:48000,
82-
2,
83-
payloadType?.parameters
102+
encoding.payloadTypeEncoding.name,
103+
encoding.clockRate,
104+
encoding.channels,
105+
encoding.parameters
84106
),
85107
CustomParameters(endpointId = epId)
86108
)
@@ -104,11 +126,34 @@ class MediaJsonSerializer(
104126
initialRtpTimestamp: Long,
105127
// Offset of this SSRC since the start time in RTP units
106128
startOffset: Long,
129+
val encoding: Encoding,
130+
val encodingChanges: Int = 0
107131
) {
108132
private val seqIndexTracker = RtpSequenceIndexTracker()
109133
private val timestampIndexTracker = RtpTimestampIndexTracker().apply { update(initialRtpTimestamp) }
110134
private val offset = startOffset - initialRtpTimestamp
111135
fun getTimestamp(rtpTimestamp: Long): Long = offset + timestampIndexTracker.update(rtpTimestamp)
112136
fun getSequenceNumber(seq: Int) = seqIndexTracker.update(seq).toInt()
113137
}
138+
139+
private data class Encoding(
140+
val payloadTypeEncoding: PayloadTypeEncoding,
141+
val clockRate: Int,
142+
val channels: Int,
143+
val parameters: Map<String, String>?
144+
)
145+
146+
private fun PacketInfo.encoding(): Encoding {
147+
return Encoding(
148+
payloadType?.encoding ?: PayloadTypeEncoding.OPUS,
149+
payloadType?.clockRate ?: 48000,
150+
if (payloadType?.encoding == null || payloadType?.encoding == PayloadTypeEncoding.OPUS) 2 else 1,
151+
payloadType?.parameters
152+
)
153+
}
154+
155+
companion object {
156+
// Maximum number of times that an SSRC is allowed to change its format
157+
const val MAX_ENCODING_CHANGES = 50
158+
}
114159
}

0 commit comments

Comments
 (0)