1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
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 
11 #include "video/rtp_streams_synchronizer.h"
12 
13 #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"
19 
20 namespace webrtc {
21 namespace {
UpdateMeasurements(StreamSynchronization::Measurements * stream,const Syncable::Info & info)22 bool UpdateMeasurements(StreamSynchronization::Measurements* stream,
23                         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;
27   bool new_rtcp_sr = false;
28   if (!stream->rtp_to_ntp.UpdateMeasurements(info.capture_time_ntp_secs,
29                                              info.capture_time_ntp_frac,
30                                              info.capture_time_source_clock,
31                                              &new_rtcp_sr)) {
32     return false;
33   }
34   return true;
35 }
36 }  // namespace
37 
RtpStreamsSynchronizer(Syncable * syncable_video)38 RtpStreamsSynchronizer::RtpStreamsSynchronizer(Syncable* syncable_video)
39     : syncable_video_(syncable_video),
40       syncable_audio_(nullptr),
41       sync_(),
42       last_sync_time_(rtc::TimeNanos()) {
43   RTC_DCHECK(syncable_video);
44   process_thread_checker_.DetachFromThread();
45 }
46 
ConfigureSync(Syncable * syncable_audio)47 void RtpStreamsSynchronizer::ConfigureSync(Syncable* syncable_audio) {
48   rtc::CritScope lock(&crit_);
49   if (syncable_audio == syncable_audio_) {
50     // This prevents expensive no-ops.
51     return;
52   }
53 
54   syncable_audio_ = syncable_audio;
55   sync_.reset(nullptr);
56   if (syncable_audio_) {
57     sync_.reset(new StreamSynchronization(syncable_video_->id(),
58                                           syncable_audio_->id()));
59   }
60 }
61 
TimeUntilNextProcess()62 int64_t RtpStreamsSynchronizer::TimeUntilNextProcess() {
63   RTC_DCHECK_RUN_ON(&process_thread_checker_);
64   const int64_t kSyncIntervalMs = 1000;
65   return kSyncIntervalMs -
66       (rtc::TimeNanos() - last_sync_time_) / rtc::kNumNanosecsPerMillisec;
67 }
68 
Process()69 void RtpStreamsSynchronizer::Process() {
70   RTC_DCHECK_RUN_ON(&process_thread_checker_);
71   last_sync_time_ = rtc::TimeNanos();
72 
73   rtc::CritScope lock(&crit_);
74   if (!syncable_audio_) {
75     return;
76   }
77   RTC_DCHECK(sync_.get());
78 
79   rtc::Optional<Syncable::Info> audio_info = syncable_audio_->GetInfo();
80   if (!audio_info || !UpdateMeasurements(&audio_measurement_, *audio_info)) {
81     return;
82   }
83 
84   int64_t last_video_receive_ms = video_measurement_.latest_receive_time_ms;
85   rtc::Optional<Syncable::Info> video_info = syncable_video_->GetInfo();
86   if (!video_info || !UpdateMeasurements(&video_measurement_, *video_info)) {
87     return;
88   }
89 
90   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 
95   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)) {
99     return;
100   }
101 
102   TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay",
103       video_info->current_delay_ms);
104   TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay",
105       audio_info->current_delay_ms);
106   TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
107   int target_audio_delay_ms = 0;
108   int target_video_delay_ms = video_info->current_delay_ms;
109   // Calculate the necessary extra audio delay and desired total video
110   // delay to get the streams in sync.
111   if (!sync_->ComputeDelays(relative_delay_ms,
112                             audio_info->current_delay_ms,
113                             &target_audio_delay_ms,
114                             &target_video_delay_ms)) {
115     return;
116   }
117 
118   syncable_audio_->SetMinimumPlayoutDelay(target_audio_delay_ms);
119   syncable_video_->SetMinimumPlayoutDelay(target_video_delay_ms);
120 }
121 
GetStreamSyncOffsetInMs(uint32_t timestamp,int64_t render_time_ms,int64_t * stream_offset_ms,double * estimated_freq_khz) const122 bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
123     uint32_t timestamp,
124     int64_t render_time_ms,
125     int64_t* stream_offset_ms,
126     double* estimated_freq_khz) const {
127   rtc::CritScope lock(&crit_);
128   if (!syncable_audio_) {
129     return false;
130   }
131 
132   uint32_t playout_timestamp = syncable_audio_->GetPlayoutTimestamp();
133 
134   int64_t latest_audio_ntp;
135   if (!audio_measurement_.rtp_to_ntp.Estimate(playout_timestamp,
136                                               &latest_audio_ntp)) {
137     return false;
138   }
139 
140   int64_t latest_video_ntp;
141   if (!video_measurement_.rtp_to_ntp.Estimate(timestamp, &latest_video_ntp)) {
142     return false;
143   }
144 
145   int64_t time_to_render_ms = render_time_ms - rtc::TimeMillis();
146   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;
150   *estimated_freq_khz = video_measurement_.rtp_to_ntp.params()->frequency_khz;
151   return true;
152 }
153 
154 }  // namespace webrtc
155