|  | /* | 
|  | *  Copyright 2017 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "webrtc/base/gunit.h" | 
|  | #include "webrtc/ortc/rtpparametersconversion.h" | 
|  | #include "webrtc/ortc/testrtpparameters.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketFeedbackParam) { | 
|  | auto result = ToCricketFeedbackParam( | 
|  | {RtcpFeedbackType::CCM, RtcpFeedbackMessageType::FIR}); | 
|  | EXPECT_EQ(cricket::FeedbackParam("ccm", "fir"), result.value()); | 
|  | result = ToCricketFeedbackParam( | 
|  | {RtcpFeedbackType::NACK, RtcpFeedbackMessageType::GENERIC_NACK}); | 
|  | EXPECT_EQ(cricket::FeedbackParam("nack"), result.value()); | 
|  | result = ToCricketFeedbackParam( | 
|  | {RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI}); | 
|  | EXPECT_EQ(cricket::FeedbackParam("nack", "pli"), result.value()); | 
|  | result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::REMB)); | 
|  | EXPECT_EQ(cricket::FeedbackParam("goog-remb"), result.value()); | 
|  | result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC)); | 
|  | EXPECT_EQ(cricket::FeedbackParam("transport-cc"), result.value()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketFeedbackParamErrors) { | 
|  | // CCM with missing or invalid message type. | 
|  | auto result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::CCM)); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  | result = ToCricketFeedbackParam( | 
|  | {RtcpFeedbackType::CCM, RtcpFeedbackMessageType::PLI}); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  | // NACK with missing or invalid message type. | 
|  | result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::NACK)); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  | result = ToCricketFeedbackParam( | 
|  | {RtcpFeedbackType::NACK, RtcpFeedbackMessageType::FIR}); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  | // REMB with message type (should be left empty). | 
|  | result = ToCricketFeedbackParam( | 
|  | {RtcpFeedbackType::REMB, RtcpFeedbackMessageType::GENERIC_NACK}); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  | // TRANSPORT_CC with message type (should be left empty). | 
|  | result = ToCricketFeedbackParam( | 
|  | {RtcpFeedbackType::TRANSPORT_CC, RtcpFeedbackMessageType::FIR}); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToAudioCodec) { | 
|  | RtpCodecParameters codec; | 
|  | codec.name = "AuDiO"; | 
|  | codec.kind = cricket::MEDIA_TYPE_AUDIO; | 
|  | codec.payload_type = 120; | 
|  | codec.clock_rate.emplace(36000); | 
|  | codec.num_channels.emplace(6); | 
|  | codec.parameters["foo"] = "bar"; | 
|  | codec.rtcp_feedback.emplace_back(RtcpFeedbackType::TRANSPORT_CC); | 
|  | auto result = ToCricketCodec<cricket::AudioCodec>(codec); | 
|  | ASSERT_TRUE(result.ok()); | 
|  |  | 
|  | EXPECT_EQ("AuDiO", result.value().name); | 
|  | EXPECT_EQ(120, result.value().id); | 
|  | EXPECT_EQ(36000, result.value().clockrate); | 
|  | EXPECT_EQ(6u, result.value().channels); | 
|  | ASSERT_EQ(1u, result.value().params.size()); | 
|  | EXPECT_EQ("bar", result.value().params["foo"]); | 
|  | EXPECT_EQ(1u, result.value().feedback_params.params().size()); | 
|  | EXPECT_TRUE(result.value().feedback_params.Has( | 
|  | cricket::FeedbackParam("transport-cc"))); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToVideoCodec) { | 
|  | RtpCodecParameters codec; | 
|  | codec.name = "coolcodec"; | 
|  | codec.kind = cricket::MEDIA_TYPE_VIDEO; | 
|  | codec.payload_type = 101; | 
|  | codec.clock_rate.emplace(90000); | 
|  | codec.parameters["foo"] = "bar"; | 
|  | codec.parameters["PING"] = "PONG"; | 
|  | codec.rtcp_feedback.emplace_back(RtcpFeedbackType::TRANSPORT_CC); | 
|  | codec.rtcp_feedback.emplace_back(RtcpFeedbackType::NACK, | 
|  | RtcpFeedbackMessageType::PLI); | 
|  | auto result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | ASSERT_TRUE(result.ok()); | 
|  |  | 
|  | EXPECT_EQ("coolcodec", result.value().name); | 
|  | EXPECT_EQ(101, result.value().id); | 
|  | EXPECT_EQ(90000, result.value().clockrate); | 
|  | ASSERT_EQ(2u, result.value().params.size()); | 
|  | EXPECT_EQ("bar", result.value().params["foo"]); | 
|  | EXPECT_EQ("PONG", result.value().params["PING"]); | 
|  | EXPECT_EQ(2u, result.value().feedback_params.params().size()); | 
|  | EXPECT_TRUE(result.value().feedback_params.Has( | 
|  | cricket::FeedbackParam("transport-cc"))); | 
|  | EXPECT_TRUE(result.value().feedback_params.Has( | 
|  | cricket::FeedbackParam("nack", "pli"))); | 
|  | } | 
|  |  | 
|  | // Trying to convert to an AudioCodec if the kind is "video" should fail. | 
|  | TEST(RtpParametersConversionTest, ToCricketCodecInvalidKind) { | 
|  | RtpCodecParameters audio_codec; | 
|  | audio_codec.name = "opus"; | 
|  | audio_codec.kind = cricket::MEDIA_TYPE_VIDEO; | 
|  | audio_codec.payload_type = 111; | 
|  | audio_codec.clock_rate.emplace(48000); | 
|  | audio_codec.num_channels.emplace(2); | 
|  |  | 
|  | RtpCodecParameters video_codec; | 
|  | video_codec.name = "VP8"; | 
|  | video_codec.kind = cricket::MEDIA_TYPE_AUDIO; | 
|  | video_codec.payload_type = 102; | 
|  | video_codec.clock_rate.emplace(90000); | 
|  |  | 
|  | auto audio_result = ToCricketCodec<cricket::AudioCodec>(audio_codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, audio_result.error().type()); | 
|  |  | 
|  | auto video_result = ToCricketCodec<cricket::VideoCodec>(video_codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, video_result.error().type()); | 
|  |  | 
|  | // Sanity check that if the kind is correct, the conversion succeeds. | 
|  | audio_codec.kind = cricket::MEDIA_TYPE_AUDIO; | 
|  | video_codec.kind = cricket::MEDIA_TYPE_VIDEO; | 
|  | audio_result = ToCricketCodec<cricket::AudioCodec>(audio_codec); | 
|  | EXPECT_TRUE(audio_result.ok()); | 
|  | video_result = ToCricketCodec<cricket::VideoCodec>(video_codec); | 
|  | EXPECT_TRUE(video_result.ok()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToAudioCodecInvalidParameters) { | 
|  | // Missing channels. | 
|  | RtpCodecParameters codec; | 
|  | codec.name = "opus"; | 
|  | codec.kind = cricket::MEDIA_TYPE_AUDIO; | 
|  | codec.payload_type = 111; | 
|  | codec.clock_rate.emplace(48000); | 
|  | auto result = ToCricketCodec<cricket::AudioCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  |  | 
|  | // Negative number of channels. | 
|  | codec.num_channels.emplace(-1); | 
|  | result = ToCricketCodec<cricket::AudioCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.error().type()); | 
|  |  | 
|  | // Missing clock rate. | 
|  | codec.num_channels.emplace(2); | 
|  | codec.clock_rate.reset(); | 
|  | result = ToCricketCodec<cricket::AudioCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  |  | 
|  | // Negative clock rate. | 
|  | codec.clock_rate.emplace(-48000); | 
|  | result = ToCricketCodec<cricket::AudioCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.error().type()); | 
|  |  | 
|  | // Sanity check that conversion succeeds if these errors are fixed. | 
|  | codec.clock_rate.emplace(48000); | 
|  | result = ToCricketCodec<cricket::AudioCodec>(codec); | 
|  | EXPECT_TRUE(result.ok()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToVideoCodecInvalidParameters) { | 
|  | // Missing clock rate. | 
|  | RtpCodecParameters codec; | 
|  | codec.name = "VP8"; | 
|  | codec.kind = cricket::MEDIA_TYPE_VIDEO; | 
|  | codec.payload_type = 102; | 
|  | auto result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  |  | 
|  | // Invalid clock rate. | 
|  | codec.clock_rate.emplace(48000); | 
|  | result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  |  | 
|  | // Channels set (should be unset). | 
|  | codec.clock_rate.emplace(90000); | 
|  | codec.num_channels.emplace(2); | 
|  | result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  |  | 
|  | // Sanity check that conversion succeeds if these errors are fixed. | 
|  | codec.num_channels.reset(); | 
|  | result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_TRUE(result.ok()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketCodecInvalidPayloadType) { | 
|  | RtpCodecParameters codec; | 
|  | codec.name = "VP8"; | 
|  | codec.kind = cricket::MEDIA_TYPE_VIDEO; | 
|  | codec.clock_rate.emplace(90000); | 
|  |  | 
|  | codec.payload_type = -1000; | 
|  | auto result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.error().type()); | 
|  |  | 
|  | // Max payload type is 127. | 
|  | codec.payload_type = 128; | 
|  | result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.error().type()); | 
|  |  | 
|  | // Sanity check that conversion succeeds with a valid payload type. | 
|  | codec.payload_type = 127; | 
|  | result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_TRUE(result.ok()); | 
|  | } | 
|  |  | 
|  | // There are already tests for ToCricketFeedbackParam, but ensure that those | 
|  | // errors are propagated from ToCricketCodec. | 
|  | TEST(RtpParametersConversionTest, ToCricketCodecInvalidRtcpFeedback) { | 
|  | RtpCodecParameters codec; | 
|  | codec.name = "VP8"; | 
|  | codec.kind = cricket::MEDIA_TYPE_VIDEO; | 
|  | codec.clock_rate.emplace(90000); | 
|  | codec.payload_type = 99; | 
|  | codec.rtcp_feedback.emplace_back(RtcpFeedbackType::CCM, | 
|  | RtcpFeedbackMessageType::PLI); | 
|  |  | 
|  | auto result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  |  | 
|  | // Sanity check that conversion succeeds without invalid feedback. | 
|  | codec.rtcp_feedback.clear(); | 
|  | result = ToCricketCodec<cricket::VideoCodec>(codec); | 
|  | EXPECT_TRUE(result.ok()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketCodecs) { | 
|  | std::vector<RtpCodecParameters> codecs; | 
|  | RtpCodecParameters codec; | 
|  | codec.name = "VP8"; | 
|  | codec.kind = cricket::MEDIA_TYPE_VIDEO; | 
|  | codec.clock_rate.emplace(90000); | 
|  | codec.payload_type = 99; | 
|  | codecs.push_back(codec); | 
|  |  | 
|  | codec.name = "VP9"; | 
|  | codec.payload_type = 100; | 
|  | codecs.push_back(codec); | 
|  |  | 
|  | auto result = ToCricketCodecs<cricket::VideoCodec>(codecs); | 
|  | ASSERT_TRUE(result.ok()); | 
|  | ASSERT_EQ(2u, result.value().size()); | 
|  | EXPECT_EQ("VP8", result.value()[0].name); | 
|  | EXPECT_EQ(99, result.value()[0].id); | 
|  | EXPECT_EQ("VP9", result.value()[1].name); | 
|  | EXPECT_EQ(100, result.value()[1].id); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketCodecsDuplicatePayloadType) { | 
|  | std::vector<RtpCodecParameters> codecs; | 
|  | RtpCodecParameters codec; | 
|  | codec.name = "VP8"; | 
|  | codec.kind = cricket::MEDIA_TYPE_VIDEO; | 
|  | codec.clock_rate.emplace(90000); | 
|  | codec.payload_type = 99; | 
|  | codecs.push_back(codec); | 
|  |  | 
|  | codec.name = "VP9"; | 
|  | codec.payload_type = 99; | 
|  | codecs.push_back(codec); | 
|  |  | 
|  | auto result = ToCricketCodecs<cricket::VideoCodec>(codecs); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  |  | 
|  | // Sanity check that this succeeds without the duplicate payload type. | 
|  | codecs[1].payload_type = 120; | 
|  | result = ToCricketCodecs<cricket::VideoCodec>(codecs); | 
|  | EXPECT_TRUE(result.ok()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketRtpHeaderExtensions) { | 
|  | std::vector<RtpHeaderExtensionParameters> extensions = { | 
|  | {"http://example.com", 1}, {"urn:foo:bar", 14}}; | 
|  | auto result = ToCricketRtpHeaderExtensions(extensions); | 
|  | ASSERT_TRUE(result.ok()); | 
|  | ASSERT_EQ(2u, result.value().size()); | 
|  | EXPECT_EQ("http://example.com", result.value()[0].uri); | 
|  | EXPECT_EQ(1, result.value()[0].id); | 
|  | EXPECT_EQ("urn:foo:bar", result.value()[1].uri); | 
|  | EXPECT_EQ(14, result.value()[1].id); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketRtpHeaderExtensionsErrors) { | 
|  | // First, IDs outside the range 1-14. | 
|  | std::vector<RtpHeaderExtensionParameters> extensions = { | 
|  | {"http://example.com", 0}}; | 
|  | auto result = ToCricketRtpHeaderExtensions(extensions); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.error().type()); | 
|  |  | 
|  | extensions[0].id = 15; | 
|  | result = ToCricketRtpHeaderExtensions(extensions); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.error().type()); | 
|  |  | 
|  | // Duplicate IDs. | 
|  | extensions = {{"http://example.com", 1}, {"urn:foo:bar", 1}}; | 
|  | result = ToCricketRtpHeaderExtensions(extensions); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketStreamParamsVecSimple) { | 
|  | std::vector<RtpEncodingParameters> encodings; | 
|  | RtpEncodingParameters encoding; | 
|  | encoding.ssrc.emplace(0xbaadf00d); | 
|  | encodings.push_back(encoding); | 
|  | auto result = ToCricketStreamParamsVec(encodings); | 
|  | ASSERT_TRUE(result.ok()); | 
|  | ASSERT_EQ(1u, result.value().size()); | 
|  | EXPECT_EQ(1u, result.value()[0].ssrcs.size()); | 
|  | EXPECT_EQ(0xbaadf00d, result.value()[0].first_ssrc()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToCricketStreamParamsVecWithRtx) { | 
|  | std::vector<RtpEncodingParameters> encodings; | 
|  | RtpEncodingParameters encoding; | 
|  | // Test a corner case SSRC of 0. | 
|  | encoding.ssrc.emplace(0u); | 
|  | encoding.rtx.emplace(0xdeadbeef); | 
|  | encodings.push_back(encoding); | 
|  | auto result = ToCricketStreamParamsVec(encodings); | 
|  | ASSERT_TRUE(result.ok()); | 
|  | ASSERT_EQ(1u, result.value().size()); | 
|  | EXPECT_EQ(2u, result.value()[0].ssrcs.size()); | 
|  | EXPECT_EQ(0u, result.value()[0].first_ssrc()); | 
|  | uint32_t rtx_ssrc = 0; | 
|  | EXPECT_TRUE(result.value()[0].GetFidSsrc(0u, &rtx_ssrc)); | 
|  | EXPECT_EQ(0xdeadbeef, rtx_ssrc); | 
|  | } | 
|  |  | 
|  | // No encodings should be accepted; an endpoint may want to prepare a | 
|  | // decoder/encoder without having something to receive/send yet. | 
|  | TEST(RtpParametersConversionTest, ToCricketStreamParamsVecNoEncodings) { | 
|  | std::vector<RtpEncodingParameters> encodings; | 
|  | auto result = ToCricketStreamParamsVec(encodings); | 
|  | ASSERT_TRUE(result.ok()); | 
|  | EXPECT_EQ(0u, result.value().size()); | 
|  | } | 
|  |  | 
|  | // An encoding without SSRCs should be accepted. This could be the case when | 
|  | // SSRCs aren't signaled and payload-type based demuxing is used. | 
|  | TEST(RtpParametersConversionTest, ToCricketStreamParamsVecMissingSsrcs) { | 
|  | std::vector<RtpEncodingParameters> encodings = {{}}; | 
|  | // Creates RtxParameters with empty SSRC. | 
|  | encodings[0].rtx.emplace(); | 
|  | auto result = ToCricketStreamParamsVec(encodings); | 
|  | ASSERT_TRUE(result.ok()); | 
|  | EXPECT_EQ(0u, result.value().size()); | 
|  | } | 
|  |  | 
|  | // The media engine doesn't have a way of receiving an RTX SSRC that's known | 
|  | // with a primary SSRC that's unknown, so this should produce an error. | 
|  | TEST(RtpParametersConversionTest, ToStreamParamsWithPrimarySsrcSetAndRtxUnset) { | 
|  | std::vector<RtpEncodingParameters> encodings = {{}}; | 
|  | encodings[0].rtx.emplace(0xdeadbeef); | 
|  | EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, | 
|  | ToCricketStreamParamsVec(encodings).error().type()); | 
|  | } | 
|  |  | 
|  | // TODO(deadbeef): Update this test when we support multiple encodings. | 
|  | TEST(RtpParametersConversionTest, ToCricketStreamParamsVecMultipleEncodings) { | 
|  | std::vector<RtpEncodingParameters> encodings = {{}, {}}; | 
|  | auto result = ToCricketStreamParamsVec(encodings); | 
|  | EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, result.error().type()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToRtcpFeedback) { | 
|  | rtc::Optional<RtcpFeedback> result = ToRtcpFeedback({"ccm", "fir"}); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::CCM, RtcpFeedbackMessageType::FIR), | 
|  | *result); | 
|  | result = ToRtcpFeedback(cricket::FeedbackParam("nack")); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, | 
|  | RtcpFeedbackMessageType::GENERIC_NACK), | 
|  | *result); | 
|  | result = ToRtcpFeedback({"nack", "pli"}); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI), | 
|  | *result); | 
|  | result = ToRtcpFeedback(cricket::FeedbackParam("goog-remb")); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::REMB), *result); | 
|  | result = ToRtcpFeedback(cricket::FeedbackParam("transport-cc")); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC), *result); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToRtcpFeedbackErrors) { | 
|  | // CCM with missing or invalid message type. | 
|  | rtc::Optional<RtcpFeedback> result = ToRtcpFeedback({"ccm", "pli"}); | 
|  | EXPECT_FALSE(result); | 
|  | result = ToRtcpFeedback(cricket::FeedbackParam("ccm")); | 
|  | EXPECT_FALSE(result); | 
|  | // NACK with missing or invalid message type. | 
|  | result = ToRtcpFeedback({"nack", "fir"}); | 
|  | EXPECT_FALSE(result); | 
|  | // REMB with message type (should be left empty). | 
|  | result = ToRtcpFeedback({"goog-remb", "pli"}); | 
|  | EXPECT_FALSE(result); | 
|  | // TRANSPORT_CC with message type (should be left empty). | 
|  | result = ToRtcpFeedback({"transport-cc", "fir"}); | 
|  | EXPECT_FALSE(result); | 
|  | // Unknown message type. | 
|  | result = ToRtcpFeedback(cricket::FeedbackParam("foo")); | 
|  | EXPECT_FALSE(result); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToAudioRtpCodecCapability) { | 
|  | cricket::AudioCodec cricket_codec; | 
|  | cricket_codec.name = "foo"; | 
|  | cricket_codec.id = 50; | 
|  | cricket_codec.clockrate = 22222; | 
|  | cricket_codec.channels = 4; | 
|  | cricket_codec.params["foo"] = "bar"; | 
|  | cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc")); | 
|  | RtpCodecCapability codec = ToRtpCodecCapability(cricket_codec); | 
|  |  | 
|  | EXPECT_EQ("foo", codec.name); | 
|  | EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, codec.kind); | 
|  | EXPECT_EQ(rtc::Optional<int>(50), codec.preferred_payload_type); | 
|  | EXPECT_EQ(rtc::Optional<int>(22222), codec.clock_rate); | 
|  | EXPECT_EQ(rtc::Optional<int>(4), codec.num_channels); | 
|  | ASSERT_EQ(1u, codec.parameters.size()); | 
|  | EXPECT_EQ("bar", codec.parameters["foo"]); | 
|  | EXPECT_EQ(1u, codec.rtcp_feedback.size()); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC), | 
|  | codec.rtcp_feedback[0]); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToVideoRtpCodecCapability) { | 
|  | cricket::VideoCodec cricket_codec; | 
|  | cricket_codec.name = "VID"; | 
|  | cricket_codec.id = 101; | 
|  | cricket_codec.clockrate = 80000; | 
|  | cricket_codec.params["foo"] = "bar"; | 
|  | cricket_codec.params["ANOTHER"] = "param"; | 
|  | cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc")); | 
|  | cricket_codec.feedback_params.Add({"nack", "pli"}); | 
|  | RtpCodecCapability codec = ToRtpCodecCapability(cricket_codec); | 
|  |  | 
|  | EXPECT_EQ("VID", codec.name); | 
|  | EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, codec.kind); | 
|  | EXPECT_EQ(rtc::Optional<int>(101), codec.preferred_payload_type); | 
|  | EXPECT_EQ(rtc::Optional<int>(80000), codec.clock_rate); | 
|  | ASSERT_EQ(2u, codec.parameters.size()); | 
|  | EXPECT_EQ("bar", codec.parameters["foo"]); | 
|  | EXPECT_EQ("param", codec.parameters["ANOTHER"]); | 
|  | EXPECT_EQ(2u, codec.rtcp_feedback.size()); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC), | 
|  | codec.rtcp_feedback[0]); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI), | 
|  | codec.rtcp_feedback[1]); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToRtpEncodingsWithEmptyStreamParamsVec) { | 
|  | cricket::StreamParamsVec streams; | 
|  | auto rtp_encodings = ToRtpEncodings(streams); | 
|  | ASSERT_EQ(0u, rtp_encodings.size()); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToRtpEncodingsWithMultipleStreamParams) { | 
|  | cricket::StreamParamsVec streams; | 
|  | cricket::StreamParams stream1; | 
|  | stream1.ssrcs.push_back(1111u); | 
|  | stream1.AddFidSsrc(1111u, 0xaaaaaaaa); | 
|  |  | 
|  | cricket::StreamParams stream2; | 
|  | stream2.ssrcs.push_back(2222u); | 
|  | stream2.AddFidSsrc(2222u, 0xaaaaaaab); | 
|  |  | 
|  | streams.push_back(stream1); | 
|  | streams.push_back(stream2); | 
|  |  | 
|  | auto rtp_encodings = ToRtpEncodings(streams); | 
|  | ASSERT_EQ(2u, rtp_encodings.size()); | 
|  | EXPECT_EQ(1111u, rtp_encodings[0].ssrc); | 
|  | EXPECT_EQ(0xaaaaaaaa, rtp_encodings[0].rtx->ssrc); | 
|  | EXPECT_EQ(2222u, rtp_encodings[1].ssrc); | 
|  | EXPECT_EQ(0xaaaaaaab, rtp_encodings[1].rtx->ssrc); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToAudioRtpCodecParameters) { | 
|  | cricket::AudioCodec cricket_codec; | 
|  | cricket_codec.name = "foo"; | 
|  | cricket_codec.id = 50; | 
|  | cricket_codec.clockrate = 22222; | 
|  | cricket_codec.channels = 4; | 
|  | cricket_codec.params["foo"] = "bar"; | 
|  | cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc")); | 
|  | RtpCodecParameters codec = ToRtpCodecParameters(cricket_codec); | 
|  |  | 
|  | EXPECT_EQ("foo", codec.name); | 
|  | EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, codec.kind); | 
|  | EXPECT_EQ(50, codec.payload_type); | 
|  | EXPECT_EQ(rtc::Optional<int>(22222), codec.clock_rate); | 
|  | EXPECT_EQ(rtc::Optional<int>(4), codec.num_channels); | 
|  | ASSERT_EQ(1u, codec.parameters.size()); | 
|  | EXPECT_EQ("bar", codec.parameters["foo"]); | 
|  | EXPECT_EQ(1u, codec.rtcp_feedback.size()); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC), | 
|  | codec.rtcp_feedback[0]); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToVideoRtpCodecParameters) { | 
|  | cricket::VideoCodec cricket_codec; | 
|  | cricket_codec.name = "VID"; | 
|  | cricket_codec.id = 101; | 
|  | cricket_codec.clockrate = 80000; | 
|  | cricket_codec.params["foo"] = "bar"; | 
|  | cricket_codec.params["ANOTHER"] = "param"; | 
|  | cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc")); | 
|  | cricket_codec.feedback_params.Add({"nack", "pli"}); | 
|  | RtpCodecParameters codec = ToRtpCodecParameters(cricket_codec); | 
|  |  | 
|  | EXPECT_EQ("VID", codec.name); | 
|  | EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, codec.kind); | 
|  | EXPECT_EQ(101, codec.payload_type); | 
|  | EXPECT_EQ(rtc::Optional<int>(80000), codec.clock_rate); | 
|  | ASSERT_EQ(2u, codec.parameters.size()); | 
|  | EXPECT_EQ("bar", codec.parameters["foo"]); | 
|  | EXPECT_EQ("param", codec.parameters["ANOTHER"]); | 
|  | EXPECT_EQ(2u, codec.rtcp_feedback.size()); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC), | 
|  | codec.rtcp_feedback[0]); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI), | 
|  | codec.rtcp_feedback[1]); | 
|  | } | 
|  |  | 
|  | // An unknown feedback param should just be ignored. | 
|  | TEST(RtpParametersConversionTest, ToRtpCodecCapabilityUnknownFeedbackParam) { | 
|  | cricket::AudioCodec cricket_codec; | 
|  | cricket_codec.name = "foo"; | 
|  | cricket_codec.id = 50; | 
|  | cricket_codec.clockrate = 22222; | 
|  | cricket_codec.channels = 4; | 
|  | cricket_codec.params["foo"] = "bar"; | 
|  | cricket_codec.feedback_params.Add({"unknown", "param"}); | 
|  | cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc")); | 
|  | RtpCodecCapability codec = ToRtpCodecCapability(cricket_codec); | 
|  |  | 
|  | ASSERT_EQ(1u, codec.rtcp_feedback.size()); | 
|  | EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC), | 
|  | codec.rtcp_feedback[0]); | 
|  | } | 
|  |  | 
|  | // Most of ToRtpCapabilities is tested by ToRtpCodecCapability, but we need to | 
|  | // test that the result of ToRtpCodecCapability ends up in the result, and that | 
|  | // the "fec" list is assembled correctly. | 
|  | TEST(RtpParametersConversionTest, ToRtpCapabilities) { | 
|  | cricket::VideoCodec vp8; | 
|  | vp8.name = "VP8"; | 
|  | vp8.id = 101; | 
|  | vp8.clockrate = 90000; | 
|  |  | 
|  | cricket::VideoCodec red; | 
|  | red.name = "red"; | 
|  | red.id = 102; | 
|  | red.clockrate = 90000; | 
|  |  | 
|  | cricket::VideoCodec ulpfec; | 
|  | ulpfec.name = "ulpfec"; | 
|  | ulpfec.id = 103; | 
|  | ulpfec.clockrate = 90000; | 
|  |  | 
|  | cricket::VideoCodec flexfec; | 
|  | flexfec.name = "flexfec-03"; | 
|  | flexfec.id = 102; | 
|  | flexfec.clockrate = 90000; | 
|  |  | 
|  | RtpCapabilities capabilities = ToRtpCapabilities<cricket::VideoCodec>( | 
|  | {vp8, ulpfec}, {{"uri", 1}, {"uri2", 3}}); | 
|  | ASSERT_EQ(2u, capabilities.codecs.size()); | 
|  | EXPECT_EQ("VP8", capabilities.codecs[0].name); | 
|  | EXPECT_EQ("ulpfec", capabilities.codecs[1].name); | 
|  | ASSERT_EQ(2u, capabilities.header_extensions.size()); | 
|  | EXPECT_EQ("uri", capabilities.header_extensions[0].uri); | 
|  | EXPECT_EQ(1, capabilities.header_extensions[0].preferred_id); | 
|  | EXPECT_EQ("uri2", capabilities.header_extensions[1].uri); | 
|  | EXPECT_EQ(3, capabilities.header_extensions[1].preferred_id); | 
|  | EXPECT_EQ(0u, capabilities.fec.size()); | 
|  |  | 
|  | capabilities = ToRtpCapabilities<cricket::VideoCodec>( | 
|  | {vp8, red, ulpfec}, cricket::RtpHeaderExtensions()); | 
|  | EXPECT_EQ(3u, capabilities.codecs.size()); | 
|  | EXPECT_EQ(2u, capabilities.fec.size()); | 
|  | EXPECT_NE(capabilities.fec.end(), | 
|  | std::find(capabilities.fec.begin(), capabilities.fec.end(), | 
|  | FecMechanism::RED)); | 
|  | EXPECT_NE(capabilities.fec.end(), | 
|  | std::find(capabilities.fec.begin(), capabilities.fec.end(), | 
|  | FecMechanism::RED_AND_ULPFEC)); | 
|  |  | 
|  | capabilities = ToRtpCapabilities<cricket::VideoCodec>( | 
|  | {vp8, red, flexfec}, cricket::RtpHeaderExtensions()); | 
|  | EXPECT_EQ(3u, capabilities.codecs.size()); | 
|  | EXPECT_EQ(2u, capabilities.fec.size()); | 
|  | EXPECT_NE(capabilities.fec.end(), | 
|  | std::find(capabilities.fec.begin(), capabilities.fec.end(), | 
|  | FecMechanism::RED)); | 
|  | EXPECT_NE(capabilities.fec.end(), | 
|  | std::find(capabilities.fec.begin(), capabilities.fec.end(), | 
|  | FecMechanism::FLEXFEC)); | 
|  | } | 
|  |  | 
|  | TEST(RtpParametersConversionTest, ToRtpParameters) { | 
|  | cricket::VideoCodec vp8; | 
|  | vp8.name = "VP8"; | 
|  | vp8.id = 101; | 
|  | vp8.clockrate = 90000; | 
|  |  | 
|  | cricket::VideoCodec red; | 
|  | red.name = "red"; | 
|  | red.id = 102; | 
|  | red.clockrate = 90000; | 
|  |  | 
|  | cricket::VideoCodec ulpfec; | 
|  | ulpfec.name = "ulpfec"; | 
|  | ulpfec.id = 103; | 
|  | ulpfec.clockrate = 90000; | 
|  |  | 
|  | cricket::StreamParamsVec streams; | 
|  | cricket::StreamParams stream; | 
|  | stream.ssrcs.push_back(1234u); | 
|  | streams.push_back(stream); | 
|  |  | 
|  | RtpParameters rtp_parameters = ToRtpParameters<cricket::VideoCodec>( | 
|  | {vp8, red, ulpfec}, {{"uri", 1}, {"uri2", 3}}, streams); | 
|  | ASSERT_EQ(3u, rtp_parameters.codecs.size()); | 
|  | EXPECT_EQ("VP8", rtp_parameters.codecs[0].name); | 
|  | EXPECT_EQ("red", rtp_parameters.codecs[1].name); | 
|  | EXPECT_EQ("ulpfec", rtp_parameters.codecs[2].name); | 
|  | ASSERT_EQ(2u, rtp_parameters.header_extensions.size()); | 
|  | EXPECT_EQ("uri", rtp_parameters.header_extensions[0].uri); | 
|  | EXPECT_EQ(1, rtp_parameters.header_extensions[0].id); | 
|  | EXPECT_EQ("uri2", rtp_parameters.header_extensions[1].uri); | 
|  | EXPECT_EQ(3, rtp_parameters.header_extensions[1].id); | 
|  | ASSERT_EQ(1u, rtp_parameters.encodings.size()); | 
|  | EXPECT_EQ(1234u, rtp_parameters.encodings[0].ssrc); | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |