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;
|
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 {
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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: {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
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)
|
||||||
|
@ -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]);
|
||||||
|
@ -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',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user