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@5654 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
wu@webrtc.org 2014-03-06 23:49:08 +00:00
parent 79047f99c1
commit ebdb0e3ad0
18 changed files with 490 additions and 300 deletions

View File

@ -32,6 +32,11 @@ struct RTPHeaderExtension {
int32_t transmissionTimeOffset; int32_t transmissionTimeOffset;
bool hasAbsoluteSendTime; bool hasAbsoluteSendTime;
uint32_t absoluteSendTime; 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 { struct RTPHeader {

View File

@ -670,25 +670,6 @@ class RtpRtcp : public Module {
virtual int32_t SendREDPayloadType( virtual int32_t SendREDPayloadType(
int8_t& payloadType) const = 0; 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- * Store the audio level in dBov for header-extension-for-audio-level-
* indication. * indication.

View File

@ -22,7 +22,7 @@ const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
const size_t kRtpOneByteHeaderLength = 4; const size_t kRtpOneByteHeaderLength = 4;
const size_t kTransmissionTimeOffsetLength = 4; const size_t kTransmissionTimeOffsetLength = 4;
const size_t kAudioLevelLength = 2; const size_t kAudioLevelLength = 4;
const size_t kAbsoluteSendTimeLength = 4; const size_t kAbsoluteSendTimeLength = 4;
struct HeaderExtension { struct HeaderExtension {
@ -37,11 +37,7 @@ struct HeaderExtension {
length = kTransmissionTimeOffsetLength; length = kTransmissionTimeOffsetLength;
break; break;
case kRtpExtensionAudioLevel: case kRtpExtensionAudioLevel:
// TODO(solenberg): Because of how the audio level extension is handled length = kAudioLevelLength;
// 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; break;
case kRtpExtensionAbsoluteSendTime: case kRtpExtensionAbsoluteSendTime:
length = kAbsoluteSendTimeLength; length = kAbsoluteSendTimeLength;

View File

@ -1209,29 +1209,6 @@ int32_t ModuleRtpRtcpImpl::SetAudioPacketSize(
return rtp_sender_.SetAudioPacketSize(packet_size_samples); 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( int32_t ModuleRtpRtcpImpl::SetAudioLevel(
const uint8_t level_d_bov) { const uint8_t level_d_bov) {
WEBRTC_TRACE(kTraceModuleCall, WEBRTC_TRACE(kTraceModuleCall,

View File

@ -295,14 +295,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
// Get payload type for Redundant Audio Data RFC 2198. // Get payload type for Redundant Audio Data RFC 2198.
virtual int32_t SendREDPayloadType(int8_t& payload_type) const OVERRIDE; 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- // Store the audio level in d_bov for header-extension-for-audio-level-
// indication. // indication.
virtual int32_t SetAudioLevel(const uint8_t level_d_bov) OVERRIDE; virtual int32_t SetAudioLevel(const uint8_t level_d_bov) OVERRIDE;

View File

@ -1117,9 +1117,8 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer) const {
data_buffer + kHeaderLength + total_block_length); data_buffer + kHeaderLength + total_block_length);
break; break;
case kRtpExtensionAudioLevel: case kRtpExtensionAudioLevel:
// Because AudioLevel is handled specially by RTPSenderAudio, we pretend block_length = BuildAudioLevelExtension(
// we don't have to care about it here, which is true until we wan't to data_buffer + kHeaderLength + total_block_length);
// use it together with any of the other extensions we support.
break; break;
case kRtpExtensionAbsoluteSendTime: case kRtpExtensionAbsoluteSendTime:
block_length = BuildAbsoluteSendTimeExtension( block_length = BuildAbsoluteSendTimeExtension(
@ -1179,8 +1178,42 @@ uint8_t RTPSender::BuildTransmissionTimeOffsetExtension(
return kTransmissionTimeOffsetLength; return kTransmissionTimeOffsetLength;
} }
uint8_t RTPSender::BuildAbsoluteSendTimeExtension( uint8_t RTPSender::BuildAudioLevelExtension(uint8_t* data_buffer) const {
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. // Absolute send time in RTP streams.
// //
// The absolute send time is signaled to the receiver in-band using the // The absolute send time is signaled to the receiver in-band using the
@ -1265,6 +1298,55 @@ bool RTPSender::UpdateTransmissionTimeOffset(
return true; 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( bool RTPSender::UpdateAbsoluteSendTime(
uint8_t *rtp_packet, const uint16_t rtp_packet_length, uint8_t *rtp_packet, const uint16_t rtp_packet_length,
const RTPHeader &rtp_header, const int64_t now_ms) const { const RTPHeader &rtp_header, const int64_t now_ms) const {
@ -1463,19 +1545,6 @@ int32_t RTPSender::SetAudioPacketSize(
return audio_->SetAudioPacketSize(packet_size_samples); 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) { int32_t RTPSender::SetAudioLevel(const uint8_t level_d_bov) {
return audio_->SetAudioLevel(level_d_bov); return audio_->SetAudioLevel(level_d_bov);
} }

View File

@ -153,15 +153,19 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
uint16_t BuildRTPHeaderExtension(uint8_t* data_buffer) const; uint16_t BuildRTPHeaderExtension(uint8_t* data_buffer) const;
uint8_t BuildTransmissionTimeOffsetExtension( uint8_t BuildTransmissionTimeOffsetExtension(uint8_t *data_buffer) const;
uint8_t *data_buffer) const; uint8_t BuildAudioLevelExtension(uint8_t* data_buffer) const;
uint8_t BuildAbsoluteSendTimeExtension( uint8_t BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const;
uint8_t* data_buffer) const;
bool UpdateTransmissionTimeOffset(uint8_t *rtp_packet, bool UpdateTransmissionTimeOffset(uint8_t *rtp_packet,
const uint16_t rtp_packet_length, const uint16_t rtp_packet_length,
const RTPHeader &rtp_header, const RTPHeader &rtp_header,
const int64_t time_diff_ms) const; 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, bool UpdateAbsoluteSendTime(uint8_t *rtp_packet,
const uint16_t rtp_packet_length, const uint16_t rtp_packet_length,
const RTPHeader &rtp_header, const RTPHeader &rtp_header,
@ -228,12 +232,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
// packet in silence (CNG). // packet in silence (CNG).
int32_t SetAudioPacketSize(const uint16_t packet_size_samples); 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 // Store the audio level in d_bov for
// header-extension-for-audio-level-indication. // header-extension-for-audio-level-indication.
int32_t SetAudioLevel(const uint8_t level_d_bov); int32_t SetAudioLevel(const uint8_t level_d_bov);

View File

@ -17,7 +17,7 @@
namespace webrtc { namespace webrtc {
RTPSenderAudio::RTPSenderAudio(const int32_t id, Clock* clock, RTPSenderAudio::RTPSenderAudio(const int32_t id, Clock* clock,
RTPSenderInterface* rtpSender) : RTPSender* rtpSender) :
_id(id), _id(id),
_clock(clock), _clock(clock),
_rtpSender(rtpSender), _rtpSender(rtpSender),
@ -42,8 +42,6 @@ RTPSenderAudio::RTPSenderAudio(const int32_t id, Clock* clock,
_cngSWBPayloadType(-1), _cngSWBPayloadType(-1),
_cngFBPayloadType(-1), _cngFBPayloadType(-1),
_lastPayloadType(-1), _lastPayloadType(-1),
_includeAudioLevelIndication(false), // @TODO - reset at Init()?
_audioLevelIndicationID(0),
_audioLevel_dBov(0) { _audioLevel_dBov(0) {
}; };
@ -365,52 +363,12 @@ int32_t RTPSenderAudio::SendAudio(
if (rtpHeaderLength <= 0) { if (rtpHeaderLength <= 0) {
return -1; return -1;
} }
if (maxPayloadLength < (rtpHeaderLength + payloadSize)) {
// Too large payload buffer.
return -1;
}
{ {
CriticalSectionScoped cs(_sendAudioCritsect); 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? if (_REDPayloadType >= 0 && // Have we configured RED?
fragmentation && fragmentation &&
fragmentation->fragmentationVectorSize > 1 && fragmentation->fragmentationVectorSize > 1 &&
@ -474,6 +432,17 @@ int32_t RTPSenderAudio::SendAudio(
} }
} }
_lastPayloadType = payloadType; _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 } // end critical section
TRACE_EVENT_ASYNC_END2("webrtc", "Audio", captureTimeStamp, TRACE_EVENT_ASYNC_END2("webrtc", "Audio", captureTimeStamp,
"timestamp", _rtpSender->Timestamp(), "timestamp", _rtpSender->Timestamp(),
@ -486,32 +455,6 @@ int32_t RTPSenderAudio::SendAudio(
PacedSender::kHighPriority); 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 // Audio level magnitude and voice activity flag are set for each RTP packet
int32_t int32_t
RTPSenderAudio::SetAudioLevel(const uint8_t level_dBov) RTPSenderAudio::SetAudioLevel(const uint8_t level_dBov)

View File

@ -23,7 +23,7 @@ class RTPSenderAudio: public DTMFqueue
{ {
public: public:
RTPSenderAudio(const int32_t id, Clock* clock, RTPSenderAudio(const int32_t id, Clock* clock,
RTPSenderInterface* rtpSender); RTPSender* rtpSender);
virtual ~RTPSenderAudio(); virtual ~RTPSenderAudio();
int32_t RegisterAudioPayload( 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) // 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); 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. // Store the audio level in dBov for header-extension-for-audio-level-indication.
// Valid range is [0,100]. Actual value is negative. // Valid range is [0,100]. Actual value is negative.
int32_t SetAudioLevel(const uint8_t level_dBov); int32_t SetAudioLevel(const uint8_t level_dBov);
@ -86,7 +79,7 @@ protected:
private: private:
int32_t _id; int32_t _id;
Clock* _clock; Clock* _clock;
RTPSenderInterface* _rtpSender; RTPSender* _rtpSender;
CriticalSectionWrapper* _audioFeedbackCritsect; CriticalSectionWrapper* _audioFeedbackCritsect;
RtpAudioFeedback* _audioFeedback; RtpAudioFeedback* _audioFeedback;
@ -117,8 +110,6 @@ private:
int8_t _lastPayloadType; int8_t _lastPayloadType;
// Audio level indication (https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/) // Audio level indication (https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/)
bool _includeAudioLevelIndication;
uint8_t _audioLevelIndicationID;
uint8_t _audioLevel_dBov; uint8_t _audioLevel_dBov;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -160,11 +160,8 @@ TEST_F(RtpSenderTest, RegisterRtpAudioLevelHeaderExtension) {
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, kAudioLevelExtensionId)); kRtpExtensionAudioLevel, kAudioLevelExtensionId));
// Accounted size for audio level is zero because it is currently specially EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength,
// treated by RTPSenderAudio. rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
// EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength,
// rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAudioLevel)); kRtpExtensionAudioLevel));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
@ -183,14 +180,16 @@ TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) {
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, kAudioLevelExtensionId)); kRtpExtensionAudioLevel, kAudioLevelExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength +
kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength()); kAbsoluteSendTimeLength + kAudioLevelLength,
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset));
EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength,
rtp_sender_->RtpHeaderExtensionTotalLength()); rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset));
EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength +
kAudioLevelLength, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime)); kRtpExtensionAbsoluteSendTime));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength,
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAudioLevel)); kRtpExtensionAudioLevel));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
@ -202,23 +201,24 @@ TEST_F(RtpSenderTest, BuildRTPPacket) {
kMarkerBit, kMarkerBit,
kTimestamp, kTimestamp,
0); 0);
EXPECT_EQ(12, length); EXPECT_EQ(kRtpHeaderSize, length);
// Verify // Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
webrtc::RTPHeader rtp_header; webrtc::RTPHeader rtp_header;
RtpHeaderExtensionMap map; const bool valid_rtp_header = rtp_parser.Parse(rtp_header, NULL);
map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header); ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtp_parser.RTCP()); ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header); VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength); 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(0, rtp_header.extension.transmissionTimeOffset);
EXPECT_EQ(0u, rtp_header.extension.absoluteSendTime); EXPECT_EQ(0u, rtp_header.extension.absoluteSendTime);
EXPECT_EQ(0u, rtp_header.extension.audioLevel);
} }
TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) { TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
@ -231,7 +231,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
kMarkerBit, kMarkerBit,
kTimestamp, kTimestamp,
0); 0);
EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
length);
// Verify // Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
@ -246,6 +247,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
ASSERT_FALSE(rtp_parser.RTCP()); ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header); VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength); EXPECT_EQ(length, rtp_header.headerLength);
EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset);
EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset); EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset);
// Parse without map extension // Parse without map extension
@ -255,6 +257,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
ASSERT_TRUE(valid_rtp_header2); ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2); VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.headerLength); EXPECT_EQ(length, rtp_header2.headerLength);
EXPECT_FALSE(rtp_header2.extension.hasTransmissionTimeOffset);
EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset); EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset);
} }
@ -269,7 +272,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithNegativeTransmissionOffsetExtension) {
kMarkerBit, kMarkerBit,
kTimestamp, kTimestamp,
0); 0);
EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
length);
// Verify // Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
@ -284,6 +288,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithNegativeTransmissionOffsetExtension) {
ASSERT_FALSE(rtp_parser.RTCP()); ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header); VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength); EXPECT_EQ(length, rtp_header.headerLength);
EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset);
EXPECT_EQ(kNegTimeOffset, rtp_header.extension.transmissionTimeOffset); EXPECT_EQ(kNegTimeOffset, rtp_header.extension.transmissionTimeOffset);
} }
@ -297,7 +302,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithAbsoluteSendTimeExtension) {
kMarkerBit, kMarkerBit,
kTimestamp, kTimestamp,
0); 0);
EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
length);
// Verify // Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
@ -311,6 +317,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithAbsoluteSendTimeExtension) {
ASSERT_FALSE(rtp_parser.RTCP()); ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header); VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength); EXPECT_EQ(length, rtp_header.headerLength);
EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime);
EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime); EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime);
// Parse without map extension // Parse without map extension
@ -320,9 +327,54 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithAbsoluteSendTimeExtension) {
ASSERT_TRUE(valid_rtp_header2); ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2); VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.headerLength); EXPECT_EQ(length, rtp_header2.headerLength);
EXPECT_FALSE(rtp_header2.extension.hasAbsoluteSendTime);
EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime); 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) { TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset)); EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset));
EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime)); EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime));
@ -330,30 +382,42 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, kAudioLevelExtensionId));
int32_t length = rtp_sender_->BuildRTPheader(packet_, int32_t length = rtp_sender_->BuildRTPheader(packet_,
kPayload, kPayload,
kMarkerBit, kMarkerBit,
kTimestamp, kTimestamp,
0); 0);
EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); EXPECT_EQ(kRtpHeaderSize + rtp_sender_->RtpHeaderExtensionTotalLength(),
length);
// Verify // Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
webrtc::RTPHeader rtp_header; 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; RtpHeaderExtensionMap map;
map.Register(kRtpExtensionTransmissionTimeOffset, map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId); kTransmissionTimeOffsetExtensionId);
map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId); map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId);
map.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map); const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header); ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtp_parser.RTCP()); ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header); VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.headerLength); 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(kTimeOffset, rtp_header.extension.transmissionTimeOffset);
EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime); EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime);
EXPECT_EQ(kAudioLevel + 0x80u, rtp_header.extension.audioLevel);
// Parse without map extension // Parse without map extension
webrtc::RTPHeader rtp_header2; webrtc::RTPHeader rtp_header2;
@ -362,8 +426,12 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
ASSERT_TRUE(valid_rtp_header2); ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2); VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.headerLength); 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(0, rtp_header2.extension.transmissionTimeOffset);
EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime); EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime);
EXPECT_EQ(0u, rtp_header2.extension.audioLevel);
} }
TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) { TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) {
@ -493,7 +561,7 @@ TEST_F(RtpSenderTest, SendPadding) {
uint16_t seq_num = kSeqNum; uint16_t seq_num = kSeqNum;
uint32_t timestamp = kTimestamp; uint32_t timestamp = kTimestamp;
rtp_sender_->SetStorePacketsStatus(true, 10); rtp_sender_->SetStorePacketsStatus(true, 10);
int rtp_header_len = 12; int32_t rtp_header_len = kRtpHeaderSize;
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
rtp_header_len += 4; // 4 bytes extension. rtp_header_len += 4; // 4 bytes extension.
@ -613,7 +681,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) {
uint16_t seq_num = kSeqNum; uint16_t seq_num = kSeqNum;
rtp_sender_->SetStorePacketsStatus(true, 10); rtp_sender_->SetStorePacketsStatus(true, 10);
int rtp_header_len = 12; int32_t rtp_header_len = kRtpHeaderSize;
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
rtp_header_len += 4; // 4 bytes extension. rtp_header_len += 4; // 4 bytes extension.
@ -939,48 +1007,6 @@ TEST_F(RtpSenderTest, StreamDataCountersCallbacks) {
rtp_sender_->RegisterRtpStatisticsCallback(NULL); 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) { TEST_F(RtpSenderAudioTest, SendAudio) {
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME"; char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME";
const uint8_t payload_type = 127; const uint8_t payload_type = 127;
@ -1007,8 +1033,6 @@ TEST_F(RtpSenderAudioTest, SendAudio) {
} }
TEST_F(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) { TEST_F(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) {
EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(true,
kAudioLevelExtensionId));
EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel)); EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, kAudioLevelExtensionId)); kRtpExtensionAudioLevel, kAudioLevelExtensionId));
@ -1044,7 +1068,6 @@ TEST_F(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) {
EXPECT_EQ(0, memcmp(extension, payload_data - sizeof(extension), EXPECT_EQ(0, memcmp(extension, payload_data - sizeof(extension),
sizeof(extension))); sizeof(extension)));
EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(false, 0));
} }
} // namespace webrtc } // namespace webrtc

View File

@ -398,6 +398,10 @@ bool RTPHeaderParser::Parse(RTPHeader& header,
header.extension.hasAbsoluteSendTime = false; header.extension.hasAbsoluteSendTime = false;
header.extension.absoluteSendTime = 0; header.extension.absoluteSendTime = 0;
// May not be present in packet.
header.extension.hasAudioLevel = false;
header.extension.audioLevel = 0;
if (X) { if (X) {
/* RTP header extension, RFC 3550. /* RTP header extension, RFC 3550.
0 1 2 3 0 1 2 3
@ -496,7 +500,11 @@ void RTPHeaderParser::ParseOneByteExtensionHeader(
break; break;
} }
case kRtpExtensionAudioLevel: { 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
// 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 // 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); // const uint8_t level = (*ptr & 0x7f);
// DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u, // DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u,
// level=%u", ID, len, V, level); // level=%u", ID, len, V, level);
header.extension.audioLevel = *ptr++;
header.extension.hasAudioLevel = true;
break; break;
} }
case kRtpExtensionAbsoluteSendTime: { case kRtpExtensionAbsoluteSendTime: {

View File

@ -3503,9 +3503,7 @@ Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
return CSRCs; return CSRCs;
} }
int int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
{
if (rtp_audioproc_.get() == NULL) { if (rtp_audioproc_.get() == NULL) {
rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId, rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
_channelId))); _channelId)));
@ -3519,23 +3517,24 @@ Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
} }
_includeAudioLevelIndication = enable; _includeAudioLevelIndication = enable;
if (enable) {
rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel, return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
ID);
} else {
rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
}
return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
} }
int int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID) return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
{ }
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_instanceId,_channelId), int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
"GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u", rtp_header_parser_->DeregisterRtpHeaderExtension(
enabled, ID); kRtpExtensionAbsoluteSendTime);
return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID); if (enable) {
if (!rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, id)) {
return -1;
}
}
return 0;
} }
int int
@ -5059,5 +5058,14 @@ int Channel::SetRedPayloadType(int red_payload_type) {
return 0; 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 voe
} // namespace webrtc } // namespace webrtc

View File

@ -253,8 +253,9 @@ public:
int GetLocalSSRC(unsigned int& ssrc); int GetLocalSSRC(unsigned int& ssrc);
int GetRemoteSSRC(unsigned int& ssrc); int GetRemoteSSRC(unsigned int& ssrc);
int GetRemoteCSRCs(unsigned int arrCSRC[15]); int GetRemoteCSRCs(unsigned int arrCSRC[15]);
int SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID); int SetSendAudioLevelIndicationStatus(bool enable, unsigned char id);
int GetRTPAudioLevelIndicationStatus(bool& enable, unsigned char& ID); int SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id);
int SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id);
int SetRTCPStatus(bool enable); int SetRTCPStatus(bool enable);
int GetRTCPStatus(bool& enabled); int GetRTCPStatus(bool& enabled);
int SetRTCP_CNAME(const char cName[256]); int SetRTCP_CNAME(const char cName[256]);
@ -438,6 +439,8 @@ private:
void RegisterReceiveCodecsToRTPModule(); void RegisterReceiveCodecsToRTPModule();
int SetRedPayloadType(int red_payload_type); int SetRedPayloadType(int red_payload_type);
int SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
unsigned char id);
CriticalSectionWrapper& _fileCritSect; CriticalSectionWrapper& _fileCritSect;
CriticalSectionWrapper& _callbackCritSect; CriticalSectionWrapper& _callbackCritSect;

View File

@ -152,12 +152,19 @@ public:
virtual int GetRemoteSSRC(int channel, unsigned int& ssrc) = 0; virtual int GetRemoteSSRC(int channel, unsigned int& ssrc) = 0;
// Sets the status of rtp-audio-level-indication on a specific |channel|. // Sets the status of rtp-audio-level-indication on a specific |channel|.
virtual int SetRTPAudioLevelIndicationStatus( virtual int SetSendAudioLevelIndicationStatus(int channel,
int channel, bool enable, unsigned char ID = 1) = 0; bool enable,
unsigned char id = 1) = 0;
// Sets the status of rtp-audio-level-indication on a specific |channel|. // Sets the status of sending absolute sender time on a specific |channel|.
virtual int GetRTPAudioLevelIndicationStatus( virtual int SetSendAbsoluteSenderTimeStatus(int channel,
int channel, bool& enabled, unsigned char& ID) = 0; 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. // Gets the CSRCs of the incoming RTP packets.
virtual int GetRemoteCSRCs(int channel, unsigned int arrCSRC[15]) = 0; virtual int GetRemoteCSRCs(int channel, unsigned int arrCSRC[15]) = 0;

View File

@ -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.
}

View File

@ -211,62 +211,96 @@ int VoERTP_RTCPImpl::GetRemoteCSRCs(int channel, unsigned int arrCSRC[15])
return channelPtr->GetRemoteCSRCs(arrCSRC); return channelPtr->GetRemoteCSRCs(arrCSRC);
} }
int VoERTP_RTCPImpl::SetSendAudioLevelIndicationStatus(int channel,
int VoERTP_RTCPImpl::SetRTPAudioLevelIndicationStatus(int channel, bool enable,
bool enable, unsigned char id)
unsigned char ID)
{ {
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"SetRTPAudioLevelIndicationStatus(channel=%d, enable=%d," "SetSendAudioLevelIndicationStatus(channel=%d, enable=%d,"
" ID=%u)", channel, enable, ID); " ID=%u)", channel, enable, id);
if (!_shared->statistics().Initialized()) if (!_shared->statistics().Initialized())
{ {
_shared->SetLastError(VE_NOT_INITED, kTraceError); _shared->SetLastError(VE_NOT_INITED, kTraceError);
return -1; return -1;
} }
if (enable && (ID < kVoiceEngineMinRtpExtensionId || if (enable && (id < kVoiceEngineMinRtpExtensionId ||
ID > kVoiceEngineMaxRtpExtensionId)) 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. // the range 1-14 inclusive.
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
"SetRTPAudioLevelIndicationStatus() invalid ID parameter"); "SetSendAudioLevelIndicationStatus() invalid ID parameter");
return -1; 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::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
voe::Channel* channelPtr = ch.channel(); voe::Channel* channelPtr = ch.channel();
if (channelPtr == NULL) if (channelPtr == NULL)
{ {
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
"SetRTPAudioLevelIndicationStatus() failed to locate channel"); "SetSendAudioLevelIndicationStatus() failed to locate channel");
return -1; return -1;
} }
return channelPtr->SetRTPAudioLevelIndicationStatus(enable, ID); return channelPtr->SetSendAudioLevelIndicationStatus(enable, id);
} }
int VoERTP_RTCPImpl::GetRTPAudioLevelIndicationStatus(int channel, int VoERTP_RTCPImpl::SetSendAbsoluteSenderTimeStatus(int channel,
bool& enabled, bool enable,
unsigned char& ID) unsigned char id) {
{ WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), "SetSendAbsoluteSenderTimeStatus(channel=%d, enable=%d, id=%u)",
"GetRTPAudioLevelIndicationStatus(channel=%d, enable=?, ID=?)", channel, enable, id);
channel); if (!_shared->statistics().Initialized()) {
if (!_shared->statistics().Initialized()) _shared->SetLastError(VE_NOT_INITED, kTraceError);
{ return -1;
_shared->SetLastError(VE_NOT_INITED, kTraceError); }
return -1; if (enable && (id < kVoiceEngineMinRtpExtensionId ||
} id > kVoiceEngineMaxRtpExtensionId)) {
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); // [RFC5285] The 4-bit id is the local identifier of this element in
voe::Channel* channelPtr = ch.channel(); // the range 1-14 inclusive.
if (channelPtr == NULL) _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
{ "SetSendAbsoluteSenderTimeStatus() invalid id parameter");
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, return -1;
"GetRTPAudioLevelIndicationStatus() failed to locate channel"); }
return -1; // Set state and id for the specified channel.
} voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
return channelPtr->GetRTPAudioLevelIndicationStatus(enabled, ID); 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) int VoERTP_RTCPImpl::SetRTCPStatus(int channel, bool enable)

View File

@ -63,13 +63,17 @@ public:
virtual int GetRemoteSSRC(int channel, unsigned int& ssrc); virtual int GetRemoteSSRC(int channel, unsigned int& ssrc);
// RTP Header Extension for Client-to-Mixer Audio Level Indication // RTP Header Extension for Client-to-Mixer Audio Level Indication
virtual int SetRTPAudioLevelIndicationStatus(int channel, virtual int SetSendAudioLevelIndicationStatus(int channel,
bool enable, bool enable,
unsigned char ID); unsigned char id);
virtual int GetRTPAudioLevelIndicationStatus(int channel, // RTP Header Extension for Absolute Sender Time
bool& enabled, virtual int SetSendAbsoluteSenderTimeStatus(int channel,
unsigned char& ID); bool enable,
unsigned char id);
virtual int SetReceiveAbsoluteSenderTimeStatus(int channel,
bool enable,
unsigned char id);
// CSRC // CSRC
virtual int GetRemoteCSRCs(int channel, unsigned int arrCSRC[15]); virtual int GetRemoteCSRCs(int channel, unsigned int arrCSRC[15]);

View File

@ -184,6 +184,7 @@
'test/auto_test/standard/neteq_test.cc', 'test/auto_test/standard/neteq_test.cc',
'test/auto_test/standard/network_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_before_streaming_test.cc',
'test/auto_test/standard/rtp_rtcp_extensions.cc',
'test/auto_test/standard/rtp_rtcp_test.cc', 'test/auto_test/standard/rtp_rtcp_test.cc',
'test/auto_test/standard/voe_base_misc_test.cc', 'test/auto_test/standard/voe_base_misc_test.cc',
'test/auto_test/standard/video_sync_test.cc', 'test/auto_test/standard/video_sync_test.cc',