فهرست مقاله
شمارهٔ توالیِ ناپیوسته در دریافت صوت، بلافاصله به معنی از دست رفتن قطعی یک بسته نیست. شاید بستهٔ قبلی بعداً برسد، نسخهای تکراری دریافت شود یا شمارنده از انتهای دامنه عبور کرده باشد. در این درس هشت دریافت ساختگی را با پایتون ردگیری میکنیم تا هرکدام جدا ثبت شوند. داده از شبکه نیامده است و کد، گیرندهٔ RTP یا ابزار اندازهگیری تماس واقعی نیست.
۱. شکاف توالی را از زمان و موعد پخش جدا کنیم

ورودی هر دریافت فقط یک عدد صحیح بین صفر و ۶۵۵۳۵ است؛ آن را شمارهٔ روی سیم مینامیم. بهطور قراردادی فرض میکنیم همهٔ ورودیها متعلق به یک منبعِ ازپیشتعیینشدهاند. هیچ سرآیند، SSRC، صدای فشرده یا زمان ورود بررسی نمیشود. بخش ۵٫۱ از RFC 3550 شمارهٔ توالی RTP را شانزدهبیتی تعریف میکند؛ خواندن همان شماره با اعتبارسنجی کامل بسته برابر نیست.
کمیتی که اینجا گزارش میکنیم «شکاف یکتا در بازهٔ مشاهدهشده» است: از اولین شمارهٔ امتدادیِ پذیرفتهشده تا بزرگترین شماره، کدام شمارهها هنوز دیده نشدهاند؟ واحد شمارش، بسته است. دربارهٔ شمارههای پیش از اولین مشاهده یا پس از بزرگترین مشاهده چیزی استنتاج نمیکنیم. حتی شکاف داخل این بازه نیز ممکن است با دریافت بعدی پر شود؛ نام «گمشدهٔ دائمی» برای آن مناسب نیست.
در درس جیتر بینورودی RTP، زمان ورود و timestamp لازم بودند. اینجا هیچکدام وجود ندارند؛ بنابراین تأخیر، جیتر یا دیررسیدن نسبت به موعد صوت محاسبه نمیشود. تمایز ساده است: خارج از ترتیب بودنِ شماره میتواند بدون داشتن ساعت تشخیص داده شود، اما دیرشدن برای پخش به قرارداد زمانی جدا نیاز دارد.
۲. شمارندهٔ محدود را با فرض پذیرش روشن امتداد دهیم

تفریق معمولیِ ۶۵۵۳۵ از صفر، حرکت روبهجلوی شمارنده را به پرشی منفی تبدیل میکند. در مثال ما اختلاف نسبت به بزرگترین شمارهٔ فعلی، ابتدا پیمانهٔ ۶۵۵۳۶ گرفته میشود. اختلاف کمتر از ۳۲۷۶۸، نامزد حرکت جلو است؛ برای اختلاف بزرگتر، ۶۵۵۳۶ کم میکنیم تا نامزد حرکت عقب ساخته شود. اختلاف دقیقاً نیمدامنه مبهم است و رد میشود.
تفسیر پیمانهای بدون فرض کافی معتبر نیست. قرارداد خودمان حداکثر شانزده گام جلو و هشت گام عقب نسبت به بزرگترین شماره را میپذیرد؛ هر دو بسیار کمتر از نیمدامنهاند. عدد قبل از اولین شمارهٔ مشاهدهشده نیز رد میشود. این حدها انتخاب آموزشی ما هستند؛ الگوریتم اعتبارسنجی و شروع مجددِ پیوست A.1 را پیاده نمیکنیم و جهش بزرگ را به شروع مجدد حدس نمیزنیم.
برای هشت شمارهٔ روی سیم ۶۵۵۳۴، صفر، ۶۵۵۳۵، صفر، دو، یک، چهار، چهار، شمارههای امتدادی بهترتیب ۶۵۵۳۴، ۶۵۵۳۶، ۶۵۵۳۵، ۶۵۵۳۶، ۶۵۵۳۸، ۶۵۵۳۷، ۶۵۵۴۰ و ۶۵۵۴۰ میشوند. امتداد، عدد صحیح پایتون در همین بازهٔ کوچک است؛ فیلد سیودوبیتیِ گزارش RTCP تولید نمیشود و مبدأ واقعیِ چرخههای فرستنده معلوم نیست. قرارداد برای ردگیری بلندمدت یا شروع مجدد منبع، بازیابی خودکار تعریف نمیکند.
۳. بستهٔ خارج از ترتیب میتواند شکاف را پر کند

پس از دریافت دوم، بزرگترین شمارهٔ امتدادی ۶۵۵۳۶ است و شمارهٔ ۶۵۵۳۵ دیده نشده است. دریافت سوم دقیقاً همان شکاف را پر میکند؛ بزرگترین شماره عقب نمیرود. این دریافت تازه و خارج از ترتیب است. نسخهٔ بعدیِ صفر، همان ۶۵۵۳۶ قبلاًدیدهشده است و در دستهٔ تکراری قرار میگیرد.
در دریافت پنجم، شمارهٔ امتدادی ۶۵۵۳۸ دیده میشود و شکاف تازهٔ ۶۵۵۳۷ به وجود میآید. دریافت ششم آن را پر میکند. با رسیدن چهار، شکاف ۶۵۵۳۹ باقی میماند؛ روی سیم، آن شماره سه است. تعداد شکافها پس از هر دریافت برابر صفر، یک، صفر، صفر، یک، صفر، یک و یک است. این ردِ مرحلهای از گزارشِ صرفِ عدد پایانی قابلبررسیتر است.
RFC 4737 معیار ترتیبیِ عقبنرونده را توضیح میدهد و شکاف را از مشاهدهٔ واقعیِ دریافت خارج از ترتیب جدا میکند. ما فقط شمارندهٔ آموزشیِ دریافت تازهٔ خارج از ترتیب داریم؛ همهٔ سنجهها، پارامترهای آزمون یا معیار زمانی آن سند را اجرا نکردهایم. «تازه» مهم است، چون نسخهٔ تکراریِ همان بسته دوباره دریافت تازهٔ خارج از ترتیب محسوب نمیشود.
۴. تکرار را جدا بشماریم و کد را اجرا کنیم

بازهٔ نهایی از ۶۵۵۳۴ تا ۶۵۵۴۰، با احتساب دو سر، هفت جایگاه دارد. شش شمارهٔ یکتا در هشت دریافت پذیرفتهشده دیدهایم؛ دو دریافت تکراری و دو دریافت تازهٔ خارج از ترتیباند. فقط ۶۵۵۳۹ در مجموعه نیست. نسبت قراردادیِ شکاف یکتا یکهفتم است. دریافت تکراریِ چهار، هیچ شکافی را پر نمیکند.
تفاضل خامِ طول بازه و تعداد دریافتها، هفت منهای هشت، منفی یک است؛ این عدد با تعداد شکاف یکتا فرق دارد. بخش ۶٫۴٫۱ از RFC 3550 دربارهٔ اثر دریافت تکراری در حساب گزارش توضیح میدهد. خروجی ما گزارش RTCP، کسر اتلافِ فاصلهٔ گزارشها یا نرخ اتلاف شبکه نیست؛ یکهفتم و منفی یک را با همان نامهای محدود خودشان نگه میداریم.
"""Bounded synthetic 16-bit sequence audit for one already-assumed source.
Not an RTP parser/receiver/RTCP report or a network-loss/latency measurement.
"""
from fractions import Fraction
from itertools import permutations
import json
import platform
MODULUS = 65536
HALF = MODULUS // 2
MAX_FORWARD, MAX_REORDER, MAX_SPAN, MAX_EVENTS = 16, 8, 128, 256
class SequenceAudit:
def __init__(self):
self._base = self._highest = None
self._seen = set()
self._arrivals = self._duplicates = self._reordered_new = 0
def snapshot(self):
span = 0 if self._base is None else self._highest - self._base + 1
missing = [] if not span else [value for value in range(self._base, self._highest + 1)
if value not in self._seen]
return {'base_extended': self._base, 'highest_extended': self._highest,
'observed_span_packets': span, 'unique_received': len(self._seen),
'accepted_arrivals': self._arrivals, 'duplicates': self._duplicates,
'reordered_new': self._reordered_new, 'missing_extended': missing,
'missing_count': len(missing),
'unique_gap_fraction': str(Fraction(len(missing), span)) if span else None,
'span_minus_arrivals': span - self._arrivals}
def receive(self, wire_sequence):
if type(wire_sequence) is not int or not 0 <= wire_sequence < MODULUS:
raise ValueError('wire_sequence')
if self._arrivals >= MAX_EVENTS:
raise ValueError('event_limit')
if self._base is None:
extended = wire_sequence
status = 'first'
else:
forward = (wire_sequence - self._highest % MODULUS) % MODULUS
if forward == HALF:
raise ValueError('ambiguous_half_cycle')
delta = forward if forward < HALF else forward - MODULUS
extended = self._highest + delta
if extended < self._base:
raise ValueError('before_observed_base')
if delta > MAX_FORWARD:
raise ValueError('forward_window')
if -delta > MAX_REORDER:
raise ValueError('reorder_window')
if extended - self._base + 1 > MAX_SPAN:
raise ValueError('span_limit')
status = ('duplicate' if extended in self._seen else
'reordered' if extended < self._highest else 'new_high')
# No state changed until every contract check succeeds.
if self._base is None:
self._base = extended
if status == 'duplicate':
self._duplicates += 1
else:
self._seen.add(extended)
if status == 'reordered':
self._reordered_new += 1
self._highest = extended if self._highest is None else max(self._highest, extended)
self._arrivals += 1
return {'wire_sequence': wire_sequence, 'extended_sequence': extended,
'status': status, 'summary': self.snapshot()}
def known_sender_oracle(extended_values):
"""Independent prefix audit from known synthetic sender IDs, no unwrapping."""
trace = []
for index, current in enumerate(extended_values):
prefix = extended_values[:index + 1]
previous = extended_values[:index]
unique = set(prefix)
high, base = max(prefix), prefix[0]
missing = sorted(set(range(base, high + 1)) - unique)
reordered = sum(1 for i, value in enumerate(prefix)
if i and value not in prefix[:i] and value < max(prefix[:i]))
status = ('first' if not previous else 'duplicate' if current in previous else
'reordered' if current < max(previous) else 'new_high')
span = high - base + 1
trace.append({'wire_sequence': current % MODULUS, 'extended_sequence': current,
'status': status, 'summary': {'base_extended': base, 'highest_extended': high,
'observed_span_packets': span, 'unique_received': len(unique),
'accepted_arrivals': len(prefix), 'duplicates': len(prefix) - len(unique),
'reordered_new': reordered, 'missing_extended': missing,
'missing_count': len(missing), 'unique_gap_fraction': str(Fraction(len(missing), span)),
'span_minus_arrivals': span - len(prefix)}})
return trace
def rejected(call, message):
try:
call()
except ValueError as error:
return str(error) == message
return False
def run_example():
wire = [65534, 0, 65535, 0, 2, 1, 4, 4]
before_wire = list(wire)
audit = SequenceAudit()
trace = [audit.receive(value) for value in wire]
final = audit.snapshot()
known_extended = [65534, 65536, 65535, 65536, 65538, 65537, 65540, 65540]
advance = SequenceAudit(); advance.receive(100)
before_advance = advance.snapshot()
rejected_17 = rejected(lambda: advance.receive(117), 'forward_window')
unchanged_17 = advance.snapshot() == before_advance
accepted_16 = advance.receive(116)
reordered_8 = advance.receive(108)
before_reorder = advance.snapshot()
rejected_9 = rejected(lambda: advance.receive(107), 'reorder_window')
unchanged_9 = advance.snapshot() == before_reorder
ambiguity = SequenceAudit(); ambiguity.receive(100)
before_ambiguity = ambiguity.snapshot()
ambiguous_rejected = rejected(lambda: ambiguity.receive((100 + HALF) % MODULUS), 'ambiguous_half_cycle')
before_base = SequenceAudit(); before_base.receive(100)
prior_base = before_base.snapshot()
base_rejected = rejected(lambda: before_base.receive(99), 'before_observed_base')
invalid = SequenceAudit(); invalid.receive(100)
prior_invalid = invalid.snapshot()
invalid_rejected = all(rejected(lambda value=value: invalid.receive(value), 'wire_sequence')
for value in [-1, 65536, True, 1.0, '1', None])
span = SequenceAudit()
for value in [0, 16, 32, 48, 64, 80, 96, 112, 127]:
span.receive(value)
before_span = span.snapshot()
rejected_span = rejected(lambda: span.receive(128), 'span_limit')
events = SequenceAudit()
for _ in range(256):
events.receive(100)
before_events = events.snapshot()
rejected_events = rejected(lambda: events.receive(100), 'event_limit')
duplicate = SequenceAudit()
duplicate.receive(10); duplicate.receive(12)
repeated_gap = duplicate.receive(12)
fill = duplicate.receive(11)
repeated_fill = duplicate.receive(11)
oracle_cases, oracle_ok = 0, True
for base in [100, 65534]:
for order in permutations(range(1, 5)):
sender_ids = [base] + [base + offset for offset in order] + [base + 2]
instance = SequenceAudit()
observed = [instance.receive(value % MODULUS) for value in sender_ids]
oracle_ok &= observed == known_sender_oracle(sender_ids)
oracle_cases += 1
monotone = SequenceAudit()
monotone_ext = [monotone.receive(value)['extended_sequence'] for value in [65534, 65535, 0, 1]]
copied_instance = SequenceAudit()
copied_instance.receive(10)
returned = copied_instance.receive(12)
before_copy_mutation = copied_instance.snapshot()
returned['summary']['missing_extended'].append(-1)
returned['summary']['unique_received'] = -10
fresh_summary = audit.snapshot()
fresh_summary['missing_extended'].clear()
checks = {
'hand_unwrapped_sequence_trace': [row['extended_sequence'] for row in trace] == known_extended,
'hand_arrival_classifications': [row['status'] for row in trace] == ['first', 'new_high', 'reordered', 'duplicate', 'new_high', 'reordered', 'new_high', 'duplicate'],
'hand_prefix_gap_counts': [row['summary']['missing_count'] for row in trace] == [0, 1, 0, 0, 1, 0, 1, 1],
'hand_final_unique_duplicates_and_span_difference': final == {'base_extended': 65534, 'highest_extended': 65540, 'observed_span_packets': 7, 'unique_received': 6, 'accepted_arrivals': 8, 'duplicates': 2, 'reordered_new': 2, 'missing_extended': [65539], 'missing_count': 1, 'unique_gap_fraction': '1/7', 'span_minus_arrivals': -1},
'out_of_order_new_packet_fills_pending_gap': fill['summary']['missing_count'] == 0 and fill['status'] == 'reordered',
'duplicate_does_not_fill_gap_or_add_unique_packet': repeated_gap['summary']['missing_count'] == 1 and repeated_gap['summary']['unique_received'] == 2 and repeated_gap['status'] == 'duplicate',
'monotone_wrap_is_forward_not_massive_negative_jump': monotone_ext == [65534, 65535, 65536, 65537] and monotone.snapshot()['missing_count'] == 0,
'duplicate_of_reordered_packet_not_reordered_again': repeated_fill['status'] == 'duplicate' and repeated_fill['summary']['reordered_new'] == 1 and repeated_fill['summary']['duplicates'] == 2,
'forward_window_includes_sixteen_rejects_seventeen': rejected_17 and unchanged_17 and accepted_16['extended_sequence'] == 116,
'reorder_window_includes_eight_rejects_nine': reordered_8['extended_sequence'] == 108 and rejected_9 and unchanged_9,
'half_cycle_ambiguity_rejects_without_change': ambiguous_rejected and ambiguity.snapshot() == before_ambiguity,
'sequence_before_first_observed_base_rejects': base_rejected and before_base.snapshot() == prior_base,
'wire_type_and_range_errors_preserve_state': invalid_rejected and invalid.snapshot() == prior_invalid,
'observed_span_includes_128_rejects_129': before_span['observed_span_packets'] == 128 and rejected_span and span.snapshot() == before_span,
'bounded_accepted_arrivals_includes_256': before_events['accepted_arrivals'] == 256 and before_events['duplicates'] == 255 and rejected_events and events.snapshot() == before_events,
'empty_audit_has_no_inferred_future_or_prior_loss': SequenceAudit().snapshot() == {'base_extended': None, 'highest_extended': None, 'observed_span_packets': 0, 'unique_received': 0, 'accepted_arrivals': 0, 'duplicates': 0, 'reordered_new': 0, 'missing_extended': [], 'missing_count': 0, 'unique_gap_fraction': None, 'span_minus_arrivals': 0},
'independent_sender_id_prefix_oracle': oracle_cases == 48 and bool(oracle_ok) and trace == known_sender_oracle(known_extended),
'returned_records_are_copies_and_input_order_unchanged': copied_instance.snapshot() == before_copy_mutation and audit.snapshot() == final and wire == before_wire,
}
assert len(checks) == 18 and all(type(value) is bool and value for value in checks.values()), checks
return {'python': platform.python_version(), 'dependencies': 'Python standard library only',
'scope': 'One assumed source, bounded synthetic sequence gaps only; no real packets, RTP validation, RTCP report, latency, jitter or permanent network loss measurement',
'results': {'wire_sequence_trace': wire, 'extended_sequence_trace': known_extended,
'trace': trace, 'final': final,
'limits': {'max_forward': MAX_FORWARD, 'max_reorder': MAX_REORDER,
'max_observed_span': MAX_SPAN, 'max_accepted_arrivals': MAX_EVENTS},
'oracle_cases_inside_one_group': oracle_cases}, 'checks': checks}
if __name__ == '__main__':
print(json.dumps(run_example(), ensure_ascii=False, indent=2))
فایل rtp_sequence_gaps.py با Python 3.14.5 و کتابخانهٔ استاندارد اجرا شده است. هجده گروه بررسی دارد. مرجع مستقل، شناسههای مطلقِ ازپیشمعلومِ فرستندهٔ ساختگی را برای همهٔ پیشوندها حساب میکند و از تابع امتداد استفاده نمیکند؛ چهلوهشت ترتیب کوچک در یک گروه مقایسه میشوند. اجرای دوبارهٔ آنها، بررسی جدید یا دادهٔ شبکه نمیسازد.
۵. مرزها و چهار پرسش پاسخدار را ثبت کنیم

بازه حداکثر ۱۲۸ جایگاه و عمر نمونه حداکثر ۲۵۶ دریافتِ پذیرفتهشده، شامل تکرارهاست. پیشروی شانزده و عقبماندگی هشت پذیرفته میشوند؛ هفده و نه رد میشوند. نوع bool، عدد شناور و شمارهٔ خارج از دامنه نیز رد میشوند. خطای ورودی، حالت قبلی را تغییر نمیدهد؛ ردشدن را به تعداد دریافت پذیرفتهشده یا بستهٔ گمشده اضافه نمیکنیم.
{
"python": "3.14.5",
"dependencies": "Python standard library only",
"scope": "One assumed source, bounded synthetic sequence gaps only; no real packets, RTP validation, RTCP report, latency, jitter or permanent network loss measurement",
"results": {
"wire_sequence_trace": [
65534,
0,
65535,
0,
2,
1,
4,
4
],
"extended_sequence_trace": [
65534,
65536,
65535,
65536,
65538,
65537,
65540,
65540
],
"trace": [
{
"wire_sequence": 65534,
"extended_sequence": 65534,
"status": "first",
"summary": {
"base_extended": 65534,
"highest_extended": 65534,
"observed_span_packets": 1,
"unique_received": 1,
"accepted_arrivals": 1,
"duplicates": 0,
"reordered_new": 0,
"missing_extended": [],
"missing_count": 0,
"unique_gap_fraction": "0",
"span_minus_arrivals": 0
}
},
{
"wire_sequence": 0,
"extended_sequence": 65536,
"status": "new_high",
"summary": {
"base_extended": 65534,
"highest_extended": 65536,
"observed_span_packets": 3,
"unique_received": 2,
"accepted_arrivals": 2,
"duplicates": 0,
"reordered_new": 0,
"missing_extended": [
65535
],
"missing_count": 1,
"unique_gap_fraction": "1/3",
"span_minus_arrivals": 1
}
},
{
"wire_sequence": 65535,
"extended_sequence": 65535,
"status": "reordered",
"summary": {
"base_extended": 65534,
"highest_extended": 65536,
"observed_span_packets": 3,
"unique_received": 3,
"accepted_arrivals": 3,
"duplicates": 0,
"reordered_new": 1,
"missing_extended": [],
"missing_count": 0,
"unique_gap_fraction": "0",
"span_minus_arrivals": 0
}
},
{
"wire_sequence": 0,
"extended_sequence": 65536,
"status": "duplicate",
"summary": {
"base_extended": 65534,
"highest_extended": 65536,
"observed_span_packets": 3,
"unique_received": 3,
"accepted_arrivals": 4,
"duplicates": 1,
"reordered_new": 1,
"missing_extended": [],
"missing_count": 0,
"unique_gap_fraction": "0",
"span_minus_arrivals": -1
}
},
{
"wire_sequence": 2,
"extended_sequence": 65538,
"status": "new_high",
"summary": {
"base_extended": 65534,
"highest_extended": 65538,
"observed_span_packets": 5,
"unique_received": 4,
"accepted_arrivals": 5,
"duplicates": 1,
"reordered_new": 1,
"missing_extended": [
65537
],
"missing_count": 1,
"unique_gap_fraction": "1/5",
"span_minus_arrivals": 0
}
},
{
"wire_sequence": 1,
"extended_sequence": 65537,
"status": "reordered",
"summary": {
"base_extended": 65534,
"highest_extended": 65538,
"observed_span_packets": 5,
"unique_received": 5,
"accepted_arrivals": 6,
"duplicates": 1,
"reordered_new": 2,
"missing_extended": [],
"missing_count": 0,
"unique_gap_fraction": "0",
"span_minus_arrivals": -1
}
},
{
"wire_sequence": 4,
"extended_sequence": 65540,
"status": "new_high",
"summary": {
"base_extended": 65534,
"highest_extended": 65540,
"observed_span_packets": 7,
"unique_received": 6,
"accepted_arrivals": 7,
"duplicates": 1,
"reordered_new": 2,
"missing_extended": [
65539
],
"missing_count": 1,
"unique_gap_fraction": "1/7",
"span_minus_arrivals": 0
}
},
{
"wire_sequence": 4,
"extended_sequence": 65540,
"status": "duplicate",
"summary": {
"base_extended": 65534,
"highest_extended": 65540,
"observed_span_packets": 7,
"unique_received": 6,
"accepted_arrivals": 8,
"duplicates": 2,
"reordered_new": 2,
"missing_extended": [
65539
],
"missing_count": 1,
"unique_gap_fraction": "1/7",
"span_minus_arrivals": -1
}
}
],
"final": {
"base_extended": 65534,
"highest_extended": 65540,
"observed_span_packets": 7,
"unique_received": 6,
"accepted_arrivals": 8,
"duplicates": 2,
"reordered_new": 2,
"missing_extended": [
65539
],
"missing_count": 1,
"unique_gap_fraction": "1/7",
"span_minus_arrivals": -1
},
"limits": {
"max_forward": 16,
"max_reorder": 8,
"max_observed_span": 128,
"max_accepted_arrivals": 256
},
"oracle_cases_inside_one_group": 48
},
"checks": {
"hand_unwrapped_sequence_trace": true,
"hand_arrival_classifications": true,
"hand_prefix_gap_counts": true,
"hand_final_unique_duplicates_and_span_difference": true,
"out_of_order_new_packet_fills_pending_gap": true,
"duplicate_does_not_fill_gap_or_add_unique_packet": true,
"monotone_wrap_is_forward_not_massive_negative_jump": true,
"duplicate_of_reordered_packet_not_reordered_again": true,
"forward_window_includes_sixteen_rejects_seventeen": true,
"reorder_window_includes_eight_rejects_nine": true,
"half_cycle_ambiguity_rejects_without_change": true,
"sequence_before_first_observed_base_rejects": true,
"wire_type_and_range_errors_preserve_state": true,
"observed_span_includes_128_rejects_129": true,
"bounded_accepted_arrivals_includes_256": true,
"empty_audit_has_no_inferred_future_or_prior_loss": true,
"independent_sender_id_prefix_oracle": true,
"returned_records_are_copies_and_input_order_unchanged": true
}
}
پرسش اول: پس از ۶۵۵۳۵، صفر چه شمارهای میگیرد؟ پاسخ: در توالیِ روبهجلوی مجاز، ۶۵۵۳۶؛ این پاسخ به فرض پنجره وابسته است و برای جهشِ نامعلومِ چند چرخه صادر نمیشود.
پرسش دوم: چرا نتیجهٔ نهایی یک شکاف و تفاضل منفی یک دارد؟ پاسخ: شش شمارهٔ یکتا از هفت جایگاه دیدهایم، اما دو نسخهٔ تکراری تعداد دریافتها را به هشت رساندهاند. این دو شمارنده پرسشهای متفاوتی دارند.
پرسش سوم: آیا دریافت خارج از ترتیب الزاماً برای پخش دیر است؟ پاسخ: خیر؛ این کد زمان ندارد. برای آن پرسش، مدل موعد پخش و بافر صوت باید جدا تعریف شود.
پرسش چهارم: با اختلاف دقیقاً ۳۲۷۶۸ چه کنیم؟ پاسخ: این قرارداد آن را مبهم اعلام و بدون تغییر حالت رد میکند. انتخاب جهت، اطلاعاتی را اختراع میکند که ورودی نداده است. منابع در ۲۴ مهر ۱۴۰۵ خوانده شدند؛ اسناد اصلی مربوط به ژوئیهٔ ۲۰۰۳ و نوامبر ۲۰۰۶ هستند. این آموزش پایه است و نتیجهٔ تماس واقعی یا خبر تازه معرفی نمیشود.
منابع و مطالعهٔ بیشتر
- RFC3550؛ شمارهٔ توالی، اعتبارسنجی و گزارش دریافت RTP
- RFC4737؛ تمایز شکاف توالی، دریافت خارج از ترتیب و نسخهٔ تکراری
بررسی منابع: ۲۴ مهر ۱۴۰۵. تحلیلها و پیشنهادهای اجرایی، جمعبندی نویسندهاند.


