blob: 6ad579ce6887166c9eb79a47b9a86a39266b66e9 [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
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000013#include <algorithm>
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000014#include <assert.h>
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000015#include <cmath>
16
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000017#include "webrtc/system_wrappers/interface/trace.h"
stefan@webrtc.org5f284982012-06-28 07:51:16 +000018
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;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000032 network_delay = 120;
33 }
34
35 int extra_video_delay_ms;
36 int last_video_delay_ms;
37 int extra_audio_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000038 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),
pwestin@webrtc.org63117332013-04-22 18:57:14 +000046 base_target_delay_ms_(0),
47 avg_diff_ms_(0) {}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000048
49StreamSynchronization::~StreamSynchronization() {
50 delete channel_delay_;
51}
52
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000053bool StreamSynchronization::ComputeRelativeDelay(
54 const Measurements& audio_measurement,
55 const Measurements& video_measurement,
56 int* relative_delay_ms) {
57 assert(relative_delay_ms);
58 if (audio_measurement.rtcp.size() < 2 || video_measurement.rtcp.size() < 2) {
59 // We need two RTCP SR reports per stream to do synchronization.
60 return false;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000061 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000062 int64_t audio_last_capture_time_ms;
63 if (!synchronization::RtpToNtpMs(audio_measurement.latest_timestamp,
64 audio_measurement.rtcp,
65 &audio_last_capture_time_ms)) {
66 return false;
67 }
68 int64_t video_last_capture_time_ms;
69 if (!synchronization::RtpToNtpMs(video_measurement.latest_timestamp,
70 video_measurement.rtcp,
71 &video_last_capture_time_ms)) {
72 return false;
73 }
74 if (video_last_capture_time_ms < 0) {
75 return false;
76 }
77 // Positive diff means that video_measurement is behind audio_measurement.
78 *relative_delay_ms = video_measurement.latest_receive_time_ms -
79 audio_measurement.latest_receive_time_ms -
80 (video_last_capture_time_ms - audio_last_capture_time_ms);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000081 if (*relative_delay_ms > kMaxDeltaDelayMs ||
82 *relative_delay_ms < -kMaxDeltaDelayMs) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000083 return false;
84 }
85 return true;
86}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000087
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000088bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
89 int current_audio_delay_ms,
90 int* extra_audio_delay_ms,
91 int* total_video_delay_target_ms) {
92 assert(extra_audio_delay_ms && total_video_delay_target_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000093
94 int current_video_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
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000107 int current_diff_ms = current_video_delay_ms - current_audio_delay_ms +
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000108 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
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000122 // Reset the average after a move to prevent overshooting reaction.
123 avg_diff_ms_ = 0;
124
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000125 if (diff_ms > 0) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000126 // The minimum video delay is longer than the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000127 // We need to decrease extra video delay, or add extra audio delay.
128 if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000129 // We have extra delay added to ViE. Reduce this delay before adding
130 // extra delay to VoE.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000131 channel_delay_->extra_video_delay_ms -= diff_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000132 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000133 } else { // channel_delay_->extra_video_delay_ms > 0
134 // We have no extra video delay to remove, increase the audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000135 channel_delay_->extra_audio_delay_ms += diff_ms;
136 channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000137 }
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000138 } else { // if (diff_ms > 0)
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000139 // The video delay is lower than the current audio delay.
140 // We need to decrease extra audio delay, or add extra video delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000141 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
142 // We have extra delay in VoiceEngine.
143 // Start with decreasing the voice delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000144 // Note: diff_ms is negative; add the negative difference.
145 channel_delay_->extra_audio_delay_ms += diff_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000146 channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
147 } else { // channel_delay_->extra_audio_delay_ms > base_target_delay_ms_
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000148 // We have no extra delay in VoiceEngine, increase the video delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000149 // Note: diff_ms is negative; subtract the negative difference.
150 channel_delay_->extra_video_delay_ms -= diff_ms; // X - (-Y) = X + Y.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000151 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000152 }
153 }
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000154
155 // Make sure that video is never below our target.
156 channel_delay_->extra_video_delay_ms = std::max(
157 channel_delay_->extra_video_delay_ms, base_target_delay_ms_);
158
159 int new_video_delay_ms;
160 if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
161 new_video_delay_ms = channel_delay_->extra_video_delay_ms;
162 } else {
163 // No change to the extra video delay. We are changing audio and we only
164 // allow to change one at the time.
165 new_video_delay_ms = channel_delay_->last_video_delay_ms;
166 }
167
168 // Make sure that we don't go below the extra video delay.
169 new_video_delay_ms = std::max(
170 new_video_delay_ms, channel_delay_->extra_video_delay_ms);
171
172 // Verify we don't go above the maximum allowed video delay.
173 new_video_delay_ms =
174 std::min(new_video_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
175
176 // Make sure that audio is never below our target.
177 channel_delay_->extra_audio_delay_ms =
178 std::max(base_target_delay_ms_, channel_delay_->extra_audio_delay_ms);
179
180 // Verify we don't go above the maximum allowed audio delay.
181 channel_delay_->extra_audio_delay_ms = std::min(
182 channel_delay_->extra_audio_delay_ms,
183 base_target_delay_ms_ + kMaxDeltaDelayMs);
184
185 // Remember our last video delay.
186 channel_delay_->last_video_delay_ms = new_video_delay_ms;
187
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000188 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, video_channel_id_,
189 "Sync video delay %d ms for video channel and audio delay %d for audio "
190 "channel %d",
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000191 new_video_delay_ms, channel_delay_->extra_audio_delay_ms,
192 audio_channel_id_);
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000193
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000194 // Return values.
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000195 *extra_audio_delay_ms = channel_delay_->extra_audio_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000196 *total_video_delay_target_ms = new_video_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000197 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000198}
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000199
200void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000201 // Initial extra delay for audio (accounting for existing extra delay).
202 channel_delay_->extra_audio_delay_ms +=
203 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000204
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000205 // The video delay is compared to the last value (and how much we can update
206 // is limited by that as well).
207 channel_delay_->last_video_delay_ms +=
208 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000209
210 channel_delay_->extra_video_delay_ms +=
211 target_delay_ms - base_target_delay_ms_;
212
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000213 // Video is already delayed by the desired amount.
214 base_target_delay_ms_ = target_delay_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000215}
216
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000217} // namespace webrtc