blob: b78cfe88744b87f149e95a672140559d17b424d3 [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
kjellander8237abf2015-12-08 07:12:06 -080011#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
Peter Boström415d2cd2015-10-26 11:35:17 +010019#include "webrtc/base/logging.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
Peter Boström36a14382015-05-21 17:00:24 +020045StreamSynchronization::StreamSynchronization(uint32_t video_primary_ssrc,
46 int audio_channel_id)
stefan@webrtc.org5f284982012-06-28 07:51:16 +000047 : channel_delay_(new ViESyncDelay),
Peter Boström36a14382015-05-21 17:00:24 +020048 video_primary_ssrc_(video_primary_ssrc),
stefan@webrtc.org5f284982012-06-28 07:51:16 +000049 audio_channel_id_(audio_channel_id),
pwestin@webrtc.org63117332013-04-22 18:57:14 +000050 base_target_delay_ms_(0),
Peter Boström36a14382015-05-21 17:00:24 +020051 avg_diff_ms_(0) {
52}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000053
54StreamSynchronization::~StreamSynchronization() {
55 delete channel_delay_;
56}
57
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000058bool StreamSynchronization::ComputeRelativeDelay(
59 const Measurements& audio_measurement,
60 const Measurements& video_measurement,
61 int* relative_delay_ms) {
62 assert(relative_delay_ms);
63 if (audio_measurement.rtcp.size() < 2 || video_measurement.rtcp.size() < 2) {
64 // We need two RTCP SR reports per stream to do synchronization.
65 return false;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000066 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000067 int64_t audio_last_capture_time_ms;
wu@webrtc.org66773a02014-05-07 17:09:44 +000068 if (!RtpToNtpMs(audio_measurement.latest_timestamp,
69 audio_measurement.rtcp,
70 &audio_last_capture_time_ms)) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000071 return false;
72 }
73 int64_t video_last_capture_time_ms;
wu@webrtc.org66773a02014-05-07 17:09:44 +000074 if (!RtpToNtpMs(video_measurement.latest_timestamp,
75 video_measurement.rtcp,
76 &video_last_capture_time_ms)) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000077 return false;
78 }
79 if (video_last_capture_time_ms < 0) {
80 return false;
81 }
82 // Positive diff means that video_measurement is behind audio_measurement.
83 *relative_delay_ms = video_measurement.latest_receive_time_ms -
84 audio_measurement.latest_receive_time_ms -
85 (video_last_capture_time_ms - audio_last_capture_time_ms);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000086 if (*relative_delay_ms > kMaxDeltaDelayMs ||
87 *relative_delay_ms < -kMaxDeltaDelayMs) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000088 return false;
89 }
90 return true;
91}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000092
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000093bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
94 int current_audio_delay_ms,
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000095 int* total_audio_delay_target_ms,
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000096 int* total_video_delay_target_ms) {
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000097 assert(total_audio_delay_target_ms && total_video_delay_target_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000098
99 int current_video_delay_ms = *total_video_delay_target_ms;
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000100 LOG(LS_VERBOSE) << "Audio delay: " << current_audio_delay_ms
101 << ", network delay diff: " << channel_delay_->network_delay
102 << " current diff: " << relative_delay_ms
103 << " for channel " << audio_channel_id_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000104 // Calculate the difference between the lowest possible video delay and
105 // the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000106 int current_diff_ms = current_video_delay_ms - current_audio_delay_ms +
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000107 relative_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000108
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000109 avg_diff_ms_ = ((kFilterLength - 1) * avg_diff_ms_ +
110 current_diff_ms) / kFilterLength;
111 if (abs(avg_diff_ms_) < kMinDeltaMs) {
112 // Don't adjust if the diff is within our margin.
113 return false;
114 }
115
116 // Make sure we don't move too fast.
117 int diff_ms = avg_diff_ms_ / 2;
118 diff_ms = std::min(diff_ms, kMaxChangeMs);
119 diff_ms = std::max(diff_ms, -kMaxChangeMs);
120
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000121 // Reset the average after a move to prevent overshooting reaction.
122 avg_diff_ms_ = 0;
123
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000124 if (diff_ms > 0) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000125 // The minimum video delay is longer than the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000126 // We need to decrease extra video delay, or add extra audio delay.
127 if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000128 // We have extra delay added to ViE. Reduce this delay before adding
129 // extra delay to VoE.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000130 channel_delay_->extra_video_delay_ms -= diff_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000131 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000132 } else { // channel_delay_->extra_video_delay_ms > 0
133 // We have no extra video delay to remove, increase the audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000134 channel_delay_->extra_audio_delay_ms += diff_ms;
135 channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000136 }
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000137 } else { // if (diff_ms > 0)
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000138 // The video delay is lower than the current audio delay.
139 // We need to decrease extra audio delay, or add extra video delay.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000140 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
141 // We have extra delay in VoiceEngine.
142 // Start with decreasing the voice delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000143 // Note: diff_ms is negative; add the negative difference.
144 channel_delay_->extra_audio_delay_ms += diff_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000145 channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
146 } else { // channel_delay_->extra_audio_delay_ms > base_target_delay_ms_
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000147 // We have no extra delay in VoiceEngine, increase the video delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000148 // Note: diff_ms is negative; subtract the negative difference.
149 channel_delay_->extra_video_delay_ms -= diff_ms; // X - (-Y) = X + Y.
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000150 channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000151 }
152 }
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000153
154 // Make sure that video is never below our target.
155 channel_delay_->extra_video_delay_ms = std::max(
156 channel_delay_->extra_video_delay_ms, base_target_delay_ms_);
157
158 int new_video_delay_ms;
159 if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
160 new_video_delay_ms = channel_delay_->extra_video_delay_ms;
161 } else {
162 // No change to the extra video delay. We are changing audio and we only
163 // allow to change one at the time.
164 new_video_delay_ms = channel_delay_->last_video_delay_ms;
165 }
166
167 // Make sure that we don't go below the extra video delay.
168 new_video_delay_ms = std::max(
169 new_video_delay_ms, channel_delay_->extra_video_delay_ms);
170
171 // Verify we don't go above the maximum allowed video delay.
172 new_video_delay_ms =
173 std::min(new_video_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
174
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000175 int new_audio_delay_ms;
176 if (channel_delay_->extra_audio_delay_ms > base_target_delay_ms_) {
177 new_audio_delay_ms = channel_delay_->extra_audio_delay_ms;
178 } else {
179 // No change to the audio delay. We are changing video and we only
180 // allow to change one at the time.
181 new_audio_delay_ms = channel_delay_->last_audio_delay_ms;
182 }
183
184 // Make sure that we don't go below the extra audio delay.
185 new_audio_delay_ms = std::max(
186 new_audio_delay_ms, channel_delay_->extra_audio_delay_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000187
188 // Verify we don't go above the maximum allowed audio delay.
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000189 new_audio_delay_ms =
190 std::min(new_audio_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000191
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000192 // Remember our last audio and video delays.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000193 channel_delay_->last_video_delay_ms = new_video_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000194 channel_delay_->last_audio_delay_ms = new_audio_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000195
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000196 LOG(LS_VERBOSE) << "Sync video delay " << new_video_delay_ms
Peter Boström36a14382015-05-21 17:00:24 +0200197 << " for video primary SSRC " << video_primary_ssrc_
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000198 << " and audio delay " << channel_delay_->extra_audio_delay_ms
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000199 << " for audio channel " << audio_channel_id_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000200
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000201 // Return values.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000202 *total_video_delay_target_ms = new_video_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000203 *total_audio_delay_target_ms = new_audio_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000204 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000205}
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000206
207void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000208 // Initial extra delay for audio (accounting for existing extra delay).
209 channel_delay_->extra_audio_delay_ms +=
210 target_delay_ms - base_target_delay_ms_;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000211 channel_delay_->last_audio_delay_ms +=
212 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000213
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000214 // The video delay is compared to the last value (and how much we can update
215 // is limited by that as well).
216 channel_delay_->last_video_delay_ms +=
217 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000218
219 channel_delay_->extra_video_delay_ms +=
220 target_delay_ms - base_target_delay_ms_;
221
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000222 // Video is already delayed by the desired amount.
223 base_target_delay_ms_ = target_delay_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000224}
225
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000226} // namespace webrtc