Check before send/receive rtp header extensions.
BUG=1788
R=pbos@webrtc.org, tommi@webrtc.org, wu@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/13949004
Patch from Changbin Shao <changbin.shao@intel.com>.
git-svn-id: http://webrtc.googlecode.com/svn/trunk@6744 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc
index 21e51eb..12fcec0 100644
--- a/talk/media/webrtc/webrtcvideoengine2.cc
+++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -34,6 +34,7 @@
#include <math.h>
+#include <set>
#include <string>
#include "libyuv/convert_from.h"
@@ -136,6 +137,34 @@
return codecs;
}
+static bool ValidateRtpHeaderExtensionIds(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ std::set<int> extensions_used;
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ if (extensions[i].id < 0 || extensions[i].id >= 15 ||
+ !extensions_used.insert(extensions[i].id).second) {
+ LOG(LS_ERROR) << "RTP extensions are with incorrect or duplicate ids.";
+ return false;
+ }
+ }
+ return true;
+}
+
+static std::vector<webrtc::RtpExtension> FilterRtpExtensions(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ std::vector<webrtc::RtpExtension> webrtc_extensions;
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ // Unsupported extensions will be ignored.
+ if (webrtc::RtpExtension::IsSupported(extensions[i].uri)) {
+ webrtc_extensions.push_back(webrtc::RtpExtension(
+ extensions[i].uri, extensions[i].id));
+ } else {
+ LOG(LS_WARNING) << "Unsupported RTP extension: " << extensions[i].uri;
+ }
+ }
+ return webrtc_extensions;
+}
+
WebRtcVideoEncoderFactory2::~WebRtcVideoEncoderFactory2() {
}
@@ -1099,22 +1128,16 @@
const std::vector<RtpHeaderExtension>& extensions) {
LOG(LS_INFO) << "SetRecvRtpHeaderExtensions: "
<< RtpExtensionsToString(extensions);
- std::vector<webrtc::RtpExtension> webrtc_extensions;
- for (size_t i = 0; i < extensions.size(); ++i) {
- // TODO(pbos): Make sure we don't pass unsupported extensions!
- webrtc::RtpExtension webrtc_extension(extensions[i].uri.c_str(),
- extensions[i].id);
- webrtc_extensions.push_back(webrtc_extension);
- }
- recv_rtp_extensions_ = webrtc_extensions;
+ if (!ValidateRtpHeaderExtensionIds(extensions))
+ return false;
+ recv_rtp_extensions_ = FilterRtpExtensions(extensions);
for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
receive_streams_.begin();
it != receive_streams_.end();
++it) {
it->second->SetRtpExtensions(recv_rtp_extensions_);
}
-
return true;
}
@@ -1122,14 +1145,10 @@
const std::vector<RtpHeaderExtension>& extensions) {
LOG(LS_INFO) << "SetSendRtpHeaderExtensions: "
<< RtpExtensionsToString(extensions);
- std::vector<webrtc::RtpExtension> webrtc_extensions;
- for (size_t i = 0; i < extensions.size(); ++i) {
- // TODO(pbos): Make sure we don't pass unsupported extensions!
- webrtc::RtpExtension webrtc_extension(extensions[i].uri.c_str(),
- extensions[i].id);
- webrtc_extensions.push_back(webrtc_extension);
- }
- send_rtp_extensions_ = webrtc_extensions;
+ if (!ValidateRtpHeaderExtensionIds(extensions))
+ return false;
+
+ send_rtp_extensions_ = FilterRtpExtensions(extensions);
for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
send_streams_.begin();
it != send_streams_.end();
diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
index 45ea161..0d46e2b 100644
--- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -49,6 +49,8 @@
static const uint32 kSsrcs1[] = {1};
static const uint32 kRtxSsrcs1[] = {4};
+static const char kUnsupportedExtensionName[] =
+ "urn:ietf:params:rtp-hdrext:unsupported";
void VerifyCodecHasDefaultFeedbackParams(const cricket::VideoCodec& codec) {
EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
@@ -822,6 +824,110 @@
webrtc::RtpExtension::kAbsSendTime);
}
+TEST_F(WebRtcVideoChannel2Test,
+ SetSendRtpHeaderExtensionsExcludeUnsupportedExtensions) {
+ const int kUnsupportedId = 1;
+ const int kTOffsetId = 2;
+
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(
+ kUnsupportedExtensionName, kUnsupportedId));
+ extensions.push_back(cricket::RtpHeaderExtension(
+ webrtc::RtpExtension::kTOffset, kTOffsetId));
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
+ FakeVideoSendStream* send_stream =
+ AddSendStream(cricket::StreamParams::CreateLegacy(123));
+
+ // Only timestamp offset extension is set to send stream,
+ // unsupported rtp extension is ignored.
+ ASSERT_EQ(1u, send_stream->GetConfig().rtp.extensions.size());
+ EXPECT_STREQ(webrtc::RtpExtension::kTOffset,
+ send_stream->GetConfig().rtp.extensions[0].name.c_str());
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ SetRecvRtpHeaderExtensionsExcludeUnsupportedExtensions) {
+ const int kUnsupportedId = 1;
+ const int kTOffsetId = 2;
+
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(
+ kUnsupportedExtensionName, kUnsupportedId));
+ extensions.push_back(cricket::RtpHeaderExtension(
+ webrtc::RtpExtension::kTOffset, kTOffsetId));
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+ FakeVideoReceiveStream* recv_stream =
+ AddRecvStream(cricket::StreamParams::CreateLegacy(123));
+
+ // Only timestamp offset extension is set to receive stream,
+ // unsupported rtp extension is ignored.
+ ASSERT_EQ(1u, recv_stream->GetConfig().rtp.extensions.size());
+ EXPECT_STREQ(webrtc::RtpExtension::kTOffset,
+ recv_stream->GetConfig().rtp.extensions[0].name.c_str());
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ SetSendRtpHeaderExtensionsRejectsIncorrectIds) {
+ const size_t kNumIncorrectIds = 4;
+ const int kIncorrectIds[kNumIncorrectIds] = {-2, -1, 15, 16};
+ for (size_t i = 0; i < kNumIncorrectIds; ++i) {
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(
+ webrtc::RtpExtension::kTOffset, kIncorrectIds[i]));
+ EXPECT_FALSE(channel_->SetSendRtpHeaderExtensions(extensions))
+ << "Bad extension id '" << kIncorrectIds[i] << "' accepted.";
+ }
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ SetRecvRtpHeaderExtensionsRejectsIncorrectIds) {
+ const size_t kNumIncorrectIds = 4;
+ const int kIncorrectIds[kNumIncorrectIds] = {-2, -1, 15, 16};
+ for (size_t i = 0; i < kNumIncorrectIds; ++i) {
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(
+ webrtc::RtpExtension::kTOffset, kIncorrectIds[i]));
+ EXPECT_FALSE(channel_->SetRecvRtpHeaderExtensions(extensions))
+ << "Bad extension id '" << kIncorrectIds[i] << "' accepted.";
+ }
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ SetSendRtpHeaderExtensionsRejectsDuplicateIds) {
+ const int id = 1;
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(
+ webrtc::RtpExtension::kTOffset, id));
+ extensions.push_back(cricket::RtpHeaderExtension(
+ kRtpAbsoluteSenderTimeHeaderExtension, id));
+ EXPECT_FALSE(channel_->SetSendRtpHeaderExtensions(extensions));
+
+ // Duplicate entries are also not supported.
+ extensions.clear();
+ extensions.push_back(cricket::RtpHeaderExtension(
+ webrtc::RtpExtension::kTOffset, id));
+ extensions.push_back(extensions.back());
+ EXPECT_FALSE(channel_->SetSendRtpHeaderExtensions(extensions));
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ SetRecvRtpHeaderExtensionsRejectsDuplicateIds) {
+ const int id = 1;
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(
+ webrtc::RtpExtension::kTOffset, id));
+ extensions.push_back(cricket::RtpHeaderExtension(
+ kRtpAbsoluteSenderTimeHeaderExtension, id));
+ EXPECT_FALSE(channel_->SetRecvRtpHeaderExtensions(extensions));
+
+ // Duplicate entries are also not supported.
+ extensions.clear();
+ extensions.push_back(cricket::RtpHeaderExtension(
+ webrtc::RtpExtension::kTOffset, id));
+ extensions.push_back(extensions.back());
+ EXPECT_FALSE(channel_->SetRecvRtpHeaderExtensions(extensions));
+}
+
TEST_F(WebRtcVideoChannel2Test, DISABLED_LeakyBucketTest) {
FAIL() << "Not implemented."; // TODO(pbos): Implement.
}
diff --git a/webrtc/config.h b/webrtc/config.h
index 2e96ec1..e4bccf9 100644
--- a/webrtc/config.h
+++ b/webrtc/config.h
@@ -10,8 +10,8 @@
// TODO(pbos): Move Config from common.h to here.
-#ifndef WEBRTC_VIDEO_ENGINE_NEW_INCLUDE_CONFIG_H_
-#define WEBRTC_VIDEO_ENGINE_NEW_INCLUDE_CONFIG_H_
+#ifndef WEBRTC_CONFIG_H_
+#define WEBRTC_CONFIG_H_
#include <string>
#include <vector>
@@ -73,9 +73,10 @@
// RTP header extension to use for the video stream, see RFC 5285.
struct RtpExtension {
- RtpExtension(const char* name, int id) : name(name), id(id) {}
+ RtpExtension(const std::string& name, int id) : name(name), id(id) {}
std::string ToString() const;
- // TODO(mflodman) Add API to query supported extensions.
+ static bool IsSupported(const std::string& name);
+
static const char* kTOffset;
static const char* kAbsSendTime;
std::string name;
@@ -109,4 +110,4 @@
} // namespace webrtc
-#endif // WEBRTC_VIDEO_ENGINE_NEW_INCLUDE_CONFIG_H_
+#endif // WEBRTC_CONFIG_H_
diff --git a/webrtc/video/call.cc b/webrtc/video/call.cc
index 95e1c7b..bcce6f0 100644
--- a/webrtc/video/call.cc
+++ b/webrtc/video/call.cc
@@ -33,6 +33,12 @@
const char* RtpExtension::kTOffset = "urn:ietf:params:rtp-hdrext:toffset";
const char* RtpExtension::kAbsSendTime =
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
+
+bool RtpExtension::IsSupported(const std::string& name) {
+ return name == webrtc::RtpExtension::kTOffset ||
+ name == webrtc::RtpExtension::kAbsSendTime;
+}
+
namespace internal {
class CpuOveruseObserverProxy : public webrtc::CpuOveruseObserver {