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/vie_sync_module.h"
     12 
     13 #include "webrtc/base/logging.h"
     14 #include "webrtc/base/trace_event.h"
     15 #include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
     16 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
     17 #include "webrtc/modules/video_coding/include/video_coding.h"
     18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
     19 #include "webrtc/video/stream_synchronization.h"
     20 #include "webrtc/voice_engine/include/voe_video_sync.h"
     21 
     22 namespace webrtc {
     23 
     24 int UpdateMeasurements(StreamSynchronization::Measurements* stream,
     25                        const RtpRtcp& rtp_rtcp, const RtpReceiver& receiver) {
     26   if (!receiver.Timestamp(&stream->latest_timestamp))
     27     return -1;
     28   if (!receiver.LastReceivedTimeMs(&stream->latest_receive_time_ms))
     29     return -1;
     30 
     31   uint32_t ntp_secs = 0;
     32   uint32_t ntp_frac = 0;
     33   uint32_t rtp_timestamp = 0;
     34   if (0 != rtp_rtcp.RemoteNTP(&ntp_secs,
     35                               &ntp_frac,
     36                               NULL,
     37                               NULL,
     38                               &rtp_timestamp)) {
     39     return -1;
     40   }
     41 
     42   bool new_rtcp_sr = false;
     43   if (!UpdateRtcpList(
     44       ntp_secs, ntp_frac, rtp_timestamp, &stream->rtcp, &new_rtcp_sr)) {
     45     return -1;
     46   }
     47 
     48   return 0;
     49 }
     50 
     51 ViESyncModule::ViESyncModule(VideoCodingModule* vcm)
     52     : data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
     53       vcm_(vcm),
     54       video_receiver_(NULL),
     55       video_rtp_rtcp_(NULL),
     56       voe_channel_id_(-1),
     57       voe_sync_interface_(NULL),
     58       last_sync_time_(TickTime::Now()),
     59       sync_() {
     60 }
     61 
     62 ViESyncModule::~ViESyncModule() {
     63 }
     64 
     65 int ViESyncModule::ConfigureSync(int voe_channel_id,
     66                                  VoEVideoSync* voe_sync_interface,
     67                                  RtpRtcp* video_rtcp_module,
     68                                  RtpReceiver* video_receiver) {
     69   CriticalSectionScoped cs(data_cs_.get());
     70   // Prevent expensive no-ops.
     71   if (voe_channel_id_ == voe_channel_id &&
     72       voe_sync_interface_ == voe_sync_interface &&
     73       video_receiver_ == video_receiver &&
     74       video_rtp_rtcp_ == video_rtcp_module) {
     75     return 0;
     76   }
     77   voe_channel_id_ = voe_channel_id;
     78   voe_sync_interface_ = voe_sync_interface;
     79   video_receiver_ = video_receiver;
     80   video_rtp_rtcp_ = video_rtcp_module;
     81   sync_.reset(
     82       new StreamSynchronization(video_rtp_rtcp_->SSRC(), voe_channel_id));
     83 
     84   if (!voe_sync_interface) {
     85     voe_channel_id_ = -1;
     86     if (voe_channel_id >= 0) {
     87       // Trying to set a voice channel but no interface exist.
     88       return -1;
     89     }
     90     return 0;
     91   }
     92   return 0;
     93 }
     94 
     95 int ViESyncModule::VoiceChannel() {
     96   return voe_channel_id_;
     97 }
     98 
     99 int64_t ViESyncModule::TimeUntilNextProcess() {
    100   const int64_t kSyncIntervalMs = 1000;
    101   return kSyncIntervalMs - (TickTime::Now() - last_sync_time_).Milliseconds();
    102 }
    103 
    104 int32_t ViESyncModule::Process() {
    105   CriticalSectionScoped cs(data_cs_.get());
    106   last_sync_time_ = TickTime::Now();
    107 
    108   const int current_video_delay_ms = vcm_->Delay();
    109 
    110   if (voe_channel_id_ == -1) {
    111     return 0;
    112   }
    113   assert(video_rtp_rtcp_ && voe_sync_interface_);
    114   assert(sync_.get());
    115 
    116   int audio_jitter_buffer_delay_ms = 0;
    117   int playout_buffer_delay_ms = 0;
    118   if (voe_sync_interface_->GetDelayEstimate(voe_channel_id_,
    119                                             &audio_jitter_buffer_delay_ms,
    120                                             &playout_buffer_delay_ms) != 0) {
    121     return 0;
    122   }
    123   const int current_audio_delay_ms = audio_jitter_buffer_delay_ms +
    124       playout_buffer_delay_ms;
    125 
    126   RtpRtcp* voice_rtp_rtcp = NULL;
    127   RtpReceiver* voice_receiver = NULL;
    128   if (0 != voe_sync_interface_->GetRtpRtcp(voe_channel_id_, &voice_rtp_rtcp,
    129                                            &voice_receiver)) {
    130     return 0;
    131   }
    132   assert(voice_rtp_rtcp);
    133   assert(voice_receiver);
    134 
    135   if (UpdateMeasurements(&video_measurement_, *video_rtp_rtcp_,
    136                          *video_receiver_) != 0) {
    137     return 0;
    138   }
    139 
    140   if (UpdateMeasurements(&audio_measurement_, *voice_rtp_rtcp,
    141                          *voice_receiver) != 0) {
    142     return 0;
    143   }
    144 
    145   int relative_delay_ms;
    146   // Calculate how much later or earlier the audio stream is compared to video.
    147   if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
    148                                    &relative_delay_ms)) {
    149     return 0;
    150   }
    151 
    152   TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay", current_video_delay_ms);
    153   TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay", current_audio_delay_ms);
    154   TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
    155   int target_audio_delay_ms = 0;
    156   int target_video_delay_ms = current_video_delay_ms;
    157   // Calculate the necessary extra audio delay and desired total video
    158   // delay to get the streams in sync.
    159   if (!sync_->ComputeDelays(relative_delay_ms,
    160                             current_audio_delay_ms,
    161                             &target_audio_delay_ms,
    162                             &target_video_delay_ms)) {
    163     return 0;
    164   }
    165 
    166   if (voe_sync_interface_->SetMinimumPlayoutDelay(
    167       voe_channel_id_, target_audio_delay_ms) == -1) {
    168     LOG(LS_ERROR) << "Error setting voice delay.";
    169   }
    170   vcm_->SetMinimumPlayoutDelay(target_video_delay_ms);
    171   return 0;
    172 }
    173 
    174 }  // namespace webrtc
    175