Hand over loopback packets to a network thread.
This version of LoopBackTransport hands packets over to a network thread
which will deliver them instead. This allows SendRTP and SendRTCP to
always be able to return, preventing deadlocks in voe_auto_test. The
previous case did not represent actual network usage. Now the send and
receive side can run concurrently with the receiving side. Previously
the sender thread also drove the receiving side, which does not
represent the regular use case where packets are put on a network
socket.
BUG=1568,2081,2178
TEST=Ran VoiceEngine RtpRtcpTest.*, known for deadlocking, 100+ times.
R=xians@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/1985005
git-svn-id: http://webrtc.googlecode.com/svn/trunk@4516 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/voice_engine/test/auto_test/fixtures/after_initialization_fixture.h b/webrtc/voice_engine/test/auto_test/fixtures/after_initialization_fixture.h
index 0a9f1dd..e854120 100644
--- a/webrtc/voice_engine/test/auto_test/fixtures/after_initialization_fixture.h
+++ b/webrtc/voice_engine/test/auto_test/fixtures/after_initialization_fixture.h
@@ -11,8 +11,13 @@
#ifndef SRC_VOICE_ENGINE_MAIN_TEST_AUTO_TEST_STANDARD_TEST_BASE_AFTER_INIT_H_
#define SRC_VOICE_ENGINE_MAIN_TEST_AUTO_TEST_STANDARD_TEST_BASE_AFTER_INIT_H_
+#include <deque>
+
#include "webrtc/common_types.h"
+#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/voice_engine/test/auto_test/fixtures/before_initialization_fixture.h"
class TestErrorObserver;
@@ -20,20 +25,94 @@
class LoopBackTransport : public webrtc::Transport {
public:
LoopBackTransport(webrtc::VoENetwork* voe_network)
- : voe_network_(voe_network) {
+ : crit_(webrtc::CriticalSectionWrapper::CreateCriticalSection()),
+ packet_event_(webrtc::EventWrapper::Create()),
+ thread_(webrtc::ThreadWrapper::CreateThread(NetworkProcess, this)),
+ voe_network_(voe_network) {
+ unsigned int id;
+ thread_->Start(id);
+ }
+ ~LoopBackTransport() {
+ thread_->Stop();
}
virtual int SendPacket(int channel, const void *data, int len) {
- voe_network_->ReceivedRTPPacket(channel, data, len);
+ StorePacket(Packet::Rtp, channel, data, len);
return len;
}
virtual int SendRTCPPacket(int channel, const void *data, int len) {
- voe_network_->ReceivedRTCPPacket(channel, data, len);
+ StorePacket(Packet::Rtcp, channel, data, len);
return len;
}
+
private:
+ struct Packet {
+ enum Type {
+ Rtp,
+ Rtcp,
+ } type;
+
+ Packet() : len(0) {}
+ Packet(Type type, int channel, const void* data, int len)
+ : type(type), channel(channel), len(len) {
+ assert(len <= 1500);
+ memcpy(this->data, data, static_cast<size_t>(len));
+ }
+
+ int channel;
+ uint8_t data[1500];
+ int len;
+ };
+
+ void StorePacket(Packet::Type type, int channel, const void* data, int len) {
+ webrtc::CriticalSectionScoped(crit_.get());
+ packet_queue_.push_back(Packet(type, channel, data, len));
+ packet_event_->Set();
+ }
+ static bool NetworkProcess(void* transport) {
+ return static_cast<LoopBackTransport*>(transport)->SendPackets();
+ }
+
+ bool SendPackets() {
+ switch (packet_event_->Wait(10)) {
+ case webrtc::kEventSignaled:
+ packet_event_->Reset();
+ break;
+ case webrtc::kEventTimeout:
+ break;
+ case webrtc::kEventError:
+ // TODO(pbos): Log a warning here?
+ return true;
+ }
+
+ while (true) {
+ Packet p;
+ {
+ webrtc::CriticalSectionScoped lock(crit_.get());
+ if (packet_queue_.empty())
+ break;
+ p = packet_queue_.front();
+ packet_queue_.pop_front();
+ }
+
+ switch (p.type) {
+ case Packet::Rtp:
+ voe_network_->ReceivedRTPPacket(p.channel, p.data, p.len);
+ break;
+ case Packet::Rtcp:
+ voe_network_->ReceivedRTCPPacket(p.channel, p.data, p.len);
+ break;
+ }
+ }
+ return true;
+ }
+
+ webrtc::scoped_ptr<webrtc::CriticalSectionWrapper> crit_;
+ webrtc::scoped_ptr<webrtc::EventWrapper> packet_event_;
+ webrtc::scoped_ptr<webrtc::ThreadWrapper> thread_;
+ std::deque<Packet> packet_queue_;
webrtc::VoENetwork* voe_network_;
};