blob: f47037d0ed1e6d793c09fee88c8931287371b072 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "video/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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_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
solenberg3ebbcb52017-01-31 03:58:40 -080029StreamSynchronization::StreamSynchronization(int video_stream_id,
30 int audio_stream_id)
31 : video_stream_id_(video_stream_id),
32 audio_stream_id_(audio_stream_id),
pwestin@webrtc.org63117332013-04-22 18:57:14 +000033 base_target_delay_ms_(0),
Peter Boström36a14382015-05-21 17:00:24 +020034 avg_diff_ms_(0) {
35}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000036
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000037bool StreamSynchronization::ComputeRelativeDelay(
38 const Measurements& audio_measurement,
39 const Measurements& video_measurement,
40 int* relative_delay_ms) {
41 assert(relative_delay_ms);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000042 int64_t audio_last_capture_time_ms;
asaperssonfe50b4d2016-12-22 07:53:51 -080043 if (!audio_measurement.rtp_to_ntp.Estimate(audio_measurement.latest_timestamp,
44 &audio_last_capture_time_ms)) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000045 return false;
46 }
47 int64_t video_last_capture_time_ms;
asaperssonfe50b4d2016-12-22 07:53:51 -080048 if (!video_measurement.rtp_to_ntp.Estimate(video_measurement.latest_timestamp,
49 &video_last_capture_time_ms)) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000050 return false;
51 }
52 if (video_last_capture_time_ms < 0) {
53 return false;
54 }
55 // Positive diff means that video_measurement is behind audio_measurement.
56 *relative_delay_ms = video_measurement.latest_receive_time_ms -
57 audio_measurement.latest_receive_time_ms -
58 (video_last_capture_time_ms - audio_last_capture_time_ms);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000059 if (*relative_delay_ms > kMaxDeltaDelayMs ||
60 *relative_delay_ms < -kMaxDeltaDelayMs) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000061 return false;
62 }
63 return true;
64}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000065
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000066bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
67 int current_audio_delay_ms,
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000068 int* total_audio_delay_target_ms,
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000069 int* total_video_delay_target_ms) {
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000070 assert(total_audio_delay_target_ms && total_video_delay_target_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000071
72 int current_video_delay_ms = *total_video_delay_target_ms;
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000073 LOG(LS_VERBOSE) << "Audio delay: " << current_audio_delay_ms
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000074 << " current diff: " << relative_delay_ms
solenberg3ebbcb52017-01-31 03:58:40 -080075 << " for stream " << audio_stream_id_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000076 // Calculate the difference between the lowest possible video delay and
77 // the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000078 int current_diff_ms = current_video_delay_ms - current_audio_delay_ms +
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000079 relative_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000080
pwestin@webrtc.org63117332013-04-22 18:57:14 +000081 avg_diff_ms_ = ((kFilterLength - 1) * avg_diff_ms_ +
82 current_diff_ms) / kFilterLength;
83 if (abs(avg_diff_ms_) < kMinDeltaMs) {
84 // Don't adjust if the diff is within our margin.
85 return false;
86 }
87
88 // Make sure we don't move too fast.
89 int diff_ms = avg_diff_ms_ / 2;
90 diff_ms = std::min(diff_ms, kMaxChangeMs);
91 diff_ms = std::max(diff_ms, -kMaxChangeMs);
92
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000093 // Reset the average after a move to prevent overshooting reaction.
94 avg_diff_ms_ = 0;
95
pwestin@webrtc.org63117332013-04-22 18:57:14 +000096 if (diff_ms > 0) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +000097 // The minimum video delay is longer than the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000098 // We need to decrease extra video delay, or add extra audio delay.
mflodman4cd27902016-08-05 06:28:45 -070099 if (channel_delay_.extra_video_delay_ms > base_target_delay_ms_) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000100 // We have extra delay added to ViE. Reduce this delay before adding
101 // extra delay to VoE.
mflodman4cd27902016-08-05 06:28:45 -0700102 channel_delay_.extra_video_delay_ms -= diff_ms;
103 channel_delay_.extra_audio_delay_ms = base_target_delay_ms_;
104 } else { // channel_delay_.extra_video_delay_ms > 0
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000105 // We have no extra video delay to remove, increase the audio delay.
mflodman4cd27902016-08-05 06:28:45 -0700106 channel_delay_.extra_audio_delay_ms += diff_ms;
107 channel_delay_.extra_video_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000108 }
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000109 } else { // if (diff_ms > 0)
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000110 // The video delay is lower than the current audio delay.
111 // We need to decrease extra audio delay, or add extra video delay.
mflodman4cd27902016-08-05 06:28:45 -0700112 if (channel_delay_.extra_audio_delay_ms > base_target_delay_ms_) {
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000113 // We have extra delay in VoiceEngine.
114 // Start with decreasing the voice delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000115 // Note: diff_ms is negative; add the negative difference.
mflodman4cd27902016-08-05 06:28:45 -0700116 channel_delay_.extra_audio_delay_ms += diff_ms;
117 channel_delay_.extra_video_delay_ms = base_target_delay_ms_;
118 } else { // channel_delay_.extra_audio_delay_ms > base_target_delay_ms_
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000119 // We have no extra delay in VoiceEngine, increase the video delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000120 // Note: diff_ms is negative; subtract the negative difference.
mflodman4cd27902016-08-05 06:28:45 -0700121 channel_delay_.extra_video_delay_ms -= diff_ms; // X - (-Y) = X + Y.
122 channel_delay_.extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000123 }
124 }
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000125
126 // Make sure that video is never below our target.
mflodman4cd27902016-08-05 06:28:45 -0700127 channel_delay_.extra_video_delay_ms = std::max(
128 channel_delay_.extra_video_delay_ms, base_target_delay_ms_);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000129
130 int new_video_delay_ms;
mflodman4cd27902016-08-05 06:28:45 -0700131 if (channel_delay_.extra_video_delay_ms > base_target_delay_ms_) {
132 new_video_delay_ms = channel_delay_.extra_video_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000133 } else {
134 // No change to the extra video delay. We are changing audio and we only
135 // allow to change one at the time.
mflodman4cd27902016-08-05 06:28:45 -0700136 new_video_delay_ms = channel_delay_.last_video_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000137 }
138
139 // Make sure that we don't go below the extra video delay.
140 new_video_delay_ms = std::max(
mflodman4cd27902016-08-05 06:28:45 -0700141 new_video_delay_ms, channel_delay_.extra_video_delay_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000142
143 // Verify we don't go above the maximum allowed video delay.
144 new_video_delay_ms =
145 std::min(new_video_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
146
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000147 int new_audio_delay_ms;
mflodman4cd27902016-08-05 06:28:45 -0700148 if (channel_delay_.extra_audio_delay_ms > base_target_delay_ms_) {
149 new_audio_delay_ms = channel_delay_.extra_audio_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000150 } else {
151 // No change to the audio delay. We are changing video and we only
152 // allow to change one at the time.
mflodman4cd27902016-08-05 06:28:45 -0700153 new_audio_delay_ms = channel_delay_.last_audio_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000154 }
155
156 // Make sure that we don't go below the extra audio delay.
157 new_audio_delay_ms = std::max(
mflodman4cd27902016-08-05 06:28:45 -0700158 new_audio_delay_ms, channel_delay_.extra_audio_delay_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000159
160 // Verify we don't go above the maximum allowed audio delay.
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000161 new_audio_delay_ms =
162 std::min(new_audio_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000163
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000164 // Remember our last audio and video delays.
mflodman4cd27902016-08-05 06:28:45 -0700165 channel_delay_.last_video_delay_ms = new_video_delay_ms;
166 channel_delay_.last_audio_delay_ms = new_audio_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000167
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000168 LOG(LS_VERBOSE) << "Sync video delay " << new_video_delay_ms
solenberg3ebbcb52017-01-31 03:58:40 -0800169 << " for video stream " << video_stream_id_
mflodman4cd27902016-08-05 06:28:45 -0700170 << " and audio delay " << channel_delay_.extra_audio_delay_ms
solenberg3ebbcb52017-01-31 03:58:40 -0800171 << " for audio stream " << audio_stream_id_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000172
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000173 // Return values.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000174 *total_video_delay_target_ms = new_video_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000175 *total_audio_delay_target_ms = new_audio_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000176 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000177}
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000178
179void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000180 // Initial extra delay for audio (accounting for existing extra delay).
mflodman4cd27902016-08-05 06:28:45 -0700181 channel_delay_.extra_audio_delay_ms +=
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000182 target_delay_ms - base_target_delay_ms_;
mflodman4cd27902016-08-05 06:28:45 -0700183 channel_delay_.last_audio_delay_ms +=
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000184 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000185
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000186 // The video delay is compared to the last value (and how much we can update
187 // is limited by that as well).
mflodman4cd27902016-08-05 06:28:45 -0700188 channel_delay_.last_video_delay_ms +=
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000189 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000190
mflodman4cd27902016-08-05 06:28:45 -0700191 channel_delay_.extra_video_delay_ms +=
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000192 target_delay_ms - base_target_delay_ms_;
193
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000194 // Video is already delayed by the desired amount.
195 base_target_delay_ms_ = target_delay_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000196}
197
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000198} // namespace webrtc