From c0352d566a4291cf587c25ca023e44b52ad7484e Mon Sep 17 00:00:00 2001 From: "solenberg@webrtc.org" Date: Mon, 20 May 2013 20:55:07 +0000 Subject: [PATCH] Fix assertions in rtp_header_extension.h caused by not handling the AudioLevel extension. Added unit tests to do basic checks of the AudioLevel extension. BUG= R=asapersson@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1510004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4069 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../rtp_rtcp/source/rtp_header_extension.h | 8 + webrtc/modules/rtp_rtcp/source/rtp_sender.cc | 5 + .../rtp_rtcp/source/rtp_sender_unittest.cc | 158 +++++++++++++++++- 3 files changed, 166 insertions(+), 5 deletions(-) diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h index 35391d2ce4..d39ffdb441 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h @@ -22,6 +22,7 @@ const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE; const size_t kRtpOneByteHeaderLength = 4; const size_t kTransmissionTimeOffsetLength = 4; +const size_t kAudioLevelLength = 2; const size_t kAbsoluteSendTimeLength = 4; struct HeaderExtension { @@ -35,6 +36,13 @@ struct HeaderExtension { case kRtpExtensionTransmissionTimeOffset: length = kTransmissionTimeOffsetLength; break; + case kRtpExtensionAudioLevel: + // TODO(solenberg): Because of how the audio level extension is handled + // in RTPSenderAudio::SendAudio(), we cannot set the actual length here + // but must leave it at zero. The consequence is that any other header + // extensions registered for an audio channel are effectively ignored. + // length = kAudioLevelLength; + break; case kRtpExtensionAbsoluteSendTime: length = kAbsoluteSendTimeLength; break; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index 91dd1d26d5..ed2412e185 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -892,6 +892,11 @@ uint16_t RTPSender::BuildRTPHeaderExtension( block_length = BuildTransmissionTimeOffsetExtension( data_buffer + kHeaderLength + total_block_length); break; + case kRtpExtensionAudioLevel: + // Because AudioLevel is handled specially by RTPSenderAudio, we pretend + // we don't have to care about it here, which is true until we wan't to + // use it together with any of the other extensions we support. + break; case kRtpExtensionAbsoluteSendTime: block_length = BuildAbsoluteSendTimeExtension( data_buffer + kHeaderLength + total_block_length); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index f62de5d6e3..9ee59e2297 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -34,6 +34,9 @@ const uint16_t kSeqNum = 33; const int kTimeOffset = 22222; const int kMaxPacketLength = 1500; const uint32_t kAbsoluteSendTime = 0x00aabbcc; +const uint8_t kAudioLevel = 0x5a; +const uint8_t kAudioLevelExtensionId = 9; +const int kAudioPayload = 103; } // namespace using testing::_; @@ -63,23 +66,31 @@ class RtpSenderTest : public ::testing::Test { RtpSenderTest() : fake_clock_(123456789), mock_paced_sender_(), - rtp_sender_(new RTPSender(0, false, &fake_clock_, &transport_, NULL, - &mock_paced_sender_)), + rtp_sender_(), + payload_(kPayload), + transport_(), kMarkerBit(true) { - rtp_sender_->SetSequenceNumber(kSeqNum); EXPECT_CALL(mock_paced_sender_, SendPacket(_, _, _, _, _)).WillRepeatedly(testing::Return(true)); } + + virtual void SetUp() { + rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL, + &mock_paced_sender_)); + rtp_sender_->SetSequenceNumber(kSeqNum); + } + SimulatedClock fake_clock_; MockPacedSender mock_paced_sender_; scoped_ptr rtp_sender_; + int payload_; LoopbackTransportTest transport_; const bool kMarkerBit; uint8_t packet_[kMaxPacketLength]; void VerifyRTPHeaderCommon(const WebRtcRTPHeader& rtp_header) { EXPECT_EQ(kMarkerBit, rtp_header.header.markerBit); - EXPECT_EQ(kPayload, rtp_header.header.payloadType); + EXPECT_EQ(payload_, rtp_header.header.payloadType); EXPECT_EQ(kSeqNum, rtp_header.header.sequenceNumber); EXPECT_EQ(kTimestamp, rtp_header.header.timestamp); EXPECT_EQ(rtp_sender_->SSRC(), rtp_header.header.ssrc); @@ -110,6 +121,20 @@ TEST_F(RtpSenderTest, RegisterRtpAbsoluteSendTimeHeaderExtension) { EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); } +TEST_F(RtpSenderTest, RegisterRtpAudioLevelHeaderExtension) { + EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionAudioLevel, kAudioLevelExtensionId)); + // Accounted size for audio level is zero because it is currently specially + // treated by RTPSenderAudio. + EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); + // EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength, + // rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( + kRtpExtensionAudioLevel)); + EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); +} + TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) { EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( @@ -120,6 +145,10 @@ TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) { kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionAudioLevel, kAudioLevelExtensionId)); + EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + + kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset)); EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength, @@ -127,6 +156,9 @@ TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) { EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime)); EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( + kRtpExtensionAudioLevel)); + EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); } TEST_F(RtpSenderTest, BuildRTPPacket) { @@ -465,5 +497,121 @@ TEST_F(RtpSenderTest, SendGenericVideo) { EXPECT_EQ(0, memcmp(payload, payload_data, sizeof(payload))); } -} // namespace webrtc +class RtpSenderAudioTest : public RtpSenderTest { + protected: + RtpSenderAudioTest() {} + virtual void SetUp() { + payload_ = kAudioPayload; + rtp_sender_.reset(new RTPSender(0, true, &fake_clock_, &transport_, NULL, + &mock_paced_sender_)); + rtp_sender_->SetSequenceNumber(kSeqNum); + } +}; + +TEST_F(RtpSenderAudioTest, BuildRTPPacketWithAudioLevelExtension) { + EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(true, + kAudioLevelExtensionId)); + EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel)); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionAudioLevel, kAudioLevelExtensionId)); + + int32_t length = rtp_sender_->BuildRTPheader(packet_, + kAudioPayload, + kMarkerBit, + kTimestamp); + EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); + + // Currently, no space is added by for header extension by BuildRTPHeader(). + EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); + + // Verify + webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); + webrtc::WebRtcRTPHeader rtp_header; + + RtpHeaderExtensionMap map; + map.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId); + const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map); + + ASSERT_TRUE(valid_rtp_header); + ASSERT_FALSE(rtp_parser.RTCP()); + VerifyRTPHeaderCommon(rtp_header); + EXPECT_EQ(length, rtp_header.header.headerLength); + // TODO(solenberg): Should verify that we got audio level in header extension. + + // Parse without map extension + webrtc::WebRtcRTPHeader rtp_header2; + const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, NULL); + + ASSERT_TRUE(valid_rtp_header2); + VerifyRTPHeaderCommon(rtp_header2); + EXPECT_EQ(length, rtp_header2.header.headerLength); + // TODO(solenberg): Should verify that we didn't get audio level. +} + +TEST_F(RtpSenderAudioTest, SendAudio) { + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME"; + const uint8_t payload_type = 127; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + + ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kAudioFrameCN, payload_type, 1234, + 4321, payload, sizeof(payload), + NULL)); + + ModuleRTPUtility::RTPHeaderParser rtp_parser(transport_.last_sent_packet_, + transport_.last_sent_packet_len_); + webrtc::WebRtcRTPHeader rtp_header; + ASSERT_TRUE(rtp_parser.Parse(rtp_header)); + + const uint8_t* payload_data = ModuleRTPUtility::GetPayloadData(&rtp_header, + transport_.last_sent_packet_); + + ASSERT_EQ(sizeof(payload), ModuleRTPUtility::GetPayloadDataLength(&rtp_header, + transport_.last_sent_packet_len_)); + + EXPECT_EQ(0, memcmp(payload, payload_data, sizeof(payload))); +} + +TEST_F(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) { + EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(true, + kAudioLevelExtensionId)); + EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel)); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionAudioLevel, kAudioLevelExtensionId)); + + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME"; + const uint8_t payload_type = 127; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + + ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kAudioFrameCN, payload_type, 1234, + 4321, payload, sizeof(payload), + NULL)); + + ModuleRTPUtility::RTPHeaderParser rtp_parser(transport_.last_sent_packet_, + transport_.last_sent_packet_len_); + webrtc::WebRtcRTPHeader rtp_header; + ASSERT_TRUE(rtp_parser.Parse(rtp_header)); + + const uint8_t* payload_data = ModuleRTPUtility::GetPayloadData(&rtp_header, + transport_.last_sent_packet_); + + ASSERT_EQ(sizeof(payload), ModuleRTPUtility::GetPayloadDataLength(&rtp_header, + transport_.last_sent_packet_len_)); + + EXPECT_EQ(0, memcmp(payload, payload_data, sizeof(payload))); + + uint8_t extension[] = { 0xbe, 0xde, 0x00, 0x01, + (kAudioLevelExtensionId << 4) + 0, // ID + length. + kAudioLevel, // Data. + 0x00, 0x00 // Padding. + }; + + EXPECT_EQ(0, memcmp(extension, payload_data - sizeof(extension), + sizeof(extension))); +} + +} // namespace webrtc