blob: c330a4434a1a5ce55d7caac2e8b95cd0df4c60ad [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;
solenberg3ebbcb52017-01-31 03:58:40 -080028 if (!stream->rtp_to_ntp.UpdateMeasurements(info.capture_time_ntp_secs,
29 info.capture_time_ntp_frac,
30 info.capture_time_source_clock,
asaperssonfe50b4d2016-12-22 07:53:51 -080031 &new_rtcp_sr)) {
asaperssonb7e7b492016-11-17 02:27:14 -080032 return false;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000033 }
asaperssonb7e7b492016-11-17 02:27:14 -080034 return true;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000035}
asaperssonf8cdd182016-03-15 01:00:47 -070036} // namespace
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000037
solenberg3ebbcb52017-01-31 03:58:40 -080038RtpStreamsSynchronizer::RtpStreamsSynchronizer(Syncable* syncable_video)
39 : syncable_video_(syncable_video),
40 syncable_audio_(nullptr),
mflodman4cd27902016-08-05 06:28:45 -070041 sync_(),
42 last_sync_time_(rtc::TimeNanos()) {
solenberg3ebbcb52017-01-31 03:58:40 -080043 RTC_DCHECK(syncable_video);
mflodman4cd27902016-08-05 06:28:45 -070044 process_thread_checker_.DetachFromThread();
niklase@google.com470e71d2011-07-07 08:21:25 +000045}
46
solenberg3ebbcb52017-01-31 03:58:40 -080047void RtpStreamsSynchronizer::ConfigureSync(Syncable* syncable_audio) {
mflodman4cd27902016-08-05 06:28:45 -070048 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -080049 if (syncable_audio == syncable_audio_) {
mflodman4cd27902016-08-05 06:28:45 -070050 // This prevents expensive no-ops.
Peter Boström1794b262016-02-16 14:12:02 +010051 return;
pbos8fc7fa72015-07-15 08:02:58 -070052 }
mflodman4cd27902016-08-05 06:28:45 -070053
solenberg3ebbcb52017-01-31 03:58:40 -080054 syncable_audio_ = syncable_audio;
mflodman4cd27902016-08-05 06:28:45 -070055 sync_.reset(nullptr);
solenberg3ebbcb52017-01-31 03:58:40 -080056 if (syncable_audio_) {
57 sync_.reset(new StreamSynchronization(syncable_video_->id(),
58 syncable_audio_->id()));
mflodman4cd27902016-08-05 06:28:45 -070059 }
niklase@google.com470e71d2011-07-07 08:21:25 +000060}
61
mflodman4cd27902016-08-05 06:28:45 -070062int64_t RtpStreamsSynchronizer::TimeUntilNextProcess() {
63 RTC_DCHECK_RUN_ON(&process_thread_checker_);
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000064 const int64_t kSyncIntervalMs = 1000;
Niels Möllerd28db7f2016-05-10 16:31:47 +020065 return kSyncIntervalMs -
66 (rtc::TimeNanos() - last_sync_time_) / rtc::kNumNanosecsPerMillisec;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000067}
68
mflodman4cd27902016-08-05 06:28:45 -070069void RtpStreamsSynchronizer::Process() {
70 RTC_DCHECK_RUN_ON(&process_thread_checker_);
mflodman4cd27902016-08-05 06:28:45 -070071 last_sync_time_ = rtc::TimeNanos();
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000072
mflodman4cd27902016-08-05 06:28:45 -070073 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -080074 if (!syncable_audio_) {
pbosa26ac922016-02-25 04:50:01 -080075 return;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000076 }
mflodman4cd27902016-08-05 06:28:45 -070077 RTC_DCHECK(sync_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +000078
solenberg3ebbcb52017-01-31 03:58:40 -080079 rtc::Optional<Syncable::Info> audio_info = syncable_audio_->GetInfo();
80 if (!audio_info || !UpdateMeasurements(&audio_measurement_, *audio_info)) {
pbosa26ac922016-02-25 04:50:01 -080081 return;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000082 }
niklase@google.com470e71d2011-07-07 08:21:25 +000083
asaperssonb0c1b4e2016-09-17 01:00:01 -070084 int64_t last_video_receive_ms = video_measurement_.latest_receive_time_ms;
solenberg3ebbcb52017-01-31 03:58:40 -080085 rtc::Optional<Syncable::Info> video_info = syncable_video_->GetInfo();
86 if (!video_info || !UpdateMeasurements(&video_measurement_, *video_info)) {
pbosa26ac922016-02-25 04:50:01 -080087 return;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000088 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000089
asaperssonb0c1b4e2016-09-17 01:00:01 -070090 if (last_video_receive_ms == video_measurement_.latest_receive_time_ms) {
91 // No new video packet has been received since last update.
92 return;
93 }
94
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000095 int relative_delay_ms;
96 // Calculate how much later or earlier the audio stream is compared to video.
97 if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
98 &relative_delay_ms)) {
pbosa26ac922016-02-25 04:50:01 -080099 return;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000100 }
101
solenberg3ebbcb52017-01-31 03:58:40 -0800102 TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay",
103 video_info->current_delay_ms);
104 TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay",
105 audio_info->current_delay_ms);
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000106 TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000107 int target_audio_delay_ms = 0;
solenberg3ebbcb52017-01-31 03:58:40 -0800108 int target_video_delay_ms = video_info->current_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000109 // Calculate the necessary extra audio delay and desired total video
110 // delay to get the streams in sync.
stefan@webrtc.org8d185262012-11-12 18:51:52 +0000111 if (!sync_->ComputeDelays(relative_delay_ms,
solenberg3ebbcb52017-01-31 03:58:40 -0800112 audio_info->current_delay_ms,
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000113 &target_audio_delay_ms,
114 &target_video_delay_ms)) {
pbosa26ac922016-02-25 04:50:01 -0800115 return;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000116 }
edjee@google.com79b02892013-04-04 19:43:34 +0000117
solenberg3ebbcb52017-01-31 03:58:40 -0800118 syncable_audio_->SetMinimumPlayoutDelay(target_audio_delay_ms);
119 syncable_video_->SetMinimumPlayoutDelay(target_video_delay_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000120}
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000121
mflodman4cd27902016-08-05 06:28:45 -0700122bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
solenberg3ebbcb52017-01-31 03:58:40 -0800123 uint32_t timestamp,
124 int64_t render_time_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700125 int64_t* stream_offset_ms,
126 double* estimated_freq_khz) const {
mflodman4cd27902016-08-05 06:28:45 -0700127 rtc::CritScope lock(&crit_);
solenberg3ebbcb52017-01-31 03:58:40 -0800128 if (!syncable_audio_) {
asaperssonf8cdd182016-03-15 01:00:47 -0700129 return false;
130 }
131
solenberg3ebbcb52017-01-31 03:58:40 -0800132 uint32_t playout_timestamp = syncable_audio_->GetPlayoutTimestamp();
133
asaperssonf8cdd182016-03-15 01:00:47 -0700134 int64_t latest_audio_ntp;
asaperssonfe50b4d2016-12-22 07:53:51 -0800135 if (!audio_measurement_.rtp_to_ntp.Estimate(playout_timestamp,
136 &latest_audio_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700137 return false;
138 }
139
140 int64_t latest_video_ntp;
solenberg3ebbcb52017-01-31 03:58:40 -0800141 if (!video_measurement_.rtp_to_ntp.Estimate(timestamp, &latest_video_ntp)) {
asaperssonf8cdd182016-03-15 01:00:47 -0700142 return false;
143 }
144
solenberg3ebbcb52017-01-31 03:58:40 -0800145 int64_t time_to_render_ms = render_time_ms - rtc::TimeMillis();
asaperssonf8cdd182016-03-15 01:00:47 -0700146 if (time_to_render_ms > 0)
147 latest_video_ntp += time_to_render_ms;
148
149 *stream_offset_ms = latest_audio_ntp - latest_video_ntp;
Ilya Nikolaevskiy558cabf2017-11-14 10:32:15 +0100150 *estimated_freq_khz = video_measurement_.rtp_to_ntp.params()->frequency_khz;
asaperssonf8cdd182016-03-15 01:00:47 -0700151 return true;
152}
153
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000154} // namespace webrtc