-
-
Notifications
You must be signed in to change notification settings - Fork 193
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
Issue 688: FEC estimates block duration #717
base: develop
Are you sure you want to change the base?
Issue 688: FEC estimates block duration #717
Conversation
🤖 Upon creation, pull request description does not have a link to an issue. If there is a related issue, please add it to the description using any of the supported formats. |
🤖 The latest upstream change made this pull request unmergeable. Please resolve the merge conflicts. |
bool LatencyMonitor::pre_process_(const Frame& frame) { | ||
if (fec_reader_) { | ||
latency_metrics_.fec_block_duration = | ||
packet_sample_spec_.stream_timestamp_2_ns(fec_reader_->max_block_duration()); | ||
} else { | ||
latency_metrics_.fec_block_duration = 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In LatencyMonitor::read, we have:
compute_niq_latency_();
query_link_meter_();
if (!pre_process_(frame)) {
alive_ = false;
}
All metrics except fec_block_duration are filled before calling pre-process. So for consistency, I suggest to add a method like query_fec_reader() and also call it there.
if (next_packet_ == 0) { | ||
if (pp) { | ||
update_block_duration_(pp); | ||
} else { | ||
prev_block_timestamp_valid_ = false; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is triggered when the very first packet of a block is received.
What about moving this logic to next_block_()
?
It is triggered when we're going to switch to the next block.
Inside next_block_()
, even if the first packet was lost, there is the maximum chance that it was repaired.
if (!ptr->rtp()) { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use Packet::stream_timestamp()
instead of Packet::rtp()
, this way fec::Reader will continue to be RTP-independent.
block_dur = packet::stream_timestamp_diff(ptr->rtp()->stream_timestamp, | ||
prev_block_timestamp_); | ||
} | ||
roc_panic_if_msg(block_dur < 0, "fec reader: negative block duration"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think panic is not appropriate here, because corrupted/malformed packets would lead to a crash?
Instead we can skip the check. Probably also log to LogTrace.
prev_block_timestamp_); | ||
} | ||
roc_panic_if_msg(block_dur < 0, "fec reader: negative block duration"); | ||
block_max_duration_ = std::max(block_max_duration_, block_dur); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we compute maximum in LatencyTuner instead of fec::Reader? And report only immediate value from fec::Reader?
Why:
-
Most likely we want running maximum instead of total maxium. Maybe at least in later versions. But this kind of details (running window, etc) should belong to LatencyTuner?
-
This logic (running max) would probably be the same for sender & receiver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the manner the metrics are passed into tuner, it would be difficult to be sure that it has updates of fec block duration on every new block arrived. And this could potentially lead to wrong estimation of maximum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, given it one more thought, this is probably not the case.
While latency tuner updates FE with some big period, like 200ms, latency monitor and feedback monitor are invoked every frame.
And, while user is allowed to read and write big frames, top-level pipeline code will anyway split them in smaller frames (to ensure that we don't block in processing for long time and that frames can fit max size of pool buffer).
So in practice all pipeline components are invoked with small frames (e.g. 1ms), much lower than FEC block size, and I think in our design (in general) we can assume that it's always true, because it simplifies many things.
For example, we already do the same with incoming queue - we're sampling it's size every frame. I think we in general can sample anything per frame.
So I guess you can just sample FEC block duration in LatencyMonitor::read?
@@ -109,6 +114,7 @@ status::StatusCode Writer::write(const packet::PacketPtr& pp) { | |||
} | |||
|
|||
if (cur_packet_ == 0) { | |||
update_block_duration_(pp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to call this from begin_block_ or end_block_ - so that everything called on block boundary would be in same place.
if (!ptr->rtp()) { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about rtp()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we create a separate set of tests for block_duration feature?
This feature feels pretty isolated from the main "purpose" of fec::Reader (repairing packets) and I think the story of its test is a bit different from story of the rest tests.
The story of original tests goes from simpler to more complicated, starting from one block, then introducing a loss, then switching to multiple blocks, introducing more losses, reordering, etc.
The story of block_duration tests I think should include:
- good case
- lost first packet of first block
- lost first packet of non-first block
- lost packet inside block (maybe even everything except first packet)
- lost whole block (in other words, switched to other block)
- resizing block (look at other
resize_xxx
tests for an example)
Sorry for complicating your life, but fec reader & writer are so complicated that I think having so many tests for every feature is worth it.
Reader and writer esimate duration of FEC block in ns as this value could vary even though number of packets is known. For now it is decided to keep the greates value seen in the current session, not average.
6584217
to
3f2a94f
Compare
0693040
to
549f677
Compare
Reader and writer esimate duration of
FEC block in ns as this value could vary
even though number of packets is known.
For now it is decided to keep the greates
value seen in the current session, not
average.
#688