1 /**
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <RtcpXrEncoder.h>
18 #include <RtcpConfig.h>
19 #include <ImsMediaTrace.h>
20 #include <limits.h>
21 #include <cmath>
22
RtcpXrEncoder()23 RtcpXrEncoder::RtcpXrEncoder()
24 {
25 mSsrc = 0;
26 mSamplingRate = 16;
27 mRoundTripDelay = 0;
28 mVoipLossCount = 0;
29 mVoipDiscardedCount = 0;
30 mVoipPktCount = 0;
31 mVoipLostCountInBurst = 0;
32 mJitterBufferNominal = 0;
33 mJitterBufferMax = 0;
34 mJitterBufferAbsMax = 0;
35 mVoipC11 = 0;
36 mVoipC13 = 0;
37 mVoipC14 = 0;
38 mVoipC22 = 0;
39 mVoipC23 = 0;
40 mVoipC33 = 0;
41 mVoipC31 = 0;
42 mVoipC32 = 0;
43 }
44
~RtcpXrEncoder()45 RtcpXrEncoder::~RtcpXrEncoder() {}
46
setSsrc(const uint32_t ssrc)47 void RtcpXrEncoder::setSsrc(const uint32_t ssrc)
48 {
49 mSsrc = ssrc;
50 }
51
setSamplingRate(const uint32_t rate)52 void RtcpXrEncoder::setSamplingRate(const uint32_t rate)
53 {
54 IMLOGD1("[setSamplingRate] rate[%d]", rate);
55 mSamplingRate = rate;
56 }
57
setRoundTripDelay(const uint32_t delay)58 void RtcpXrEncoder::setRoundTripDelay(const uint32_t delay)
59 {
60 IMLOGD1("[setRoundTripDelay] delay[%d]", delay);
61 mRoundTripDelay = delay;
62 }
63
stackRxRtpStatus(const int32_t status,const uint32_t delay)64 void RtcpXrEncoder::stackRxRtpStatus(const int32_t status, const uint32_t delay)
65 {
66 bool packetLost = false;
67 bool packetDiscarded = false;
68
69 if (status == kRtpStatusLost)
70 {
71 mVoipLossCount++;
72 packetLost = true;
73 }
74 else if (status == kRtpStatusLate || status == kRtpStatusDiscarded ||
75 status == kRtpStatusDuplicated)
76 {
77 mVoipDiscardedCount++;
78 packetDiscarded = true;
79 }
80
81 if (!packetLost && !packetDiscarded)
82 {
83 mVoipPktCount++;
84 }
85 else
86 {
87 if (mVoipPktCount >= G_MIN_THRESHOLD)
88 {
89 if (mVoipLostCountInBurst == 1)
90 {
91 mVoipC14++;
92 }
93 else
94 {
95 mVoipC13++;
96 }
97
98 mVoipLostCountInBurst = 1;
99 mVoipC11 += mVoipPktCount;
100 }
101 else
102 {
103 mVoipLostCountInBurst++;
104
105 if (mVoipPktCount == 0)
106 {
107 mVoipC33++;
108 }
109 else
110 {
111 mVoipC23++;
112 mVoipC22 += (mVoipPktCount - 1);
113 }
114 }
115
116 mVoipPktCount = 0;
117 }
118
119 if (status == kRtpStatusNormal && delay > mJitterBufferMax)
120 {
121 mJitterBufferMax = delay;
122 }
123
124 IMLOGD_PACKET8(IM_PACKET_LOG_RTCP,
125 "[stackRxRtpStatus] lost[%d], discarded[%d], C11[%d], C13[%d], C14[%d], C22[%d], "
126 "C23[%d], C33[%d]",
127 packetLost, packetDiscarded, mVoipC11, mVoipC13, mVoipC14, mVoipC22, mVoipC23,
128 mVoipC33);
129 }
130
setJitterBufferStatus(const uint32_t current,const uint32_t max)131 void RtcpXrEncoder::setJitterBufferStatus(const uint32_t current, const uint32_t max)
132 {
133 IMLOGD_PACKET2(
134 IM_PACKET_LOG_RTCP, "[setJitterBufferStatus] current[%d], max[%d]", current, max);
135 mJitterBufferNominal = current;
136 mJitterBufferAbsMax = max;
137 }
138
createRtcpXrReport(const uint32_t rtcpXrReport,std::list<RtpPacket * > * packets,std::list<LostPacket * > * lostPackets,uint16_t beginSeq,uint16_t endSeq,uint8_t * data,uint32_t & size)139 bool RtcpXrEncoder::createRtcpXrReport(const uint32_t rtcpXrReport, std::list<RtpPacket*>* packets,
140 std::list<LostPacket*>* lostPackets, uint16_t beginSeq, uint16_t endSeq, uint8_t* data,
141 uint32_t& size)
142 {
143 size = 0;
144
145 if (data == nullptr || rtcpXrReport == RtcpConfig::FLAG_RTCPXR_NONE)
146 {
147 return false;
148 }
149
150 uint8_t* buffer = data;
151
152 if (rtcpXrReport & RtcpConfig::FLAG_RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK)
153 {
154 tLossReport* lossReport = createLossAnalysisReport(packets, lostPackets, beginSeq, endSeq);
155 tJitterReport* jitterReport = createJitterAnalysisReport(packets, beginSeq, endSeq);
156 tTTLReport* ttlReport = createTTLAnalysisReport(packets, beginSeq, endSeq);
157 tDuplicateReport* duplicateReport =
158 createDuplicateAnalysisReport(packets, beginSeq, endSeq);
159
160 encodeStatisticSummeryReport(lossReport, jitterReport, ttlReport, duplicateReport, buffer);
161
162 if (lossReport != nullptr)
163 {
164 delete lossReport;
165 }
166
167 if (jitterReport != nullptr)
168 {
169 delete jitterReport;
170 }
171
172 if (ttlReport != nullptr)
173 {
174 delete ttlReport;
175 }
176
177 if (duplicateReport != nullptr)
178 {
179 delete duplicateReport;
180 }
181
182 size += BLOCK_LENGTH_STATISTICS;
183 }
184
185 if (rtcpXrReport & RtcpConfig::FLAG_RTCPXR_VOIP_METRICS_REPORT_BLOCK)
186 {
187 tVoIPMatricReport* voipReport = createVoIPMatricReport();
188 encodeVoipMetricReport(voipReport, buffer + size);
189 size += BLOCK_LENGTH_STATISTICS;
190
191 if (voipReport != nullptr)
192 {
193 delete voipReport;
194 }
195 }
196
197 IMLOGD_PACKET2(IM_PACKET_LOG_RTCP, "[createRtcpXrReport] rtcpXrReport[%d], size[%d]",
198 rtcpXrReport, size);
199
200 return (size > 0);
201 }
202
createLossAnalysisReport(std::list<RtpPacket * > * packets,std::list<LostPacket * > * lostPackets,uint16_t beginSeq,uint16_t endSeq)203 tLossReport* RtcpXrEncoder::createLossAnalysisReport(std::list<RtpPacket*>* packets,
204 std::list<LostPacket*>* lostPackets, uint16_t beginSeq, uint16_t endSeq)
205 {
206 tLossReport* report = new tLossReport();
207 report->beginSeq = beginSeq;
208 report->endSeq = endSeq;
209 report->numLostPackets = 0;
210 report->numPacketsReceived = 0;
211
212 for (const auto& packet : *packets)
213 {
214 if (packet->seqNum >= beginSeq && packet->seqNum <= endSeq)
215 {
216 report->numPacketsReceived++;
217 }
218 }
219
220 for (const auto& packet : *lostPackets)
221 {
222 if (packet->seqNum >= beginSeq && packet->seqNum <= endSeq)
223 {
224 for (int32_t i = 0; i < packet->numLoss; i++)
225 {
226 if (packet->seqNum + i > endSeq)
227 {
228 break;
229 }
230
231 report->numLostPackets++;
232 }
233 }
234 }
235
236 IMLOGD_PACKET4(IM_PACKET_LOG_RTCP,
237 "[createLossAnalysisReport] begin[%d], end[%d], lost[%d], received[%d]", beginSeq,
238 endSeq, report->numLostPackets, report->numPacketsReceived);
239
240 return report;
241 }
242
createJitterAnalysisReport(std::list<RtpPacket * > * packets,uint16_t beginSeq,uint16_t endSeq)243 tJitterReport* RtcpXrEncoder::createJitterAnalysisReport(
244 std::list<RtpPacket*>* packets, uint16_t beginSeq, uint16_t endSeq)
245 {
246 tJitterReport* report = new tJitterReport();
247 report->beginSeq = beginSeq;
248 report->endSeq = endSeq;
249
250 report->minJitter = INT_MAX;
251 report->maxJitter = INT_MIN;
252 int64_t sumJitter = 0;
253 int64_t sumJitterSqr = 0;
254 uint32_t count = 0;
255
256 for (const auto& packet : *packets)
257 {
258 if (packet->seqNum >= beginSeq && packet->seqNum <= endSeq)
259 {
260 // change units from ms to timestamp
261 int32_t jitter = packet->jitter * mSamplingRate;
262 // min
263 if (jitter < report->minJitter)
264 {
265 report->minJitter = jitter;
266 }
267
268 // max
269 if (jitter > report->maxJitter)
270 {
271 report->maxJitter = jitter;
272 }
273
274 sumJitter += jitter;
275 sumJitterSqr += jitter * jitter;
276 count++;
277 }
278 }
279
280 count == 0 ? report->meanJitter = 0 : report->meanJitter = (double)sumJitter / count;
281
282 report->devJitter = (int32_t)sqrt((double)(sumJitterSqr) / count -
283 (double)(sumJitter) / count * (double)(sumJitter) / count);
284
285 IMLOGD6("[createJitterAnalysisReport] begin[%d], end[%d], min[%d], max[%d], mean[%d], dev[%d]",
286 beginSeq, endSeq, report->minJitter, report->maxJitter, report->meanJitter,
287 report->devJitter);
288
289 return report;
290 }
291
createTTLAnalysisReport(std::list<RtpPacket * > * packets,uint16_t beginSeq,uint16_t endSeq)292 tTTLReport* RtcpXrEncoder::createTTLAnalysisReport(
293 std::list<RtpPacket*>* packets, uint16_t beginSeq, uint16_t endSeq)
294 {
295 (void)packets;
296 tTTLReport* report = new tTTLReport();
297 report->beginSeq = beginSeq;
298 report->endSeq = endSeq;
299
300 // TODO: add implementation
301 report->minTTL = 0;
302 report->meanTTL = 0;
303 report->maxTTL = 0;
304 report->devTTL = 0;
305
306 IMLOGD6("[createTTLAnalysisReport] begin[%d], end[%d], min[%d], max[%d], mean[%d], dev[%d]",
307 beginSeq, endSeq, report->minTTL, report->maxTTL, report->meanTTL, report->devTTL);
308
309 return report;
310 }
311
createDuplicateAnalysisReport(std::list<RtpPacket * > * packets,uint16_t beginSeq,uint16_t endSeq)312 tDuplicateReport* RtcpXrEncoder::createDuplicateAnalysisReport(
313 std::list<RtpPacket*>* packets, uint16_t beginSeq, uint16_t endSeq)
314 {
315 tDuplicateReport* report = new tDuplicateReport();
316 report->beginSeq = beginSeq;
317 report->endSeq = endSeq;
318 report->numDuplicatedPackets = 0;
319 report->numPacketsReceived = 0;
320
321 for (const auto& packet : *packets)
322 {
323 if (packet->seqNum >= beginSeq && packet->seqNum <= endSeq)
324 {
325 if (packet->status == kRtpStatusDuplicated)
326 {
327 report->numDuplicatedPackets++;
328 }
329
330 report->numPacketsReceived++;
331 }
332 }
333
334 IMLOGD4("[createDuplicateAnalysisReport] begin[%d], end[%d], dup[%d], received[%d]", beginSeq,
335 endSeq, report->numDuplicatedPackets, report->numPacketsReceived);
336
337 return report;
338 }
339
createVoIPMatricReport()340 tVoIPMatricReport* RtcpXrEncoder::createVoIPMatricReport()
341 {
342 double p32 = 0;
343 double p23 = 0;
344
345 /** consider it is gap in case of (b) the period from the end of the last burst to either the
346 time of the report in RFC3611 4.7.2. */
347 if (mVoipPktCount != 0)
348 {
349 mVoipC11 += mVoipPktCount;
350 mVoipPktCount = 0;
351 }
352
353 // Calculate additional transition counts.
354 mVoipC31 = mVoipC13;
355 mVoipC32 = mVoipC23;
356 uint32_t cTotal =
357 mVoipC11 + mVoipC14 + mVoipC13 + mVoipC22 + mVoipC23 + mVoipC31 + mVoipC32 + mVoipC33;
358
359 // Calculate burst and densities.
360 if (mVoipC32 == 0 || (mVoipC31 + mVoipC32 + mVoipC33) == 0)
361 {
362 p32 = 0;
363 }
364 else
365 {
366 p32 = static_cast<double>(mVoipC32) / (mVoipC31 + mVoipC32 + mVoipC33);
367 }
368
369 if ((mVoipC22 + mVoipC23) == 0)
370 {
371 p23 = 0;
372 }
373 else
374 {
375 p23 = 1 - static_cast<double>(mVoipC22) / (mVoipC22 + mVoipC23);
376 }
377
378 IMLOGD3("[createVoIPMatricReport] cTotal[%d], P23[%lf], P32[%lf]", cTotal, p23, p32);
379
380 tVoIPMatricReport* report = new tVoIPMatricReport();
381 report->ssrc = mSsrc;
382 /* calculate loss and discard rates */
383 report->lossRate = 255 * (double)mVoipLossCount / cTotal;
384 report->discardRate = 255 * (double)mVoipDiscardedCount / cTotal;
385 report->burstDensity = 255 * (double)p23 / (p23 + p32);
386 report->gapDensity = 255 * (double)mVoipC14 / (mVoipC11 + mVoipC14);
387 // Calculate burst and gap durations in ms
388 uint32_t denum = 0;
389 mVoipC13 == 0 ? denum = 1 : denum = mVoipC13;
390 report->gapDuration = (mVoipC11 + mVoipC14 + mVoipC13) * 20 / denum;
391 report->burstDuration = cTotal * 20 / denum - report->gapDuration;
392 // get it from the rtp stack
393 report->roundTripDelay = mRoundTripDelay;
394 // not implemented yet
395 report->endSystemDelay = 0;
396 // sound signal quality - not support
397 report->signalLevel = 0;
398 report->noiseLevel = 0;
399 report->rerl = 0;
400 report->gMin = G_MIN_THRESHOLD;
401 // call quaility - not support
402 report->rFactor = 0;
403 report->extRFactor = 0;
404 report->rxConfig = 127;
405 report->jitterBufferNominal = mJitterBufferNominal;
406 report->jitterBufferMaximum = mJitterBufferMax;
407 report->jitterBufferAbsMaximum = mJitterBufferAbsMax;
408
409 IMLOGD6("[createVoIPMatricReport] lossRate[%d], discardRate[%d], burstDensity[%d], "
410 "gapDensity[%d], gapDuration[%d], burstDuration[%d]",
411 report->lossRate, report->discardRate, report->burstDensity, report->gapDensity,
412 report->gapDuration, report->burstDuration);
413 IMLOGD3("[createVoIPMatricReport] JBNominal[%d], JBMax[%d], JBAbsMaximum[%d]",
414 report->jitterBufferNominal, report->jitterBufferMaximum,
415 report->jitterBufferAbsMaximum);
416 return report;
417 }
418
encodeStatisticSummeryReport(tLossReport * lossReport,tJitterReport * jitterReport,tTTLReport * ttlReport,tDuplicateReport * duplicateReport,uint8_t * data)419 void RtcpXrEncoder::encodeStatisticSummeryReport(tLossReport* lossReport,
420 tJitterReport* jitterReport, tTTLReport* ttlReport, tDuplicateReport* duplicateReport,
421 uint8_t* data)
422 {
423 /** The Statistics Summary Report* block format
424 0 1 2 3
425 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
426 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427 | Block Type = 6|L|D|J|ToH|rsvd.| block length = 9 |
428 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
429 | SSRC of source |
430 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
431 | begin_seq | end_seq |
432 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433 | lost_packets |
434 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435 | dup_packets |
436 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437 | min_jitter |
438 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
439 | max_jitter |
440 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
441 | mean_jitter |
442 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
443 | dev_jitter |
444 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
445 | min_ttl_or_hl | max_ttl_or_hl |mean_ttl_or_hl | dev_ttl_or_hl |
446 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
447 */
448 if (data == nullptr || lossReport == nullptr || jitterReport == nullptr ||
449 ttlReport == nullptr || duplicateReport == nullptr)
450 {
451 return;
452 }
453
454 memset(data, 0, BLOCK_LENGTH_STATISTICS);
455 mBitWriter.SetBuffer(data, BLOCK_LENGTH_STATISTICS);
456 mBitWriter.Write(6, 8);
457 // flag of lost and duplicated packets --> always set
458 mBitWriter.Write(1, 1);
459 mBitWriter.Write(1, 1);
460 // flag of jitter
461 mBitWriter.Write(1, 1);
462
463 // TTL and HL : 0 - not using, 1 - IPv4, 2 - IPv6, 3 must not used
464 if (ttlReport->ipVersion == -1)
465 {
466 mBitWriter.Write(0, 2);
467 }
468 else if (ttlReport->ipVersion == IPV4)
469 {
470 mBitWriter.Write(1, 2);
471 }
472 else
473 {
474 mBitWriter.Write(2, 2);
475 }
476
477 // padding
478 mBitWriter.Write(0, 3);
479 // block length
480 mBitWriter.Write(9, 16);
481 // ssrc of source
482 mBitWriter.WriteByteBuffer(mSsrc);
483 // sequence number
484 mBitWriter.Write(lossReport->beginSeq, 16);
485 mBitWriter.Write(lossReport->endSeq, 16);
486 // lost packets
487 mBitWriter.WriteByteBuffer(lossReport->numLostPackets);
488 // dup packets
489 mBitWriter.WriteByteBuffer(duplicateReport->numDuplicatedPackets);
490 IMLOGD6("[encodeStatisticSummeryReport] beginSeq[%hu], endSeq[%hu], nMinJitter[%d], "
491 "nMaxJitter[%d], nMeanJitter[%d], nDevJitter[%d]",
492 lossReport->beginSeq, lossReport->endSeq, jitterReport->minJitter,
493 jitterReport->maxJitter, jitterReport->meanJitter, jitterReport->devJitter);
494 // min, max, mean, dev jitter
495 mBitWriter.WriteByteBuffer(jitterReport->minJitter);
496 mBitWriter.WriteByteBuffer(jitterReport->maxJitter);
497 mBitWriter.WriteByteBuffer(jitterReport->meanJitter);
498 mBitWriter.WriteByteBuffer(jitterReport->devJitter);
499 IMLOGD4("[encodeStatisticSummeryReport] nMinTTL[%d], nMaxTTL[%d], "
500 "nMeanTTL[%d], nDevTTL[%d]",
501 ttlReport->minTTL, ttlReport->maxTTL, ttlReport->meanTTL, ttlReport->devTTL);
502 // min, max, mean, dev ttl/hl
503 mBitWriter.Write(ttlReport->minTTL, 8);
504 mBitWriter.Write(ttlReport->maxTTL, 8);
505 mBitWriter.Write(ttlReport->meanTTL, 8);
506 mBitWriter.Write(ttlReport->devTTL, 8);
507 }
508
encodeVoipMetricReport(tVoIPMatricReport * report,uint8_t * data)509 void RtcpXrEncoder::encodeVoipMetricReport(tVoIPMatricReport* report, uint8_t* data)
510 {
511 if (report == nullptr || data == nullptr)
512 {
513 return;
514 }
515
516 /** The VoIP Matircs Report block format
517 0 1 2 3
518 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
519 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
520 | BT=7 | reserved | block length = 8 |
521 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
522 | SSRC of source |
523 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
524 | loss rate | discard rate | burst density | gap density |
525 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
526 | burst duration | gap duration |
527 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
528 | round trip delay | end system delay |
529 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
530 | signal level | noise level | RERL | Gmin |
531 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
532 | R factor | ext. R factor | MOS-LQ | MOS-CQ |
533 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
534 | RX config | reserved | JB nominal |
535 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
536 | JB maximum | JB abs max |
537 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538 */
539 IMLOGD0("[encodeVoipMetricReport]");
540
541 memset(data, 0, BLOCK_LENGTH_VOIP_METRICS);
542 mBitWriter.SetBuffer(data, BLOCK_LENGTH_VOIP_METRICS);
543 mBitWriter.Write(7, 8);
544 mBitWriter.Write(0, 8);
545 // block length
546 mBitWriter.Write(8, 16);
547 // ssrc of source
548 mBitWriter.WriteByteBuffer(report->ssrc);
549 mBitWriter.Write(report->lossRate, 8);
550 mBitWriter.Write(report->discardRate, 8);
551 mBitWriter.Write(report->burstDensity, 8);
552 mBitWriter.Write(report->gapDensity, 8);
553 mBitWriter.Write(report->burstDuration, 16);
554 mBitWriter.Write(report->gapDuration, 16);
555 mBitWriter.Write(report->roundTripDelay, 16);
556 mBitWriter.Write(report->endSystemDelay, 16);
557 // signal level - 127 unavailable
558 mBitWriter.Write(127, 8);
559 mBitWriter.Write(127, 8);
560 mBitWriter.Write(127, 8);
561 mBitWriter.Write(report->gMin, 8);
562 // R factor - 127 unavailable
563 mBitWriter.Write(127, 8);
564 mBitWriter.Write(127, 8);
565 // MOS - 127 unavailable
566 mBitWriter.Write(127, 8);
567 mBitWriter.Write(127, 8);
568 // receiver configuration byte(Rx Config)
569 mBitWriter.Write(report->rxConfig, 8);
570 mBitWriter.Write(0, 8);
571 // Jitter Buffer - milliseconds
572 mBitWriter.Write(report->jitterBufferNominal, 16);
573 mBitWriter.Write(report->jitterBufferMaximum, 16);
574 mBitWriter.Write(report->jitterBufferAbsMaximum, 16);
575 }
576