blob: 3dedc43eaa9ce4a741f7ea7d64ddd2b9b544a215 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
leozwang@webrtc.org39e96592012-03-01 18:22:48 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "video/rtp_streams_synchronizer.h"
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "call/syncable.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "rtc_base/checks.h"
Åsa Persson74d2b1d2020-02-10 16:33:29 +010016#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/trace_event.h"
Yves Gerey3e707812018-11-28 16:47:49 +010019#include "system_wrappers/include/rtp_to_ntp_estimator.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000020
21namespace webrtc {
asaperssonf8cdd182016-03-15 01:00:47 -070022namespace {
Åsa Persson74d2b1d2020-02-10 16:33:29 +010023// Time interval for logging stats.
24constexpr int64_t kStatsLogIntervalMs = 10000;
25
asaperssonb7e7b492016-11-17 02:27:14 -080026bool UpdateMeasurements(StreamSynchronization::Measurements* stream,
solenberg3ebbcb52017-01-31 03:58:40 -080027 const Syncable::Info& info) {
28 RTC_DCHECK(stream);
29 stream->latest_timestamp = info.latest_received_capture_timestamp;
30 stream->latest_receive_time_ms = info.latest_receive_time_ms;
wu@webrtc.orgcd701192014-04-24 22:10:24 +000031 bool new_rtcp_sr = false;
Yves Gerey665174f2018-06-19 15:03:05 +020032 if (!stream->rtp_to_ntp.UpdateMeasurements(
33 info.capture_time_ntp_secs, info.capture_time_ntp_frac,
34 info.capture_time_source_clock, &new_rtcp_sr)) {
asaperssonb7e7b492016-11-17 02:27:14 -080035 return false;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000036 }
asaperssonb7e7b492016-11-17 02:27:14 -080037 return true;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000038}
asaperssonf8cdd182016-03-15 01:00:47 -070039} // namespace
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000040
solenberg3ebbcb52017-01-31 03:58:40 -080041RtpStreamsSynchronizer::RtpStreamsSynchronizer(Syncable* syncable_video)
42 : syncable_video_(syncable_video),
43 syncable_audio_(nullptr),
mflodman4cd27902016-08-05 06:28:45 -070044 sync_(),
Åsa Persson74d2b1d2020-02-10 16:33:29 +010045 last_sync_time_(rtc::TimeNanos()),
46 last_stats_log_ms_(rtc::TimeMillis()) {
solenberg3ebbcb52017-01-31 03:58:40 -080047 RTC_DCHECK(syncable_video);
Sebastian Janssonc01367d2019-04-08 15:20:44 +020048 process_thread_checker_.Detach();
niklase@google.com470e71d2011-07-07 08:21:25 +000049}
50
Mirko Bonadei8fdcac32018-08-28 16:30:18 +020051RtpStreamsSynchronizer::~RtpStreamsSynchronizer() = default;
52
solenberg3ebbcb52017-01-31 03:58:40 -080053void RtpStreamsSynchronizer::ConfigureSync(Syncable* syncable_audio) {
mflodman4cd27902016-08-05 06:28:45 -070054 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -080055 if (syncable_audio == syncable_audio_) {
mflodman4cd27902016-08-05 06:28:45 -070056 // This prevents expensive no-ops.
Peter Boström1794b262016-02-16 14:12:02 +010057 return;
pbos8fc7fa72015-07-15 08:02:58 -070058 }
mflodman4cd27902016-08-05 06:28:45 -070059
solenberg3ebbcb52017-01-31 03:58:40 -080060 syncable_audio_ = syncable_audio;
mflodman4cd27902016-08-05 06:28:45 -070061 sync_.reset(nullptr);
solenberg3ebbcb52017-01-31 03:58:40 -080062 if (syncable_audio_) {
63 sync_.reset(new StreamSynchronization(syncable_video_->id(),
64 syncable_audio_->id()));
mflodman4cd27902016-08-05 06:28:45 -070065 }
niklase@google.com470e71d2011-07-07 08:21:25 +000066}
67
mflodman4cd27902016-08-05 06:28:45 -070068int64_t RtpStreamsSynchronizer::TimeUntilNextProcess() {
69 RTC_DCHECK_RUN_ON(&process_thread_checker_);
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000070 const int64_t kSyncIntervalMs = 1000;
Niels Möllerd28db7f2016-05-10 16:31:47 +020071 return kSyncIntervalMs -
Yves Gerey665174f2018-06-19 15:03:05 +020072 (rtc::TimeNanos() - last_sync_time_) / rtc::kNumNanosecsPerMillisec;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000073}
74
mflodman4cd27902016-08-05 06:28:45 -070075void RtpStreamsSynchronizer::Process() {
76 RTC_DCHECK_RUN_ON(&process_thread_checker_);
mflodman4cd27902016-08-05 06:28:45 -070077 last_sync_time_ = rtc::TimeNanos();
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000078
mflodman4cd27902016-08-05 06:28:45 -070079 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -080080 if (!syncable_audio_) {
pbosa26ac922016-02-25 04:50:01 -080081 return;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000082 }
mflodman4cd27902016-08-05 06:28:45 -070083 RTC_DCHECK(sync_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +000084
Åsa Persson74d2b1d2020-02-10 16:33:29 +010085 bool log_stats = false;
86 const int64_t now_ms = rtc::TimeMillis();
87 if (now_ms - last_stats_log_ms_ > kStatsLogIntervalMs) {
88 last_stats_log_ms_ = now_ms;
89 log_stats = true;
90 }
91
Danil Chapovalovb9b146c2018-06-15 12:28:07 +020092 absl::optional<Syncable::Info> audio_info = syncable_audio_->GetInfo();
solenberg3ebbcb52017-01-31 03:58:40 -080093 if (!audio_info || !UpdateMeasurements(&audio_measurement_, *audio_info)) {
pbosa26ac922016-02-25 04:50:01 -080094 return;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000095 }
niklase@google.com470e71d2011-07-07 08:21:25 +000096
asaperssonb0c1b4e2016-09-17 01:00:01 -070097 int64_t last_video_receive_ms = video_measurement_.latest_receive_time_ms;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +020098 absl::optional<Syncable::Info> video_info = syncable_video_->GetInfo();
solenberg3ebbcb52017-01-31 03:58:40 -080099 if (!video_info || !UpdateMeasurements(&video_measurement_, *video_info)) {
pbosa26ac922016-02-25 04:50:01 -0800100 return;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000101 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000102
asaperssonb0c1b4e2016-09-17 01:00:01 -0700103 if (last_video_receive_ms == video_measurement_.latest_receive_time_ms) {
104 // No new video packet has been received since last update.
105 return;
106 }
107
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000108 int relative_delay_ms;
109 // Calculate how much later or earlier the audio stream is compared to video.
110 if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
111 &relative_delay_ms)) {
pbosa26ac922016-02-25 04:50:01 -0800112 return;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000113 }
114
Åsa Persson74d2b1d2020-02-10 16:33:29 +0100115 if (log_stats) {
116 RTC_LOG(LS_INFO) << "Sync info stats: " << now_ms
117 << ", {ssrc: " << sync_->audio_stream_id() << ", "
118 << "cur_delay_ms: " << audio_info->current_delay_ms
119 << "} {ssrc: " << sync_->video_stream_id() << ", "
120 << "cur_delay_ms: " << video_info->current_delay_ms
121 << "} {relative_delay_ms: " << relative_delay_ms << "} ";
122 }
123
solenberg3ebbcb52017-01-31 03:58:40 -0800124 TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay",
Yves Gerey665174f2018-06-19 15:03:05 +0200125 video_info->current_delay_ms);
solenberg3ebbcb52017-01-31 03:58:40 -0800126 TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay",
Yves Gerey665174f2018-06-19 15:03:05 +0200127 audio_info->current_delay_ms);
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000128 TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
Åsa Persson74d2b1d2020-02-10 16:33:29 +0100129
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000130 int target_audio_delay_ms = 0;
solenberg3ebbcb52017-01-31 03:58:40 -0800131 int target_video_delay_ms = video_info->current_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000132 // Calculate the necessary extra audio delay and desired total video
133 // delay to get the streams in sync.
Yves Gerey665174f2018-06-19 15:03:05 +0200134 if (!sync_->ComputeDelays(relative_delay_ms, audio_info->current_delay_ms,
135 &target_audio_delay_ms, &target_video_delay_ms)) {
pbosa26ac922016-02-25 04:50:01 -0800136 return;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000137 }
edjee@google.com79b02892013-04-04 19:43:34 +0000138
Åsa Persson74d2b1d2020-02-10 16:33:29 +0100139 if (log_stats) {
140 RTC_LOG(LS_INFO) << "Sync delay stats: " << now_ms
141 << ", {ssrc: " << sync_->audio_stream_id() << ", "
142 << "target_delay_ms: " << target_audio_delay_ms
143 << "} {ssrc: " << sync_->video_stream_id() << ", "
144 << "target_delay_ms: " << target_video_delay_ms << "} ";
145 }
146
solenberg3ebbcb52017-01-31 03:58:40 -0800147 syncable_audio_->SetMinimumPlayoutDelay(target_audio_delay_ms);
148 syncable_video_->SetMinimumPlayoutDelay(target_video_delay_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000149}
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000150
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200151// TODO(https://bugs.webrtc.org/7065): Move RtpToNtpEstimator out of
152// RtpStreamsSynchronizer and into respective receive stream to always populate
153// the estimated playout timestamp.
mflodman4cd27902016-08-05 06:28:45 -0700154bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200155 uint32_t rtp_timestamp,
solenberg3ebbcb52017-01-31 03:58:40 -0800156 int64_t render_time_ms,
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200157 int64_t* video_playout_ntp_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700158 int64_t* stream_offset_ms,
159 double* estimated_freq_khz) const {
mflodman4cd27902016-08-05 06:28:45 -0700160 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -0800161 if (!syncable_audio_) {
asaperssonf8cdd182016-03-15 01:00:47 -0700162 return false;
163 }
164
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200165 uint32_t audio_rtp_timestamp;
166 int64_t time_ms;
167 if (!syncable_audio_->GetPlayoutRtpTimestamp(&audio_rtp_timestamp,
168 &time_ms)) {
169 return false;
170 }
solenberg3ebbcb52017-01-31 03:58:40 -0800171
asaperssonf8cdd182016-03-15 01:00:47 -0700172 int64_t latest_audio_ntp;
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200173 if (!audio_measurement_.rtp_to_ntp.Estimate(audio_rtp_timestamp,
asaperssonfe50b4d2016-12-22 07:53:51 -0800174 &latest_audio_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700175 return false;
176 }
177
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200178 syncable_audio_->SetEstimatedPlayoutNtpTimestampMs(latest_audio_ntp, time_ms);
179
asaperssonf8cdd182016-03-15 01:00:47 -0700180 int64_t latest_video_ntp;
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200181 if (!video_measurement_.rtp_to_ntp.Estimate(rtp_timestamp,
182 &latest_video_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700183 return false;
184 }
185
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200186 // Current audio ntp.
187 int64_t now_ms = rtc::TimeMillis();
188 latest_audio_ntp += (now_ms - time_ms);
asaperssonf8cdd182016-03-15 01:00:47 -0700189
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200190 // Remove video playout delay.
191 int64_t time_to_render_ms = render_time_ms - now_ms;
192 if (time_to_render_ms > 0)
193 latest_video_ntp -= time_to_render_ms;
194
195 *video_playout_ntp_ms = latest_video_ntp;
asaperssonf8cdd182016-03-15 01:00:47 -0700196 *stream_offset_ms = latest_audio_ntp - latest_video_ntp;
Ilya Nikolaevskiy558cabf2017-11-14 10:32:15 +0100197 *estimated_freq_khz = video_measurement_.rtp_to_ntp.params()->frequency_khz;
asaperssonf8cdd182016-03-15 01:00:47 -0700198 return true;
199}
200
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000201} // namespace webrtc