blob: 11caf3d2997f280173c109eef68c5175eb2a4362 [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;
23const int kMaxDelay = 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),
45 video_channel_id_(video_channel_id) {}
46
47StreamSynchronization::~StreamSynchronization() {
48 delete channel_delay_;
49}
50
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000051bool StreamSynchronization::ComputeRelativeDelay(
52 const Measurements& audio_measurement,
53 const Measurements& video_measurement,
54 int* relative_delay_ms) {
55 assert(relative_delay_ms);
56 if (audio_measurement.rtcp.size() < 2 || video_measurement.rtcp.size() < 2) {
57 // We need two RTCP SR reports per stream to do synchronization.
58 return false;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000059 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000060 int64_t audio_last_capture_time_ms;
61 if (!synchronization::RtpToNtpMs(audio_measurement.latest_timestamp,
62 audio_measurement.rtcp,
63 &audio_last_capture_time_ms)) {
64 return false;
65 }
66 int64_t video_last_capture_time_ms;
67 if (!synchronization::RtpToNtpMs(video_measurement.latest_timestamp,
68 video_measurement.rtcp,
69 &video_last_capture_time_ms)) {
70 return false;
71 }
72 if (video_last_capture_time_ms < 0) {
73 return false;
74 }
75 // Positive diff means that video_measurement is behind audio_measurement.
76 *relative_delay_ms = video_measurement.latest_receive_time_ms -
77 audio_measurement.latest_receive_time_ms -
78 (video_last_capture_time_ms - audio_last_capture_time_ms);
79 if (*relative_delay_ms > 1000 || *relative_delay_ms < -1000) {
80 return false;
81 }
82 return true;
83}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000084
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000085bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
86 int current_audio_delay_ms,
87 int* extra_audio_delay_ms,
88 int* total_video_delay_target_ms) {
89 assert(extra_audio_delay_ms && total_video_delay_target_ms);
stefan@webrtc.org5f284982012-06-28 07:51:16 +000090 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
91 "Audio delay is: %d for voice channel: %d",
92 current_audio_delay_ms, audio_channel_id_);
93 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
94 "Network delay diff is: %d for voice channel: %d",
95 channel_delay_->network_delay, audio_channel_id_);
96 // Calculate the difference between the lowest possible video delay and
97 // the current audio delay.
stefan@webrtc.org5f284982012-06-28 07:51:16 +000098 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
99 "Current diff is: %d for audio channel: %d",
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000100 relative_delay_ms, audio_channel_id_);
101
102 int current_diff_ms = *total_video_delay_target_ms - current_audio_delay_ms +
103 relative_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000104
105 int video_delay_ms = 0;
106 if (current_diff_ms > 0) {
107 // The minimum video delay is longer than the current audio delay.
108 // We need to decrease extra video delay, if we have added extra delay
109 // earlier, or add extra audio delay.
110 if (channel_delay_->extra_video_delay_ms > 0) {
111 // We have extra delay added to ViE. Reduce this delay before adding
112 // extra delay to VoE.
113
114 // This is the desired delay, we can't reduce more than this.
115 video_delay_ms = *total_video_delay_target_ms;
116
117 // Check that we don't reduce the delay more than what is allowed.
118 if (video_delay_ms <
119 channel_delay_->last_video_delay_ms - kMaxVideoDiffMs) {
120 video_delay_ms =
121 channel_delay_->last_video_delay_ms - kMaxVideoDiffMs;
122 channel_delay_->extra_video_delay_ms =
123 video_delay_ms - *total_video_delay_target_ms;
124 } else {
125 channel_delay_->extra_video_delay_ms = 0;
126 }
127 channel_delay_->last_video_delay_ms = video_delay_ms;
128 channel_delay_->last_sync_delay = -1;
129 channel_delay_->extra_audio_delay_ms = 0;
130 } else { // channel_delay_->extra_video_delay_ms > 0
131 // We have no extra video delay to remove, increase the audio delay.
132 if (channel_delay_->last_sync_delay >= 0) {
133 // We have increased the audio delay earlier, increase it even more.
134 int audio_diff_ms = current_diff_ms / 2;
135 if (audio_diff_ms > kMaxAudioDiffMs) {
136 // We only allow a maximum change of KMaxAudioDiffMS for audio
137 // due to NetEQ maximum changes.
138 audio_diff_ms = kMaxAudioDiffMs;
139 }
140 // Increase the audio delay
141 channel_delay_->extra_audio_delay_ms += audio_diff_ms;
142
143 // Don't set a too high delay.
144 if (channel_delay_->extra_audio_delay_ms > kMaxDelay) {
145 channel_delay_->extra_audio_delay_ms = kMaxDelay;
146 }
147
148 // Don't add any extra video delay.
149 video_delay_ms = *total_video_delay_target_ms;
150 channel_delay_->extra_video_delay_ms = 0;
151 channel_delay_->last_video_delay_ms = video_delay_ms;
152 channel_delay_->last_sync_delay = 1;
153 } else { // channel_delay_->last_sync_delay >= 0
154 // First time after a delay change, don't add any extra delay.
155 // This is to not toggle back and forth too much.
156 channel_delay_->extra_audio_delay_ms = 0;
157 // Set minimum 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 = 0;
162 }
163 }
164 } else { // if (current_diffMS > 0)
165 // The minimum video delay is lower than the current audio delay.
166 // We need to decrease possible extra audio delay, or
167 // add extra video delay.
168
169 if (channel_delay_->extra_audio_delay_ms > 0) {
170 // We have extra delay in VoiceEngine
171 // Start with decreasing the voice delay
172 int audio_diff_ms = current_diff_ms / 2;
173 if (audio_diff_ms < -1 * kMaxAudioDiffMs) {
174 // Don't change the delay too much at once.
175 audio_diff_ms = -1 * kMaxAudioDiffMs;
176 }
177 // Add the negative difference.
178 channel_delay_->extra_audio_delay_ms += audio_diff_ms;
179
180 if (channel_delay_->extra_audio_delay_ms < 0) {
181 // Negative values not allowed.
182 channel_delay_->extra_audio_delay_ms = 0;
183 channel_delay_->last_sync_delay = 0;
184 } else {
185 // There is more audio delay to use for the next round.
186 channel_delay_->last_sync_delay = 1;
187 }
188
189 // Keep the video delay at the minimum values.
190 video_delay_ms = *total_video_delay_target_ms;
191 channel_delay_->extra_video_delay_ms = 0;
192 channel_delay_->last_video_delay_ms = video_delay_ms;
193 } else { // channel_delay_->extra_audio_delay_ms > 0
194 // We have no extra delay in VoiceEngine, increase the video delay.
195 channel_delay_->extra_audio_delay_ms = 0;
196
197 // Make the difference positive.
198 int video_diff_ms = -1 * current_diff_ms;
199
200 // This is the desired delay.
201 video_delay_ms = *total_video_delay_target_ms + video_diff_ms;
202 if (video_delay_ms > channel_delay_->last_video_delay_ms) {
203 if (video_delay_ms >
204 channel_delay_->last_video_delay_ms + kMaxVideoDiffMs) {
205 // Don't increase the delay too much at once
206 video_delay_ms =
207 channel_delay_->last_video_delay_ms + kMaxVideoDiffMs;
208 }
209 // Verify we don't go above the maximum allowed delay
210 if (video_delay_ms > kMaxDelay) {
211 video_delay_ms = kMaxDelay;
212 }
213 } else {
214 if (video_delay_ms <
215 channel_delay_->last_video_delay_ms - kMaxVideoDiffMs) {
216 // Don't decrease the delay too much at once
217 video_delay_ms =
218 channel_delay_->last_video_delay_ms - kMaxVideoDiffMs;
219 }
220 // Verify we don't go below the minimum delay
221 if (video_delay_ms < *total_video_delay_target_ms) {
222 video_delay_ms = *total_video_delay_target_ms;
223 }
224 }
225 // Store the values
226 channel_delay_->extra_video_delay_ms =
227 video_delay_ms - *total_video_delay_target_ms;
228 channel_delay_->last_video_delay_ms = video_delay_ms;
229 channel_delay_->last_sync_delay = -1;
230 }
231 }
232
233 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
234 "Sync video delay %d ms for video channel and audio delay %d for audio "
235 "channel %d",
236 video_delay_ms, channel_delay_->extra_audio_delay_ms, audio_channel_id_);
237
238 *extra_audio_delay_ms = channel_delay_->extra_audio_delay_ms;
239
240 if (video_delay_ms < 0) {
241 video_delay_ms = 0;
242 }
243 *total_video_delay_target_ms =
244 (*total_video_delay_target_ms > video_delay_ms) ?
245 *total_video_delay_target_ms : video_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000246 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000247}
248} // namespace webrtc