blob: 906f7dfbace9e22f98c13c896cf159e1e50d28e5 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
leozwang@webrtc.org39e96592012-03-01 18:22:48 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000011#include "webrtc/video_engine/vie_sync_module.h"
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000012
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +000013#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000014#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
15#include "webrtc/modules/video_coding/main/interface/video_coding.h"
16#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
17#include "webrtc/system_wrappers/interface/trace.h"
18#include "webrtc/system_wrappers/interface/trace_event.h"
19#include "webrtc/video_engine/stream_synchronization.h"
20#include "webrtc/video_engine/vie_channel.h"
21#include "webrtc/voice_engine/include/voe_video_sync.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000022
23namespace webrtc {
24
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000025enum { kSyncInterval = 1000};
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000026
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000027int UpdateMeasurements(StreamSynchronization::Measurements* stream,
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +000028 const RtpRtcp& rtp_rtcp, const RtpReceiver& receiver) {
29 stream->latest_timestamp = receiver.TimeStamp();
30 stream->latest_receive_time_ms = receiver.LastReceivedTimeMs();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000031 synchronization::RtcpMeasurement measurement;
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +000032 if (0 != rtp_rtcp.RemoteNTP(&measurement.ntp_secs,
33 &measurement.ntp_frac,
34 NULL,
35 NULL,
36 &measurement.rtp_timestamp)) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000037 return -1;
38 }
39 if (measurement.ntp_secs == 0 && measurement.ntp_frac == 0) {
40 return -1;
41 }
42 for (synchronization::RtcpList::iterator it = stream->rtcp.begin();
43 it != stream->rtcp.end(); ++it) {
44 if (measurement.ntp_secs == (*it).ntp_secs &&
45 measurement.ntp_frac == (*it).ntp_frac) {
46 // This RTCP has already been added to the list.
47 return 0;
48 }
49 }
50 // We need two RTCP SR reports to map between RTP and NTP. More than two will
51 // not improve the mapping.
52 if (stream->rtcp.size() == 2) {
53 stream->rtcp.pop_back();
54 }
55 stream->rtcp.push_front(measurement);
56 return 0;
57}
58
59ViESyncModule::ViESyncModule(VideoCodingModule* vcm,
60 ViEChannel* vie_channel)
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +000061 : data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000062 vcm_(vcm),
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000063 vie_channel_(vie_channel),
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +000064 video_receiver_(NULL),
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000065 video_rtp_rtcp_(NULL),
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000066 voe_channel_id_(-1),
67 voe_sync_interface_(NULL),
stefan@webrtc.org5f284982012-06-28 07:51:16 +000068 last_sync_time_(TickTime::Now()),
69 sync_() {
niklase@google.com470e71d2011-07-07 08:21:25 +000070}
71
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000072ViESyncModule::~ViESyncModule() {
niklase@google.com470e71d2011-07-07 08:21:25 +000073}
74
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000075int ViESyncModule::ConfigureSync(int voe_channel_id,
76 VoEVideoSync* voe_sync_interface,
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +000077 RtpRtcp* video_rtcp_module,
78 RtpReceiver* video_receiver) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +000079 CriticalSectionScoped cs(data_cs_.get());
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000080 voe_channel_id_ = voe_channel_id;
81 voe_sync_interface_ = voe_sync_interface;
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +000082 video_receiver_ = video_receiver;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000083 video_rtp_rtcp_ = video_rtcp_module;
84 sync_.reset(new StreamSynchronization(voe_channel_id, vie_channel_->Id()));
niklase@google.com470e71d2011-07-07 08:21:25 +000085
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000086 if (!voe_sync_interface) {
87 voe_channel_id_ = -1;
88 if (voe_channel_id >= 0) {
89 // Trying to set a voice channel but no interface exist.
90 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000091 }
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000092 return 0;
93 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000094 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000095}
96
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +000097int ViESyncModule::VoiceChannel() {
98 return voe_channel_id_;
niklase@google.com470e71d2011-07-07 08:21:25 +000099}
100
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000101int32_t ViESyncModule::TimeUntilNextProcess() {
102 return static_cast<int32_t>(kSyncInterval -
103 (TickTime::Now() - last_sync_time_).Milliseconds());
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000104}
105
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000106int32_t ViESyncModule::Process() {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000107 CriticalSectionScoped cs(data_cs_.get());
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000108 last_sync_time_ = TickTime::Now();
109
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000110 const int current_video_delay_ms = vcm_->Delay();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000111 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000112 "Video delay (JB + decoder) is %d ms", current_video_delay_ms);
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000113
114 if (voe_channel_id_ == -1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000115 return 0;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000116 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000117 assert(video_rtp_rtcp_ && voe_sync_interface_);
stefan@webrtc.org5f284982012-06-28 07:51:16 +0000118 assert(sync_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000119
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000120 int audio_jitter_buffer_delay_ms = 0;
121 int playout_buffer_delay_ms = 0;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000122 if (voe_sync_interface_->GetDelayEstimate(voe_channel_id_,
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000123 &audio_jitter_buffer_delay_ms,
124 &playout_buffer_delay_ms) != 0) {
125 // Could not get VoE delay value, probably not a valid channel Id or
126 // the channel have not received enough packets.
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000127 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, vie_channel_->Id(),
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000128 "%s: VE_GetDelayEstimate error for voice_channel %d",
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000129 __FUNCTION__, voe_channel_id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 return 0;
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000131 }
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000132 const int current_audio_delay_ms = audio_jitter_buffer_delay_ms +
133 playout_buffer_delay_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +0000134
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000135 RtpRtcp* voice_rtp_rtcp = NULL;
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000136 RtpReceiver* voice_receiver = NULL;
137 if (0 != voe_sync_interface_->GetRtpRtcp(voe_channel_id_, &voice_rtp_rtcp,
138 &voice_receiver)) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000139 return 0;
140 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000141 assert(voice_rtp_rtcp);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000142 assert(voice_receiver);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000143
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000144 if (UpdateMeasurements(&video_measurement_, *video_rtp_rtcp_,
145 *video_receiver_) != 0) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000146 return 0;
147 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000148
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000149 if (UpdateMeasurements(&audio_measurement_, *voice_rtp_rtcp,
150 *voice_receiver) != 0) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000151 return 0;
152 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000153
154 int relative_delay_ms;
155 // Calculate how much later or earlier the audio stream is compared to video.
156 if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
157 &relative_delay_ms)) {
158 return 0;
159 }
160
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000161 TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay", current_video_delay_ms);
162 TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay", current_audio_delay_ms);
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000163 TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000164 int target_audio_delay_ms = 0;
hclam@chromium.org7262ad12013-06-15 06:51:27 +0000165 int target_video_delay_ms = current_video_delay_ms;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000166 // Calculate the necessary extra audio delay and desired total video
167 // delay to get the streams in sync.
stefan@webrtc.org8d185262012-11-12 18:51:52 +0000168 if (!sync_->ComputeDelays(relative_delay_ms,
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000169 current_audio_delay_ms,
170 &target_audio_delay_ms,
171 &target_video_delay_ms)) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000172 return 0;
173 }
edjee@google.com79b02892013-04-04 19:43:34 +0000174
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000175 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
176 "Set delay current(a=%d v=%d rel=%d) target(a=%d v=%d)",
177 current_audio_delay_ms, current_video_delay_ms,
178 relative_delay_ms,
179 target_audio_delay_ms, target_video_delay_ms);
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000180 if (voe_sync_interface_->SetMinimumPlayoutDelay(
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000181 voe_channel_id_, target_audio_delay_ms) == -1) {
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000182 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, vie_channel_->Id(),
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000183 "Error setting voice delay");
184 }
hclam@chromium.org9b23ecb2013-06-14 23:30:58 +0000185 vcm_->SetMinimumPlayoutDelay(target_video_delay_ms);
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000186 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000187}
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000188
mikhal@webrtc.orgefe4edb2013-03-06 23:29:33 +0000189int ViESyncModule::SetTargetBufferingDelay(int target_delay_ms) {
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000190 CriticalSectionScoped cs(data_cs_.get());
mikhal@webrtc.orgefe4edb2013-03-06 23:29:33 +0000191 if (!voe_sync_interface_) {
192 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
193 "voe_sync_interface_ NULL, can't set playout delay.");
194 return -1;
195 }
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000196 sync_->SetTargetBufferingDelay(target_delay_ms);
197 // Setting initial playout delay to voice engine (video engine is updated via
198 // the VCM interface).
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000199 voe_sync_interface_->SetInitialPlayoutDelay(voe_channel_id_,
200 target_delay_ms);
mikhal@webrtc.orgefe4edb2013-03-06 23:29:33 +0000201 return 0;
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000202}
203
mflodman@webrtc.org511f82e2011-11-30 18:31:36 +0000204} // namespace webrtc