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