1 /*
2 * Copyright (c) 2015 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/voice_engine/test/auto_test/fakes/conference_transport.h"
12
13 #include <string>
14
15 #include "webrtc/base/byteorder.h"
16 #include "webrtc/base/timeutils.h"
17 #include "webrtc/system_wrappers/include/sleep.h"
18
19 namespace {
20 static const unsigned int kReflectorSsrc = 0x0000;
21 static const unsigned int kLocalSsrc = 0x0001;
22 static const unsigned int kFirstRemoteSsrc = 0x0002;
23 static const webrtc::CodecInst kCodecInst =
24 {120, "opus", 48000, 960, 2, 64000};
25 static const int kAudioLevelHeaderId = 1;
26
ParseRtcpSsrc(const void * data,size_t len)27 static unsigned int ParseRtcpSsrc(const void* data, size_t len) {
28 const size_t ssrc_pos = 4;
29 unsigned int ssrc = 0;
30 if (len >= (ssrc_pos + sizeof(ssrc))) {
31 ssrc = rtc::GetBE32(static_cast<const char*>(data) + ssrc_pos);
32 }
33 return ssrc;
34 }
35 } // namespace
36
37 namespace voetest {
38
ConferenceTransport()39 ConferenceTransport::ConferenceTransport()
40 : pq_crit_(webrtc::CriticalSectionWrapper::CreateCriticalSection()),
41 stream_crit_(webrtc::CriticalSectionWrapper::CreateCriticalSection()),
42 packet_event_(webrtc::EventWrapper::Create()),
43 thread_(Run, this, "ConferenceTransport"),
44 rtt_ms_(0),
45 stream_count_(0),
46 rtp_header_parser_(webrtc::RtpHeaderParser::Create()) {
47 rtp_header_parser_->
48 RegisterRtpHeaderExtension(webrtc::kRtpExtensionAudioLevel,
49 kAudioLevelHeaderId);
50
51 local_voe_ = webrtc::VoiceEngine::Create();
52 local_base_ = webrtc::VoEBase::GetInterface(local_voe_);
53 local_network_ = webrtc::VoENetwork::GetInterface(local_voe_);
54 local_rtp_rtcp_ = webrtc::VoERTP_RTCP::GetInterface(local_voe_);
55
56 // In principle, we can use one VoiceEngine to achieve the same goal. Well, in
57 // here, we use two engines to make it more like reality.
58 remote_voe_ = webrtc::VoiceEngine::Create();
59 remote_base_ = webrtc::VoEBase::GetInterface(remote_voe_);
60 remote_codec_ = webrtc::VoECodec::GetInterface(remote_voe_);
61 remote_network_ = webrtc::VoENetwork::GetInterface(remote_voe_);
62 remote_rtp_rtcp_ = webrtc::VoERTP_RTCP::GetInterface(remote_voe_);
63 remote_file_ = webrtc::VoEFile::GetInterface(remote_voe_);
64
65 EXPECT_EQ(0, local_base_->Init());
66 local_sender_ = local_base_->CreateChannel();
67 EXPECT_EQ(0, local_network_->RegisterExternalTransport(local_sender_, *this));
68 EXPECT_EQ(0, local_rtp_rtcp_->SetLocalSSRC(local_sender_, kLocalSsrc));
69 EXPECT_EQ(0, local_rtp_rtcp_->
70 SetSendAudioLevelIndicationStatus(local_sender_, true,
71 kAudioLevelHeaderId));
72
73 EXPECT_EQ(0, local_base_->StartSend(local_sender_));
74
75 EXPECT_EQ(0, remote_base_->Init());
76 reflector_ = remote_base_->CreateChannel();
77 EXPECT_EQ(0, remote_network_->RegisterExternalTransport(reflector_, *this));
78 EXPECT_EQ(0, remote_rtp_rtcp_->SetLocalSSRC(reflector_, kReflectorSsrc));
79
80 thread_.Start();
81 thread_.SetPriority(rtc::kHighPriority);
82 }
83
~ConferenceTransport()84 ConferenceTransport::~ConferenceTransport() {
85 // Must stop sending, otherwise DispatchPackets() cannot quit.
86 EXPECT_EQ(0, remote_network_->DeRegisterExternalTransport(reflector_));
87 EXPECT_EQ(0, local_network_->DeRegisterExternalTransport(local_sender_));
88
89 while (!streams_.empty()) {
90 auto stream = streams_.begin();
91 RemoveStream(stream->first);
92 }
93
94 thread_.Stop();
95
96 remote_file_->Release();
97 remote_rtp_rtcp_->Release();
98 remote_network_->Release();
99 remote_base_->Release();
100
101 local_rtp_rtcp_->Release();
102 local_network_->Release();
103 local_base_->Release();
104
105 EXPECT_TRUE(webrtc::VoiceEngine::Delete(remote_voe_));
106 EXPECT_TRUE(webrtc::VoiceEngine::Delete(local_voe_));
107 }
108
SendRtp(const uint8_t * data,size_t len,const webrtc::PacketOptions & options)109 bool ConferenceTransport::SendRtp(const uint8_t* data,
110 size_t len,
111 const webrtc::PacketOptions& options) {
112 StorePacket(Packet::Rtp, data, len);
113 return true;
114 }
115
SendRtcp(const uint8_t * data,size_t len)116 bool ConferenceTransport::SendRtcp(const uint8_t* data, size_t len) {
117 StorePacket(Packet::Rtcp, data, len);
118 return true;
119 }
120
GetReceiverChannelForSsrc(unsigned int sender_ssrc) const121 int ConferenceTransport::GetReceiverChannelForSsrc(unsigned int sender_ssrc)
122 const {
123 webrtc::CriticalSectionScoped lock(stream_crit_.get());
124 auto it = streams_.find(sender_ssrc);
125 if (it != streams_.end()) {
126 return it->second.second;
127 }
128 return -1;
129 }
130
StorePacket(Packet::Type type,const void * data,size_t len)131 void ConferenceTransport::StorePacket(Packet::Type type,
132 const void* data,
133 size_t len) {
134 {
135 webrtc::CriticalSectionScoped lock(pq_crit_.get());
136 packet_queue_.push_back(Packet(type, data, len, rtc::Time()));
137 }
138 packet_event_->Set();
139 }
140
141 // This simulates the flow of RTP and RTCP packets. Complications like that
142 // a packet is first sent to the reflector, and then forwarded to the receiver
143 // are simplified, in this particular case, to a direct link between the sender
144 // and the receiver.
SendPacket(const Packet & packet)145 void ConferenceTransport::SendPacket(const Packet& packet) {
146 int destination = -1;
147
148 switch (packet.type_) {
149 case Packet::Rtp: {
150 webrtc::RTPHeader rtp_header;
151 rtp_header_parser_->Parse(packet.data_, packet.len_, &rtp_header);
152 if (rtp_header.ssrc == kLocalSsrc) {
153 remote_network_->ReceivedRTPPacket(reflector_, packet.data_,
154 packet.len_, webrtc::PacketTime());
155 } else {
156 if (loudest_filter_.ForwardThisPacket(rtp_header)) {
157 destination = GetReceiverChannelForSsrc(rtp_header.ssrc);
158 if (destination != -1) {
159 local_network_->ReceivedRTPPacket(destination, packet.data_,
160 packet.len_,
161 webrtc::PacketTime());
162 }
163 }
164 }
165 break;
166 }
167 case Packet::Rtcp: {
168 unsigned int sender_ssrc = ParseRtcpSsrc(packet.data_, packet.len_);
169 if (sender_ssrc == kLocalSsrc) {
170 remote_network_->ReceivedRTCPPacket(reflector_, packet.data_,
171 packet.len_);
172 } else if (sender_ssrc == kReflectorSsrc) {
173 local_network_->ReceivedRTCPPacket(local_sender_, packet.data_,
174 packet.len_);
175 } else {
176 destination = GetReceiverChannelForSsrc(sender_ssrc);
177 if (destination != -1) {
178 local_network_->ReceivedRTCPPacket(destination, packet.data_,
179 packet.len_);
180 }
181 }
182 break;
183 }
184 }
185 }
186
DispatchPackets()187 bool ConferenceTransport::DispatchPackets() {
188 switch (packet_event_->Wait(1000)) {
189 case webrtc::kEventSignaled:
190 break;
191 case webrtc::kEventTimeout:
192 return true;
193 case webrtc::kEventError:
194 ADD_FAILURE() << "kEventError encountered.";
195 return true;
196 }
197
198 while (true) {
199 Packet packet;
200 {
201 webrtc::CriticalSectionScoped lock(pq_crit_.get());
202 if (packet_queue_.empty())
203 break;
204 packet = packet_queue_.front();
205 packet_queue_.pop_front();
206 }
207
208 int32_t elapsed_time_ms = rtc::TimeSince(packet.send_time_ms_);
209 int32_t sleep_ms = rtt_ms_ / 2 - elapsed_time_ms;
210 if (sleep_ms > 0) {
211 // Every packet should be delayed by half of RTT.
212 webrtc::SleepMs(sleep_ms);
213 }
214
215 SendPacket(packet);
216 }
217 return true;
218 }
219
SetRtt(unsigned int rtt_ms)220 void ConferenceTransport::SetRtt(unsigned int rtt_ms) {
221 rtt_ms_ = rtt_ms;
222 }
223
AddStream(std::string file_name,webrtc::FileFormats format)224 unsigned int ConferenceTransport::AddStream(std::string file_name,
225 webrtc::FileFormats format) {
226 const int new_sender = remote_base_->CreateChannel();
227 EXPECT_EQ(0, remote_network_->RegisterExternalTransport(new_sender, *this));
228
229 const unsigned int remote_ssrc = kFirstRemoteSsrc + stream_count_++;
230 EXPECT_EQ(0, remote_rtp_rtcp_->SetLocalSSRC(new_sender, remote_ssrc));
231 EXPECT_EQ(0, remote_rtp_rtcp_->
232 SetSendAudioLevelIndicationStatus(new_sender, true, kAudioLevelHeaderId));
233
234 EXPECT_EQ(0, remote_codec_->SetSendCodec(new_sender, kCodecInst));
235 EXPECT_EQ(0, remote_base_->StartSend(new_sender));
236 EXPECT_EQ(0, remote_file_->StartPlayingFileAsMicrophone(
237 new_sender, file_name.c_str(), true, false, format, 1.0));
238
239 const int new_receiver = local_base_->CreateChannel();
240 EXPECT_EQ(0, local_base_->AssociateSendChannel(new_receiver, local_sender_));
241
242 EXPECT_EQ(0, local_network_->RegisterExternalTransport(new_receiver, *this));
243 // Receive channels have to have the same SSRC in order to send receiver
244 // reports with this SSRC.
245 EXPECT_EQ(0, local_rtp_rtcp_->SetLocalSSRC(new_receiver, kLocalSsrc));
246
247 {
248 webrtc::CriticalSectionScoped lock(stream_crit_.get());
249 streams_[remote_ssrc] = std::make_pair(new_sender, new_receiver);
250 }
251 return remote_ssrc; // remote ssrc used as stream id.
252 }
253
RemoveStream(unsigned int id)254 bool ConferenceTransport::RemoveStream(unsigned int id) {
255 webrtc::CriticalSectionScoped lock(stream_crit_.get());
256 auto it = streams_.find(id);
257 if (it == streams_.end()) {
258 return false;
259 }
260 EXPECT_EQ(0, remote_network_->
261 DeRegisterExternalTransport(it->second.second));
262 EXPECT_EQ(0, local_network_->
263 DeRegisterExternalTransport(it->second.first));
264 EXPECT_EQ(0, remote_base_->DeleteChannel(it->second.second));
265 EXPECT_EQ(0, local_base_->DeleteChannel(it->second.first));
266 streams_.erase(it);
267 return true;
268 }
269
StartPlayout(unsigned int id)270 bool ConferenceTransport::StartPlayout(unsigned int id) {
271 int dst = GetReceiverChannelForSsrc(id);
272 if (dst == -1) {
273 return false;
274 }
275 EXPECT_EQ(0, local_base_->StartPlayout(dst));
276 return true;
277 }
278
GetReceiverStatistics(unsigned int id,webrtc::CallStatistics * stats)279 bool ConferenceTransport::GetReceiverStatistics(unsigned int id,
280 webrtc::CallStatistics* stats) {
281 int dst = GetReceiverChannelForSsrc(id);
282 if (dst == -1) {
283 return false;
284 }
285 EXPECT_EQ(0, local_rtp_rtcp_->GetRTCPStatistics(dst, *stats));
286 return true;
287 }
288 } // namespace voetest
289