blob: e46a2200c5533378f24d8c9840eaf5fd864b6391 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "call/syncable.h"
14#include "modules/video_coding/video_coding_impl.h"
15#include "rtc_base/checks.h"
16#include "rtc_base/logging.h"
17#include "rtc_base/timeutils.h"
18#include "rtc_base/trace_event.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
solenberg3ebbcb52017-01-31 03:58:40 -080046void RtpStreamsSynchronizer::ConfigureSync(Syncable* syncable_audio) {
mflodman4cd27902016-08-05 06:28:45 -070047 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -080048 if (syncable_audio == syncable_audio_) {
mflodman4cd27902016-08-05 06:28:45 -070049 // This prevents expensive no-ops.
Peter Boström1794b262016-02-16 14:12:02 +010050 return;
pbos8fc7fa72015-07-15 08:02:58 -070051 }
mflodman4cd27902016-08-05 06:28:45 -070052
solenberg3ebbcb52017-01-31 03:58:40 -080053 syncable_audio_ = syncable_audio;
mflodman4cd27902016-08-05 06:28:45 -070054 sync_.reset(nullptr);
solenberg3ebbcb52017-01-31 03:58:40 -080055 if (syncable_audio_) {
56 sync_.reset(new StreamSynchronization(syncable_video_->id(),
57 syncable_audio_->id()));
mflodman4cd27902016-08-05 06:28:45 -070058 }
niklase@google.com470e71d2011-07-07 08:21:25 +000059}
60
mflodman4cd27902016-08-05 06:28:45 -070061int64_t RtpStreamsSynchronizer::TimeUntilNextProcess() {
62 RTC_DCHECK_RUN_ON(&process_thread_checker_);
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000063 const int64_t kSyncIntervalMs = 1000;
Niels Möllerd28db7f2016-05-10 16:31:47 +020064 return kSyncIntervalMs -
Yves Gerey665174f2018-06-19 15:03:05 +020065 (rtc::TimeNanos() - last_sync_time_) / rtc::kNumNanosecsPerMillisec;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000066}
67
mflodman4cd27902016-08-05 06:28:45 -070068void RtpStreamsSynchronizer::Process() {
69 RTC_DCHECK_RUN_ON(&process_thread_checker_);
mflodman4cd27902016-08-05 06:28:45 -070070 last_sync_time_ = rtc::TimeNanos();
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000071
mflodman4cd27902016-08-05 06:28:45 -070072 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -080073 if (!syncable_audio_) {
pbosa26ac922016-02-25 04:50:01 -080074 return;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000075 }
mflodman4cd27902016-08-05 06:28:45 -070076 RTC_DCHECK(sync_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +000077
Danil Chapovalovb9b146c2018-06-15 12:28:07 +020078 absl::optional<Syncable::Info> audio_info = syncable_audio_->GetInfo();
solenberg3ebbcb52017-01-31 03:58:40 -080079 if (!audio_info || !UpdateMeasurements(&audio_measurement_, *audio_info)) {
pbosa26ac922016-02-25 04:50:01 -080080 return;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000081 }
niklase@google.com470e71d2011-07-07 08:21:25 +000082
asaperssonb0c1b4e2016-09-17 01:00:01 -070083 int64_t last_video_receive_ms = video_measurement_.latest_receive_time_ms;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +020084 absl::optional<Syncable::Info> video_info = syncable_video_->GetInfo();
solenberg3ebbcb52017-01-31 03:58:40 -080085 if (!video_info || !UpdateMeasurements(&video_measurement_, *video_info)) {
pbosa26ac922016-02-25 04:50:01 -080086 return;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000087 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000088
asaperssonb0c1b4e2016-09-17 01:00:01 -070089 if (last_video_receive_ms == video_measurement_.latest_receive_time_ms) {
90 // No new video packet has been received since last update.
91 return;
92 }
93
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000094 int relative_delay_ms;
95 // Calculate how much later or earlier the audio stream is compared to video.
96 if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
97 &relative_delay_ms)) {
pbosa26ac922016-02-25 04:50:01 -080098 return;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000099 }
100
solenberg3ebbcb52017-01-31 03:58:40 -0800101 TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay",
Yves Gerey665174f2018-06-19 15:03:05 +0200102 video_info->current_delay_ms);
solenberg3ebbcb52017-01-31 03:58:40 -0800103 TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay",
Yves Gerey665174f2018-06-19 15:03:05 +0200104 audio_info->current_delay_ms);
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000105 TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000106 int target_audio_delay_ms = 0;
solenberg3ebbcb52017-01-31 03:58:40 -0800107 int target_video_delay_ms = video_info->current_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000108 // Calculate the necessary extra audio delay and desired total video
109 // delay to get the streams in sync.
Yves Gerey665174f2018-06-19 15:03:05 +0200110 if (!sync_->ComputeDelays(relative_delay_ms, audio_info->current_delay_ms,
111 &target_audio_delay_ms, &target_video_delay_ms)) {
pbosa26ac922016-02-25 04:50:01 -0800112 return;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000113 }
edjee@google.com79b02892013-04-04 19:43:34 +0000114
solenberg3ebbcb52017-01-31 03:58:40 -0800115 syncable_audio_->SetMinimumPlayoutDelay(target_audio_delay_ms);
116 syncable_video_->SetMinimumPlayoutDelay(target_video_delay_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000118
mflodman4cd27902016-08-05 06:28:45 -0700119bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
solenberg3ebbcb52017-01-31 03:58:40 -0800120 uint32_t timestamp,
121 int64_t render_time_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700122 int64_t* stream_offset_ms,
123 double* estimated_freq_khz) const {
mflodman4cd27902016-08-05 06:28:45 -0700124 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -0800125 if (!syncable_audio_) {
asaperssonf8cdd182016-03-15 01:00:47 -0700126 return false;
127 }
128
solenberg3ebbcb52017-01-31 03:58:40 -0800129 uint32_t playout_timestamp = syncable_audio_->GetPlayoutTimestamp();
130
asaperssonf8cdd182016-03-15 01:00:47 -0700131 int64_t latest_audio_ntp;
asaperssonfe50b4d2016-12-22 07:53:51 -0800132 if (!audio_measurement_.rtp_to_ntp.Estimate(playout_timestamp,
133 &latest_audio_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700134 return false;
135 }
136
137 int64_t latest_video_ntp;
solenberg3ebbcb52017-01-31 03:58:40 -0800138 if (!video_measurement_.rtp_to_ntp.Estimate(timestamp, &latest_video_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700139 return false;
140 }
141
solenberg3ebbcb52017-01-31 03:58:40 -0800142 int64_t time_to_render_ms = render_time_ms - rtc::TimeMillis();
asaperssonf8cdd182016-03-15 01:00:47 -0700143 if (time_to_render_ms > 0)
144 latest_video_ntp += time_to_render_ms;
145
146 *stream_offset_ms = latest_audio_ntp - latest_video_ntp;
Ilya Nikolaevskiy558cabf2017-11-14 10:32:15 +0100147 *estimated_freq_khz = video_measurement_.rtp_to_ntp.params()->frequency_khz;
asaperssonf8cdd182016-03-15 01:00:47 -0700148 return true;
149}
150
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000151} // namespace webrtc