blob: 3e8d0eaafa68ddc8a0bd46e1bfaaa8ff37d9f8c6 [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
pwestin@webrtc.org63117332013-04-22 18:57:14 +000021static const int kMaxChangeMs = 80;
22static const int kMaxDeltaDelayMs = 10000;
23static const int kFilterLength = 4;
24// Minimum difference between audio and video to warrant a change.
25static const int kMinDeltaMs = 30;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000026
stefan@webrtc.org5f284982012-06-28 07:51:16 +000027struct ViESyncDelay {
28 ViESyncDelay() {
29 extra_video_delay_ms = 0;
30 last_video_delay_ms = 0;
31 extra_audio_delay_ms = 0;
32 last_sync_delay = 0;
33 network_delay = 120;
34 }
35
36 int extra_video_delay_ms;
37 int last_video_delay_ms;
38 int extra_audio_delay_ms;
39 int last_sync_delay;
40 int network_delay;
41};
42
43StreamSynchronization::StreamSynchronization(int audio_channel_id,
44 int video_channel_id)
45 : channel_delay_(new ViESyncDelay),
46 audio_channel_id_(audio_channel_id),
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000047 video_channel_id_(video_channel_id),
pwestin@webrtc.org63117332013-04-22 18:57:14 +000048 base_target_delay_ms_(0),
49 avg_diff_ms_(0) {}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000050
51StreamSynchronization::~StreamSynchronization() {
52 delete channel_delay_;
53}
54
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000055bool StreamSynchronization::ComputeRelativeDelay(
56 const Measurements& audio_measurement,
57 const Measurements& video_measurement,
58 int* relative_delay_ms) {
59 assert(relative_delay_ms);
60 if (audio_measurement.rtcp.size() < 2 || video_measurement.rtcp.size() < 2) {
61 // We need two RTCP SR reports per stream to do synchronization.
62 return false;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000063 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000064 int64_t audio_last_capture_time_ms;
65 if (!synchronization::RtpToNtpMs(audio_measurement.latest_timestamp,
66 audio_measurement.rtcp,
67 &audio_last_capture_time_ms)) {
68 return false;
69 }
70 int64_t video_last_capture_time_ms;
71 if (!synchronization::RtpToNtpMs(video_measurement.latest_timestamp,
72 video_measurement.rtcp,
73 &video_last_capture_time_ms)) {
74 return false;
75 }
76 if (video_last_capture_time_ms < 0) {
77 return false;
78 }
79 // Positive diff means that video_measurement is behind audio_measurement.
80 *relative_delay_ms = video_measurement.latest_receive_time_ms -
81 audio_measurement.latest_receive_time_ms -
82 (video_last_capture_time_ms - audio_last_capture_time_ms);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000083 if (*relative_delay_ms > kMaxDeltaDelayMs ||
84 *relative_delay_ms < -kMaxDeltaDelayMs) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000085 return false;
86 }
87 return true;
88}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000089
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000090bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
91 int current_audio_delay_ms,
92 int* extra_audio_delay_ms,
93 int* total_video_delay_target_ms) {
94 assert(extra_audio_delay_ms && total_video_delay_target_ms);
stefan@webrtc.org5f284982012-06-28 07:51:16 +000095 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
96 "Audio delay is: %d for voice channel: %d",
97 current_audio_delay_ms, audio_channel_id_);
98 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
99 "Network delay diff is: %d for voice channel: %d",
100 channel_delay_->network_delay, audio_channel_id_);
101 // Calculate the difference between the lowest possible video delay and
102 // the current audio delay.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000103 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
104 "Current diff is: %d for audio channel: %d",
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000105 relative_delay_ms, audio_channel_id_);
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000106
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000107 int current_diff_ms = *total_video_delay_target_ms - current_audio_delay_ms +
108 relative_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000109
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000110 avg_diff_ms_ = ((kFilterLength - 1) * avg_diff_ms_ +
111 current_diff_ms) / kFilterLength;
112 if (abs(avg_diff_ms_) < kMinDeltaMs) {
113 // Don't adjust if the diff is within our margin.
114 return false;
115 }
116
117 // Make sure we don't move too fast.
118 int diff_ms = avg_diff_ms_ / 2;
119 diff_ms = std::min(diff_ms, kMaxChangeMs);
120 diff_ms = std::max(diff_ms, -kMaxChangeMs);
121
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000122 int video_delay_ms = base_target_delay_ms_;
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000123 if (diff_ms > 0) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000124 // The minimum video delay is longer than the current audio delay.
125 // We need to decrease extra video delay, if we have added extra delay
126 // earlier, or add extra audio delay.
127 if (channel_delay_->extra_video_delay_ms > 0) {
128 // We have extra delay added to ViE. Reduce this delay before adding
129 // extra delay to VoE.
130
131 // This is the desired delay, we can't reduce more than this.
132 video_delay_ms = *total_video_delay_target_ms;
133
134 // Check that we don't reduce the delay more than what is allowed.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000135 if (video_delay_ms < channel_delay_->last_video_delay_ms - diff_ms) {
136 video_delay_ms = channel_delay_->last_video_delay_ms - diff_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000137 channel_delay_->extra_video_delay_ms =
138 video_delay_ms - *total_video_delay_target_ms;
139 } else {
140 channel_delay_->extra_video_delay_ms = 0;
141 }
142 channel_delay_->last_video_delay_ms = video_delay_ms;
143 channel_delay_->last_sync_delay = -1;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000144 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000145 } else { // channel_delay_->extra_video_delay_ms > 0
146 // We have no extra video delay to remove, increase the audio delay.
147 if (channel_delay_->last_sync_delay >= 0) {
148 // We have increased the audio delay earlier, increase it even more.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000149 // Increase the audio delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000150 channel_delay_->extra_audio_delay_ms += diff_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000151
152 // Don't set a too high delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000153 channel_delay_->extra_audio_delay_ms = std::min(
154 channel_delay_->extra_audio_delay_ms,
155 base_target_delay_ms_ + kMaxDeltaDelayMs);
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000156
157 // Don't add any extra video delay.
158 video_delay_ms = *total_video_delay_target_ms;
159 channel_delay_->extra_video_delay_ms = 0;
160 channel_delay_->last_video_delay_ms = video_delay_ms;
161 channel_delay_->last_sync_delay = 1;
162 } else { // channel_delay_->last_sync_delay >= 0
163 // First time after a delay change, don't add any extra delay.
164 // This is to not toggle back and forth too much.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000165 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000166 // Set minimum video delay
167 video_delay_ms = *total_video_delay_target_ms;
168 channel_delay_->extra_video_delay_ms = 0;
169 channel_delay_->last_video_delay_ms = video_delay_ms;
170 channel_delay_->last_sync_delay = 0;
171 }
172 }
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000173 } else { // if (diff_ms > 0)
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000174 // The minimum video delay is lower than the current audio delay.
175 // We need to decrease possible extra audio delay, or
176 // add extra video delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000177 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
178 // We have extra delay in VoiceEngine.
179 // Start with decreasing the voice delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000180 // Note: diff_ms is negative; add the negative difference.
181 channel_delay_->extra_audio_delay_ms += diff_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000182
183 if (channel_delay_->extra_audio_delay_ms < 0) {
184 // Negative values not allowed.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000185 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000186 channel_delay_->last_sync_delay = 0;
187 } else {
188 // There is more audio delay to use for the next round.
189 channel_delay_->last_sync_delay = 1;
190 }
191
192 // Keep the video delay at the minimum values.
193 video_delay_ms = *total_video_delay_target_ms;
194 channel_delay_->extra_video_delay_ms = 0;
195 channel_delay_->last_video_delay_ms = video_delay_ms;
196 } else { // channel_delay_->extra_audio_delay_ms > 0
197 // We have no extra delay in VoiceEngine, increase the video delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000198 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000199
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000200 // This is the desired delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000201 // Note: diff_ms is negative.
202 video_delay_ms = std::max(*total_video_delay_target_ms,
203 channel_delay_->last_video_delay_ms) - diff_ms;
204
205 // Verify we don't go above the maximum allowed delay.
206 video_delay_ms = std::min(video_delay_ms,
207 base_target_delay_ms_ + kMaxDeltaDelayMs);
208
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000209 // Store the values.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000210 channel_delay_->extra_video_delay_ms =
211 video_delay_ms - *total_video_delay_target_ms;
212 channel_delay_->last_video_delay_ms = video_delay_ms;
213 channel_delay_->last_sync_delay = -1;
214 }
215 }
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000216 avg_diff_ms_ = 0;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000217 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
218 "Sync video delay %d ms for video channel and audio delay %d for audio "
219 "channel %d",
220 video_delay_ms, channel_delay_->extra_audio_delay_ms, audio_channel_id_);
221
222 *extra_audio_delay_ms = channel_delay_->extra_audio_delay_ms;
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000223 video_delay_ms = std::max(video_delay_ms, 0);
224 *total_video_delay_target_ms = std::max(*total_video_delay_target_ms,
225 video_delay_ms);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000226 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000227}
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000228
229void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000230 // Initial extra delay for audio (accounting for existing extra delay).
231 channel_delay_->extra_audio_delay_ms +=
232 target_delay_ms - base_target_delay_ms_;
233 // The video delay is compared to the last value (and how much we can update
234 // is limited by that as well).
235 channel_delay_->last_video_delay_ms +=
236 target_delay_ms - base_target_delay_ms_;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000237 // Video is already delayed by the desired amount.
238 base_target_delay_ms_ = target_delay_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000239}
240
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000241} // namespace webrtc