• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
UpdateMeasurements(StreamSynchronization::Measurements * stream,const RtpRtcp & rtp_rtcp,const RtpReceiver & receiver)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 
ViESyncModule(VideoCodingModule * vcm)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 
~ViESyncModule()62 ViESyncModule::~ViESyncModule() {
63 }
64 
ConfigureSync(int voe_channel_id,VoEVideoSync * voe_sync_interface,RtpRtcp * video_rtcp_module,RtpReceiver * video_receiver)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 
VoiceChannel()95 int ViESyncModule::VoiceChannel() {
96   return voe_channel_id_;
97 }
98 
TimeUntilNextProcess()99 int64_t ViESyncModule::TimeUntilNextProcess() {
100   const int64_t kSyncIntervalMs = 1000;
101   return kSyncIntervalMs - (TickTime::Now() - last_sync_time_).Milliseconds();
102 }
103 
Process()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