blob: 6192dfa5bf2212f605523f7d7441325adeaf41ad [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
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000011#include "webrtc/video_engine/stream_synchronization.h"
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000012
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000013#include <assert.h>
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000014#include <math.h>
stefan@webrtc.org47fadba2013-11-25 12:03:56 +000015#include <stdlib.h>
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000016
17#include <algorithm>
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000018
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000019#include "webrtc/system_wrappers/interface/trace.h"
stefan@webrtc.org5f284982012-06-28 07:51:16 +000020
21namespace webrtc {
22
pwestin@webrtc.org63117332013-04-22 18:57:14 +000023static const int kMaxChangeMs = 80;
24static const int kMaxDeltaDelayMs = 10000;
25static const int kFilterLength = 4;
26// Minimum difference between audio and video to warrant a change.
27static const int kMinDeltaMs = 30;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000028
stefan@webrtc.org5f284982012-06-28 07:51:16 +000029struct ViESyncDelay {
30 ViESyncDelay() {
31 extra_video_delay_ms = 0;
32 last_video_delay_ms = 0;
33 extra_audio_delay_ms = 0;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000034 last_audio_delay_ms = 0;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000035 network_delay = 120;
36 }
37
38 int extra_video_delay_ms;
39 int last_video_delay_ms;
40 int extra_audio_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000041 int last_audio_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000042 int network_delay;
43};
44
45StreamSynchronization::StreamSynchronization(int audio_channel_id,
46 int video_channel_id)
47 : channel_delay_(new ViESyncDelay),
48 audio_channel_id_(audio_channel_id),
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000049 video_channel_id_(video_channel_id),
pwestin@webrtc.org63117332013-04-22 18:57:14 +000050 base_target_delay_ms_(0),
51 avg_diff_ms_(0) {}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000052
53StreamSynchronization::~StreamSynchronization() {
54 delete channel_delay_;
55}
56
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000057bool StreamSynchronization::ComputeRelativeDelay(
58 const Measurements& audio_measurement,
59 const Measurements& video_measurement,
60 int* relative_delay_ms) {
61 assert(relative_delay_ms);
62 if (audio_measurement.rtcp.size() < 2 || video_measurement.rtcp.size() < 2) {
63 // We need two RTCP SR reports per stream to do synchronization.
64 return false;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000065 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000066 int64_t audio_last_capture_time_ms;
67 if (!synchronization::RtpToNtpMs(audio_measurement.latest_timestamp,
68 audio_measurement.rtcp,
69 &audio_last_capture_time_ms)) {
70 return false;
71 }
72 int64_t video_last_capture_time_ms;
73 if (!synchronization::RtpToNtpMs(video_measurement.latest_timestamp,
74 video_measurement.rtcp,
75 &video_last_capture_time_ms)) {
76 return false;
77 }
78 if (video_last_capture_time_ms < 0) {
79 return false;
80 }
81 // Positive diff means that video_measurement is behind audio_measurement.
82 *relative_delay_ms = video_measurement.latest_receive_time_ms -
83 audio_measurement.latest_receive_time_ms -
84 (video_last_capture_time_ms - audio_last_capture_time_ms);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000085 if (*relative_delay_ms > kMaxDeltaDelayMs ||
86 *relative_delay_ms < -kMaxDeltaDelayMs) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000087 return false;
88 }
89 return true;
90}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000091
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000092bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
93 int current_audio_delay_ms,
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000094 int* total_audio_delay_target_ms,
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000095 int* total_video_delay_target_ms) {
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000096 assert(total_audio_delay_target_ms && total_video_delay_target_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000097
98 int current_video_delay_ms = *total_video_delay_target_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000099 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
100 "Audio delay is: %d for voice channel: %d",
101 current_audio_delay_ms, audio_channel_id_);
102 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
103 "Network delay diff is: %d for voice channel: %d",
104 channel_delay_->network_delay, audio_channel_id_);
105 // Calculate the difference between the lowest possible video delay and
106 // the current audio delay.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000107 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
108 "Current diff is: %d for audio channel: %d",
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000109 relative_delay_ms, audio_channel_id_);
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000110
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000111 int current_diff_ms = current_video_delay_ms - current_audio_delay_ms +
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000112 relative_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000113
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000114 avg_diff_ms_ = ((kFilterLength - 1) * avg_diff_ms_ +
115 current_diff_ms) / kFilterLength;
116 if (abs(avg_diff_ms_) < kMinDeltaMs) {
117 // Don't adjust if the diff is within our margin.
118 return false;
119 }
120
121 // Make sure we don't move too fast.
122 int diff_ms = avg_diff_ms_ / 2;
123 diff_ms = std::min(diff_ms, kMaxChangeMs);
124 diff_ms = std::max(diff_ms, -kMaxChangeMs);
125
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000126 // Reset the average after a move to prevent overshooting reaction.
127 avg_diff_ms_ = 0;
128
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000129 if (diff_ms > 0) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000130 // The minimum video delay is longer than the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000131 // We need to decrease extra video delay, or add extra audio delay.
132 if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000133 // We have extra delay added to ViE. Reduce this delay before adding
134 // extra delay to VoE.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000135 channel_delay_->extra_video_delay_ms -= diff_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000136 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000137 } else { // channel_delay_->extra_video_delay_ms > 0
138 // We have no extra video delay to remove, increase the audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000139 channel_delay_->extra_audio_delay_ms += diff_ms;
140 channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000141 }
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000142 } else { // if (diff_ms > 0)
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000143 // The video delay is lower than the current audio delay.
144 // We need to decrease extra audio delay, or add extra video delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000145 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
146 // We have extra delay in VoiceEngine.
147 // Start with decreasing the voice delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000148 // Note: diff_ms is negative; add the negative difference.
149 channel_delay_->extra_audio_delay_ms += diff_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000150 channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
151 } else { // channel_delay_->extra_audio_delay_ms > base_target_delay_ms_
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000152 // We have no extra delay in VoiceEngine, increase the video delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000153 // Note: diff_ms is negative; subtract the negative difference.
154 channel_delay_->extra_video_delay_ms -= diff_ms; // X - (-Y) = X + Y.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000155 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000156 }
157 }
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000158
159 // Make sure that video is never below our target.
160 channel_delay_->extra_video_delay_ms = std::max(
161 channel_delay_->extra_video_delay_ms, base_target_delay_ms_);
162
163 int new_video_delay_ms;
164 if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
165 new_video_delay_ms = channel_delay_->extra_video_delay_ms;
166 } else {
167 // No change to the extra video delay. We are changing audio and we only
168 // allow to change one at the time.
169 new_video_delay_ms = channel_delay_->last_video_delay_ms;
170 }
171
172 // Make sure that we don't go below the extra video delay.
173 new_video_delay_ms = std::max(
174 new_video_delay_ms, channel_delay_->extra_video_delay_ms);
175
176 // Verify we don't go above the maximum allowed video delay.
177 new_video_delay_ms =
178 std::min(new_video_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
179
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000180 int new_audio_delay_ms;
181 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
182 new_audio_delay_ms = channel_delay_->extra_audio_delay_ms;
183 } else {
184 // No change to the audio delay. We are changing video and we only
185 // allow to change one at the time.
186 new_audio_delay_ms = channel_delay_->last_audio_delay_ms;
187 }
188
189 // Make sure that we don't go below the extra audio delay.
190 new_audio_delay_ms = std::max(
191 new_audio_delay_ms, channel_delay_->extra_audio_delay_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000192
193 // Verify we don't go above the maximum allowed audio delay.
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000194 new_audio_delay_ms =
195 std::min(new_audio_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000196
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000197 // Remember our last audio and video delays.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000198 channel_delay_->last_video_delay_ms = new_video_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000199 channel_delay_->last_audio_delay_ms = new_audio_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000200
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000201 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
202 "Sync video delay %d ms for video channel and audio delay %d for audio "
203 "channel %d",
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000204 new_video_delay_ms, channel_delay_->extra_audio_delay_ms,
205 audio_channel_id_);
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000206
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000207 // Return values.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000208 *total_video_delay_target_ms = new_video_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000209 *total_audio_delay_target_ms = new_audio_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000210 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000211}
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000212
213void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000214 // Initial extra delay for audio (accounting for existing extra delay).
215 channel_delay_->extra_audio_delay_ms +=
216 target_delay_ms - base_target_delay_ms_;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000217 channel_delay_->last_audio_delay_ms +=
218 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000219
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000220 // The video delay is compared to the last value (and how much we can update
221 // is limited by that as well).
222 channel_delay_->last_video_delay_ms +=
223 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000224
225 channel_delay_->extra_video_delay_ms +=
226 target_delay_ms - base_target_delay_ms_;
227
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000228 // Video is already delayed by the desired amount.
229 base_target_delay_ms_ = target_delay_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000230}
231
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000232} // namespace webrtc