blob: ff389736f4bd09883ac89d188a3d334e27c3545b [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
Peter Boström7623ce42015-12-09 12:13:30 +010011#include "webrtc/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
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
Peter Boström36a14382015-05-21 17:00:24 +020029StreamSynchronization::StreamSynchronization(uint32_t video_primary_ssrc,
30 int audio_channel_id)
mflodman4cd27902016-08-05 06:28:45 -070031 : video_primary_ssrc_(video_primary_ssrc),
stefan@webrtc.org5f284982012-06-28 07:51:16 +000032 audio_channel_id_(audio_channel_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;
wu@webrtc.org66773a02014-05-07 17:09:44 +000043 if (!RtpToNtpMs(audio_measurement.latest_timestamp,
44 audio_measurement.rtcp,
45 &audio_last_capture_time_ms)) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000046 return false;
47 }
48 int64_t video_last_capture_time_ms;
wu@webrtc.org66773a02014-05-07 17:09:44 +000049 if (!RtpToNtpMs(video_measurement.latest_timestamp,
50 video_measurement.rtcp,
51 &video_last_capture_time_ms)) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000052 return false;
53 }
54 if (video_last_capture_time_ms < 0) {
55 return false;
56 }
57 // Positive diff means that video_measurement is behind audio_measurement.
58 *relative_delay_ms = video_measurement.latest_receive_time_ms -
59 audio_measurement.latest_receive_time_ms -
60 (video_last_capture_time_ms - audio_last_capture_time_ms);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000061 if (*relative_delay_ms > kMaxDeltaDelayMs ||
62 *relative_delay_ms < -kMaxDeltaDelayMs) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000063 return false;
64 }
65 return true;
66}
stefan@webrtc.org5f284982012-06-28 07:51:16 +000067
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000068bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
69 int current_audio_delay_ms,
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000070 int* total_audio_delay_target_ms,
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000071 int* total_video_delay_target_ms) {
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +000072 assert(total_audio_delay_target_ms && total_video_delay_target_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000073
74 int current_video_delay_ms = *total_video_delay_target_ms;
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000075 LOG(LS_VERBOSE) << "Audio delay: " << current_audio_delay_ms
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000076 << " current diff: " << relative_delay_ms
77 << " for channel " << audio_channel_id_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000078 // Calculate the difference between the lowest possible video delay and
79 // the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000080 int current_diff_ms = current_video_delay_ms - current_audio_delay_ms +
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000081 relative_delay_ms;
stefan@webrtc.org5f284982012-06-28 07:51:16 +000082
pwestin@webrtc.org63117332013-04-22 18:57:14 +000083 avg_diff_ms_ = ((kFilterLength - 1) * avg_diff_ms_ +
84 current_diff_ms) / kFilterLength;
85 if (abs(avg_diff_ms_) < kMinDeltaMs) {
86 // Don't adjust if the diff is within our margin.
87 return false;
88 }
89
90 // Make sure we don't move too fast.
91 int diff_ms = avg_diff_ms_ / 2;
92 diff_ms = std::min(diff_ms, kMaxChangeMs);
93 diff_ms = std::max(diff_ms, -kMaxChangeMs);
94
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +000095 // Reset the average after a move to prevent overshooting reaction.
96 avg_diff_ms_ = 0;
97
pwestin@webrtc.org63117332013-04-22 18:57:14 +000098 if (diff_ms > 0) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +000099 // The minimum video delay is longer than the current audio delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000100 // We need to decrease extra video delay, or add extra audio delay.
mflodman4cd27902016-08-05 06:28:45 -0700101 if (channel_delay_.extra_video_delay_ms > base_target_delay_ms_) {
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000102 // We have extra delay added to ViE. Reduce this delay before adding
103 // extra delay to VoE.
mflodman4cd27902016-08-05 06:28:45 -0700104 channel_delay_.extra_video_delay_ms -= diff_ms;
105 channel_delay_.extra_audio_delay_ms = base_target_delay_ms_;
106 } else { // channel_delay_.extra_video_delay_ms > 0
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000107 // We have no extra video delay to remove, increase the audio delay.
mflodman4cd27902016-08-05 06:28:45 -0700108 channel_delay_.extra_audio_delay_ms += diff_ms;
109 channel_delay_.extra_video_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000110 }
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000111 } else { // if (diff_ms > 0)
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000112 // The video delay is lower than the current audio delay.
113 // We need to decrease extra audio delay, or add extra video delay.
mflodman4cd27902016-08-05 06:28:45 -0700114 if (channel_delay_.extra_audio_delay_ms > base_target_delay_ms_) {
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000115 // We have extra delay in VoiceEngine.
116 // Start with decreasing the voice delay.
pwestin@webrtc.org63117332013-04-22 18:57:14 +0000117 // Note: diff_ms is negative; add the negative difference.
mflodman4cd27902016-08-05 06:28:45 -0700118 channel_delay_.extra_audio_delay_ms += diff_ms;
119 channel_delay_.extra_video_delay_ms = base_target_delay_ms_;
120 } else { // channel_delay_.extra_audio_delay_ms > base_target_delay_ms_
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000121 // We have no extra delay in VoiceEngine, increase the video delay.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000122 // Note: diff_ms is negative; subtract the negative difference.
mflodman4cd27902016-08-05 06:28:45 -0700123 channel_delay_.extra_video_delay_ms -= diff_ms; // X - (-Y) = X + Y.
124 channel_delay_.extra_audio_delay_ms = base_target_delay_ms_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000125 }
126 }
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000127
128 // Make sure that video is never below our target.
mflodman4cd27902016-08-05 06:28:45 -0700129 channel_delay_.extra_video_delay_ms = std::max(
130 channel_delay_.extra_video_delay_ms, base_target_delay_ms_);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000131
132 int new_video_delay_ms;
mflodman4cd27902016-08-05 06:28:45 -0700133 if (channel_delay_.extra_video_delay_ms > base_target_delay_ms_) {
134 new_video_delay_ms = channel_delay_.extra_video_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000135 } else {
136 // No change to the extra video delay. We are changing audio and we only
137 // allow to change one at the time.
mflodman4cd27902016-08-05 06:28:45 -0700138 new_video_delay_ms = channel_delay_.last_video_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000139 }
140
141 // Make sure that we don't go below the extra video delay.
142 new_video_delay_ms = std::max(
mflodman4cd27902016-08-05 06:28:45 -0700143 new_video_delay_ms, channel_delay_.extra_video_delay_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000144
145 // Verify we don't go above the maximum allowed video delay.
146 new_video_delay_ms =
147 std::min(new_video_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
148
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000149 int new_audio_delay_ms;
mflodman4cd27902016-08-05 06:28:45 -0700150 if (channel_delay_.extra_audio_delay_ms > base_target_delay_ms_) {
151 new_audio_delay_ms = channel_delay_.extra_audio_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000152 } else {
153 // No change to the audio delay. We are changing video and we only
154 // allow to change one at the time.
mflodman4cd27902016-08-05 06:28:45 -0700155 new_audio_delay_ms = channel_delay_.last_audio_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000156 }
157
158 // Make sure that we don't go below the extra audio delay.
159 new_audio_delay_ms = std::max(
mflodman4cd27902016-08-05 06:28:45 -0700160 new_audio_delay_ms, channel_delay_.extra_audio_delay_ms);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000161
162 // Verify we don't go above the maximum allowed audio delay.
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000163 new_audio_delay_ms =
164 std::min(new_audio_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000165
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000166 // Remember our last audio and video delays.
mflodman4cd27902016-08-05 06:28:45 -0700167 channel_delay_.last_video_delay_ms = new_video_delay_ms;
168 channel_delay_.last_audio_delay_ms = new_audio_delay_ms;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000169
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000170 LOG(LS_VERBOSE) << "Sync video delay " << new_video_delay_ms
Peter Boström36a14382015-05-21 17:00:24 +0200171 << " for video primary SSRC " << video_primary_ssrc_
mflodman4cd27902016-08-05 06:28:45 -0700172 << " and audio delay " << channel_delay_.extra_audio_delay_ms
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000173 << " for audio channel " << audio_channel_id_;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000174
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000175 // Return values.
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000176 *total_video_delay_target_ms = new_video_delay_ms;
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000177 *total_audio_delay_target_ms = new_audio_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000178 return true;
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000179}
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000180
181void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000182 // Initial extra delay for audio (accounting for existing extra delay).
mflodman4cd27902016-08-05 06:28:45 -0700183 channel_delay_.extra_audio_delay_ms +=
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000184 target_delay_ms - base_target_delay_ms_;
mflodman4cd27902016-08-05 06:28:45 -0700185 channel_delay_.last_audio_delay_ms +=
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000186 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000187
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000188 // The video delay is compared to the last value (and how much we can update
189 // is limited by that as well).
mflodman4cd27902016-08-05 06:28:45 -0700190 channel_delay_.last_video_delay_ms +=
mikhal@webrtc.org0d8d0102013-02-22 19:30:44 +0000191 target_delay_ms - base_target_delay_ms_;
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000192
mflodman4cd27902016-08-05 06:28:45 -0700193 channel_delay_.extra_video_delay_ms +=
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000194 target_delay_ms - base_target_delay_ms_;
195
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000196 // Video is already delayed by the desired amount.
197 base_target_delay_ms_ = target_delay_ms;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000198}
199
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000200} // namespace webrtc