summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwu@webrtc.org <wu@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-03-06 23:49:08 +0000
committerwu@webrtc.org <wu@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-03-06 23:49:08 +0000
commit9a8232203a0793a3bbd7edc8bba04a4b48e00210 (patch)
tree7c2ab0789be2304ee9d5f13cde4f54b86c132393
parent7a560797ddeafa0472a0bd85aa9ad62b2530ffba (diff)
downloadwebrtc-9a8232203a0793a3bbd7edc8bba04a4b48e00210.tar.gz
Help to land 7969005 on behalf of solenberg. The review and try is done in 7969005.
- Add ability to VoE to send Absolute Sender Time header extension. - Refactor handling of RTP header extensions in VoE to work the same as in ViE. - Add API to enable receiving Absolute Sender Time in VoE. This is part of the work to include audio packets in bandwidth estimation, for better accuracy in estimates. BUG= TBR=solenberg@webrtc.org,henrikg@webrtc.org,stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/9509004 git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@5654 4adac7df-926f-26a2-2b94-8c16560cd09d
-rw-r--r--modules/interface/module_common_types.h5
-rw-r--r--modules/rtp_rtcp/interface/rtp_rtcp.h19
-rw-r--r--modules/rtp_rtcp/source/rtp_header_extension.h8
-rw-r--r--modules/rtp_rtcp/source/rtp_rtcp_impl.cc23
-rw-r--r--modules/rtp_rtcp/source/rtp_rtcp_impl.h8
-rw-r--r--modules/rtp_rtcp/source/rtp_sender.cc105
-rw-r--r--modules/rtp_rtcp/source/rtp_sender.h18
-rw-r--r--modules/rtp_rtcp/source/rtp_sender_audio.cc89
-rw-r--r--modules/rtp_rtcp/source/rtp_sender_audio.h13
-rw-r--r--modules/rtp_rtcp/source/rtp_sender_unittest.cc153
-rw-r--r--modules/rtp_rtcp/source/rtp_utility.cc13
-rw-r--r--voice_engine/channel.cc44
-rw-r--r--voice_engine/channel.h7
-rw-r--r--voice_engine/include/voe_rtp_rtcp.h19
-rw-r--r--voice_engine/test/auto_test/standard/rtp_rtcp_extensions.cc147
-rw-r--r--voice_engine/voe_rtp_rtcp_impl.cc102
-rw-r--r--voice_engine/voe_rtp_rtcp_impl.h18
-rw-r--r--voice_engine/voice_engine.gyp1
18 files changed, 491 insertions, 301 deletions
diff --git a/modules/interface/module_common_types.h b/modules/interface/module_common_types.h
index 2494d68b..f9f1676f 100644
--- a/modules/interface/module_common_types.h
+++ b/modules/interface/module_common_types.h
@@ -32,6 +32,11 @@ struct RTPHeaderExtension {
int32_t transmissionTimeOffset;
bool hasAbsoluteSendTime;
uint32_t absoluteSendTime;
+
+ // Audio Level includes both level in dBov and voiced/unvoiced bit. See:
+ // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
+ bool hasAudioLevel;
+ uint8_t audioLevel;
};
struct RTPHeader {
diff --git a/modules/rtp_rtcp/interface/rtp_rtcp.h b/modules/rtp_rtcp/interface/rtp_rtcp.h
index 080aafdb..cd8550c8 100644
--- a/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -671,25 +671,6 @@ class RtpRtcp : public Module {
int8_t& payloadType) const = 0;
/*
- * Set status and ID for header-extension-for-audio-level-indication.
- * See http://tools.ietf.org/html/rfc6464 for more details.
- *
- * return -1 on failure else 0
- */
- virtual int32_t SetRTPAudioLevelIndicationStatus(
- const bool enable,
- const uint8_t ID) = 0;
-
- /*
- * Get status and ID for header-extension-for-audio-level-indication.
- *
- * return -1 on failure else 0
- */
- virtual int32_t GetRTPAudioLevelIndicationStatus(
- bool& enable,
- uint8_t& ID) const = 0;
-
- /*
* Store the audio level in dBov for header-extension-for-audio-level-
* indication.
* This API shall be called before transmision of an RTP packet to ensure
diff --git a/modules/rtp_rtcp/source/rtp_header_extension.h b/modules/rtp_rtcp/source/rtp_header_extension.h
index fcc7587c..b41653c8 100644
--- a/modules/rtp_rtcp/source/rtp_header_extension.h
+++ b/modules/rtp_rtcp/source/rtp_header_extension.h
@@ -22,7 +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 kAudioLevelLength = 4;
const size_t kAbsoluteSendTimeLength = 4;
struct HeaderExtension {
@@ -37,11 +37,7 @@ struct HeaderExtension {
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;
+ length = kAudioLevelLength;
break;
case kRtpExtensionAbsoluteSendTime:
length = kAbsoluteSendTimeLength;
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index b9609419..575da60a 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -1209,29 +1209,6 @@ int32_t ModuleRtpRtcpImpl::SetAudioPacketSize(
return rtp_sender_.SetAudioPacketSize(packet_size_samples);
}
-int32_t ModuleRtpRtcpImpl::SetRTPAudioLevelIndicationStatus(
- const bool enable,
- const uint8_t id) {
-
- WEBRTC_TRACE(kTraceModuleCall,
- kTraceRtpRtcp,
- id_,
- "SetRTPAudioLevelIndicationStatus(enable=%d, ID=%u)",
- enable,
- id);
- return rtp_sender_.SetAudioLevelIndicationStatus(enable, id);
-}
-
-int32_t ModuleRtpRtcpImpl::GetRTPAudioLevelIndicationStatus(
- bool& enable,
- uint8_t& id) const {
- WEBRTC_TRACE(kTraceModuleCall,
- kTraceRtpRtcp,
- id_,
- "GetRTPAudioLevelIndicationStatus()");
- return rtp_sender_.AudioLevelIndicationStatus(&enable, &id);
-}
-
int32_t ModuleRtpRtcpImpl::SetAudioLevel(
const uint8_t level_d_bov) {
WEBRTC_TRACE(kTraceModuleCall,
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 34c4fa2f..d8cbc80d 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -295,14 +295,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
// Get payload type for Redundant Audio Data RFC 2198.
virtual int32_t SendREDPayloadType(int8_t& payload_type) const OVERRIDE;
- // Set status and id for header-extension-for-audio-level-indication.
- virtual int32_t SetRTPAudioLevelIndicationStatus(
- const bool enable, const uint8_t id) OVERRIDE;
-
- // Get status and id for header-extension-for-audio-level-indication.
- virtual int32_t GetRTPAudioLevelIndicationStatus(
- bool& enable, uint8_t& id) const OVERRIDE;
-
// Store the audio level in d_bov for header-extension-for-audio-level-
// indication.
virtual int32_t SetAudioLevel(const uint8_t level_d_bov) OVERRIDE;
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index 0711356e..af1c49bc 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -1117,9 +1117,8 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer) const {
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.
+ block_length = BuildAudioLevelExtension(
+ data_buffer + kHeaderLength + total_block_length);
break;
case kRtpExtensionAbsoluteSendTime:
block_length = BuildAbsoluteSendTimeExtension(
@@ -1179,8 +1178,42 @@ uint8_t RTPSender::BuildTransmissionTimeOffsetExtension(
return kTransmissionTimeOffsetLength;
}
-uint8_t RTPSender::BuildAbsoluteSendTimeExtension(
- uint8_t* data_buffer) const {
+uint8_t RTPSender::BuildAudioLevelExtension(uint8_t* data_buffer) const {
+ // An RTP Header Extension for Client-to-Mixer Audio Level Indication
+ //
+ // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
+ //
+ // The form of the audio level extension block:
+ //
+ // 0 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | ID | len=0 |V| level | 0x00 | 0x00 |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ // Note that we always include 2 pad bytes, which will result in legal and
+ // correctly parsed RTP, but may be a bit wasteful if more short extensions
+ // are implemented. Right now the pad bytes would anyway be required at end
+ // of the extension block, so it makes no difference.
+
+ // Get id defined by user.
+ uint8_t id;
+ if (rtp_header_extension_map_.GetId(kRtpExtensionAudioLevel, &id) != 0) {
+ // Not registered.
+ return 0;
+ }
+ size_t pos = 0;
+ const uint8_t len = 0;
+ data_buffer[pos++] = (id << 4) + len;
+ data_buffer[pos++] = (1 << 7) + 0; // Voice, 0 dBov.
+ data_buffer[pos++] = 0; // Padding.
+ data_buffer[pos++] = 0; // Padding.
+ // kAudioLevelLength is including pad bytes.
+ assert(pos == kAudioLevelLength);
+ return kAudioLevelLength;
+}
+
+uint8_t RTPSender::BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const {
// Absolute send time in RTP streams.
//
// The absolute send time is signaled to the receiver in-band using the
@@ -1265,6 +1298,55 @@ bool RTPSender::UpdateTransmissionTimeOffset(
return true;
}
+bool RTPSender::UpdateAudioLevel(uint8_t *rtp_packet,
+ const uint16_t rtp_packet_length,
+ const RTPHeader &rtp_header,
+ const bool is_voiced,
+ const uint8_t dBov) const {
+ CriticalSectionScoped cs(send_critsect_);
+
+ // Get length until start of header extension block.
+ int extension_block_pos =
+ rtp_header_extension_map_.GetLengthUntilBlockStartInBytes(
+ kRtpExtensionAudioLevel);
+ if (extension_block_pos < 0) {
+ WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
+ "Failed to update audio level, not registered.");
+ return false;
+ }
+ int block_pos = 12 + rtp_header.numCSRCs + extension_block_pos;
+ if (rtp_packet_length < block_pos + kAudioLevelLength ||
+ rtp_header.headerLength < block_pos + kAudioLevelLength) {
+ WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
+ "Failed to update audio level, invalid length.");
+ return false;
+ }
+ // Verify that header contains extension.
+ if (!((rtp_packet[12 + rtp_header.numCSRCs] == 0xBE) &&
+ (rtp_packet[12 + rtp_header.numCSRCs + 1] == 0xDE))) {
+ WEBRTC_TRACE(
+ kTraceStream, kTraceRtpRtcp, id_,
+ "Failed to update audio level, hdr extension not found.");
+ return false;
+ }
+ // Get id.
+ uint8_t id = 0;
+ if (rtp_header_extension_map_.GetId(kRtpExtensionAudioLevel, &id) != 0) {
+ WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
+ "Failed to update audio level, no id.");
+ return false;
+ }
+ // Verify first byte in block.
+ const uint8_t first_block_byte = (id << 4) + 0;
+ if (rtp_packet[block_pos] != first_block_byte) {
+ WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
+ "Failed to update audio level.");
+ return false;
+ }
+ rtp_packet[block_pos + 1] = (is_voiced ? 0x80 : 0x00) + (dBov & 0x7f);
+ return true;
+}
+
bool RTPSender::UpdateAbsoluteSendTime(
uint8_t *rtp_packet, const uint16_t rtp_packet_length,
const RTPHeader &rtp_header, const int64_t now_ms) const {
@@ -1463,19 +1545,6 @@ int32_t RTPSender::SetAudioPacketSize(
return audio_->SetAudioPacketSize(packet_size_samples);
}
-int32_t RTPSender::SetAudioLevelIndicationStatus(const bool enable,
- const uint8_t ID) {
- if (!audio_configured_) {
- return -1;
- }
- return audio_->SetAudioLevelIndicationStatus(enable, ID);
-}
-
-int32_t RTPSender::AudioLevelIndicationStatus(bool *enable,
- uint8_t* id) const {
- return audio_->AudioLevelIndicationStatus(*enable, *id);
-}
-
int32_t RTPSender::SetAudioLevel(const uint8_t level_d_bov) {
return audio_->SetAudioLevel(level_d_bov);
}
diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
index e1cc3a18..8153396c 100644
--- a/modules/rtp_rtcp/source/rtp_sender.h
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -153,15 +153,19 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
uint16_t BuildRTPHeaderExtension(uint8_t* data_buffer) const;
- uint8_t BuildTransmissionTimeOffsetExtension(
- uint8_t *data_buffer) const;
- uint8_t BuildAbsoluteSendTimeExtension(
- uint8_t* data_buffer) const;
+ uint8_t BuildTransmissionTimeOffsetExtension(uint8_t *data_buffer) const;
+ uint8_t BuildAudioLevelExtension(uint8_t* data_buffer) const;
+ uint8_t BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const;
bool UpdateTransmissionTimeOffset(uint8_t *rtp_packet,
const uint16_t rtp_packet_length,
const RTPHeader &rtp_header,
const int64_t time_diff_ms) const;
+ bool UpdateAudioLevel(uint8_t *rtp_packet,
+ const uint16_t rtp_packet_length,
+ const RTPHeader &rtp_header,
+ const bool is_voiced,
+ const uint8_t dBov) const;
bool UpdateAbsoluteSendTime(uint8_t *rtp_packet,
const uint16_t rtp_packet_length,
const RTPHeader &rtp_header,
@@ -228,12 +232,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
// packet in silence (CNG).
int32_t SetAudioPacketSize(const uint16_t packet_size_samples);
- // Set status and ID for header-extension-for-audio-level-indication.
- int32_t SetAudioLevelIndicationStatus(const bool enable, const uint8_t ID);
-
- // Get status and ID for header-extension-for-audio-level-indication.
- int32_t AudioLevelIndicationStatus(bool *enable, uint8_t *id) const;
-
// Store the audio level in d_bov for
// header-extension-for-audio-level-indication.
int32_t SetAudioLevel(const uint8_t level_d_bov);
diff --git a/modules/rtp_rtcp/source/rtp_sender_audio.cc b/modules/rtp_rtcp/source/rtp_sender_audio.cc
index f8001428..6b3e2276 100644
--- a/modules/rtp_rtcp/source/rtp_sender_audio.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_audio.cc
@@ -17,7 +17,7 @@
namespace webrtc {
RTPSenderAudio::RTPSenderAudio(const int32_t id, Clock* clock,
- RTPSenderInterface* rtpSender) :
+ RTPSender* rtpSender) :
_id(id),
_clock(clock),
_rtpSender(rtpSender),
@@ -42,8 +42,6 @@ RTPSenderAudio::RTPSenderAudio(const int32_t id, Clock* clock,
_cngSWBPayloadType(-1),
_cngFBPayloadType(-1),
_lastPayloadType(-1),
- _includeAudioLevelIndication(false), // @TODO - reset at Init()?
- _audioLevelIndicationID(0),
_audioLevel_dBov(0) {
};
@@ -365,52 +363,12 @@ int32_t RTPSenderAudio::SendAudio(
if (rtpHeaderLength <= 0) {
return -1;
}
+ if (maxPayloadLength < (rtpHeaderLength + payloadSize)) {
+ // Too large payload buffer.
+ return -1;
+ }
{
CriticalSectionScoped cs(_sendAudioCritsect);
-
- // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
- if (_includeAudioLevelIndication) {
- dataBuffer[0] |= 0x10; // set eXtension bit
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | 0xBE | 0xDE | length=1 |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | ID | len=0 |V| level | 0x00 | 0x00 |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- // add our ID (0xBEDE)
- ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer+rtpHeaderLength,
- RTP_AUDIO_LEVEL_UNIQUE_ID);
- rtpHeaderLength += 2;
-
- // add the length (length=1) in number of word32
- const uint8_t length = 1;
- ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer+rtpHeaderLength,
- length);
- rtpHeaderLength += 2;
-
- // add ID (defined by the user) and len(=0) byte
- const uint8_t id = _audioLevelIndicationID;
- const uint8_t len = 0;
- dataBuffer[rtpHeaderLength++] = (id << 4) + len;
-
- // add voice-activity flag (V) bit and the audio level (in dBov)
- const uint8_t V = (frameType == kAudioFrameSpeech);
- uint8_t level = _audioLevel_dBov;
- dataBuffer[rtpHeaderLength++] = (V << 7) + level;
-
- // add two bytes zero padding
- ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer+rtpHeaderLength, 0);
- rtpHeaderLength += 2;
- }
-
- if(maxPayloadLength < rtpHeaderLength + payloadSize ) {
- // too large payload buffer
- return -1;
- }
-
if (_REDPayloadType >= 0 && // Have we configured RED?
fragmentation &&
fragmentation->fragmentationVectorSize > 1 &&
@@ -474,6 +432,17 @@ int32_t RTPSenderAudio::SendAudio(
}
}
_lastPayloadType = payloadType;
+
+ // Update audio level extension, if included.
+ {
+ uint16_t packetSize = payloadSize + rtpHeaderLength;
+ ModuleRTPUtility::RTPHeaderParser rtp_parser(dataBuffer, packetSize);
+ RTPHeader rtp_header;
+ rtp_parser.Parse(rtp_header);
+ _rtpSender->UpdateAudioLevel(dataBuffer, packetSize, rtp_header,
+ (frameType == kAudioFrameSpeech),
+ _audioLevel_dBov);
+ }
} // end critical section
TRACE_EVENT_ASYNC_END2("webrtc", "Audio", captureTimeStamp,
"timestamp", _rtpSender->Timestamp(),
@@ -486,32 +455,6 @@ int32_t RTPSenderAudio::SendAudio(
PacedSender::kHighPriority);
}
-int32_t
-RTPSenderAudio::SetAudioLevelIndicationStatus(const bool enable,
- const uint8_t ID)
-{
- if(enable && (ID < 1 || ID > 14))
- {
- return -1;
- }
- CriticalSectionScoped cs(_sendAudioCritsect);
-
- _includeAudioLevelIndication = enable;
- _audioLevelIndicationID = ID;
-
- return 0;
-}
-
-int32_t
-RTPSenderAudio::AudioLevelIndicationStatus(bool& enable,
- uint8_t& ID) const
-{
- CriticalSectionScoped cs(_sendAudioCritsect);
- enable = _includeAudioLevelIndication;
- ID = _audioLevelIndicationID;
- return 0;
-}
-
// Audio level magnitude and voice activity flag are set for each RTP packet
int32_t
RTPSenderAudio::SetAudioLevel(const uint8_t level_dBov)
diff --git a/modules/rtp_rtcp/source/rtp_sender_audio.h b/modules/rtp_rtcp/source/rtp_sender_audio.h
index 7074e7b2..732199c1 100644
--- a/modules/rtp_rtcp/source/rtp_sender_audio.h
+++ b/modules/rtp_rtcp/source/rtp_sender_audio.h
@@ -23,7 +23,7 @@ class RTPSenderAudio: public DTMFqueue
{
public:
RTPSenderAudio(const int32_t id, Clock* clock,
- RTPSenderInterface* rtpSender);
+ RTPSender* rtpSender);
virtual ~RTPSenderAudio();
int32_t RegisterAudioPayload(
@@ -44,13 +44,6 @@ public:
// set audio packet size, used to determine when it's time to send a DTMF packet in silence (CNG)
int32_t SetAudioPacketSize(const uint16_t packetSizeSamples);
- // Set status and ID for header-extension-for-audio-level-indication.
- // Valid ID range is [1,14].
- int32_t SetAudioLevelIndicationStatus(const bool enable, const uint8_t ID);
-
- // Get status and ID for header-extension-for-audio-level-indication.
- int32_t AudioLevelIndicationStatus(bool& enable, uint8_t& ID) const;
-
// Store the audio level in dBov for header-extension-for-audio-level-indication.
// Valid range is [0,100]. Actual value is negative.
int32_t SetAudioLevel(const uint8_t level_dBov);
@@ -86,7 +79,7 @@ protected:
private:
int32_t _id;
Clock* _clock;
- RTPSenderInterface* _rtpSender;
+ RTPSender* _rtpSender;
CriticalSectionWrapper* _audioFeedbackCritsect;
RtpAudioFeedback* _audioFeedback;
@@ -117,8 +110,6 @@ private:
int8_t _lastPayloadType;
// Audio level indication (https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/)
- bool _includeAudioLevelIndication;
- uint8_t _audioLevelIndicationID;
uint8_t _audioLevel_dBov;
};
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index ce615be0..8b72ce02 100644
--- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -160,11 +160,8 @@ 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(kRtpOneByteHeaderLength + kAudioLevelLength,
+ rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAudioLevel));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
@@ -183,14 +180,16 @@ TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) {
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, kAudioLevelExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength +
- kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength());
+ kAbsoluteSendTimeLength + kAudioLevelLength,
+ rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset));
- EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength,
- rtp_sender_->RtpHeaderExtensionTotalLength());
+ EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength +
+ kAudioLevelLength, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime));
- 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());
@@ -202,23 +201,24 @@ TEST_F(RtpSenderTest, BuildRTPPacket) {
kMarkerBit,
kTimestamp,
0);
- EXPECT_EQ(12, length);
+ EXPECT_EQ(kRtpHeaderSize, length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
webrtc::RTPHeader rtp_header;
- RtpHeaderExtensionMap map;
- map.Register(kRtpExtensionTransmissionTimeOffset,
- kTransmissionTimeOffsetExtensionId);
- const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
+ const bool valid_rtp_header = rtp_parser.Parse(rtp_header, NULL);
ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength);
+ EXPECT_FALSE(rtp_header.extension.hasTransmissionTimeOffset);
+ EXPECT_FALSE(rtp_header.extension.hasAbsoluteSendTime);
+ EXPECT_FALSE(rtp_header.extension.hasAudioLevel);
EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset);
EXPECT_EQ(0u, rtp_header.extension.absoluteSendTime);
+ EXPECT_EQ(0u, rtp_header.extension.audioLevel);
}
TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
@@ -231,7 +231,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
kMarkerBit,
kTimestamp,
0);
- EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length);
+ EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
+ length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
@@ -246,6 +247,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength);
+ EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset);
EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset);
// Parse without map extension
@@ -255,6 +257,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.headerLength);
+ EXPECT_FALSE(rtp_header2.extension.hasTransmissionTimeOffset);
EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset);
}
@@ -269,7 +272,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithNegativeTransmissionOffsetExtension) {
kMarkerBit,
kTimestamp,
0);
- EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length);
+ EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
+ length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
@@ -284,6 +288,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithNegativeTransmissionOffsetExtension) {
ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength);
+ EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset);
EXPECT_EQ(kNegTimeOffset, rtp_header.extension.transmissionTimeOffset);
}
@@ -297,7 +302,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithAbsoluteSendTimeExtension) {
kMarkerBit,
kTimestamp,
0);
- EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length);
+ EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
+ length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
@@ -311,6 +317,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithAbsoluteSendTimeExtension) {
ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength);
+ EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime);
EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime);
// Parse without map extension
@@ -320,9 +327,54 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithAbsoluteSendTimeExtension) {
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.headerLength);
+ EXPECT_FALSE(rtp_header2.extension.hasAbsoluteSendTime);
EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime);
}
+TEST_F(RtpSenderTest, BuildRTPPacketWithAudioLevelExtension) {
+ EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+ kRtpExtensionAudioLevel, kAudioLevelExtensionId));
+
+ int32_t length = rtp_sender_->BuildRTPheader(packet_,
+ kPayload,
+ kMarkerBit,
+ kTimestamp,
+ 0);
+ EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
+ length);
+
+ // Verify
+ webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
+ webrtc::RTPHeader rtp_header;
+
+ // Updating audio level is done in RTPSenderAudio, so simulate it here.
+ rtp_parser.Parse(rtp_header);
+ rtp_sender_->UpdateAudioLevel(packet_, length, rtp_header, true, kAudioLevel);
+
+ 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.headerLength);
+ EXPECT_TRUE(rtp_header.extension.hasAudioLevel);
+ // Expect kAudioLevel + 0x80 because we set "voiced" to true in the call to
+ // UpdateAudioLevel(), above.
+ EXPECT_EQ(kAudioLevel + 0x80u, rtp_header.extension.audioLevel);
+
+ // Parse without map extension
+ webrtc::RTPHeader 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.headerLength);
+ EXPECT_FALSE(rtp_header2.extension.hasAudioLevel);
+ EXPECT_EQ(0u, rtp_header2.extension.audioLevel);
+}
+
TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset));
EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime));
@@ -330,30 +382,42 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
+ EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+ kRtpExtensionAudioLevel, kAudioLevelExtensionId));
int32_t length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp,
0);
- EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length);
+ EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
+ length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
webrtc::RTPHeader rtp_header;
+ // Updating audio level is done in RTPSenderAudio, so simulate it here.
+ rtp_parser.Parse(rtp_header);
+ rtp_sender_->UpdateAudioLevel(packet_, length, rtp_header, true, kAudioLevel);
+
RtpHeaderExtensionMap map;
map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId);
+ 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.headerLength);
+ EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset);
+ EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime);
+ EXPECT_TRUE(rtp_header.extension.hasAudioLevel);
EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset);
EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime);
+ EXPECT_EQ(kAudioLevel + 0x80u, rtp_header.extension.audioLevel);
// Parse without map extension
webrtc::RTPHeader rtp_header2;
@@ -362,8 +426,12 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.headerLength);
+ EXPECT_FALSE(rtp_header2.extension.hasTransmissionTimeOffset);
+ EXPECT_FALSE(rtp_header2.extension.hasAbsoluteSendTime);
+ EXPECT_FALSE(rtp_header2.extension.hasAudioLevel);
EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset);
EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime);
+ EXPECT_EQ(0u, rtp_header2.extension.audioLevel);
}
TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) {
@@ -493,7 +561,7 @@ TEST_F(RtpSenderTest, SendPadding) {
uint16_t seq_num = kSeqNum;
uint32_t timestamp = kTimestamp;
rtp_sender_->SetStorePacketsStatus(true, 10);
- int rtp_header_len = 12;
+ int32_t rtp_header_len = kRtpHeaderSize;
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
rtp_header_len += 4; // 4 bytes extension.
@@ -613,7 +681,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) {
uint16_t seq_num = kSeqNum;
rtp_sender_->SetStorePacketsStatus(true, 10);
- int rtp_header_len = 12;
+ int32_t rtp_header_len = kRtpHeaderSize;
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
rtp_header_len += 4; // 4 bytes extension.
@@ -939,48 +1007,6 @@ TEST_F(RtpSenderTest, StreamDataCountersCallbacks) {
rtp_sender_->RegisterRtpStatisticsCallback(NULL);
}
-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,
- 0);
- 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::RTPHeader 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.headerLength);
- // TODO(solenberg): Should verify that we got audio level in header extension.
-
- // Parse without map extension
- webrtc::RTPHeader 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.headerLength);
- // TODO(solenberg): Should verify that we didn't get audio level.
- EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(false, 0));
-}
-
TEST_F(RtpSenderAudioTest, SendAudio) {
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME";
const uint8_t payload_type = 127;
@@ -1007,8 +1033,6 @@ TEST_F(RtpSenderAudioTest, SendAudio) {
}
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));
@@ -1044,7 +1068,6 @@ TEST_F(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) {
EXPECT_EQ(0, memcmp(extension, payload_data - sizeof(extension),
sizeof(extension)));
- EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(false, 0));
}
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_utility.cc b/modules/rtp_rtcp/source/rtp_utility.cc
index 102ebecb..be51f73b 100644
--- a/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/modules/rtp_rtcp/source/rtp_utility.cc
@@ -398,6 +398,10 @@ bool RTPHeaderParser::Parse(RTPHeader& header,
header.extension.hasAbsoluteSendTime = false;
header.extension.absoluteSendTime = 0;
+ // May not be present in packet.
+ header.extension.hasAudioLevel = false;
+ header.extension.audioLevel = 0;
+
if (X) {
/* RTP header extension, RFC 3550.
0 1 2 3
@@ -496,7 +500,11 @@ void RTPHeaderParser::ParseOneByteExtensionHeader(
break;
}
case kRtpExtensionAudioLevel: {
- // --- Only used for debugging ---
+ if (len != 0) {
+ WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
+ "Incorrect audio level len: %d", len);
+ return;
+ }
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -509,6 +517,9 @@ void RTPHeaderParser::ParseOneByteExtensionHeader(
// const uint8_t level = (*ptr & 0x7f);
// DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u,
// level=%u", ID, len, V, level);
+
+ header.extension.audioLevel = *ptr++;
+ header.extension.hasAudioLevel = true;
break;
}
case kRtpExtensionAbsoluteSendTime: {
diff --git a/voice_engine/channel.cc b/voice_engine/channel.cc
index 48f98549..480ff494 100644
--- a/voice_engine/channel.cc
+++ b/voice_engine/channel.cc
@@ -3503,9 +3503,7 @@ Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
return CSRCs;
}
-int
-Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
-{
+int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
if (rtp_audioproc_.get() == NULL) {
rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
_channelId)));
@@ -3519,23 +3517,24 @@ Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
}
_includeAudioLevelIndication = enable;
- if (enable) {
- rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
- ID);
- } else {
- rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
- }
- return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
+
+ return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
}
-int
-Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
-{
- WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
- VoEId(_instanceId,_channelId),
- "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
- enabled, ID);
- return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
+int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
+ return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
+}
+
+int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
+ rtp_header_parser_->DeregisterRtpHeaderExtension(
+ kRtpExtensionAbsoluteSendTime);
+ if (enable) {
+ if (!rtp_header_parser_->RegisterRtpHeaderExtension(
+ kRtpExtensionAbsoluteSendTime, id)) {
+ return -1;
+ }
+ }
+ return 0;
}
int
@@ -5059,5 +5058,14 @@ int Channel::SetRedPayloadType(int red_payload_type) {
return 0;
}
+int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
+ unsigned char id) {
+ int error = 0;
+ _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
+ if (enable) {
+ error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
+ }
+ return error;
+}
} // namespace voe
} // namespace webrtc
diff --git a/voice_engine/channel.h b/voice_engine/channel.h
index ed2bfc42..954d6ea3 100644
--- a/voice_engine/channel.h
+++ b/voice_engine/channel.h
@@ -253,8 +253,9 @@ public:
int GetLocalSSRC(unsigned int& ssrc);
int GetRemoteSSRC(unsigned int& ssrc);
int GetRemoteCSRCs(unsigned int arrCSRC[15]);
- int SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID);
- int GetRTPAudioLevelIndicationStatus(bool& enable, unsigned char& ID);
+ int SetSendAudioLevelIndicationStatus(bool enable, unsigned char id);
+ int SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id);
+ int SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id);
int SetRTCPStatus(bool enable);
int GetRTCPStatus(bool& enabled);
int SetRTCP_CNAME(const char cName[256]);
@@ -438,6 +439,8 @@ private:
void RegisterReceiveCodecsToRTPModule();
int SetRedPayloadType(int red_payload_type);
+ int SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
+ unsigned char id);
CriticalSectionWrapper& _fileCritSect;
CriticalSectionWrapper& _callbackCritSect;
diff --git a/voice_engine/include/voe_rtp_rtcp.h b/voice_engine/include/voe_rtp_rtcp.h
index 675a290d..6c06ef0a 100644
--- a/voice_engine/include/voe_rtp_rtcp.h
+++ b/voice_engine/include/voe_rtp_rtcp.h
@@ -152,12 +152,19 @@ public:
virtual int GetRemoteSSRC(int channel, unsigned int& ssrc) = 0;
// Sets the status of rtp-audio-level-indication on a specific |channel|.
- virtual int SetRTPAudioLevelIndicationStatus(
- int channel, bool enable, unsigned char ID = 1) = 0;
-
- // Sets the status of rtp-audio-level-indication on a specific |channel|.
- virtual int GetRTPAudioLevelIndicationStatus(
- int channel, bool& enabled, unsigned char& ID) = 0;
+ virtual int SetSendAudioLevelIndicationStatus(int channel,
+ bool enable,
+ unsigned char id = 1) = 0;
+
+ // Sets the status of sending absolute sender time on a specific |channel|.
+ virtual int SetSendAbsoluteSenderTimeStatus(int channel,
+ bool enable,
+ unsigned char id) = 0;
+
+ // Sets status of receiving absolute sender time on a specific |channel|.
+ virtual int SetReceiveAbsoluteSenderTimeStatus(int channel,
+ bool enable,
+ unsigned char id) = 0;
// Gets the CSRCs of the incoming RTP packets.
virtual int GetRemoteCSRCs(int channel, unsigned int arrCSRC[15]) = 0;
diff --git a/voice_engine/test/auto_test/standard/rtp_rtcp_extensions.cc b/voice_engine/test/auto_test/standard/rtp_rtcp_extensions.cc
new file mode 100644
index 00000000..11ac4d1b
--- /dev/null
+++ b/voice_engine/test/auto_test/standard/rtp_rtcp_extensions.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014 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 "webrtc/modules/interface/module_common_types.h"
+#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
+#include "webrtc/system_wrappers/interface/atomic32.h"
+#include "webrtc/system_wrappers/interface/sleep.h"
+#include "webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"
+
+class ExtensionVerifyTransport : public webrtc::Transport {
+ public:
+ ExtensionVerifyTransport()
+ : received_packets_(0),
+ ok_packets_(0),
+ parser_(webrtc::RtpHeaderParser::Create()),
+ audio_level_id_(-1),
+ absolute_sender_time_id_(-1) {
+ }
+
+ virtual int SendPacket(int channel, const void* data, int len) {
+ ++received_packets_;
+ webrtc::RTPHeader header = {0};
+ if (parser_->Parse(static_cast<const uint8_t*>(data), len, &header)) {
+ bool ok = true;
+ if (audio_level_id_ >= 0 && !header.extension.hasAudioLevel) {
+ ok = false;
+ }
+ if (absolute_sender_time_id_ >= 0 &&
+ !header.extension.hasAbsoluteSendTime) {
+ ok = false;
+ }
+ if (ok) {
+ ++ok_packets_;
+ }
+ }
+ return len;
+ }
+
+ virtual int SendRTCPPacket(int channel, const void* data, int len) {
+ return len;
+ }
+
+ void SetAudioLevelId(int id) {
+ audio_level_id_ = id;
+ parser_->RegisterRtpHeaderExtension(webrtc::kRtpExtensionAudioLevel, id);
+ }
+
+ void SetAbsoluteSenderTimeId(int id) {
+ absolute_sender_time_id_ = id;
+ parser_->RegisterRtpHeaderExtension(webrtc::kRtpExtensionAbsoluteSendTime,
+ id);
+ }
+
+ bool WaitForNPackets(int count) {
+ while (received_packets_.Value() < count) {
+ webrtc::SleepMs(10);
+ }
+ return (ok_packets_.Value() == count);
+ }
+
+ private:
+ webrtc::Atomic32 received_packets_;
+ webrtc::Atomic32 ok_packets_;
+ webrtc::scoped_ptr<webrtc::RtpHeaderParser> parser_;
+ int audio_level_id_;
+ int absolute_sender_time_id_;
+};
+
+class SendRtpRtcpHeaderExtensionsTest : public AfterStreamingFixture {
+ protected:
+ virtual void SetUp() {
+ PausePlaying();
+ EXPECT_EQ(0, voe_network_->DeRegisterExternalTransport(channel_));
+ EXPECT_EQ(0, voe_network_->RegisterExternalTransport(channel_,
+ verifying_transport_));
+ }
+ virtual void TearDown() {
+ PausePlaying();
+ }
+
+ ExtensionVerifyTransport verifying_transport_;
+};
+
+TEST_F(SendRtpRtcpHeaderExtensionsTest, SentPacketsIncludeAudioLevel) {
+ EXPECT_EQ(0, voe_rtp_rtcp_->SetSendAudioLevelIndicationStatus(channel_, true,
+ 9));
+ verifying_transport_.SetAudioLevelId(9);
+ ResumePlaying();
+ EXPECT_TRUE(verifying_transport_.WaitForNPackets(10));
+}
+
+TEST_F(SendRtpRtcpHeaderExtensionsTest, SentPacketsIncludeAbsoluteSenderTime) {
+ EXPECT_EQ(0, voe_rtp_rtcp_->SetSendAbsoluteSenderTimeStatus(channel_, true,
+ 11));
+ verifying_transport_.SetAbsoluteSenderTimeId(11);
+ ResumePlaying();
+ EXPECT_TRUE(verifying_transport_.WaitForNPackets(10));
+}
+
+TEST_F(SendRtpRtcpHeaderExtensionsTest, SentPacketsIncludeAllExtensions1) {
+ EXPECT_EQ(0, voe_rtp_rtcp_->SetSendAudioLevelIndicationStatus(channel_, true,
+ 9));
+ EXPECT_EQ(0, voe_rtp_rtcp_->SetSendAbsoluteSenderTimeStatus(channel_, true,
+ 11));
+ verifying_transport_.SetAudioLevelId(9);
+ verifying_transport_.SetAbsoluteSenderTimeId(11);
+ ResumePlaying();
+ EXPECT_TRUE(verifying_transport_.WaitForNPackets(10));
+}
+
+TEST_F(SendRtpRtcpHeaderExtensionsTest, SentPacketsIncludeAllExtensions2) {
+ EXPECT_EQ(0, voe_rtp_rtcp_->SetSendAbsoluteSenderTimeStatus(channel_, true,
+ 3));
+ EXPECT_EQ(0, voe_rtp_rtcp_->SetSendAudioLevelIndicationStatus(channel_, true,
+ 9));
+ verifying_transport_.SetAbsoluteSenderTimeId(3);
+ verifying_transport_.SetAudioLevelId(9);
+ ResumePlaying();
+ EXPECT_TRUE(verifying_transport_.WaitForNPackets(10));
+}
+
+class ReceiveRtpRtcpHeaderExtensionsTest : public AfterStreamingFixture {
+ protected:
+ virtual void SetUp() {
+ PausePlaying();
+ }
+};
+
+TEST_F(ReceiveRtpRtcpHeaderExtensionsTest, ReceivedAbsoluteSenderTimeWorks) {
+ EXPECT_EQ(0, voe_rtp_rtcp_->SetSendAbsoluteSenderTimeStatus(channel_, true,
+ 11));
+ EXPECT_EQ(0, voe_rtp_rtcp_->SetReceiveAbsoluteSenderTimeStatus(channel_, true,
+ 11));
+ ResumePlaying();
+
+ // Ensure the RTP-RTCP process gets scheduled.
+ Sleep(1000);
+
+ // TODO(solenberg): Verify received packets are forwarded to RBE.
+}
diff --git a/voice_engine/voe_rtp_rtcp_impl.cc b/voice_engine/voe_rtp_rtcp_impl.cc
index ac79505e..1a0b6c24 100644
--- a/voice_engine/voe_rtp_rtcp_impl.cc
+++ b/voice_engine/voe_rtp_rtcp_impl.cc
@@ -211,62 +211,96 @@ int VoERTP_RTCPImpl::GetRemoteCSRCs(int channel, unsigned int arrCSRC[15])
return channelPtr->GetRemoteCSRCs(arrCSRC);
}
-
-int VoERTP_RTCPImpl::SetRTPAudioLevelIndicationStatus(int channel,
- bool enable,
- unsigned char ID)
+int VoERTP_RTCPImpl::SetSendAudioLevelIndicationStatus(int channel,
+ bool enable,
+ unsigned char id)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
- "SetRTPAudioLevelIndicationStatus(channel=%d, enable=%d,"
- " ID=%u)", channel, enable, ID);
+ "SetSendAudioLevelIndicationStatus(channel=%d, enable=%d,"
+ " ID=%u)", channel, enable, id);
if (!_shared->statistics().Initialized())
{
_shared->SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
- if (enable && (ID < kVoiceEngineMinRtpExtensionId ||
- ID > kVoiceEngineMaxRtpExtensionId))
+ if (enable && (id < kVoiceEngineMinRtpExtensionId ||
+ id > kVoiceEngineMaxRtpExtensionId))
{
- // [RFC5285] The 4-bit ID is the local identifier of this element in
+ // [RFC5285] The 4-bit id is the local identifier of this element in
// the range 1-14 inclusive.
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
- "SetRTPAudioLevelIndicationStatus() invalid ID parameter");
+ "SetSendAudioLevelIndicationStatus() invalid ID parameter");
return -1;
}
- // Set state and ID for the specified channel.
+ // Set state and id for the specified channel.
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
voe::Channel* channelPtr = ch.channel();
if (channelPtr == NULL)
{
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
- "SetRTPAudioLevelIndicationStatus() failed to locate channel");
+ "SetSendAudioLevelIndicationStatus() failed to locate channel");
return -1;
}
- return channelPtr->SetRTPAudioLevelIndicationStatus(enable, ID);
+ return channelPtr->SetSendAudioLevelIndicationStatus(enable, id);
}
-int VoERTP_RTCPImpl::GetRTPAudioLevelIndicationStatus(int channel,
- bool& enabled,
- unsigned char& ID)
-{
- WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
- "GetRTPAudioLevelIndicationStatus(channel=%d, enable=?, ID=?)",
- channel);
- if (!_shared->statistics().Initialized())
- {
- _shared->SetLastError(VE_NOT_INITED, kTraceError);
- return -1;
- }
- voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
- voe::Channel* channelPtr = ch.channel();
- if (channelPtr == NULL)
- {
- _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
- "GetRTPAudioLevelIndicationStatus() failed to locate channel");
- return -1;
- }
- return channelPtr->GetRTPAudioLevelIndicationStatus(enabled, ID);
+int VoERTP_RTCPImpl::SetSendAbsoluteSenderTimeStatus(int channel,
+ bool enable,
+ unsigned char id) {
+ WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
+ "SetSendAbsoluteSenderTimeStatus(channel=%d, enable=%d, id=%u)",
+ channel, enable, id);
+ if (!_shared->statistics().Initialized()) {
+ _shared->SetLastError(VE_NOT_INITED, kTraceError);
+ return -1;
+ }
+ if (enable && (id < kVoiceEngineMinRtpExtensionId ||
+ id > kVoiceEngineMaxRtpExtensionId)) {
+ // [RFC5285] The 4-bit id is the local identifier of this element in
+ // the range 1-14 inclusive.
+ _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
+ "SetSendAbsoluteSenderTimeStatus() invalid id parameter");
+ return -1;
+ }
+ // Set state and id for the specified channel.
+ voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
+ voe::Channel* channelPtr = ch.channel();
+ if (channelPtr == NULL) {
+ _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
+ "SetSendAbsoluteSenderTimeStatus() failed to locate channel");
+ return -1;
+ }
+ return channelPtr->SetSendAbsoluteSenderTimeStatus(enable, id);
+}
+
+int VoERTP_RTCPImpl::SetReceiveAbsoluteSenderTimeStatus(int channel,
+ bool enable,
+ unsigned char id) {
+ WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
+ "SetReceiveAbsoluteSenderTimeStatus(channel=%d, enable=%d, id=%u)",
+ channel, enable, id);
+ if (!_shared->statistics().Initialized()) {
+ _shared->SetLastError(VE_NOT_INITED, kTraceError);
+ return -1;
+ }
+ if (enable && (id < kVoiceEngineMinRtpExtensionId ||
+ id > kVoiceEngineMaxRtpExtensionId)) {
+ // [RFC5285] The 4-bit id is the local identifier of this element in
+ // the range 1-14 inclusive.
+ _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
+ "SetReceiveAbsoluteSenderTimeStatus() invalid id parameter");
+ return -1;
+ }
+ // Set state and id for the specified channel.
+ voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
+ voe::Channel* channelPtr = ch.channel();
+ if (channelPtr == NULL) {
+ _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
+ "SetReceiveAbsoluteSenderTimeStatus() failed to locate channel");
+ return -1;
+ }
+ return channelPtr->SetReceiveAbsoluteSenderTimeStatus(enable, id);
}
int VoERTP_RTCPImpl::SetRTCPStatus(int channel, bool enable)
diff --git a/voice_engine/voe_rtp_rtcp_impl.h b/voice_engine/voe_rtp_rtcp_impl.h
index 1b8b1e92..bd1308ae 100644
--- a/voice_engine/voe_rtp_rtcp_impl.h
+++ b/voice_engine/voe_rtp_rtcp_impl.h
@@ -63,13 +63,17 @@ public:
virtual int GetRemoteSSRC(int channel, unsigned int& ssrc);
// RTP Header Extension for Client-to-Mixer Audio Level Indication
- virtual int SetRTPAudioLevelIndicationStatus(int channel,
- bool enable,
- unsigned char ID);
-
- virtual int GetRTPAudioLevelIndicationStatus(int channel,
- bool& enabled,
- unsigned char& ID);
+ virtual int SetSendAudioLevelIndicationStatus(int channel,
+ bool enable,
+ unsigned char id);
+
+ // RTP Header Extension for Absolute Sender Time
+ virtual int SetSendAbsoluteSenderTimeStatus(int channel,
+ bool enable,
+ unsigned char id);
+ virtual int SetReceiveAbsoluteSenderTimeStatus(int channel,
+ bool enable,
+ unsigned char id);
// CSRC
virtual int GetRemoteCSRCs(int channel, unsigned int arrCSRC[15]);
diff --git a/voice_engine/voice_engine.gyp b/voice_engine/voice_engine.gyp
index 21aef153..1ae4e027 100644
--- a/voice_engine/voice_engine.gyp
+++ b/voice_engine/voice_engine.gyp
@@ -184,6 +184,7 @@
'test/auto_test/standard/neteq_test.cc',
'test/auto_test/standard/network_test.cc',
'test/auto_test/standard/rtp_rtcp_before_streaming_test.cc',
+ 'test/auto_test/standard/rtp_rtcp_extensions.cc',
'test/auto_test/standard/rtp_rtcp_test.cc',
'test/auto_test/standard/voe_base_misc_test.cc',
'test/auto_test/standard/video_sync_test.cc',