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:
parent
79047f99c1
commit
ebdb0e3ad0
@ -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 {
|
||||
|
@ -670,25 +670,6 @@ class RtpRtcp : public Module {
|
||||
virtual int32_t SendREDPayloadType(
|
||||
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.
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
|
||||
kRtpExtensionTransmissionTimeOffset));
|
||||
EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength,
|
||||
kAbsoluteSendTimeLength + kAudioLevelLength,
|
||||
rtp_sender_->RtpHeaderExtensionTotalLength());
|
||||
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
|
||||
kRtpExtensionTransmissionTimeOffset));
|
||||
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
|
||||
|
@ -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: {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
virtual int SetSendAudioLevelIndicationStatus(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;
|
||||
// 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;
|
||||
|
@ -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.
|
||||
}
|
@ -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)
|
||||
|
@ -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 SetSendAudioLevelIndicationStatus(int channel,
|
||||
bool enable,
|
||||
unsigned char id);
|
||||
|
||||
virtual int GetRTPAudioLevelIndicationStatus(int channel,
|
||||
bool& enabled,
|
||||
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]);
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user