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