blob: 9646f9d262aba0a139dc9b3f98952ca363a8c1d3 [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);
mflodman4cd27902016-08-05 06:28:45 -070043 process_thread_checker_.DetachFromThread();
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
mflodman4cd27902016-08-05 06:28:45 -0700121bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
solenberg3ebbcb52017-01-31 03:58:40 -0800122 uint32_t timestamp,
123 int64_t render_time_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700124 int64_t* stream_offset_ms,
125 double* estimated_freq_khz) const {
mflodman4cd27902016-08-05 06:28:45 -0700126 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -0800127 if (!syncable_audio_) {
asaperssonf8cdd182016-03-15 01:00:47 -0700128 return false;
129 }
130
solenberg3ebbcb52017-01-31 03:58:40 -0800131 uint32_t playout_timestamp = syncable_audio_->GetPlayoutTimestamp();
132
asaperssonf8cdd182016-03-15 01:00:47 -0700133 int64_t latest_audio_ntp;
asaperssonfe50b4d2016-12-22 07:53:51 -0800134 if (!audio_measurement_.rtp_to_ntp.Estimate(playout_timestamp,
135 &latest_audio_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700136 return false;
137 }
138
139 int64_t latest_video_ntp;
solenberg3ebbcb52017-01-31 03:58:40 -0800140 if (!video_measurement_.rtp_to_ntp.Estimate(timestamp, &latest_video_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700141 return false;
142 }
143
solenberg3ebbcb52017-01-31 03:58:40 -0800144 int64_t time_to_render_ms = render_time_ms - rtc::TimeMillis();
asaperssonf8cdd182016-03-15 01:00:47 -0700145 if (time_to_render_ms > 0)
146 latest_video_ntp += time_to_render_ms;
147
148 *stream_offset_ms = latest_audio_ntp - latest_video_ntp;
Ilya Nikolaevskiy558cabf2017-11-14 10:32:15 +0100149 *estimated_freq_khz = video_measurement_.rtp_to_ntp.params()->frequency_khz;
asaperssonf8cdd182016-03-15 01:00:47 -0700150 return true;
151}
152
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000153} // namespace webrtc