Improve AV-sync when initial delay is set and NetEq has long buffer.

Review URL: https://webrtc-codereview.appspot.com/1324006

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3883 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
turaj@webrtc.org
2013-04-22 18:53:35 +00:00
parent 1b427719dc
commit 28d54ab18f
17 changed files with 522 additions and 123 deletions

View File

@ -21,7 +21,6 @@
#include "webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_internal.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/system_wrappers/interface/trace_event.h"
@ -49,7 +48,8 @@ ACMNetEQ::ACMNetEQ()
callback_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
min_of_max_num_packets_(0),
min_of_buffer_size_bytes_(0),
per_packet_overhead_bytes_(0) {
per_packet_overhead_bytes_(0),
av_sync_(false) {
for (int n = 0; n < MAX_NUM_SLAVE_NETEQ + 1; n++) {
is_initialized_[n] = false;
ptr_vadinst_[n] = NULL;
@ -436,12 +436,59 @@ int32_t ACMNetEQ::NetworkStatistics(
return 0;
}
int32_t ACMNetEQ::RecIn(const uint8_t* incoming_payload,
const int32_t length_payload,
const WebRtcRTPHeader& rtp_info) {
int16_t payload_length = static_cast<int16_t>(length_payload);
// Should only be called in AV-sync mode.
int ACMNetEQ::RecIn(const WebRtcRTPHeader& rtp_info,
uint32_t receive_timestamp) {
assert(av_sync_);
// translate to NetEq struct
// Translate to NetEq structure.
WebRtcNetEQ_RTPInfo neteq_rtpinfo;
neteq_rtpinfo.payloadType = rtp_info.header.payloadType;
neteq_rtpinfo.sequenceNumber = rtp_info.header.sequenceNumber;
neteq_rtpinfo.timeStamp = rtp_info.header.timestamp;
neteq_rtpinfo.SSRC = rtp_info.header.ssrc;
neteq_rtpinfo.markerBit = rtp_info.header.markerBit;
CriticalSectionScoped lock(neteq_crit_sect_);
// Master should be initialized.
assert(is_initialized_[0]);
// Push into Master.
int status = WebRtcNetEQ_RecInSyncRTP(inst_[0], &neteq_rtpinfo,
receive_timestamp);
if (status < 0) {
LogError("RecInSyncRTP", 0);
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"RecIn (sync): NetEq, error in pushing in Master");
return -1;
}
// If the received stream is stereo, insert a sync payload into slave.
if (rtp_info.type.Audio.channel == 2) {
// Slave should be initialized.
assert(is_initialized_[1]);
// PUSH into Slave
status = WebRtcNetEQ_RecInSyncRTP(inst_[1], &neteq_rtpinfo,
receive_timestamp);
if (status < 0) {
LogError("RecInRTPStruct", 1);
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"RecIn (sync): NetEq, error in pushing in Slave");
return -1;
}
}
return status;
}
int32_t ACMNetEQ::RecIn(const uint8_t* incoming_payload,
const int32_t length_payload,
const WebRtcRTPHeader& rtp_info,
uint32_t receive_timestamp) {
int16_t payload_length = static_cast<int16_t>(length_payload);
// Translate to NetEq structure.
WebRtcNetEQ_RTPInfo neteq_rtpinfo;
neteq_rtpinfo.payloadType = rtp_info.header.payloadType;
neteq_rtpinfo.sequenceNumber = rtp_info.header.sequenceNumber;
@ -450,15 +497,6 @@ int32_t ACMNetEQ::RecIn(const uint8_t* incoming_payload,
neteq_rtpinfo.markerBit = rtp_info.header.markerBit;
CriticalSectionScoped lock(neteq_crit_sect_);
// Down-cast the time to (32-6)-bit since we only care about
// the least significant bits. (32-6) bits cover 2^(32-6) = 67108864 ms.
// we masked 6 most significant bits of 32-bit so we don't loose resolution
// when do the following multiplication.
const uint32_t now_in_ms =
static_cast<uint32_t>(
TickTime::MillisecondTimestamp() & 0x03ffffff);
uint32_t recv_timestamp = static_cast<uint32_t>(
current_samp_freq_khz_ * now_in_ms);
int status;
// In case of stereo payload, first half of the data should be pushed into
@ -473,10 +511,10 @@ int32_t ACMNetEQ::RecIn(const uint8_t* incoming_payload,
"RecIn: NetEq is not initialized.");
return -1;
}
// PUSH into Master
// Push into Master.
status = WebRtcNetEQ_RecInRTPStruct(inst_[0], &neteq_rtpinfo,
incoming_payload, payload_length,
recv_timestamp);
receive_timestamp);
if (status < 0) {
LogError("RecInRTPStruct", 0);
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
@ -491,10 +529,10 @@ int32_t ACMNetEQ::RecIn(const uint8_t* incoming_payload,
"RecIn: NetEq is not initialized.");
return -1;
}
// PUSH into Slave
// Push into Slave.
status = WebRtcNetEQ_RecInRTPStruct(inst_[1], &neteq_rtpinfo,
&incoming_payload[payload_length],
payload_length, recv_timestamp);
payload_length, receive_timestamp);
if (status < 0) {
LogError("RecInRTPStruct", 1);
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
@ -529,7 +567,6 @@ int32_t ACMNetEQ::RecOut(AudioFrame& audio_frame) {
LogError("RecOut", 0);
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"RecOut: NetEq, error in pulling out for mono case");
// Check for errors that can be recovered from:
// RECOUT_ERROR_SAMPLEUNDERRUN = 2003
int error_code = WebRtcNetEQ_GetErrorCode(inst_[0]);
@ -1056,6 +1093,8 @@ int16_t ACMNetEQ::AddSlave(const WebRtcNetEQDecoder* used_codecs,
"AddSlave: AddSlave Failed, Could not Set Playout Mode.");
return -1;
}
// Set AV-sync for the slave.
WebRtcNetEQ_EnableAVSync(inst_[slave_idx], av_sync_ ? 1 : 0);
}
return 0;
@ -1071,4 +1110,13 @@ uint8_t ACMNetEQ::num_slaves() {
return num_slaves_;
}
void ACMNetEQ::EnableAVSync(bool enable) {
CriticalSectionScoped lock(neteq_crit_sect_);
av_sync_ = enable;
for (int i = 0; i < num_slaves_ + 1; ++i) {
assert(is_initialized_[i]);
WebRtcNetEQ_EnableAVSync(inst_[i], enable ? 1 : 0);
}
}
} // namespace webrtc