blob: fcff782000542a04ed7843b41a9c860b4a019758 [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>
15
16#include <algorithm>
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000017
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000018#include "webrtc/system_wrappers/interface/trace.h"
stefan@webrtc.org5f284982012-06-28 07:51:16 +000019
20namespace webrtc {
21
pwestin@webrtc.org63117332013-04-22 18:57:14 +000022static const int kMaxChangeMs = 80;
23static const int kMaxDeltaDelayMs = 10000;
24static const int kFilterLength = 4;
25// Minimum difference between audio and video to warrant a change.
26static const int kMinDeltaMs = 30;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000027
stefan@webrtc.org5f284982012-06-28 07:51:16 +000028struct ViESyncDelay {
29 ViESyncDelay() {
30 extra_video_delay_ms = 0;
31 last_video_delay_ms = 0;
32 extra_audio_delay_ms = 0;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000033 last_audio_delay_ms = 0;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000034 network_delay = 120;
35 }
36
37 int extra_video_delay_ms;
38 int last_video_delay_ms;
39 int extra_audio_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000040 int last_audio_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000041 int network_delay;
42};
43
44StreamSynchronization::StreamSynchronization(int audio_channel_id,
45 int video_channel_id)
46 : channel_delay_(new ViESyncDelay),
47 audio_channel_id_(audio_channel_id),
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000048 video_channel_id_(video_channel_id),
pwestin@webrtc.org63117332013-04-22 18:57:14 +000049 base_target_delay_ms_(0),
50 avg_diff_ms_(0) {}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000051
52StreamSynchronization::~StreamSynchronization() {
53 delete channel_delay_;
54}
55
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000056bool StreamSynchronization::ComputeRelativeDelay(
57 const Measurements& audio_measurement,
58 const Measurements& video_measurement,
59 int* relative_delay_ms) {
60 assert(relative_delay_ms);
61 if (audio_measurement.rtcp.size() < 2 || video_measurement.rtcp.size() < 2) {
62 // We need two RTCP SR reports per stream to do synchronization.
63 return false;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000064 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000065 int64_t audio_last_capture_time_ms;
66 if (!synchronization::RtpToNtpMs(audio_measurement.latest_timestamp,
67 audio_measurement.rtcp,
68 &audio_last_capture_time_ms)) {
69 return false;
70 }
71 int64_t video_last_capture_time_ms;
72 if (!synchronization::RtpToNtpMs(video_measurement.latest_timestamp,
73 video_measurement.rtcp,
74 &video_last_capture_time_ms)) {
75 return false;
76 }
77 if (video_last_capture_time_ms < 0) {
78 return false;
79 }
80 // Positive diff means that video_measurement is behind audio_measurement.
81 *relative_delay_ms = video_measurement.latest_receive_time_ms -
82 audio_measurement.latest_receive_time_ms -
83 (video_last_capture_time_ms - audio_last_capture_time_ms);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000084 if (*relative_delay_ms > kMaxDeltaDelayMs ||
85 *relative_delay_ms < -kMaxDeltaDelayMs) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000086 return false;
87 }
88 return true;
89}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000090
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000091bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
92 int current_audio_delay_ms,
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000093 int* total_audio_delay_target_ms,
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000094 int* total_video_delay_target_ms) {
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000095 assert(total_audio_delay_target_ms && total_video_delay_target_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000096
97 int current_video_delay_ms = *total_video_delay_target_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000098 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
99 "Audio delay is: %d for voice channel: %d",
100 current_audio_delay_ms, audio_channel_id_);
101 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
102 "Network delay diff is: %d for voice channel: %d",
103 channel_delay_->network_delay, audio_channel_id_);
104 // Calculate the difference between the lowest possible video delay and
105 // the current audio delay.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000106 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
107 "Current diff is: %d for audio channel: %d",
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000108 relative_delay_ms, audio_channel_id_);
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000109
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000110 int current_diff_ms = current_video_delay_ms - current_audio_delay_ms +
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000111 relative_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000112
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000113 avg_diff_ms_ = ((kFilterLength - 1) * avg_diff_ms_ +
114 current_diff_ms) / kFilterLength;
115 if (abs(avg_diff_ms_) < kMinDeltaMs) {
116 // Don't adjust if the diff is within our margin.
117 return false;
118 }
119
120 // Make sure we don't move too fast.
121 int diff_ms = avg_diff_ms_ / 2;
122 diff_ms = std::min(diff_ms, kMaxChangeMs);
123 diff_ms = std::max(diff_ms, -kMaxChangeMs);
124
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000125 // Reset the average after a move to prevent overshooting reaction.
126 avg_diff_ms_ = 0;
127
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000128 if (diff_ms > 0) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000129 // The minimum video delay is longer than the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000130 // We need to decrease extra video delay, or add extra audio delay.
131 if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000132 // We have extra delay added to ViE. Reduce this delay before adding
133 // extra delay to VoE.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000134 channel_delay_->extra_video_delay_ms -= diff_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000135 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000136 } else { // channel_delay_->extra_video_delay_ms > 0
137 // We have no extra video delay to remove, increase the audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000138 channel_delay_->extra_audio_delay_ms += diff_ms;
139 channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000140 }
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000141 } else { // if (diff_ms > 0)
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000142 // The video delay is lower than the current audio delay.
143 // We need to decrease extra audio delay, or add extra video delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000144 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
145 // We have extra delay in VoiceEngine.
146 // Start with decreasing the voice delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000147 // Note: diff_ms is negative; add the negative difference.
148 channel_delay_->extra_audio_delay_ms += diff_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000149 channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
150 } else { // channel_delay_->extra_audio_delay_ms > base_target_delay_ms_
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000151 // We have no extra delay in VoiceEngine, increase the video delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000152 // Note: diff_ms is negative; subtract the negative difference.
153 channel_delay_->extra_video_delay_ms -= diff_ms; // X - (-Y) = X + Y.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000154 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000155 }
156 }
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000157
158 // Make sure that video is never below our target.
159 channel_delay_->extra_video_delay_ms = std::max(
160 channel_delay_->extra_video_delay_ms, base_target_delay_ms_);
161
162 int new_video_delay_ms;
163 if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
164 new_video_delay_ms = channel_delay_->extra_video_delay_ms;
165 } else {
166 // No change to the extra video delay. We are changing audio and we only
167 // allow to change one at the time.
168 new_video_delay_ms = channel_delay_->last_video_delay_ms;
169 }
170
171 // Make sure that we don't go below the extra video delay.
172 new_video_delay_ms = std::max(
173 new_video_delay_ms, channel_delay_->extra_video_delay_ms);
174
175 // Verify we don't go above the maximum allowed video delay.
176 new_video_delay_ms =
177 std::min(new_video_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
178
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000179 int new_audio_delay_ms;
180 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
181 new_audio_delay_ms = channel_delay_->extra_audio_delay_ms;
182 } else {
183 // No change to the audio delay. We are changing video and we only
184 // allow to change one at the time.
185 new_audio_delay_ms = channel_delay_->last_audio_delay_ms;
186 }
187
188 // Make sure that we don't go below the extra audio delay.
189 new_audio_delay_ms = std::max(
190 new_audio_delay_ms, channel_delay_->extra_audio_delay_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000191
192 // Verify we don't go above the maximum allowed audio delay.
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000193 new_audio_delay_ms =
194 std::min(new_audio_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000195
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000196 // Remember our last audio and video delays.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000197 channel_delay_->last_video_delay_ms = new_video_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000198 channel_delay_->last_audio_delay_ms = new_audio_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000199
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000200 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
201 "Sync video delay %d ms for video channel and audio delay %d for audio "
202 "channel %d",
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000203 new_video_delay_ms, channel_delay_->extra_audio_delay_ms,
204 audio_channel_id_);
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000205
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000206 // Return values.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000207 *total_video_delay_target_ms = new_video_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000208 *total_audio_delay_target_ms = new_audio_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000209 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000210}
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000211
212void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000213 // Initial extra delay for audio (accounting for existing extra delay).
214 channel_delay_->extra_audio_delay_ms +=
215 target_delay_ms - base_target_delay_ms_;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000216 channel_delay_->last_audio_delay_ms +=
217 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000218
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000219 // The video delay is compared to the last value (and how much we can update
220 // is limited by that as well).
221 channel_delay_->last_video_delay_ms +=
222 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000223
224 channel_delay_->extra_video_delay_ms +=
225 target_delay_ms - base_target_delay_ms_;
226
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000227 // Video is already delayed by the desired amount.
228 base_target_delay_ms_ = target_delay_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000229}
230
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000231} // namespace webrtc