2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-03-01 18:22:48 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2016-08-05 06:28:45 -07:00
|
|
|
#include "webrtc/video/rtp_streams_synchronizer.h"
|
2011-11-30 18:31:36 +00:00
|
|
|
|
2016-02-16 14:12:02 +01:00
|
|
|
#include "webrtc/base/checks.h"
|
2015-10-26 11:35:17 +01:00
|
|
|
#include "webrtc/base/logging.h"
|
2016-05-10 16:31:47 +02:00
|
|
|
#include "webrtc/base/timeutils.h"
|
2015-10-20 23:00:48 -07:00
|
|
|
#include "webrtc/base/trace_event.h"
|
2015-11-04 08:31:52 +01:00
|
|
|
#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
|
|
|
|
|
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
|
2016-04-22 18:23:15 +02:00
|
|
|
#include "webrtc/modules/video_coding/video_coding_impl.h"
|
2016-03-15 01:00:47 -07:00
|
|
|
#include "webrtc/system_wrappers/include/clock.h"
|
2015-12-09 12:13:30 +01:00
|
|
|
#include "webrtc/video/stream_synchronization.h"
|
2016-03-15 01:00:47 -07:00
|
|
|
#include "webrtc/video_frame.h"
|
2013-05-17 13:44:48 +00:00
|
|
|
#include "webrtc/voice_engine/include/voe_video_sync.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
2016-03-15 01:00:47 -07:00
|
|
|
namespace {
|
2012-09-11 07:00:42 +00:00
|
|
|
int UpdateMeasurements(StreamSynchronization::Measurements* stream,
|
2016-08-05 06:28:45 -07:00
|
|
|
RtpRtcp* rtp_rtcp, RtpReceiver* receiver) {
|
|
|
|
|
if (!receiver->Timestamp(&stream->latest_timestamp))
|
2013-11-08 15:18:52 +00:00
|
|
|
return -1;
|
2016-08-05 06:28:45 -07:00
|
|
|
if (!receiver->LastReceivedTimeMs(&stream->latest_receive_time_ms))
|
2013-11-08 15:18:52 +00:00
|
|
|
return -1;
|
2014-04-24 22:10:24 +00:00
|
|
|
|
|
|
|
|
uint32_t ntp_secs = 0;
|
|
|
|
|
uint32_t ntp_frac = 0;
|
|
|
|
|
uint32_t rtp_timestamp = 0;
|
2016-08-05 06:28:45 -07:00
|
|
|
if (rtp_rtcp->RemoteNTP(&ntp_secs, &ntp_frac, nullptr, nullptr,
|
|
|
|
|
&rtp_timestamp) != 0) {
|
2012-09-11 07:00:42 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2014-04-24 22:10:24 +00:00
|
|
|
|
|
|
|
|
bool new_rtcp_sr = false;
|
2016-11-02 07:14:03 -07:00
|
|
|
if (!UpdateRtcpList(ntp_secs, ntp_frac, rtp_timestamp, &stream->rtcp,
|
|
|
|
|
&new_rtcp_sr)) {
|
2012-09-11 07:00:42 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2014-04-24 22:10:24 +00:00
|
|
|
|
2012-09-11 07:00:42 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2016-03-15 01:00:47 -07:00
|
|
|
} // namespace
|
2012-09-11 07:00:42 +00:00
|
|
|
|
2016-08-05 06:28:45 -07:00
|
|
|
RtpStreamsSynchronizer::RtpStreamsSynchronizer(
|
|
|
|
|
vcm::VideoReceiver* video_receiver,
|
|
|
|
|
RtpStreamReceiver* rtp_stream_receiver)
|
|
|
|
|
: clock_(Clock::GetRealTimeClock()),
|
|
|
|
|
video_receiver_(video_receiver),
|
|
|
|
|
video_rtp_receiver_(rtp_stream_receiver->GetRtpReceiver()),
|
|
|
|
|
video_rtp_rtcp_(rtp_stream_receiver->rtp_rtcp()),
|
2011-11-30 18:31:36 +00:00
|
|
|
voe_channel_id_(-1),
|
2016-04-04 17:56:10 +02:00
|
|
|
voe_sync_interface_(nullptr),
|
2016-08-05 06:28:45 -07:00
|
|
|
audio_rtp_receiver_(nullptr),
|
|
|
|
|
audio_rtp_rtcp_(nullptr),
|
|
|
|
|
sync_(),
|
|
|
|
|
last_sync_time_(rtc::TimeNanos()) {
|
|
|
|
|
process_thread_checker_.DetachFromThread();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 06:28:45 -07:00
|
|
|
void RtpStreamsSynchronizer::ConfigureSync(int voe_channel_id,
|
|
|
|
|
VoEVideoSync* voe_sync_interface) {
|
2016-02-16 14:12:02 +01:00
|
|
|
if (voe_channel_id != -1)
|
|
|
|
|
RTC_DCHECK(voe_sync_interface);
|
2016-08-05 06:28:45 -07:00
|
|
|
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
2015-07-15 08:02:58 -07:00
|
|
|
if (voe_channel_id_ == voe_channel_id &&
|
2016-08-05 06:28:45 -07:00
|
|
|
voe_sync_interface_ == voe_sync_interface) {
|
|
|
|
|
// This prevents expensive no-ops.
|
2016-02-16 14:12:02 +01:00
|
|
|
return;
|
2015-07-15 08:02:58 -07:00
|
|
|
}
|
2011-11-30 18:31:36 +00:00
|
|
|
voe_channel_id_ = voe_channel_id;
|
|
|
|
|
voe_sync_interface_ = voe_sync_interface;
|
2016-08-05 06:28:45 -07:00
|
|
|
|
|
|
|
|
audio_rtp_rtcp_ = nullptr;
|
|
|
|
|
audio_rtp_receiver_ = nullptr;
|
|
|
|
|
sync_.reset(nullptr);
|
|
|
|
|
|
|
|
|
|
if (voe_channel_id_ != -1) {
|
|
|
|
|
voe_sync_interface_->GetRtpRtcp(voe_channel_id_, &audio_rtp_rtcp_,
|
|
|
|
|
&audio_rtp_receiver_);
|
|
|
|
|
RTC_DCHECK(audio_rtp_rtcp_);
|
|
|
|
|
RTC_DCHECK(audio_rtp_receiver_);
|
|
|
|
|
sync_.reset(new StreamSynchronization(video_rtp_rtcp_->SSRC(),
|
|
|
|
|
voe_channel_id_));
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 06:28:45 -07:00
|
|
|
int64_t RtpStreamsSynchronizer::TimeUntilNextProcess() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&process_thread_checker_);
|
2014-12-15 22:09:40 +00:00
|
|
|
const int64_t kSyncIntervalMs = 1000;
|
2016-05-10 16:31:47 +02:00
|
|
|
return kSyncIntervalMs -
|
|
|
|
|
(rtc::TimeNanos() - last_sync_time_) / rtc::kNumNanosecsPerMillisec;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 06:28:45 -07:00
|
|
|
void RtpStreamsSynchronizer::Process() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&process_thread_checker_);
|
2011-11-30 18:31:36 +00:00
|
|
|
|
2016-04-22 18:23:15 +02:00
|
|
|
const int current_video_delay_ms = video_receiver_->Delay();
|
2016-08-05 06:28:45 -07:00
|
|
|
last_sync_time_ = rtc::TimeNanos();
|
2011-11-30 18:31:36 +00:00
|
|
|
|
2016-08-05 06:28:45 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2011-11-30 18:31:36 +00:00
|
|
|
if (voe_channel_id_ == -1) {
|
2016-02-25 04:50:01 -08:00
|
|
|
return;
|
2011-11-30 18:31:36 +00:00
|
|
|
}
|
2016-08-05 06:28:45 -07:00
|
|
|
RTC_DCHECK(voe_sync_interface_);
|
|
|
|
|
RTC_DCHECK(sync_.get());
|
2011-11-30 18:31:36 +00:00
|
|
|
|
2013-04-11 20:23:35 +00:00
|
|
|
int audio_jitter_buffer_delay_ms = 0;
|
|
|
|
|
int playout_buffer_delay_ms = 0;
|
2011-11-30 18:31:36 +00:00
|
|
|
if (voe_sync_interface_->GetDelayEstimate(voe_channel_id_,
|
2013-04-11 20:23:35 +00:00
|
|
|
&audio_jitter_buffer_delay_ms,
|
|
|
|
|
&playout_buffer_delay_ms) != 0) {
|
2016-02-25 04:50:01 -08:00
|
|
|
return;
|
2011-11-30 18:31:36 +00:00
|
|
|
}
|
2013-06-14 23:30:58 +00:00
|
|
|
const int current_audio_delay_ms = audio_jitter_buffer_delay_ms +
|
|
|
|
|
playout_buffer_delay_ms;
|
2011-11-30 18:31:36 +00:00
|
|
|
|
2016-09-17 01:00:01 -07:00
|
|
|
int64_t last_video_receive_ms = video_measurement_.latest_receive_time_ms;
|
2016-08-05 06:28:45 -07:00
|
|
|
if (UpdateMeasurements(&video_measurement_, video_rtp_rtcp_,
|
|
|
|
|
video_rtp_receiver_) != 0) {
|
2016-02-25 04:50:01 -08:00
|
|
|
return;
|
2012-05-11 11:08:54 +00:00
|
|
|
}
|
2012-09-11 07:00:42 +00:00
|
|
|
|
2016-08-05 06:28:45 -07:00
|
|
|
if (UpdateMeasurements(&audio_measurement_, audio_rtp_rtcp_,
|
|
|
|
|
audio_rtp_receiver_) != 0) {
|
2016-02-25 04:50:01 -08:00
|
|
|
return;
|
2012-05-11 11:08:54 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-17 01:00:01 -07:00
|
|
|
if (last_video_receive_ms == video_measurement_.latest_receive_time_ms) {
|
|
|
|
|
// No new video packet has been received since last update.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-11 07:00:42 +00:00
|
|
|
int relative_delay_ms;
|
|
|
|
|
// Calculate how much later or earlier the audio stream is compared to video.
|
|
|
|
|
if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
|
|
|
|
|
&relative_delay_ms)) {
|
2016-02-25 04:50:01 -08:00
|
|
|
return;
|
2012-05-11 11:08:54 +00:00
|
|
|
}
|
2012-09-11 07:00:42 +00:00
|
|
|
|
2013-06-14 23:30:58 +00:00
|
|
|
TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay", current_video_delay_ms);
|
|
|
|
|
TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay", current_audio_delay_ms);
|
2013-04-09 19:54:10 +00:00
|
|
|
TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
|
2013-06-14 23:30:58 +00:00
|
|
|
int target_audio_delay_ms = 0;
|
2013-06-15 06:51:27 +00:00
|
|
|
int target_video_delay_ms = current_video_delay_ms;
|
2012-09-11 07:00:42 +00:00
|
|
|
// Calculate the necessary extra audio delay and desired total video
|
|
|
|
|
// delay to get the streams in sync.
|
2012-11-12 18:51:52 +00:00
|
|
|
if (!sync_->ComputeDelays(relative_delay_ms,
|
2013-06-14 23:30:58 +00:00
|
|
|
current_audio_delay_ms,
|
|
|
|
|
&target_audio_delay_ms,
|
|
|
|
|
&target_video_delay_ms)) {
|
2016-02-25 04:50:01 -08:00
|
|
|
return;
|
2012-05-11 11:08:54 +00:00
|
|
|
}
|
2013-04-04 19:43:34 +00:00
|
|
|
|
2011-11-30 18:31:36 +00:00
|
|
|
if (voe_sync_interface_->SetMinimumPlayoutDelay(
|
2013-06-14 23:30:58 +00:00
|
|
|
voe_channel_id_, target_audio_delay_ms) == -1) {
|
2014-05-14 08:02:22 +00:00
|
|
|
LOG(LS_ERROR) << "Error setting voice delay.";
|
2011-11-30 18:31:36 +00:00
|
|
|
}
|
2016-04-22 18:23:15 +02:00
|
|
|
video_receiver_->SetMinimumPlayoutDelay(target_video_delay_ms);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-11-30 18:31:36 +00:00
|
|
|
|
2016-08-05 06:28:45 -07:00
|
|
|
bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
|
2016-11-02 07:14:03 -07:00
|
|
|
const VideoFrame& frame,
|
|
|
|
|
int64_t* stream_offset_ms,
|
|
|
|
|
double* estimated_freq_khz) const {
|
2016-08-05 06:28:45 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2016-03-15 01:00:47 -07:00
|
|
|
if (voe_channel_id_ == -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
uint32_t playout_timestamp = 0;
|
|
|
|
|
if (voe_sync_interface_->GetPlayoutTimestamp(voe_channel_id_,
|
|
|
|
|
playout_timestamp) != 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t latest_audio_ntp;
|
|
|
|
|
if (!RtpToNtpMs(playout_timestamp, audio_measurement_.rtcp,
|
|
|
|
|
&latest_audio_ntp)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t latest_video_ntp;
|
|
|
|
|
if (!RtpToNtpMs(frame.timestamp(), video_measurement_.rtcp,
|
|
|
|
|
&latest_video_ntp)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t time_to_render_ms =
|
|
|
|
|
frame.render_time_ms() - clock_->TimeInMilliseconds();
|
|
|
|
|
if (time_to_render_ms > 0)
|
|
|
|
|
latest_video_ntp += time_to_render_ms;
|
|
|
|
|
|
|
|
|
|
*stream_offset_ms = latest_audio_ntp - latest_video_ntp;
|
2016-11-02 07:14:03 -07:00
|
|
|
*estimated_freq_khz = video_measurement_.rtcp.params.frequency_khz;
|
2016-03-15 01:00:47 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-30 18:31:36 +00:00
|
|
|
} // namespace webrtc
|