blob: a7e3b25b623bb59c3c01fe4b66c9b18a7333ac92 [file] [log] [blame]
stefan@webrtc.org5f284982012-06-28 07:51:16 +00001/*
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_engine/stream_synchronization.h"
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000012
13#include <assert.h>
14#include <algorithm>
15#include <cmath>
16
stefan@webrtc.org5f284982012-06-28 07:51:16 +000017#include "system_wrappers/interface/trace.h"
18
19namespace webrtc {
20
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000021const int kMaxVideoDiffMs = 80;
22const int kMaxAudioDiffMs = 80;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000023const int kMaxDeltaDelayMs = 1500;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000024
stefan@webrtc.org5f284982012-06-28 07:51:16 +000025struct ViESyncDelay {
26 ViESyncDelay() {
27 extra_video_delay_ms = 0;
28 last_video_delay_ms = 0;
29 extra_audio_delay_ms = 0;
30 last_sync_delay = 0;
31 network_delay = 120;
32 }
33
34 int extra_video_delay_ms;
35 int last_video_delay_ms;
36 int extra_audio_delay_ms;
37 int last_sync_delay;
38 int network_delay;
39};
40
41StreamSynchronization::StreamSynchronization(int audio_channel_id,
42 int video_channel_id)
43 : channel_delay_(new ViESyncDelay),
44 audio_channel_id_(audio_channel_id),
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000045 video_channel_id_(video_channel_id),
46 base_target_delay_ms_(0) {}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000047
48StreamSynchronization::~StreamSynchronization() {
49 delete channel_delay_;
50}
51
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000052bool StreamSynchronization::ComputeRelativeDelay(
53 const Measurements& audio_measurement,
54 const Measurements& video_measurement,
55 int* relative_delay_ms) {
56 assert(relative_delay_ms);
57 if (audio_measurement.rtcp.size() < 2 || video_measurement.rtcp.size() < 2) {
58 // We need two RTCP SR reports per stream to do synchronization.
59 return false;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000060 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000061 int64_t audio_last_capture_time_ms;
62 if (!synchronization::RtpToNtpMs(audio_measurement.latest_timestamp,
63 audio_measurement.rtcp,
64 &audio_last_capture_time_ms)) {
65 return false;
66 }
67 int64_t video_last_capture_time_ms;
68 if (!synchronization::RtpToNtpMs(video_measurement.latest_timestamp,
69 video_measurement.rtcp,
70 &video_last_capture_time_ms)) {
71 return false;
72 }
73 if (video_last_capture_time_ms < 0) {
74 return false;
75 }
76 // Positive diff means that video_measurement is behind audio_measurement.
77 *relative_delay_ms = video_measurement.latest_receive_time_ms -
78 audio_measurement.latest_receive_time_ms -
79 (video_last_capture_time_ms - audio_last_capture_time_ms);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000080 if (*relative_delay_ms > kMaxDeltaDelayMs ||
81 *relative_delay_ms < -kMaxDeltaDelayMs) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000082 return false;
83 }
84 return true;
85}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000086
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000087bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
88 int current_audio_delay_ms,
89 int* extra_audio_delay_ms,
90 int* total_video_delay_target_ms) {
91 assert(extra_audio_delay_ms && total_video_delay_target_ms);
stefan@webrtc.org5f284982012-06-28 07:51:16 +000092 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
93 "Audio delay is: %d for voice channel: %d",
94 current_audio_delay_ms, audio_channel_id_);
95 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
96 "Network delay diff is: %d for voice channel: %d",
97 channel_delay_->network_delay, audio_channel_id_);
98 // Calculate the difference between the lowest possible video delay and
99 // the current audio delay.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000100 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
101 "Current diff is: %d for audio channel: %d",
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000102 relative_delay_ms, audio_channel_id_);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000103 int current_diff_ms = *total_video_delay_target_ms - current_audio_delay_ms +
104 relative_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000105
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000106 int video_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000107 if (current_diff_ms > 0) {
108 // The minimum video delay is longer than the current audio delay.
109 // We need to decrease extra video delay, if we have added extra delay
110 // earlier, or add extra audio delay.
111 if (channel_delay_->extra_video_delay_ms > 0) {
112 // We have extra delay added to ViE. Reduce this delay before adding
113 // extra delay to VoE.
114
115 // This is the desired delay, we can't reduce more than this.
116 video_delay_ms = *total_video_delay_target_ms;
117
118 // Check that we don't reduce the delay more than what is allowed.
119 if (video_delay_ms <
120 channel_delay_->last_video_delay_ms - kMaxVideoDiffMs) {
121 video_delay_ms =
122 channel_delay_->last_video_delay_ms - kMaxVideoDiffMs;
123 channel_delay_->extra_video_delay_ms =
124 video_delay_ms - *total_video_delay_target_ms;
125 } else {
126 channel_delay_->extra_video_delay_ms = 0;
127 }
128 channel_delay_->last_video_delay_ms = video_delay_ms;
129 channel_delay_->last_sync_delay = -1;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000130 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000131 } else { // channel_delay_->extra_video_delay_ms > 0
132 // We have no extra video delay to remove, increase the audio delay.
133 if (channel_delay_->last_sync_delay >= 0) {
134 // We have increased the audio delay earlier, increase it even more.
135 int audio_diff_ms = current_diff_ms / 2;
136 if (audio_diff_ms > kMaxAudioDiffMs) {
137 // We only allow a maximum change of KMaxAudioDiffMS for audio
138 // due to NetEQ maximum changes.
139 audio_diff_ms = kMaxAudioDiffMs;
140 }
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000141 // Increase the audio delay.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000142 channel_delay_->extra_audio_delay_ms += audio_diff_ms;
143
144 // Don't set a too high delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000145 if (channel_delay_->extra_audio_delay_ms >
146 base_target_delay_ms_ + kMaxDeltaDelayMs) {
147 channel_delay_->extra_audio_delay_ms =
148 base_target_delay_ms_ + kMaxDeltaDelayMs;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000149 }
150
151 // Don't add any extra video delay.
152 video_delay_ms = *total_video_delay_target_ms;
153 channel_delay_->extra_video_delay_ms = 0;
154 channel_delay_->last_video_delay_ms = video_delay_ms;
155 channel_delay_->last_sync_delay = 1;
156 } else { // channel_delay_->last_sync_delay >= 0
157 // First time after a delay change, don't add any extra delay.
158 // This is to not toggle back and forth too much.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000159 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000160 // Set minimum video delay
161 video_delay_ms = *total_video_delay_target_ms;
162 channel_delay_->extra_video_delay_ms = 0;
163 channel_delay_->last_video_delay_ms = video_delay_ms;
164 channel_delay_->last_sync_delay = 0;
165 }
166 }
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000167 } else { // if (current_diff_ms > 0)
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000168 // The minimum video delay is lower than the current audio delay.
169 // We need to decrease possible extra audio delay, or
170 // add extra video delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000171 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
172 // We have extra delay in VoiceEngine.
173 // Start with decreasing the voice delay.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000174 int audio_diff_ms = current_diff_ms / 2;
175 if (audio_diff_ms < -1 * kMaxAudioDiffMs) {
176 // Don't change the delay too much at once.
177 audio_diff_ms = -1 * kMaxAudioDiffMs;
178 }
179 // Add the negative difference.
180 channel_delay_->extra_audio_delay_ms += audio_diff_ms;
181
182 if (channel_delay_->extra_audio_delay_ms < 0) {
183 // Negative values not allowed.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000184 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000185 channel_delay_->last_sync_delay = 0;
186 } else {
187 // There is more audio delay to use for the next round.
188 channel_delay_->last_sync_delay = 1;
189 }
190
191 // Keep the video delay at the minimum values.
192 video_delay_ms = *total_video_delay_target_ms;
193 channel_delay_->extra_video_delay_ms = 0;
194 channel_delay_->last_video_delay_ms = video_delay_ms;
195 } else { // channel_delay_->extra_audio_delay_ms > 0
196 // We have no extra delay in VoiceEngine, increase the video delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000197 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000198
199 // Make the difference positive.
200 int video_diff_ms = -1 * current_diff_ms;
201
202 // This is the desired delay.
203 video_delay_ms = *total_video_delay_target_ms + video_diff_ms;
204 if (video_delay_ms > channel_delay_->last_video_delay_ms) {
205 if (video_delay_ms >
206 channel_delay_->last_video_delay_ms + kMaxVideoDiffMs) {
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000207 // Don't increase the delay too much at once.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000208 video_delay_ms =
209 channel_delay_->last_video_delay_ms + kMaxVideoDiffMs;
210 }
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000211 // Verify we don't go above the maximum allowed delay.
212 if (video_delay_ms > base_target_delay_ms_ + kMaxDeltaDelayMs) {
213 video_delay_ms = base_target_delay_ms_ + kMaxDeltaDelayMs;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000214 }
215 } else {
216 if (video_delay_ms <
217 channel_delay_->last_video_delay_ms - kMaxVideoDiffMs) {
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000218 // Don't decrease the delay too much at once.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000219 video_delay_ms =
220 channel_delay_->last_video_delay_ms - kMaxVideoDiffMs;
221 }
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000222 // Verify we don't go below the minimum delay.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000223 if (video_delay_ms < *total_video_delay_target_ms) {
224 video_delay_ms = *total_video_delay_target_ms;
225 }
226 }
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000227 // Store the values.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000228 channel_delay_->extra_video_delay_ms =
229 video_delay_ms - *total_video_delay_target_ms;
230 channel_delay_->last_video_delay_ms = video_delay_ms;
231 channel_delay_->last_sync_delay = -1;
232 }
233 }
234
235 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
236 "Sync video delay %d ms for video channel and audio delay %d for audio "
237 "channel %d",
238 video_delay_ms, channel_delay_->extra_audio_delay_ms, audio_channel_id_);
239
240 *extra_audio_delay_ms = channel_delay_->extra_audio_delay_ms;
241
242 if (video_delay_ms < 0) {
243 video_delay_ms = 0;
244 }
245 *total_video_delay_target_ms =
246 (*total_video_delay_target_ms > video_delay_ms) ?
247 *total_video_delay_target_ms : video_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000248 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000249}
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000250
251void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
252 // Video is already delayed by the desired amount.
253 base_target_delay_ms_ = target_delay_ms;
254 // Setting initial extra delay for audio.
255 channel_delay_->extra_audio_delay_ms += target_delay_ms;
256 // The video delay is compared to the last value (and how much we can updated
257 // is limited by that as well).
258 channel_delay_->last_video_delay_ms += target_delay_ms;
259}
260
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000261} // namespace webrtc