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