1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "video/stream_synchronization.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <stdlib.h>
14*d9f75844SAndroid Build Coastguard Worker
15*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
16*d9f75844SAndroid Build Coastguard Worker
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
18*d9f75844SAndroid Build Coastguard Worker
19*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
20*d9f75844SAndroid Build Coastguard Worker
21*d9f75844SAndroid Build Coastguard Worker static const int kMaxChangeMs = 80;
22*d9f75844SAndroid Build Coastguard Worker static const int kMaxDeltaDelayMs = 10000;
23*d9f75844SAndroid Build Coastguard Worker static const int kFilterLength = 4;
24*d9f75844SAndroid Build Coastguard Worker // Minimum difference between audio and video to warrant a change.
25*d9f75844SAndroid Build Coastguard Worker static const int kMinDeltaMs = 30;
26*d9f75844SAndroid Build Coastguard Worker
StreamSynchronization(uint32_t video_stream_id,uint32_t audio_stream_id)27*d9f75844SAndroid Build Coastguard Worker StreamSynchronization::StreamSynchronization(uint32_t video_stream_id,
28*d9f75844SAndroid Build Coastguard Worker uint32_t audio_stream_id)
29*d9f75844SAndroid Build Coastguard Worker : video_stream_id_(video_stream_id),
30*d9f75844SAndroid Build Coastguard Worker audio_stream_id_(audio_stream_id),
31*d9f75844SAndroid Build Coastguard Worker base_target_delay_ms_(0),
32*d9f75844SAndroid Build Coastguard Worker avg_diff_ms_(0) {}
33*d9f75844SAndroid Build Coastguard Worker
ComputeRelativeDelay(const Measurements & audio_measurement,const Measurements & video_measurement,int * relative_delay_ms)34*d9f75844SAndroid Build Coastguard Worker bool StreamSynchronization::ComputeRelativeDelay(
35*d9f75844SAndroid Build Coastguard Worker const Measurements& audio_measurement,
36*d9f75844SAndroid Build Coastguard Worker const Measurements& video_measurement,
37*d9f75844SAndroid Build Coastguard Worker int* relative_delay_ms) {
38*d9f75844SAndroid Build Coastguard Worker NtpTime audio_last_capture_time =
39*d9f75844SAndroid Build Coastguard Worker audio_measurement.rtp_to_ntp.Estimate(audio_measurement.latest_timestamp);
40*d9f75844SAndroid Build Coastguard Worker if (!audio_last_capture_time.Valid()) {
41*d9f75844SAndroid Build Coastguard Worker return false;
42*d9f75844SAndroid Build Coastguard Worker }
43*d9f75844SAndroid Build Coastguard Worker NtpTime video_last_capture_time =
44*d9f75844SAndroid Build Coastguard Worker video_measurement.rtp_to_ntp.Estimate(video_measurement.latest_timestamp);
45*d9f75844SAndroid Build Coastguard Worker if (!video_last_capture_time.Valid()) {
46*d9f75844SAndroid Build Coastguard Worker return false;
47*d9f75844SAndroid Build Coastguard Worker }
48*d9f75844SAndroid Build Coastguard Worker int64_t audio_last_capture_time_ms = audio_last_capture_time.ToMs();
49*d9f75844SAndroid Build Coastguard Worker int64_t video_last_capture_time_ms = video_last_capture_time.ToMs();
50*d9f75844SAndroid Build Coastguard Worker
51*d9f75844SAndroid Build Coastguard Worker // Positive diff means that video_measurement is behind audio_measurement.
52*d9f75844SAndroid Build Coastguard Worker *relative_delay_ms =
53*d9f75844SAndroid Build Coastguard Worker video_measurement.latest_receive_time_ms -
54*d9f75844SAndroid Build Coastguard Worker audio_measurement.latest_receive_time_ms -
55*d9f75844SAndroid Build Coastguard Worker (video_last_capture_time_ms - audio_last_capture_time_ms);
56*d9f75844SAndroid Build Coastguard Worker
57*d9f75844SAndroid Build Coastguard Worker if (*relative_delay_ms > kMaxDeltaDelayMs ||
58*d9f75844SAndroid Build Coastguard Worker *relative_delay_ms < -kMaxDeltaDelayMs) {
59*d9f75844SAndroid Build Coastguard Worker return false;
60*d9f75844SAndroid Build Coastguard Worker }
61*d9f75844SAndroid Build Coastguard Worker return true;
62*d9f75844SAndroid Build Coastguard Worker }
63*d9f75844SAndroid Build Coastguard Worker
ComputeDelays(int relative_delay_ms,int current_audio_delay_ms,int * total_audio_delay_target_ms,int * total_video_delay_target_ms)64*d9f75844SAndroid Build Coastguard Worker bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
65*d9f75844SAndroid Build Coastguard Worker int current_audio_delay_ms,
66*d9f75844SAndroid Build Coastguard Worker int* total_audio_delay_target_ms,
67*d9f75844SAndroid Build Coastguard Worker int* total_video_delay_target_ms) {
68*d9f75844SAndroid Build Coastguard Worker int current_video_delay_ms = *total_video_delay_target_ms;
69*d9f75844SAndroid Build Coastguard Worker
70*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_VERBOSE) << "Audio delay: " << current_audio_delay_ms
71*d9f75844SAndroid Build Coastguard Worker << " current diff: " << relative_delay_ms
72*d9f75844SAndroid Build Coastguard Worker << " for stream " << audio_stream_id_;
73*d9f75844SAndroid Build Coastguard Worker
74*d9f75844SAndroid Build Coastguard Worker // Calculate the difference between the lowest possible video delay and the
75*d9f75844SAndroid Build Coastguard Worker // current audio delay.
76*d9f75844SAndroid Build Coastguard Worker int current_diff_ms =
77*d9f75844SAndroid Build Coastguard Worker current_video_delay_ms - current_audio_delay_ms + relative_delay_ms;
78*d9f75844SAndroid Build Coastguard Worker
79*d9f75844SAndroid Build Coastguard Worker avg_diff_ms_ =
80*d9f75844SAndroid Build Coastguard Worker ((kFilterLength - 1) * avg_diff_ms_ + current_diff_ms) / kFilterLength;
81*d9f75844SAndroid Build Coastguard Worker if (abs(avg_diff_ms_) < kMinDeltaMs) {
82*d9f75844SAndroid Build Coastguard Worker // Don't adjust if the diff is within our margin.
83*d9f75844SAndroid Build Coastguard Worker return false;
84*d9f75844SAndroid Build Coastguard Worker }
85*d9f75844SAndroid Build Coastguard Worker
86*d9f75844SAndroid Build Coastguard Worker // Make sure we don't move too fast.
87*d9f75844SAndroid Build Coastguard Worker int diff_ms = avg_diff_ms_ / 2;
88*d9f75844SAndroid Build Coastguard Worker diff_ms = std::min(diff_ms, kMaxChangeMs);
89*d9f75844SAndroid Build Coastguard Worker diff_ms = std::max(diff_ms, -kMaxChangeMs);
90*d9f75844SAndroid Build Coastguard Worker
91*d9f75844SAndroid Build Coastguard Worker // Reset the average after a move to prevent overshooting reaction.
92*d9f75844SAndroid Build Coastguard Worker avg_diff_ms_ = 0;
93*d9f75844SAndroid Build Coastguard Worker
94*d9f75844SAndroid Build Coastguard Worker if (diff_ms > 0) {
95*d9f75844SAndroid Build Coastguard Worker // The minimum video delay is longer than the current audio delay.
96*d9f75844SAndroid Build Coastguard Worker // We need to decrease extra video delay, or add extra audio delay.
97*d9f75844SAndroid Build Coastguard Worker if (video_delay_.extra_ms > base_target_delay_ms_) {
98*d9f75844SAndroid Build Coastguard Worker // We have extra delay added to ViE. Reduce this delay before adding
99*d9f75844SAndroid Build Coastguard Worker // extra delay to VoE.
100*d9f75844SAndroid Build Coastguard Worker video_delay_.extra_ms -= diff_ms;
101*d9f75844SAndroid Build Coastguard Worker audio_delay_.extra_ms = base_target_delay_ms_;
102*d9f75844SAndroid Build Coastguard Worker } else { // video_delay_.extra_ms > 0
103*d9f75844SAndroid Build Coastguard Worker // We have no extra video delay to remove, increase the audio delay.
104*d9f75844SAndroid Build Coastguard Worker audio_delay_.extra_ms += diff_ms;
105*d9f75844SAndroid Build Coastguard Worker video_delay_.extra_ms = base_target_delay_ms_;
106*d9f75844SAndroid Build Coastguard Worker }
107*d9f75844SAndroid Build Coastguard Worker } else { // if (diff_ms > 0)
108*d9f75844SAndroid Build Coastguard Worker // The video delay is lower than the current audio delay.
109*d9f75844SAndroid Build Coastguard Worker // We need to decrease extra audio delay, or add extra video delay.
110*d9f75844SAndroid Build Coastguard Worker if (audio_delay_.extra_ms > base_target_delay_ms_) {
111*d9f75844SAndroid Build Coastguard Worker // We have extra delay in VoiceEngine.
112*d9f75844SAndroid Build Coastguard Worker // Start with decreasing the voice delay.
113*d9f75844SAndroid Build Coastguard Worker // Note: diff_ms is negative; add the negative difference.
114*d9f75844SAndroid Build Coastguard Worker audio_delay_.extra_ms += diff_ms;
115*d9f75844SAndroid Build Coastguard Worker video_delay_.extra_ms = base_target_delay_ms_;
116*d9f75844SAndroid Build Coastguard Worker } else { // audio_delay_.extra_ms > base_target_delay_ms_
117*d9f75844SAndroid Build Coastguard Worker // We have no extra delay in VoiceEngine, increase the video delay.
118*d9f75844SAndroid Build Coastguard Worker // Note: diff_ms is negative; subtract the negative difference.
119*d9f75844SAndroid Build Coastguard Worker video_delay_.extra_ms -= diff_ms; // X - (-Y) = X + Y.
120*d9f75844SAndroid Build Coastguard Worker audio_delay_.extra_ms = base_target_delay_ms_;
121*d9f75844SAndroid Build Coastguard Worker }
122*d9f75844SAndroid Build Coastguard Worker }
123*d9f75844SAndroid Build Coastguard Worker
124*d9f75844SAndroid Build Coastguard Worker // Make sure that video is never below our target.
125*d9f75844SAndroid Build Coastguard Worker video_delay_.extra_ms =
126*d9f75844SAndroid Build Coastguard Worker std::max(video_delay_.extra_ms, base_target_delay_ms_);
127*d9f75844SAndroid Build Coastguard Worker
128*d9f75844SAndroid Build Coastguard Worker int new_video_delay_ms;
129*d9f75844SAndroid Build Coastguard Worker if (video_delay_.extra_ms > base_target_delay_ms_) {
130*d9f75844SAndroid Build Coastguard Worker new_video_delay_ms = video_delay_.extra_ms;
131*d9f75844SAndroid Build Coastguard Worker } else {
132*d9f75844SAndroid Build Coastguard Worker // No change to the extra video delay. We are changing audio and we only
133*d9f75844SAndroid Build Coastguard Worker // allow to change one at the time.
134*d9f75844SAndroid Build Coastguard Worker new_video_delay_ms = video_delay_.last_ms;
135*d9f75844SAndroid Build Coastguard Worker }
136*d9f75844SAndroid Build Coastguard Worker
137*d9f75844SAndroid Build Coastguard Worker // Make sure that we don't go below the extra video delay.
138*d9f75844SAndroid Build Coastguard Worker new_video_delay_ms = std::max(new_video_delay_ms, video_delay_.extra_ms);
139*d9f75844SAndroid Build Coastguard Worker
140*d9f75844SAndroid Build Coastguard Worker // Verify we don't go above the maximum allowed video delay.
141*d9f75844SAndroid Build Coastguard Worker new_video_delay_ms =
142*d9f75844SAndroid Build Coastguard Worker std::min(new_video_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
143*d9f75844SAndroid Build Coastguard Worker
144*d9f75844SAndroid Build Coastguard Worker int new_audio_delay_ms;
145*d9f75844SAndroid Build Coastguard Worker if (audio_delay_.extra_ms > base_target_delay_ms_) {
146*d9f75844SAndroid Build Coastguard Worker new_audio_delay_ms = audio_delay_.extra_ms;
147*d9f75844SAndroid Build Coastguard Worker } else {
148*d9f75844SAndroid Build Coastguard Worker // No change to the audio delay. We are changing video and we only allow to
149*d9f75844SAndroid Build Coastguard Worker // change one at the time.
150*d9f75844SAndroid Build Coastguard Worker new_audio_delay_ms = audio_delay_.last_ms;
151*d9f75844SAndroid Build Coastguard Worker }
152*d9f75844SAndroid Build Coastguard Worker
153*d9f75844SAndroid Build Coastguard Worker // Make sure that we don't go below the extra audio delay.
154*d9f75844SAndroid Build Coastguard Worker new_audio_delay_ms = std::max(new_audio_delay_ms, audio_delay_.extra_ms);
155*d9f75844SAndroid Build Coastguard Worker
156*d9f75844SAndroid Build Coastguard Worker // Verify we don't go above the maximum allowed audio delay.
157*d9f75844SAndroid Build Coastguard Worker new_audio_delay_ms =
158*d9f75844SAndroid Build Coastguard Worker std::min(new_audio_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
159*d9f75844SAndroid Build Coastguard Worker
160*d9f75844SAndroid Build Coastguard Worker video_delay_.last_ms = new_video_delay_ms;
161*d9f75844SAndroid Build Coastguard Worker audio_delay_.last_ms = new_audio_delay_ms;
162*d9f75844SAndroid Build Coastguard Worker
163*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_VERBOSE) << "Sync video delay " << new_video_delay_ms
164*d9f75844SAndroid Build Coastguard Worker << " for video stream " << video_stream_id_
165*d9f75844SAndroid Build Coastguard Worker << " and audio delay " << audio_delay_.extra_ms
166*d9f75844SAndroid Build Coastguard Worker << " for audio stream " << audio_stream_id_;
167*d9f75844SAndroid Build Coastguard Worker
168*d9f75844SAndroid Build Coastguard Worker *total_video_delay_target_ms = new_video_delay_ms;
169*d9f75844SAndroid Build Coastguard Worker *total_audio_delay_target_ms = new_audio_delay_ms;
170*d9f75844SAndroid Build Coastguard Worker return true;
171*d9f75844SAndroid Build Coastguard Worker }
172*d9f75844SAndroid Build Coastguard Worker
SetTargetBufferingDelay(int target_delay_ms)173*d9f75844SAndroid Build Coastguard Worker void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
174*d9f75844SAndroid Build Coastguard Worker // Initial extra delay for audio (accounting for existing extra delay).
175*d9f75844SAndroid Build Coastguard Worker audio_delay_.extra_ms += target_delay_ms - base_target_delay_ms_;
176*d9f75844SAndroid Build Coastguard Worker audio_delay_.last_ms += target_delay_ms - base_target_delay_ms_;
177*d9f75844SAndroid Build Coastguard Worker
178*d9f75844SAndroid Build Coastguard Worker // The video delay is compared to the last value (and how much we can update
179*d9f75844SAndroid Build Coastguard Worker // is limited by that as well).
180*d9f75844SAndroid Build Coastguard Worker video_delay_.last_ms += target_delay_ms - base_target_delay_ms_;
181*d9f75844SAndroid Build Coastguard Worker video_delay_.extra_ms += target_delay_ms - base_target_delay_ms_;
182*d9f75844SAndroid Build Coastguard Worker
183*d9f75844SAndroid Build Coastguard Worker // Video is already delayed by the desired amount.
184*d9f75844SAndroid Build Coastguard Worker base_target_delay_ms_ = target_delay_ms;
185*d9f75844SAndroid Build Coastguard Worker }
186*d9f75844SAndroid Build Coastguard Worker
ReduceAudioDelay()187*d9f75844SAndroid Build Coastguard Worker void StreamSynchronization::ReduceAudioDelay() {
188*d9f75844SAndroid Build Coastguard Worker audio_delay_.extra_ms *= 0.9f;
189*d9f75844SAndroid Build Coastguard Worker }
190*d9f75844SAndroid Build Coastguard Worker
ReduceVideoDelay()191*d9f75844SAndroid Build Coastguard Worker void StreamSynchronization::ReduceVideoDelay() {
192*d9f75844SAndroid Build Coastguard Worker video_delay_.extra_ms *= 0.9f;
193*d9f75844SAndroid Build Coastguard Worker }
194*d9f75844SAndroid Build Coastguard Worker
195*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
196