| 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 |