}
namespace {
+template <typename T = webrtc::ImageAttr>
struct SendRecvAttrs {
- absl::optional<std::vector<webrtc::ImageAttr>> send, recv;
+ absl::optional<std::vector<T>> send, recv;
};
-SendRecvAttrs GetAttrs(const webrtc::JsepSessionDescription& jdesc) {
+SendRecvAttrs<> GetAttrs(const webrtc::JsepSessionDescription& jdesc) {
EXPECT_EQ(1U, jdesc.description()->contents().size());
const auto& content = jdesc.description()->contents().front();
EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO,
true);
}
+static std::string GenerateSdp(
+ const absl::optional<std::vector<webrtc::ImageAttr>>& send_attrs,
+ const absl::optional<std::vector<webrtc::ImageAttr>>& recv_attrs) {
+ webrtc::JsepSessionDescription jdesc{kDummyType};
+ auto set_jdesc = [&]() {
+ ASSERT_TRUE(
+ webrtc::SdpDeserialize(kSdpSessionForImageattrString, &jdesc, nullptr));
+ ASSERT_TRUE(jdesc.description());
+ ASSERT_EQ(1U, jdesc.description()->contents().size());
+ auto& content = jdesc.description()->contents().front();
+ ASSERT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO,
+ content.media_description()->type());
+ auto* description = content.media_description()->as_video();
+ auto codecs = description->codecs();
+ ASSERT_EQ(1U, codecs.size());
+ codecs.front().send_image_attr = send_attrs;
+ codecs.front().recv_image_attr = recv_attrs;
+ description->set_codecs(std::move(codecs));
+ };
+ set_jdesc();
+ return webrtc::SdpSerialize(jdesc);
+}
+
+static std::string GetImageattrLine(const std::string& sdp) {
+ std::vector<std::string> lines;
+ EXPECT_GE(rtc::split(sdp, '\n', &lines), 1U);
+ for (const auto& line : lines) {
+ if (line.find("a=imageattr") != std::string::npos) {
+ return line;
+ }
+ }
+ ADD_FAILURE() << "Failed to find the imageattr line in sdp: \"" << sdp
+ << "\"";
+ return {};
+}
+
+static std::ostream& operator<<(std::ostream& os,
+ const webrtc::ImageAttr::IntRange& range) {
+ os << "[" << range.min_val << ":" << range.max_val << "]";
+ return os;
+}
+
+static std::string ToString(const webrtc::ImageAttr::IntRange& range) {
+ std::ostringstream oss;
+ oss << range;
+ return oss.str();
+}
+
+// imageattr line generation unittests.
+TEST_F(WebRtcSdpTest, GenerateImageattrPayloadType) {
+ std::vector<webrtc::ImageAttr> send_attrs{webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 150,
+ .max_val = 330,
+ },
+ .y_range =
+ {
+ .min_val = 100,
+ .max_val = 300,
+ },
+ .framerate = webrtc::ImageAttr::IntRange{.min_val = 15, .max_val = 60},
+ }};
+ const std::string sdp = GenerateSdp(send_attrs, absl::nullopt);
+ const std::string imgattr = GetImageattrLine(sdp);
+ ASSERT_FALSE(imgattr.empty());
+ // See kSdpSessionForImageattrString where the codec of id 98 is set.
+ EXPECT_NE(std::string::npos, imgattr.find("a=imageattr:98"));
+}
+
+TEST_F(WebRtcSdpTest, GenerateImageattrSendSingle) {
+ std::vector<webrtc::ImageAttr> send_attrs{webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 150,
+ .max_val = 330,
+ },
+ .y_range =
+ {
+ .min_val = 100,
+ .max_val = 300,
+ },
+ .framerate = webrtc::ImageAttr::IntRange{.min_val = 15, .max_val = 60},
+ }};
+ const std::string sdp = GenerateSdp(send_attrs, absl::nullopt);
+ const std::string imgattr = GetImageattrLine(sdp);
+ ASSERT_FALSE(imgattr.empty());
+ EXPECT_NE(std::string::npos, imgattr.find("send"));
+ EXPECT_NE(std::string::npos,
+ imgattr.find("x=" + ToString(send_attrs.front().x_range)));
+ EXPECT_NE(std::string::npos,
+ imgattr.find("y=" + ToString(send_attrs.front().y_range)));
+ EXPECT_NE(
+ std::string::npos,
+ imgattr.find("fps=" + ToString(send_attrs.front().framerate.value())));
+}
+
+static SendRecvAttrs<std::string> GetAttrTokens(const std::string& imgattr) {
+ std::vector<std::string> imgattr_tokens;
+ rtc::split(imgattr, ' ', &imgattr_tokens);
+ bool collecting_send_tokens = false;
+ bool collecting_recv_tokens = false;
+ std::vector<std::string> send_tokens;
+ std::vector<std::string> recv_tokens;
+ for (const auto& token : imgattr_tokens) {
+ if (token == "send") {
+ collecting_send_tokens = true;
+ collecting_recv_tokens = false;
+ continue;
+ }
+ if (token == "recv") {
+ collecting_send_tokens = false;
+ collecting_recv_tokens = true;
+ continue;
+ }
+ if (collecting_send_tokens || collecting_recv_tokens) {
+ std::vector<std::string> sub_tokens;
+ rtc::split(token, ',', &sub_tokens);
+ auto& appendee = collecting_send_tokens ? send_tokens : recv_tokens;
+ std::move(sub_tokens.begin(), sub_tokens.end(),
+ std::back_inserter(appendee));
+ }
+ }
+ return {
+ .send = send_tokens,
+ .recv = recv_tokens,
+ };
+}
+
+static bool FindAndRemoveAttrsToken(std::vector<std::string>* tokens,
+ const std::string& attrs_token) {
+ for (auto token_it = tokens->begin(); token_it != tokens->end(); ++token_it) {
+ if (token_it->find(attrs_token) != std::string::npos) {
+ tokens->erase(token_it);
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool FindAttrsInImageattrLine(
+ const std::string& imgattr,
+ const std::vector<webrtc::ImageAttr>& expected_send_attrs,
+ const std::vector<webrtc::ImageAttr>& expected_recv_attrs) {
+ auto actual_attr_tokens = GetAttrTokens(imgattr);
+ if (!expected_send_attrs.empty()) {
+ EXPECT_TRUE(actual_attr_tokens.send);
+ if (!actual_attr_tokens.send)
+ return false;
+ for (const auto& attr : expected_send_attrs) {
+ EXPECT_TRUE(FindAndRemoveAttrsToken(&(*actual_attr_tokens.send),
+ "x=" + ToString(attr.x_range)));
+ EXPECT_TRUE(FindAndRemoveAttrsToken(&(*actual_attr_tokens.send),
+ "y=" + ToString(attr.y_range)));
+ if (attr.framerate) {
+ EXPECT_TRUE(FindAndRemoveAttrsToken(
+ &(*actual_attr_tokens.send), "fps=" + ToString(*attr.framerate)));
+ }
+ }
+ }
+ if (!expected_recv_attrs.empty()) {
+ EXPECT_TRUE(actual_attr_tokens.recv);
+ if (!actual_attr_tokens.recv)
+ return false;
+ for (const auto& attr : expected_recv_attrs) {
+ EXPECT_TRUE(FindAndRemoveAttrsToken(&(*actual_attr_tokens.recv),
+ "x=" + ToString(attr.x_range)));
+ EXPECT_TRUE(FindAndRemoveAttrsToken(&(*actual_attr_tokens.recv),
+ "y=" + ToString(attr.y_range)));
+ if (attr.framerate) {
+ EXPECT_TRUE(FindAndRemoveAttrsToken(
+ &(*actual_attr_tokens.recv), "fps=" + ToString(*attr.framerate)));
+ }
+ }
+ }
+ return actual_attr_tokens.send->empty() && actual_attr_tokens.recv->empty();
+}
+
+TEST_F(WebRtcSdpTest, GenerateImageattrSendMultiple) {
+ std::vector<webrtc::ImageAttr> expected_send_attrs{
+ webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 150,
+ .max_val = 330,
+ },
+ .y_range =
+ {
+ .min_val = 100,
+ .max_val = 300,
+ },
+ .framerate =
+ webrtc::ImageAttr::IntRange{.min_val = 15, .max_val = 60},
+ },
+ webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 220,
+ .max_val = 480,
+ },
+ .y_range =
+ {
+ .min_val = 180,
+ .max_val = 360,
+ },
+ .framerate = webrtc::ImageAttr::IntRange{.min_val = 5, .max_val = 24},
+ },
+ };
+ const std::string sdp = GenerateSdp(expected_send_attrs, absl::nullopt);
+ const std::string imgattr = GetImageattrLine(sdp);
+ ASSERT_FALSE(imgattr.empty());
+ EXPECT_TRUE(FindAttrsInImageattrLine(imgattr, expected_send_attrs, {}));
+}
+
+TEST_F(WebRtcSdpTest, GenerateImageattrRecvMultiple) {
+ std::vector<webrtc::ImageAttr> expected_recv_attrs{
+ webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 150,
+ .max_val = 330,
+ },
+ .y_range =
+ {
+ .min_val = 100,
+ .max_val = 300,
+ },
+ .framerate =
+ webrtc::ImageAttr::IntRange{.min_val = 15, .max_val = 60},
+ },
+ webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 220,
+ .max_val = 480,
+ },
+ .y_range =
+ {
+ .min_val = 180,
+ .max_val = 360,
+ },
+ .framerate = webrtc::ImageAttr::IntRange{.min_val = 5, .max_val = 24},
+ },
+ };
+ const std::string sdp = GenerateSdp(absl::nullopt, expected_recv_attrs);
+ const std::string imgattr = GetImageattrLine(sdp);
+ ASSERT_FALSE(imgattr.empty());
+ EXPECT_TRUE(FindAttrsInImageattrLine(imgattr, {}, expected_recv_attrs));
+}
+
+TEST_F(WebRtcSdpTest, GenerateImageattrMultiple) {
+ std::vector<webrtc::ImageAttr> expected_send_attrs{
+ webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 123,
+ .max_val = 456,
+ },
+ .y_range =
+ {
+ .min_val = 789,
+ .max_val = 800,
+ },
+ .framerate =
+ webrtc::ImageAttr::IntRange{.min_val = 15, .max_val = 60},
+ },
+ webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 220,
+ .max_val = 380,
+ },
+ .y_range =
+ {
+ .min_val = 150,
+ .max_val = 340,
+ },
+ .framerate = webrtc::ImageAttr::IntRange{.min_val = 5, .max_val = 24},
+ },
+ };
+ std::vector<webrtc::ImageAttr> expected_recv_attrs{
+ webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 150,
+ .max_val = 330,
+ },
+ .y_range =
+ {
+ .min_val = 100,
+ .max_val = 300,
+ },
+ .framerate =
+ webrtc::ImageAttr::IntRange{.min_val = 15, .max_val = 30},
+ },
+ webrtc::ImageAttr{
+ .x_range =
+ {
+ .min_val = 220,
+ .max_val = 480,
+ },
+ .y_range =
+ {
+ .min_val = 180,
+ .max_val = 360,
+ },
+ .framerate =
+ webrtc::ImageAttr::IntRange{.min_val = 50, .max_val = 60},
+ },
+ };
+ const std::string sdp = GenerateSdp(expected_send_attrs, expected_recv_attrs);
+ const std::string imgattr = GetImageattrLine(sdp);
+ ASSERT_FALSE(imgattr.empty());
+ EXPECT_TRUE(FindAttrsInImageattrLine(imgattr, expected_send_attrs,
+ expected_recv_attrs));
+}
+
#endif // OS_TIZEN_TV_PRODUCT