Run loopback tests with network thread.

Running with a network thread provides a more realistic simulation. Like
a real network, packets are handed off to a socket, or buffer, and then
the call returns. This prevents weird scenarios when both the sending
side and receiving side are on the call stack simultaneously, which can
cause deadlocks as locks could otherwise be taken simultaneously in both
the sender and receiver order by the same thread.

BUG=
R=stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/2000005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4522 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/video_engine/test/common/direct_transport.cc b/webrtc/video_engine/test/common/direct_transport.cc
new file mode 100644
index 0000000..f28c208
--- /dev/null
+++ b/webrtc/video_engine/test/common/direct_transport.cc
@@ -0,0 +1,91 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "webrtc/video_engine/test/common/direct_transport.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/video_engine/new_include/video_engine.h"
+
+namespace webrtc {
+namespace test {
+
+DirectTransport::DirectTransport()
+    : lock_(CriticalSectionWrapper::CreateCriticalSection()),
+      packet_event_(EventWrapper::Create()),
+      thread_(ThreadWrapper::CreateThread(NetworkProcess, this)),
+      receiver_(NULL) {
+  unsigned int thread_id;
+  EXPECT_TRUE(thread_->Start(thread_id));
+}
+
+DirectTransport::~DirectTransport() { StopSending(); }
+
+void DirectTransport::StopSending() { EXPECT_TRUE(thread_->Stop()); }
+
+void DirectTransport::SetReceiver(newapi::PacketReceiver* receiver) {
+  receiver_ = receiver;
+}
+
+bool DirectTransport::SendRTP(const uint8_t* data, size_t length) {
+  QueuePacket(data, length);
+  return true;
+}
+
+bool DirectTransport::SendRTCP(const uint8_t* data, size_t length) {
+  QueuePacket(data, length);
+  return true;
+}
+
+DirectTransport::Packet::Packet() : length(0) {}
+
+DirectTransport::Packet::Packet(const uint8_t* data, size_t length)
+    : length(length) {
+  EXPECT_LE(length, sizeof(this->data));
+  memcpy(this->data, data, length);
+}
+
+void DirectTransport::QueuePacket(const uint8_t* data, size_t length) {
+  CriticalSectionScoped crit(lock_.get());
+  EXPECT_TRUE(receiver_ != NULL);
+  packet_queue_.push_back(Packet(data, length));
+  packet_event_->Set();
+}
+
+bool DirectTransport::NetworkProcess(void* transport) {
+  return static_cast<DirectTransport*>(transport)->SendPackets();
+}
+
+bool DirectTransport::SendPackets() {
+  while (true) {
+    Packet p;
+    {
+      webrtc::CriticalSectionScoped crit(lock_.get());
+      if (packet_queue_.empty())
+        break;
+      p = packet_queue_.front();
+      packet_queue_.pop_front();
+    }
+    receiver_->DeliverPacket(p.data, p.length);
+  }
+
+  switch (packet_event_->Wait(10)) {
+    case kEventSignaled:
+      packet_event_->Reset();
+      break;
+    case kEventTimeout:
+      break;
+    case kEventError:
+      // TODO(pbos): Log a warning here?
+      return true;
+  }
+
+  return true;
+}
+}  // namespace test
+}  // namespace webrtc
diff --git a/webrtc/video_engine/test/common/direct_transport.h b/webrtc/video_engine/test/common/direct_transport.h
index f935641..888ed46 100644
--- a/webrtc/video_engine/test/common/direct_transport.h
+++ b/webrtc/video_engine/test/common/direct_transport.h
@@ -12,32 +12,55 @@
 
 #include <assert.h>
 
+#include <deque>
+
+#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/video_engine/new_include/transport.h"
 
 namespace webrtc {
+
+namespace newapi {
+class PacketReceiver;
+}  // namespace newapi
+
 namespace test {
 
 class DirectTransport : public newapi::Transport {
  public:
-  explicit DirectTransport(newapi::PacketReceiver* receiver)
-      : receiver_(receiver) {}
+  DirectTransport();
+  ~DirectTransport();
 
-  void SetReceiver(newapi::PacketReceiver* receiver) { receiver_ = receiver; }
+  virtual void StopSending();
+  virtual void SetReceiver(newapi::PacketReceiver* receiver);
 
-  virtual bool SendRTP(const uint8_t* data, size_t length) OVERRIDE {
-    assert(receiver_ != NULL);
-    return receiver_->DeliverPacket(data, length);
-  }
-
-  virtual bool SendRTCP(const uint8_t* data, size_t length) OVERRIDE {
-    assert(receiver_ != NULL);
-    return SendRTP(data, length);
-  }
+  virtual bool SendRTP(const uint8_t* data, size_t length) OVERRIDE;
+  virtual bool SendRTCP(const uint8_t* data, size_t length) OVERRIDE;
 
  private:
+  struct Packet {
+    Packet();
+    Packet(const uint8_t* data, size_t length);
+
+    uint8_t data[1500];
+    size_t length;
+  };
+
+  void QueuePacket(const uint8_t* data, size_t length);
+
+  static bool NetworkProcess(void* transport);
+  bool SendPackets();
+
+  scoped_ptr<CriticalSectionWrapper> lock_;
+  scoped_ptr<EventWrapper> packet_event_;
+  scoped_ptr<ThreadWrapper> thread_;
+
+  std::deque<Packet> packet_queue_;
   newapi::PacketReceiver* receiver_;
 };
-}  // test
-}  // webrtc
+}  // namespace test
+}  // namespace webrtc
 
 #endif  // WEBRTC_VIDEO_ENGINE_TEST_COMMON_DIRECT_TRANSPORT_H_