Fix the chain that propagates the audio frame's rtp and ntp timestamp including:
* In AudioCodingModuleImpl::PlayoutData10Ms, don't reset the timestamp got from GetAudio. * When there're more than one participant, set AudioFrame's RTP timestamp to 0. * Copy ntp_time_ms_ in AudioFrame::CopyFrom method. * In RemixAndResample, pass src frame's timestamp_ and ntp_time_ms_ to the dst frame. * Fix how |elapsed_time_ms| is computed in channel.cc by adding GetPlayoutFrequency. Tweaks on ntp_time_ms_: * Init ntp_time_ms_ to -1 in AudioFrame ctor. * When there're more than one participant, set AudioFrame's ntp_time_ms_ to an invalid value. I.e. we don't support ntp_time_ms_ in multiple participants case before the mixing is moved to chrome. Added elapsed_time_ms to AudioFrame and pass it to chrome, where we don't have the information about the rtp timestmp's sample rate, i.e. can't convert rtp timestamp to ms. BUG=3111 R=henrik.lundin@webrtc.org, turaj@webrtc.org, xians@webrtc.org TBR=andrew andrew to take another look on audio_conference_mixer_impl.cc Review URL: https://webrtc-codereview.appspot.com/14559004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6346 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -475,10 +475,17 @@ int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) {
|
||||
call_stats_.DecodedByNetEq(audio_frame->speech_type_);
|
||||
|
||||
// Computes the RTP timestamp of the first sample in |audio_frame| from
|
||||
// |PlayoutTimestamp|, which is the timestamp of the last sample of
|
||||
// |GetPlayoutTimestamp|, which is the timestamp of the last sample of
|
||||
// |audio_frame|.
|
||||
audio_frame->timestamp_ =
|
||||
PlayoutTimestamp() - audio_frame->samples_per_channel_;
|
||||
uint32_t playout_timestamp = 0;
|
||||
if (GetPlayoutTimestamp(&playout_timestamp)) {
|
||||
audio_frame->timestamp_ =
|
||||
playout_timestamp - audio_frame->samples_per_channel_;
|
||||
} else {
|
||||
// Remain 0 until we have a valid |playout_timestamp|.
|
||||
audio_frame->timestamp_ = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -596,13 +603,14 @@ void AcmReceiver::set_id(int id) {
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
uint32_t AcmReceiver::PlayoutTimestamp() {
|
||||
bool AcmReceiver::GetPlayoutTimestamp(uint32_t* timestamp) {
|
||||
if (av_sync_) {
|
||||
assert(initial_delay_manager_.get());
|
||||
if (initial_delay_manager_->buffering())
|
||||
return initial_delay_manager_->playout_timestamp();
|
||||
if (initial_delay_manager_->buffering()) {
|
||||
return initial_delay_manager_->GetPlayoutTimestamp(timestamp);
|
||||
}
|
||||
}
|
||||
return neteq_->PlayoutTimestamp();
|
||||
return neteq_->GetPlayoutTimestamp(timestamp);
|
||||
}
|
||||
|
||||
int AcmReceiver::last_audio_codec_id() const {
|
||||
|
||||
@@ -242,9 +242,10 @@ class AcmReceiver {
|
||||
void set_id(int id); // TODO(turajs): can be inline.
|
||||
|
||||
//
|
||||
// Returns the RTP timestamp of the last sample delivered by GetAudio().
|
||||
// Gets the RTP timestamp of the last sample delivered by GetAudio().
|
||||
// Returns true if the RTP timestamp is valid, otherwise false.
|
||||
//
|
||||
uint32_t PlayoutTimestamp();
|
||||
bool GetPlayoutTimestamp(uint32_t* timestamp);
|
||||
|
||||
//
|
||||
// Return the index of the codec associated with the last non-CNG/non-DTMF
|
||||
|
||||
@@ -1776,7 +1776,6 @@ int AudioCodingModuleImpl::PlayoutData10Ms(int desired_freq_hz,
|
||||
}
|
||||
|
||||
audio_frame->id_ = id_;
|
||||
audio_frame->timestamp_ = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1917,8 +1916,7 @@ int AudioCodingModuleImpl::ConfigISACBandwidthEstimator(
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) {
|
||||
*timestamp = receiver_.PlayoutTimestamp();
|
||||
return 0;
|
||||
return receiver_.GetPlayoutTimestamp(timestamp) ? 0 : -1;
|
||||
}
|
||||
|
||||
bool AudioCodingModuleImpl::HaveValidEncoder(const char* caller_name) const {
|
||||
|
||||
@@ -219,6 +219,14 @@ void InitialDelayManager::LatePackets(
|
||||
return;
|
||||
}
|
||||
|
||||
bool InitialDelayManager::GetPlayoutTimestamp(uint32_t* playout_timestamp) {
|
||||
if (!buffering_) {
|
||||
return false;
|
||||
}
|
||||
*playout_timestamp = playout_timestamp_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitialDelayManager::DisableBuffering() {
|
||||
buffering_ = false;
|
||||
}
|
||||
|
||||
@@ -65,8 +65,9 @@ class InitialDelayManager {
|
||||
// sequence of late (or perhaps missing) packets is computed.
|
||||
void LatePackets(uint32_t timestamp_now, SyncStream* sync_stream);
|
||||
|
||||
// Playout timestamp, valid when buffering.
|
||||
uint32_t playout_timestamp() { return playout_timestamp_; }
|
||||
// Get playout timestamp.
|
||||
// Returns true if the timestamp is valid (when buffering), otherwise false.
|
||||
bool GetPlayoutTimestamp(uint32_t* playout_timestamp);
|
||||
|
||||
// True if buffered audio is less than the given initial delay (specified at
|
||||
// the constructor). Buffering might be disabled by the client of this class.
|
||||
|
||||
@@ -359,7 +359,9 @@ TEST_F(InitialDelayManagerTest, BufferingAudio) {
|
||||
EXPECT_TRUE(manager_->buffering());
|
||||
const uint32_t expected_playout_timestamp = rtp_info_.header.timestamp -
|
||||
kInitDelayMs * kSamplingRateHz / 1000;
|
||||
EXPECT_EQ(expected_playout_timestamp, manager_->playout_timestamp());
|
||||
uint32_t actual_playout_timestamp = 0;
|
||||
EXPECT_TRUE(manager_->GetPlayoutTimestamp(&actual_playout_timestamp));
|
||||
EXPECT_EQ(expected_playout_timestamp, actual_playout_timestamp);
|
||||
NextRtpHeader(&rtp_info_, &rtp_receive_timestamp_);
|
||||
}
|
||||
|
||||
|
||||
@@ -228,8 +228,9 @@ class NetEq {
|
||||
// Disables post-decode VAD.
|
||||
virtual void DisableVad() = 0;
|
||||
|
||||
// Returns the RTP timestamp for the last sample delivered by GetAudio().
|
||||
virtual uint32_t PlayoutTimestamp() = 0;
|
||||
// Gets the RTP timestamp for the last sample delivered by GetAudio().
|
||||
// Returns true if the RTP timestamp is valid, otherwise false.
|
||||
virtual bool GetPlayoutTimestamp(uint32_t* timestamp) = 0;
|
||||
|
||||
// Not implemented.
|
||||
virtual int SetTargetNumberOfChannels() = 0;
|
||||
|
||||
@@ -335,9 +335,15 @@ void NetEqImpl::DisableVad() {
|
||||
vad_->Disable();
|
||||
}
|
||||
|
||||
uint32_t NetEqImpl::PlayoutTimestamp() {
|
||||
bool NetEqImpl::GetPlayoutTimestamp(uint32_t* timestamp) {
|
||||
CriticalSectionScoped lock(crit_sect_.get());
|
||||
return timestamp_scaler_->ToExternal(playout_timestamp_);
|
||||
if (first_packet_) {
|
||||
// We don't have a valid RTP timestamp until we have decoded our first
|
||||
// RTP packet.
|
||||
return false;
|
||||
}
|
||||
*timestamp = timestamp_scaler_->ToExternal(playout_timestamp_);
|
||||
return true;
|
||||
}
|
||||
|
||||
int NetEqImpl::LastError() {
|
||||
|
||||
@@ -166,8 +166,7 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
// Disables post-decode VAD.
|
||||
virtual void DisableVad();
|
||||
|
||||
// Returns the RTP timestamp for the last sample delivered by GetAudio().
|
||||
virtual uint32_t PlayoutTimestamp();
|
||||
virtual bool GetPlayoutTimestamp(uint32_t* timestamp);
|
||||
|
||||
virtual int SetTargetNumberOfChannels() { return kNotImplemented; }
|
||||
|
||||
|
||||
@@ -477,8 +477,10 @@ TEST_F(NetEqImplTest, VerifyTimestampPropagation) {
|
||||
// The value of the last of the output samples is the same as the number of
|
||||
// samples played from the decoded packet. Thus, this number + the RTP
|
||||
// timestamp should match the playout timestamp.
|
||||
uint32_t timestamp = 0;
|
||||
EXPECT_TRUE(neteq_->GetPlayoutTimestamp(×tamp));
|
||||
EXPECT_EQ(rtp_header.header.timestamp + output[samples_per_channel - 1],
|
||||
neteq_->PlayoutTimestamp());
|
||||
timestamp);
|
||||
|
||||
// Check the timestamp for the last value in the sync buffer. This should
|
||||
// be one full frame length ahead of the RTP timestamp.
|
||||
|
||||
@@ -228,6 +228,8 @@ class NetEqDecodingTest : public ::testing::Test {
|
||||
|
||||
void DuplicateCng();
|
||||
|
||||
uint32_t PlayoutTimestamp();
|
||||
|
||||
NetEq* neteq_;
|
||||
FILE* rtp_fp_;
|
||||
unsigned int sim_clock_;
|
||||
@@ -736,7 +738,7 @@ void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
|
||||
}
|
||||
|
||||
EXPECT_EQ(kOutputNormal, type);
|
||||
int32_t delay_before = timestamp - neteq_->PlayoutTimestamp();
|
||||
int32_t delay_before = timestamp - PlayoutTimestamp();
|
||||
|
||||
// Insert CNG for 1 minute (= 60000 ms).
|
||||
const int kCngPeriodMs = 100;
|
||||
@@ -829,7 +831,7 @@ void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
|
||||
// Check that the speech starts again within reasonable time.
|
||||
double time_until_speech_returns_ms = t_ms - speech_restart_time_ms;
|
||||
EXPECT_LT(time_until_speech_returns_ms, max_time_to_speech_ms);
|
||||
int32_t delay_after = timestamp - neteq_->PlayoutTimestamp();
|
||||
int32_t delay_after = timestamp - PlayoutTimestamp();
|
||||
// Compare delay before and after, and make sure it differs less than 20 ms.
|
||||
EXPECT_LE(delay_after, delay_before + delay_tolerance_ms * 16);
|
||||
EXPECT_GE(delay_after, delay_before - delay_tolerance_ms * 16);
|
||||
@@ -1310,7 +1312,7 @@ void NetEqDecodingTest::WrapTest(uint16_t start_seq_no,
|
||||
ASSERT_EQ(1, num_channels);
|
||||
|
||||
// Expect delay (in samples) to be less than 2 packets.
|
||||
EXPECT_LE(timestamp - neteq_->PlayoutTimestamp(),
|
||||
EXPECT_LE(timestamp - PlayoutTimestamp(),
|
||||
static_cast<uint32_t>(kSamples * 2));
|
||||
}
|
||||
// Make sure we have actually tested wrap-around.
|
||||
@@ -1391,7 +1393,7 @@ void NetEqDecodingTest::DuplicateCng() {
|
||||
kMaxBlockSize, out_data_, &out_len, &num_channels, &type));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_len);
|
||||
EXPECT_EQ(kOutputCNG, type);
|
||||
EXPECT_EQ(timestamp - algorithmic_delay_samples, neteq_->PlayoutTimestamp());
|
||||
EXPECT_EQ(timestamp - algorithmic_delay_samples, PlayoutTimestamp());
|
||||
|
||||
// Insert the same CNG packet again. Note that at this point it is old, since
|
||||
// we have already decoded the first copy of it.
|
||||
@@ -1406,7 +1408,7 @@ void NetEqDecodingTest::DuplicateCng() {
|
||||
ASSERT_EQ(kBlockSize16kHz, out_len);
|
||||
EXPECT_EQ(kOutputCNG, type);
|
||||
EXPECT_EQ(timestamp - algorithmic_delay_samples,
|
||||
neteq_->PlayoutTimestamp());
|
||||
PlayoutTimestamp());
|
||||
}
|
||||
|
||||
// Insert speech again.
|
||||
@@ -1422,7 +1424,13 @@ void NetEqDecodingTest::DuplicateCng() {
|
||||
ASSERT_EQ(kBlockSize16kHz, out_len);
|
||||
EXPECT_EQ(kOutputNormal, type);
|
||||
EXPECT_EQ(timestamp + kSamples - algorithmic_delay_samples,
|
||||
neteq_->PlayoutTimestamp());
|
||||
PlayoutTimestamp());
|
||||
}
|
||||
|
||||
uint32_t NetEqDecodingTest::PlayoutTimestamp() {
|
||||
uint32_t playout_timestamp = 0;
|
||||
EXPECT_TRUE(neteq_->GetPlayoutTimestamp(&playout_timestamp));
|
||||
return playout_timestamp;
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, DiscardDuplicateCng) { DuplicateCng(); }
|
||||
|
||||
Reference in New Issue
Block a user