Home | History | Annotate | Download | only in video
      1 /*
      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 
     11 #include "webrtc/video/stream_synchronization.h"
     12 
     13 #include <assert.h>
     14 #include <math.h>
     15 #include <stdlib.h>
     16 
     17 #include <algorithm>
     18 
     19 #include "webrtc/base/logging.h"
     20 
     21 namespace webrtc {
     22 
     23 static const int kMaxChangeMs = 80;
     24 static const int kMaxDeltaDelayMs = 10000;
     25 static const int kFilterLength = 4;
     26 // Minimum difference between audio and video to warrant a change.
     27 static const int kMinDeltaMs = 30;
     28 
     29 struct ViESyncDelay {
     30   ViESyncDelay() {
     31     extra_video_delay_ms = 0;
     32     last_video_delay_ms = 0;
     33     extra_audio_delay_ms = 0;
     34     last_audio_delay_ms = 0;
     35     network_delay = 120;
     36   }
     37 
     38   int extra_video_delay_ms;
     39   int last_video_delay_ms;
     40   int extra_audio_delay_ms;
     41   int last_audio_delay_ms;
     42   int network_delay;
     43 };
     44 
     45 StreamSynchronization::StreamSynchronization(uint32_t video_primary_ssrc,
     46                                              int audio_channel_id)
     47     : channel_delay_(new ViESyncDelay),
     48       video_primary_ssrc_(video_primary_ssrc),
     49       audio_channel_id_(audio_channel_id),
     50       base_target_delay_ms_(0),
     51       avg_diff_ms_(0) {
     52 }
     53 
     54 StreamSynchronization::~StreamSynchronization() {
     55   delete channel_delay_;
     56 }
     57 
     58 bool 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;
     66   }
     67   int64_t audio_last_capture_time_ms;
     68   if (!RtpToNtpMs(audio_measurement.latest_timestamp,
     69                   audio_measurement.rtcp,
     70                   &audio_last_capture_time_ms)) {
     71     return false;
     72   }
     73   int64_t video_last_capture_time_ms;
     74   if (!RtpToNtpMs(video_measurement.latest_timestamp,
     75                   video_measurement.rtcp,
     76                   &video_last_capture_time_ms)) {
     77     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);
     86   if (*relative_delay_ms > kMaxDeltaDelayMs ||
     87       *relative_delay_ms < -kMaxDeltaDelayMs) {
     88     return false;
     89   }
     90   return true;
     91 }
     92 
     93 bool StreamSynchronization::ComputeDelays(int relative_delay_ms,
     94                                           int current_audio_delay_ms,
     95                                           int* total_audio_delay_target_ms,
     96                                           int* total_video_delay_target_ms) {
     97   assert(total_audio_delay_target_ms && total_video_delay_target_ms);
     98 
     99   int current_video_delay_ms = *total_video_delay_target_ms;
    100   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_;
    104   // Calculate the difference between the lowest possible video delay and
    105   // the current audio delay.
    106   int current_diff_ms = current_video_delay_ms - current_audio_delay_ms +
    107       relative_delay_ms;
    108 
    109   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 
    121   // Reset the average after a move to prevent overshooting reaction.
    122   avg_diff_ms_ = 0;
    123 
    124   if (diff_ms > 0) {
    125     // The minimum video delay is longer than the current audio delay.
    126     // We need to decrease extra video delay, or add extra audio delay.
    127     if (channel_delay_->extra_video_delay_ms > base_target_delay_ms_) {
    128       // We have extra delay added to ViE. Reduce this delay before adding
    129       // extra delay to VoE.
    130       channel_delay_->extra_video_delay_ms -= diff_ms;
    131       channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
    132     } else {  // channel_delay_->extra_video_delay_ms > 0
    133       // We have no extra video delay to remove, increase the audio delay.
    134       channel_delay_->extra_audio_delay_ms += diff_ms;
    135       channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
    136     }
    137   } else {  // if (diff_ms > 0)
    138     // The video delay is lower than the current audio delay.
    139     // We need to decrease extra audio delay, or add extra video delay.
    140     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.
    143       // Note: diff_ms is negative; add the negative difference.
    144       channel_delay_->extra_audio_delay_ms += diff_ms;
    145       channel_delay_->extra_video_delay_ms = base_target_delay_ms_;
    146     } else {  // channel_delay_->extra_audio_delay_ms > base_target_delay_ms_
    147       // We have no extra delay in VoiceEngine, increase the video delay.
    148       // Note: diff_ms is negative; subtract the negative difference.
    149       channel_delay_->extra_video_delay_ms -= diff_ms;  // X - (-Y) = X + Y.
    150       channel_delay_->extra_audio_delay_ms = base_target_delay_ms_;
    151     }
    152   }
    153 
    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 
    175   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);
    187 
    188   // Verify we don't go above the maximum allowed audio delay.
    189   new_audio_delay_ms =
    190       std::min(new_audio_delay_ms, base_target_delay_ms_ + kMaxDeltaDelayMs);
    191 
    192   // Remember our last audio and video delays.
    193   channel_delay_->last_video_delay_ms = new_video_delay_ms;
    194   channel_delay_->last_audio_delay_ms = new_audio_delay_ms;
    195 
    196   LOG(LS_VERBOSE) << "Sync video delay " << new_video_delay_ms
    197                   << " for video primary SSRC " << video_primary_ssrc_
    198                   << " and audio delay " << channel_delay_->extra_audio_delay_ms
    199                   << " for audio channel " << audio_channel_id_;
    200 
    201   // Return values.
    202   *total_video_delay_target_ms = new_video_delay_ms;
    203   *total_audio_delay_target_ms = new_audio_delay_ms;
    204   return true;
    205 }
    206 
    207 void StreamSynchronization::SetTargetBufferingDelay(int target_delay_ms) {
    208   // 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_;
    211   channel_delay_->last_audio_delay_ms +=
    212       target_delay_ms - base_target_delay_ms_;
    213 
    214   // 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_;
    218 
    219   channel_delay_->extra_video_delay_ms +=
    220       target_delay_ms - base_target_delay_ms_;
    221 
    222   // Video is already delayed by the desired amount.
    223   base_target_delay_ms_ = target_delay_ms;
    224 }
    225 
    226 }  // namespace webrtc
    227