Commit 94d67f70 authored by hubbe@chromium.org's avatar hubbe@chromium.org

Smarter algorithm for extending 8-bit frame IDs to 32-bit frame IDs.

The previous algorithm was limited to jumps of ~64, the new algorithm
can handle jumps of ~127.

Review URL: https://codereview.chromium.org/458313003

Cr-Commit-Position: refs/heads/master@{#290023}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290023 0039d316-1c4b-4281-b951-d872f2087c98
parent 0c6ab158
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
'logging/simple_event_subscriber_unittest.cc', 'logging/simple_event_subscriber_unittest.cc',
'logging/stats_event_subscriber_unittest.cc', 'logging/stats_event_subscriber_unittest.cc',
'net/cast_transport_sender_impl_unittest.cc', 'net/cast_transport_sender_impl_unittest.cc',
'net/frame_id_wrap_helper_test.cc',
'net/pacing/mock_paced_packet_sender.cc', 'net/pacing/mock_paced_packet_sender.cc',
'net/pacing/mock_paced_packet_sender.h', 'net/pacing/mock_paced_packet_sender.h',
'net/pacing/paced_sender_unittest.cc', 'net/pacing/paced_sender_unittest.cc',
......
...@@ -61,64 +61,34 @@ typedef std::set<uint16> PacketIdSet; ...@@ -61,64 +61,34 @@ typedef std::set<uint16> PacketIdSet;
// Each uint8 represents one cast frame. // Each uint8 represents one cast frame.
typedef std::map<uint8, PacketIdSet> MissingFramesAndPacketsMap; typedef std::map<uint8, PacketIdSet> MissingFramesAndPacketsMap;
class FrameIdWrapHelperTest;
// TODO(miu): UGLY IN-LINE DEFINITION IN HEADER FILE! Move to appropriate // TODO(miu): UGLY IN-LINE DEFINITION IN HEADER FILE! Move to appropriate
// location, separated into .h and .cc files. // location, separated into .h and .cc files.
class FrameIdWrapHelper { class FrameIdWrapHelper {
public: public:
FrameIdWrapHelper() FrameIdWrapHelper()
: first_(true), frame_id_wrap_count_(0), range_(kLowRange) {} : largest_frame_id_seen_(kStartFrameId) {}
uint32 MapTo32bitsFrameId(const uint8 over_the_wire_frame_id) { uint32 MapTo32bitsFrameId(const uint8 over_the_wire_frame_id) {
if (first_) { uint32 ret = (largest_frame_id_seen_ & ~0xff) | over_the_wire_frame_id;
first_ = false; // Add 1000 to both sides to avoid underflows.
if (over_the_wire_frame_id == 0xff) { if (1000 + ret - largest_frame_id_seen_ > 1000 + 127) {
// Special case for startup. ret -= 0x100;
return kStartFrameId; } else if (1000 + ret - largest_frame_id_seen_ < 1000 - 128) {
} ret += 0x100;
} }
if (1000 + ret - largest_frame_id_seen_ > 1000) {
uint32 wrap_count = frame_id_wrap_count_; largest_frame_id_seen_ = ret;
switch (range_) {
case kLowRange:
if (over_the_wire_frame_id > kLowRangeThreshold &&
over_the_wire_frame_id < kHighRangeThreshold) {
range_ = kMiddleRange;
}
if (over_the_wire_frame_id >= kHighRangeThreshold) {
// Wrap count was incremented in High->Low transition, but this frame
// is 'old', actually from before the wrap count got incremented.
--wrap_count;
}
break;
case kMiddleRange:
if (over_the_wire_frame_id >= kHighRangeThreshold) {
range_ = kHighRange;
}
break;
case kHighRange:
if (over_the_wire_frame_id <= kLowRangeThreshold) {
// Wrap-around detected.
range_ = kLowRange;
++frame_id_wrap_count_;
// Frame triggering wrap-around so wrap count should be incremented as
// as well to match |frame_id_wrap_count_|.
++wrap_count;
}
break;
} }
return (wrap_count << 8) + over_the_wire_frame_id; return ret;
} }
private: private:
enum Range { kLowRange, kMiddleRange, kHighRange, }; friend class FrameIdWrapHelperTest;
static const uint8 kLowRangeThreshold = 63;
static const uint8 kHighRangeThreshold = 192;
static const uint32 kStartFrameId = UINT32_C(0xffffffff); static const uint32 kStartFrameId = UINT32_C(0xffffffff);
bool first_; uint32 largest_frame_id_seen_;
uint32 frame_id_wrap_count_;
Range range_;
DISALLOW_COPY_AND_ASSIGN(FrameIdWrapHelper); DISALLOW_COPY_AND_ASSIGN(FrameIdWrapHelper);
}; };
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "media/cast/cast_defines.h"
#include "media/cast/net/cast_transport_defines.h" #include "media/cast/net/cast_transport_defines.h"
namespace media { namespace media {
...@@ -13,6 +14,25 @@ class FrameIdWrapHelperTest : public ::testing::Test { ...@@ -13,6 +14,25 @@ class FrameIdWrapHelperTest : public ::testing::Test {
FrameIdWrapHelperTest() {} FrameIdWrapHelperTest() {}
virtual ~FrameIdWrapHelperTest() {} virtual ~FrameIdWrapHelperTest() {}
void RunOneTest(uint32 starting_point, int iterations) {
const int window_size = 127;
uint32 window_base = starting_point;
frame_id_wrap_helper_.largest_frame_id_seen_ = starting_point;
for (int i = 0; i < iterations; i++) {
uint32 largest_frame_id_seen =
frame_id_wrap_helper_.largest_frame_id_seen_;
int offset = rand() % window_size;
uint32 frame_id = window_base + offset;
uint32 mapped_frame_id =
frame_id_wrap_helper_.MapTo32bitsFrameId(frame_id & 0xff);
EXPECT_EQ(frame_id, mapped_frame_id)
<< " Largest ID seen: " << largest_frame_id_seen
<< " Window base: " << window_base
<< " Offset: " << offset;
window_base = frame_id;
}
}
FrameIdWrapHelper frame_id_wrap_helper_; FrameIdWrapHelper frame_id_wrap_helper_;
DISALLOW_COPY_AND_ASSIGN(FrameIdWrapHelperTest); DISALLOW_COPY_AND_ASSIGN(FrameIdWrapHelperTest);
...@@ -46,5 +66,15 @@ TEST_F(FrameIdWrapHelperTest, OutOfOrder) { ...@@ -46,5 +66,15 @@ TEST_F(FrameIdWrapHelperTest, OutOfOrder) {
EXPECT_EQ(257u, new_frame_id); EXPECT_EQ(257u, new_frame_id);
} }
TEST_F(FrameIdWrapHelperTest, Windowed) {
srand(0);
for (int i = 0; i < 50000 && !HasFailure(); i++) {
RunOneTest(i * 4711, 20);
// Test wrap-around scenarios.
RunOneTest(0x7fffff00ul, 20);
RunOneTest(0xffffff00ul, 20);
}
}
} // namespace cast } // namespace cast
} // namespace media } // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment