@@ -23,7 +23,7 @@ import org.jitsi.mediajson.MediaFormat
2323import org.jitsi.mediajson.Start
2424import org.jitsi.mediajson.StartEvent
2525import org.jitsi.nlj.PacketInfo
26- import org.jitsi.nlj.format.PayloadType
26+ import org.jitsi.nlj.format.PayloadTypeEncoding
2727import org.jitsi.nlj.rtp.AudioRtpPacket
2828import org.jitsi.nlj.util.RtpSequenceIndexTracker
2929import 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