blob: 156ebbb41fb67670634dd30559177a39932e5aac [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"
Steve Anton10542f22019-01-11 09:11:00 -080016#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/trace_event.h"
Yves Gerey3e707812018-11-28 16:47:49 +010018#include "system_wrappers/include/rtp_to_ntp_estimator.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
20namespace webrtc {
asaperssonf8cdd182016-03-15 01:00:47 -070021namespace {
asaperssonb7e7b492016-11-17 02:27:14 -080022bool UpdateMeasurements(StreamSynchronization::Measurements* stream,
solenberg3ebbcb52017-01-31 03:58:40 -080023 const Syncable::Info& info) {
24 RTC_DCHECK(stream);
25 stream->latest_timestamp = info.latest_received_capture_timestamp;
26 stream->latest_receive_time_ms = info.latest_receive_time_ms;
wu@webrtc.orgcd701192014-04-24 22:10:24 +000027 bool new_rtcp_sr = false;
Yves Gerey665174f2018-06-19 15:03:05 +020028 if (!stream->rtp_to_ntp.UpdateMeasurements(
29 info.capture_time_ntp_secs, info.capture_time_ntp_frac,
30 info.capture_time_source_clock, &new_rtcp_sr)) {
asaperssonb7e7b492016-11-17 02:27:14 -080031 return false;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000032 }
asaperssonb7e7b492016-11-17 02:27:14 -080033 return true;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000034}
asaperssonf8cdd182016-03-15 01:00:47 -070035} // namespace
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000036
solenberg3ebbcb52017-01-31 03:58:40 -080037RtpStreamsSynchronizer::RtpStreamsSynchronizer(Syncable* syncable_video)
38 : syncable_video_(syncable_video),
39 syncable_audio_(nullptr),
mflodman4cd27902016-08-05 06:28:45 -070040 sync_(),
41 last_sync_time_(rtc::TimeNanos()) {
solenberg3ebbcb52017-01-31 03:58:40 -080042 RTC_DCHECK(syncable_video);
Sebastian Janssonc01367d2019-04-08 15:20:44 +020043 process_thread_checker_.Detach();
niklase@google.com470e71d2011-07-07 08:21:25 +000044}
45
Mirko Bonadei8fdcac32018-08-28 16:30:18 +020046RtpStreamsSynchronizer::~RtpStreamsSynchronizer() = default;
47
solenberg3ebbcb52017-01-31 03:58:40 -080048void RtpStreamsSynchronizer::ConfigureSync(Syncable* syncable_audio) {
mflodman4cd27902016-08-05 06:28:45 -070049 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -080050 if (syncable_audio == syncable_audio_) {
mflodman4cd27902016-08-05 06:28:45 -070051 // This prevents expensive no-ops.
Peter Boström1794b262016-02-16 14:12:02 +010052 return;
pbos8fc7fa72015-07-15 08:02:58 -070053 }
mflodman4cd27902016-08-05 06:28:45 -070054
solenberg3ebbcb52017-01-31 03:58:40 -080055 syncable_audio_ = syncable_audio;
mflodman4cd27902016-08-05 06:28:45 -070056 sync_.reset(nullptr);
solenberg3ebbcb52017-01-31 03:58:40 -080057 if (syncable_audio_) {
58 sync_.reset(new StreamSynchronization(syncable_video_->id(),
59 syncable_audio_->id()));
mflodman4cd27902016-08-05 06:28:45 -070060 }
niklase@google.com470e71d2011-07-07 08:21:25 +000061}
62
mflodman4cd27902016-08-05 06:28:45 -070063int64_t RtpStreamsSynchronizer::TimeUntilNextProcess() {
64 RTC_DCHECK_RUN_ON(&process_thread_checker_);
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000065 const int64_t kSyncIntervalMs = 1000;
Niels Möllerd28db7f2016-05-10 16:31:47 +020066 return kSyncIntervalMs -
Yves Gerey665174f2018-06-19 15:03:05 +020067 (rtc::TimeNanos() - last_sync_time_) / rtc::kNumNanosecsPerMillisec;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000068}
69
mflodman4cd27902016-08-05 06:28:45 -070070void RtpStreamsSynchronizer::Process() {
71 RTC_DCHECK_RUN_ON(&process_thread_checker_);
mflodman4cd27902016-08-05 06:28:45 -070072 last_sync_time_ = rtc::TimeNanos();
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000073
mflodman4cd27902016-08-05 06:28:45 -070074 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -080075 if (!syncable_audio_) {
pbosa26ac922016-02-25 04:50:01 -080076 return;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000077 }
mflodman4cd27902016-08-05 06:28:45 -070078 RTC_DCHECK(sync_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +000079
Danil Chapovalovb9b146c2018-06-15 12:28:07 +020080 absl::optional<Syncable::Info> audio_info = syncable_audio_->GetInfo();
solenberg3ebbcb52017-01-31 03:58:40 -080081 if (!audio_info || !UpdateMeasurements(&audio_measurement_, *audio_info)) {
pbosa26ac922016-02-25 04:50:01 -080082 return;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000083 }
niklase@google.com470e71d2011-07-07 08:21:25 +000084
asaperssonb0c1b4e2016-09-17 01:00:01 -070085 int64_t last_video_receive_ms = video_measurement_.latest_receive_time_ms;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +020086 absl::optional<Syncable::Info> video_info = syncable_video_->GetInfo();
solenberg3ebbcb52017-01-31 03:58:40 -080087 if (!video_info || !UpdateMeasurements(&video_measurement_, *video_info)) {
pbosa26ac922016-02-25 04:50:01 -080088 return;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000089 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000090
asaperssonb0c1b4e2016-09-17 01:00:01 -070091 if (last_video_receive_ms == video_measurement_.latest_receive_time_ms) {
92 // No new video packet has been received since last update.
93 return;
94 }
95
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000096 int relative_delay_ms;
97 // Calculate how much later or earlier the audio stream is compared to video.
98 if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
99 &relative_delay_ms)) {
pbosa26ac922016-02-25 04:50:01 -0800100 return;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000101 }
102
solenberg3ebbcb52017-01-31 03:58:40 -0800103 TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay",
Yves Gerey665174f2018-06-19 15:03:05 +0200104 video_info->current_delay_ms);
solenberg3ebbcb52017-01-31 03:58:40 -0800105 TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay",
Yves Gerey665174f2018-06-19 15:03:05 +0200106 audio_info->current_delay_ms);
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000107 TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000108 int target_audio_delay_ms = 0;
solenberg3ebbcb52017-01-31 03:58:40 -0800109 int target_video_delay_ms = video_info->current_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000110 // Calculate the necessary extra audio delay and desired total video
111 // delay to get the streams in sync.
Yves Gerey665174f2018-06-19 15:03:05 +0200112 if (!sync_->ComputeDelays(relative_delay_ms, audio_info->current_delay_ms,
113 &target_audio_delay_ms, &target_video_delay_ms)) {
pbosa26ac922016-02-25 04:50:01 -0800114 return;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000115 }
edjee@google.com79b02892013-04-04 19:43:34 +0000116
solenberg3ebbcb52017-01-31 03:58:40 -0800117 syncable_audio_->SetMinimumPlayoutDelay(target_audio_delay_ms);
118 syncable_video_->SetMinimumPlayoutDelay(target_video_delay_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000119}
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000120
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200121// TODO(https://bugs.webrtc.org/7065): Move RtpToNtpEstimator out of
122// RtpStreamsSynchronizer and into respective receive stream to always populate
123// the estimated playout timestamp.
mflodman4cd27902016-08-05 06:28:45 -0700124bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200125 uint32_t rtp_timestamp,
solenberg3ebbcb52017-01-31 03:58:40 -0800126 int64_t render_time_ms,
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200127 int64_t* video_playout_ntp_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700128 int64_t* stream_offset_ms,
129 double* estimated_freq_khz) const {
mflodman4cd27902016-08-05 06:28:45 -0700130 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -0800131 if (!syncable_audio_) {
asaperssonf8cdd182016-03-15 01:00:47 -0700132 return false;
133 }
134
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200135 uint32_t audio_rtp_timestamp;
136 int64_t time_ms;
137 if (!syncable_audio_->GetPlayoutRtpTimestamp(&audio_rtp_timestamp,
138 &time_ms)) {
139 return false;
140 }
solenberg3ebbcb52017-01-31 03:58:40 -0800141
asaperssonf8cdd182016-03-15 01:00:47 -0700142 int64_t latest_audio_ntp;
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200143 if (!audio_measurement_.rtp_to_ntp.Estimate(audio_rtp_timestamp,
asaperssonfe50b4d2016-12-22 07:53:51 -0800144 &latest_audio_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700145 return false;
146 }
147
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200148 syncable_audio_->SetEstimatedPlayoutNtpTimestampMs(latest_audio_ntp, time_ms);
149
asaperssonf8cdd182016-03-15 01:00:47 -0700150 int64_t latest_video_ntp;
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200151 if (!video_measurement_.rtp_to_ntp.Estimate(rtp_timestamp,
152 &latest_video_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700153 return false;
154 }
155
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200156 // Current audio ntp.
157 int64_t now_ms = rtc::TimeMillis();
158 latest_audio_ntp += (now_ms - time_ms);
asaperssonf8cdd182016-03-15 01:00:47 -0700159
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200160 // Remove video playout delay.
161 int64_t time_to_render_ms = render_time_ms - now_ms;
162 if (time_to_render_ms > 0)
163 latest_video_ntp -= time_to_render_ms;
164
165 *video_playout_ntp_ms = latest_video_ntp;
asaperssonf8cdd182016-03-15 01:00:47 -0700166 *stream_offset_ms = latest_audio_ntp - latest_video_ntp;
Ilya Nikolaevskiy558cabf2017-11-14 10:32:15 +0100167 *estimated_freq_khz = video_measurement_.rtp_to_ntp.params()->frequency_khz;
asaperssonf8cdd182016-03-15 01:00:47 -0700168 return true;
169}
170
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000171} // namespace webrtc