diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/qtmain.cpp webrtc_new/trunk/talk/examples/qtwebrtc_textedit/qtmain.cpp
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/qtmain.cpp	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/qtmain.cpp	2014-03-02 20:27:05.162111536 +0100
@@ -0,0 +1,31 @@
+#include "talk/base/openssladapter.h"
+#include "widgetstreamer.h"
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QTextEdit>
+#include <QtCore/QTimer>
+#include <iostream>
+
+using namespace std;
+
+int main(int argc, char **argv)
+{
+	QApplication app(argc, argv);
+
+	QTextEdit w1;
+	TestWidget w2;
+
+	if (!talk_base::InitializeSSL(NULL) || !talk_base::InitializeSSLThread()) 
+	{
+		cerr << "Unable to initialize SSL" << endl;
+		return -1;
+	} 
+
+	WidgetStreamer conn(&w1, &w2);
+
+	w1.show();
+	w2.show();
+
+	return app.exec();
+}
+
+
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/runme.sh webrtc_new/trunk/talk/examples/qtwebrtc_textedit/runme.sh
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/runme.sh	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/runme.sh	2014-03-02 20:06:46.463111681 +0100
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+uic -o ui_testwidget.h testwidget.ui
+moc -o moc_widgetstreamer.cpp widgetstreamer.h
+moc -o moc_testwidget.cpp testwidget.h
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testvideocapturer.cpp webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testvideocapturer.cpp
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testvideocapturer.cpp	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testvideocapturer.cpp	2014-03-02 20:26:12.584111542 +0100
@@ -0,0 +1,161 @@
+#include "talk/media/devices/deviceinfo.h"
+#include "talk/media/base/mediacommon.h"
+#include "talk/base/logging.h"
+#include "talk/media/base/videoframe.h"
+#include "testvideocapturer.h"
+#include <QtCore/QElapsedTimer>
+#include <stdlib.h>
+
+using namespace cricket;
+
+CaptureThread::CaptureThread(VideoCapturer *pCapturer)
+{
+	m_pCapturer = pCapturer;
+	m_stopped = false;
+	m_pImageBytes = 0;
+	m_width = 0;
+	m_height = 0;
+	m_imageDataLen = 0;
+}
+
+CaptureThread::~CaptureThread()
+{
+	stop();
+}
+
+void CaptureThread::stop()
+{
+	QElapsedTimer timer;
+
+	timer.start();
+
+	m_stopMutex.lock();
+	m_stopped = true;
+	m_stopMutex.unlock();
+
+	while (isRunning() && !timer.hasExpired(300)) // wait 300ms at most
+	{
+		QThread::msleep(50);
+	}
+
+	if (isRunning())
+	{
+		LOG(LS_INFO) << "CaptureThread: KILLING THREAD";
+		terminate();
+	}
+	else
+	{
+		LOG(LS_INFO) << "CaptureThread: Thread stopped nicely";
+	}
+
+	delete [] m_pImageBytes;
+	m_pImageBytes = 0;
+}
+
+void CaptureThread::run()
+{
+	LOG(LS_INFO) << "CaptureThread: STARTED";
+
+	bool stopped = false;
+	uint64_t prevTimestamp = 0;
+
+	while (!stopped)
+	{
+		CapturedFrame frame;
+		
+		frame.elapsed_time = 33333333;
+		frame.time_stamp = prevTimestamp;
+		prevTimestamp += frame.elapsed_time;  // 30 fps
+
+		m_imageMutex.lock();
+		if (m_pImageBytes && m_imageDataLen > 0 && m_width > 0 && m_height > 0)
+		{
+			frame.data = m_pImageBytes;
+			frame.width = m_width;
+			frame.height = m_height;
+			frame.fourcc = FOURCC_ABGR;
+			frame.data_size = m_imageDataLen;
+
+			if (frame.width*frame.height*4 != m_imageDataLen)
+				LOG(LS_INFO) << "CaptureThread: with and height don't match size for ABGR data, skipping frame";
+			else
+			{
+				//LOG(LS_INFO) << "CaptureThread: got frame " << (int)frameVal << " glGetError: " << glGetError();
+				m_pCapturer->SignalFrameCaptured(m_pCapturer, &frame);
+			}
+		}
+		m_imageMutex.unlock();
+
+		QThread::msleep(33);
+
+		m_stopMutex.lock();
+		stopped = m_stopped;
+		m_stopMutex.unlock();
+	}
+}
+
+void CaptureThread::setImageData(uint8_t *pImageBytes, size_t len, int width, int height)
+{
+	m_imageMutex.lock();
+
+	delete [] m_pImageBytes;
+
+	m_pImageBytes = pImageBytes;
+	m_imageDataLen = len;
+	m_width = width;
+	m_height = height;
+
+	m_imageMutex.unlock();
+}
+
+TestVideoCapturer::TestVideoCapturer() : m_captureThread(this)
+{
+}
+
+bool TestVideoCapturer::GetBestCaptureFormat(const VideoFormat& desired, VideoFormat* best_format)
+{
+	LOG(LS_INFO) << "TestVideoCapturer::GetBestCaptureFormat";
+	*best_format = desired; // TODO
+	return true;
+}
+
+CaptureState TestVideoCapturer::Start(const VideoFormat& capture_format)
+{
+	LOG(LS_INFO) << "TestVideoCapturer::Start";
+	
+	m_captureThread.start();
+
+	return CS_RUNNING; 
+}
+
+void TestVideoCapturer::Stop()
+{
+	LOG(LS_INFO) << "TestVideoCapturer::Stop";
+	
+	m_captureThread.stop();
+}
+
+bool TestVideoCapturer::IsRunning()
+{
+	LOG(LS_INFO) << "TestVideoCapturer::IsRunning";
+	return m_captureThread.isRunning();
+}
+
+bool TestVideoCapturer::IsScreencast() const
+{
+	//LOG(LS_INFO) << "TestVideoCapturer::IsScreencast";
+	// TODO: is this appropriate here?
+	return true;
+}
+
+bool TestVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs)
+{
+	fourccs->push_back(FOURCC_ABGR);
+	return true;
+}
+
+void TestVideoCapturer::setImageData(uint8_t *pImageBytes, size_t len, int width, int height)
+{
+	m_captureThread.setImageData(pImageBytes, len, width, height);
+}
+
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testvideocapturer.h webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testvideocapturer.h
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testvideocapturer.h	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testvideocapturer.h	2014-03-02 20:23:03.860111565 +0100
@@ -0,0 +1,49 @@
+#ifndef TESTVIDEOCAPTURER_H
+
+#define TESTVIDEOCAPTURER_H
+
+#include "talk/media/base/videocapturer.h"
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+
+class CaptureThread : public QThread
+{
+public:
+	CaptureThread(cricket::VideoCapturer *pCapturer);
+	~CaptureThread();
+
+	void stop(); 
+	void setImageData(uint8_t *pImageBytes, size_t len, int width, int height);
+private:
+	void run();
+
+	cricket::VideoCapturer *m_pCapturer;
+	bool m_stopped;
+	QMutex m_stopMutex;
+	QMutex m_imageMutex;
+
+	uint8_t *m_pImageBytes;
+	size_t m_imageDataLen;
+	int m_width;
+	int m_height;
+
+};
+
+class TestVideoCapturer : public cricket::VideoCapturer
+{
+public:
+	TestVideoCapturer();
+
+	bool GetBestCaptureFormat(const cricket::VideoFormat& desired, cricket::VideoFormat* best_format);
+	cricket::CaptureState Start(const cricket::VideoFormat& capture_format);
+	void Stop();
+	bool IsRunning();
+	bool IsScreencast() const;
+	bool GetPreferredFourccs(std::vector<uint32>* fourccs);
+
+	void setImageData(uint8_t *pImageBytes, size_t len, int width, int height);
+private:
+	CaptureThread m_captureThread;
+};
+
+#endif // TESTVIDEOCAPTURER_H
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testwidget.cpp webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testwidget.cpp
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testwidget.cpp	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testwidget.cpp	2014-03-02 20:27:44.783111531 +0100
@@ -0,0 +1,367 @@
+#include "talk/app/webrtc/test/fakeconstraints.h"
+#include "talk/app/webrtc/videosourceinterface.h"
+#include "talk/media/devices/devicemanager.h"
+#include "testvideocapturer.h"
+#include "testwidget.h"
+#include <iostream>
+#include <stdio.h>
+
+using namespace std;
+
+class DummySetSessionDescriptionObserver : public webrtc::SetSessionDescriptionObserver 
+{
+public:
+	static DummySetSessionDescriptionObserver* Create() 
+	{
+		return new talk_base::RefCountedObject<DummySetSessionDescriptionObserver>();
+	}
+
+	void OnSuccess() 
+	{
+		cerr << "DummySetSessionDescriptionObserver: onSuccess" << endl;
+	}
+
+	void OnFailure(const std::string& error) 
+	{
+		cerr << "DummySetSessionDescriptionObserver::OnFailure" << endl;
+	}
+protected:
+	DummySetSessionDescriptionObserver() 
+	{
+	}
+	
+	~DummySetSessionDescriptionObserver() 
+	{
+	}
+};
+
+TestConnectionObserver::TestConnectionObserver()
+{
+	cerr << "TestConnectionObserver::TestConnectionObserver" << endl;
+}
+
+TestConnectionObserver::~TestConnectionObserver()
+{
+	cerr << "TestConnectionObserver::~TestConnectionObserver" << endl;
+}
+
+void TestConnectionObserver::OnError()
+{
+	cerr << "TestConnectionObserver::OnError" << endl;
+}
+
+void TestConnectionObserver::OnStateChange(webrtc::PeerConnectionObserver::StateType state_changed)
+{
+	cerr << "TestConnectionObserver::OnStateChange" << endl;
+}
+
+void TestConnectionObserver::OnAddStream(webrtc::MediaStreamInterface* stream)
+{
+	cerr << "TestConnectionObserver::OnAddStream" << endl;
+}
+
+void TestConnectionObserver::OnRemoveStream(webrtc::MediaStreamInterface* stream)
+{
+	cerr << "TestConnectionObserver::OnRemoveStream" << endl;
+}
+
+void TestConnectionObserver::OnRenegotiationNeeded() 
+{
+	cerr << "TestConnectionObserver::OnRenegotiationNeeded" << endl;
+}
+
+void TestConnectionObserver::OnIceChange() 
+{
+	cerr << "TestConnectionObserver::OnIceChange" << endl;
+}
+
+void TestConnectionObserver::OnIceCandidate(const webrtc::IceCandidateInterface* candidate)
+{
+	cerr << "TestConnectionObserver::OnIceCandidate" << endl;
+	string iceStr;
+
+	int mlineIdx = candidate->sdp_mline_index();
+	string sdpMid = candidate->sdp_mid();
+	candidate->ToString(&iceStr);
+
+	size_t len = iceStr.length();
+	if (len > 0 && iceStr[len-1] == '\n')
+		iceStr = iceStr.substr(0, len-1);
+	
+	len = iceStr.length();
+	if (len > 0 && iceStr[len-1] == '\r')
+		iceStr = iceStr.substr(0, len-1);
+
+#define BUFLEN 1024
+	char buf[BUFLEN];
+
+	snprintf(buf, BUFLEN, "{\"sdpMLineIndex\":%d,\"sdpMid\":\"%s\",\"candidate\":\"%s\\r\\n\"}", mlineIdx, sdpMid.c_str(), iceStr.c_str());
+
+	emit signalIceCandidate(QString(buf));
+}
+
+TestSDObserver::TestSDObserver()
+{
+	cerr << "TestSDObserver::TestSDObserver" << endl;
+}
+
+TestSDObserver::~TestSDObserver()
+{
+	cerr << "TestSDObserver::~TestSDObserver" << endl;
+}
+
+void TestSDObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc)
+{
+	cerr << "TestSDObserver::OnSuccess" << endl;
+	string sdpStr;
+
+	desc->ToString(&sdpStr);
+	cerr << sdpStr << endl;
+
+	emit signalSDPText(QString(sdpStr.c_str()));
+}
+
+void TestSDObserver::OnFailure(const std::string& error)
+{
+	cerr << "TestSDObserver::OnFailure" << endl;
+}
+
+TestWidget::TestWidget()
+{
+	m_pCapturer = 0;
+	m_pcfIface = 0;
+
+	setupUi(this);
+
+	QObject::connect(m_pStartButton, SIGNAL(clicked()), this, SLOT(onStartClicked()));
+	QObject::connect(m_pProcessAnswerButton, SIGNAL(clicked()), this, SLOT(onAnswerClicked()));
+	QObject::connect(m_pProcessRemoteICEButton, SIGNAL(clicked()), this, SLOT(onRemoteICEClicked()));
+}
+
+TestWidget::~TestWidget()
+{
+}
+
+void TestWidget::onStartClicked()
+{
+	if (m_pcfIface != 0)
+	{
+		cerr << "onStartClicked: already exists" << endl;
+		return;
+	}
+
+	m_pcfIface = webrtc::CreatePeerConnectionFactory();
+
+	if (!m_pcfIface.get()) // This means that the initialization failed for some reason (get retrieves the pointer)
+	{
+		m_pcfIface = 0; // Since it's ref counted, this will destroy it
+		return;
+	}
+
+  	webrtc::PeerConnectionInterface::IceServers servers;
+	webrtc::PeerConnectionInterface::IceServer server;
+  	webrtc::FakeConstraints constraints;
+
+	constraints.SetAllowDtlsSctpDataChannels();
+
+	server.uri = "stun:stun.l.google.com:19302";
+	servers.push_back(server);
+
+	// TODO: this is a memory leak for now
+	TestConnectionObserver *pTestConnObserver = new TestConnectionObserver();
+
+	QObject::connect(pTestConnObserver, SIGNAL(signalIceCandidate(const QString &)), this, SLOT(onLocalIceCandidate(const QString &)));
+
+	m_peerConnection = m_pcfIface->CreatePeerConnection(servers, &constraints, 0, pTestConnObserver);
+  
+	talk_base::scoped_refptr<webrtc::VideoSourceInterface> videoSource;
+	videoSource = m_pcfIface->CreateVideoSource(OpenVideoCaptureDevice(), 0);
+
+	talk_base::scoped_refptr<webrtc::VideoTrackInterface> videoTrack;
+	videoTrack = m_pcfIface->CreateVideoTrack("testVideoTrack", videoSource);
+  	
+	talk_base::scoped_refptr<webrtc::AudioTrackInterface> audioTrack;
+      	audioTrack = m_pcfIface->CreateAudioTrack("testAudioTrack", m_pcfIface->CreateAudioSource(NULL));
+
+	talk_base::scoped_refptr<webrtc::MediaStreamInterface> stream;
+	stream = m_pcfIface->CreateLocalMediaStream("testStream");
+
+	stream->AddTrack(audioTrack);
+  	stream->AddTrack(videoTrack);
+
+  	if (!m_peerConnection->AddStream(stream, 0))
+	{
+    		cerr << "Adding stream to PeerConnection failed" << endl;
+		return;
+  	}
+	cerr << "Successfully added stream" << endl;
+
+	TestSDObserver *pTestSD = new TestSDObserver();
+	
+	QObject::connect(pTestSD, SIGNAL(signalSDPText(const QString &)), this, SLOT(onLocalSDPInfo(const QString &)));
+
+	m_peerConnection->CreateOffer(pTestSD, 0);
+}
+
+void TestWidget::onAnswerClicked()
+{
+	cout << "onAnswerClicked" << endl;
+	string sdpInfo = m_pAnswerText->toPlainText().toStdString();
+
+	cerr << sdpInfo << endl;
+    
+    	webrtc::SessionDescriptionInterface* pSessionDescription = webrtc::CreateSessionDescription("answer", sdpInfo);
+
+	m_peerConnection->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(), pSessionDescription);
+}
+
+void TestWidget::onRemoteICEClicked()
+{
+	cout << "onRemoteICEClicked" << endl;
+	
+	QStringList iceInfo = m_pRemoteICEText->toPlainText().split('\n');
+
+	for (int i = 0 ; i < iceInfo.size() ; i++)
+	{
+		QString iceLine = iceInfo.at(i);
+
+		//cerr << iceLine.toStdString() << endl;
+
+		QStringList parts = iceLine.split(',');
+		QStringList remainingParts;
+		for (int j = 0 ; j < parts.size() ; j++)
+		{
+			QString part = parts.at(j);
+			cerr << part.toStdString() << endl;
+
+			QStringList values = part.split('"', QString::SkipEmptyParts);
+
+			if (values.size() > 2)
+			{
+				remainingParts << values.at(2);
+				//cerr << values.at(0).toStdString() << " " << values.at(2).toStdString() << endl;
+			}
+		}
+
+		if (remainingParts.size() == 3)
+		{
+			int sdpMLineIndex = atoi(remainingParts.at(0).toLatin1());
+			string sdpMid = remainingParts.at(1).toStdString();
+			QString candidate = remainingParts.at(2);
+			
+			candidate.replace(QString("\\r\\n"),QString(""));
+
+			cerr << "ICE: " << sdpMLineIndex << " " << sdpMid << " " << candidate.toStdString() << endl;
+
+			talk_base::scoped_ptr<webrtc::IceCandidateInterface> c(webrtc::CreateIceCandidate(sdpMid, sdpMLineIndex, candidate.toStdString()));
+
+			if (!c.get()) 
+			{
+				cerr << "Can't parse candidate message" << endl;
+			}
+			else
+			{
+				if (!m_peerConnection->AddIceCandidate(c.get())) 
+				{
+					cerr << "Failed to apply the received candidate" << endl;
+				}	
+			}
+		}
+	}
+}
+
+cricket::VideoCapturer* TestWidget::OpenVideoCaptureDevice() 
+{
+	cricket::VideoCapturer* capturer = NULL;
+
+#if 0
+	// TODO: doesn't seem to work using some webcams, produces an assertion error in debug mode,
+	//       and a crash in release mode
+	talk_base::scoped_ptr<cricket::DeviceManagerInterface> devManager(cricket::DeviceManagerFactory::Create());
+
+	if (!devManager->Init()) 
+	{
+		cerr << "Can't create device manager" << endl;
+		return 0;
+	}
+
+	cerr << "devManager->Init ok" << endl;
+
+	std::vector<cricket::Device> devs;
+	
+	if (!devManager->GetVideoCaptureDevices(&devs)) 
+	{
+		cerr << "Can't enumerate video devices" << endl;
+		return 0;
+	}
+
+	cerr << "devs.size() = " << devs.size() << endl;
+
+	std::vector<cricket::Device>::iterator dev_it = devs.begin();
+	
+	for ( ; dev_it != devs.end(); ++dev_it) 
+	{
+		capturer = devManager->CreateVideoCapturer(*dev_it);
+		if (capturer != NULL)
+			break;
+	}
+
+
+#else
+	m_pCapturer = new TestVideoCapturer();
+	capturer = m_pCapturer;
+#endif
+	cerr << "capturer = " << capturer << endl;
+
+	return capturer;
+}
+
+void TestWidget::onLocalSDPInfo(const QString &sdpText)
+{
+	m_pOfferText->setPlainText(sdpText);
+
+	string sdpStr = sdpText.toStdString();
+
+    	webrtc::SessionDescriptionInterface* pSessionDescription = webrtc::CreateSessionDescription("offer", sdpStr);
+	m_peerConnection->SetLocalDescription(DummySetSessionDescriptionObserver::Create(), pSessionDescription);
+}
+
+void TestWidget::onLocalIceCandidate(const QString &iceCandidate)
+{
+	QString str = m_pOwnICEText->toPlainText();
+
+	str += iceCandidate + "\n";
+
+	m_pOwnICEText->setPlainText(str);
+}
+
+void TestWidget::setNewFrame(const QImage &img)
+{
+	int width = img.width();
+	int height = img.height();
+
+	if (width <= 0 || height <= 0)
+		return;
+	if (m_pCapturer == 0)
+		return;
+
+	int numBytes = width*height*4;
+	uint8_t *pData = new uint8_t[numBytes];
+
+	for (int y = 0 ; y < height ; y++)
+	{
+		for (int x = 0 ; x < width ; x++)
+		{
+			QRgb pixel = img.pixel(x,y);
+
+			int offset = (x+y*width)*4;
+			pData[offset+3] = qAlpha(pixel);
+			pData[offset+2] = qBlue(pixel);
+			pData[offset+1] = qGreen(pixel);
+			pData[offset+0] = qRed(pixel);
+		}
+	}
+
+	m_pCapturer->setImageData(pData, numBytes, width, height);
+}
+
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testwidget.h webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testwidget.h
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testwidget.h	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testwidget.h	2014-03-02 20:25:47.765111545 +0100
@@ -0,0 +1,65 @@
+#ifndef TESTWIDGET_H
+
+#define TESTWIDGET_H
+
+#include "talk/app/webrtc/peerconnectioninterface.h"
+#include "ui_testwidget.h"
+#include <QtWidgets/QMainWindow>
+
+class TestVideoCapturer;
+
+class TestWidget : public QMainWindow, public Ui::TestWidget
+{
+	Q_OBJECT
+public:
+	TestWidget();
+	~TestWidget();
+
+	void setNewFrame(const QImage &img);
+private slots:
+	void onStartClicked();
+	void onAnswerClicked();
+	void onRemoteICEClicked();
+	void onLocalSDPInfo(const QString &sdpText);
+	void onLocalIceCandidate(const QString &iceCandidate);
+private:
+	cricket::VideoCapturer* OpenVideoCaptureDevice();
+	TestVideoCapturer *m_pCapturer;
+
+	talk_base::scoped_refptr<webrtc::PeerConnectionFactoryInterface> m_pcfIface;
+	talk_base::scoped_refptr<webrtc::PeerConnectionInterface> m_peerConnection;
+};
+
+class TestSDObserver : public QObject, public talk_base::RefCountedObject<webrtc::CreateSessionDescriptionObserver>
+{
+	Q_OBJECT
+public:
+	TestSDObserver();
+	~TestSDObserver();
+	
+	void OnSuccess(webrtc::SessionDescriptionInterface* desc);
+ 	void OnFailure(const std::string& error);
+signals:
+	void signalSDPText(const QString &sdp);
+};
+
+
+class TestConnectionObserver : public QObject, public webrtc::PeerConnectionObserver
+{
+	Q_OBJECT
+public:
+	TestConnectionObserver();
+	~TestConnectionObserver();
+
+	void OnError();
+	void OnStateChange(webrtc::PeerConnectionObserver::StateType state_changed);
+	void OnAddStream(webrtc::MediaStreamInterface* stream);
+	void OnRemoveStream(webrtc::MediaStreamInterface* stream);
+	void OnRenegotiationNeeded();
+	void OnIceChange();
+	void OnIceCandidate(const webrtc::IceCandidateInterface* candidate);
+signals:
+	void signalIceCandidate(const QString &iceCandidate);
+};
+
+#endif // TESTWIDGET_H
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testwidget.ui webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testwidget.ui
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/testwidget.ui	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/testwidget.ui	2014-03-02 20:06:46.463111681 +0100
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TestWidget</class>
+ <widget class="QMainWindow" name="TestWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>872</width>
+    <height>600</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>TestWidget</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout_2">
+    <item row="0" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QLabel" name="label">
+        <property name="font">
+         <font>
+          <pointsize>26</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>Sender</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </item>
+    <item row="1" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QPushButton" name="m_pStartButton">
+        <property name="text">
+         <string>Start</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="m_pProcessAnswerButton">
+        <property name="text">
+         <string>Process answer</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="m_pProcessRemoteICEButton">
+        <property name="text">
+         <string>Process remote ICE info</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </item>
+    <item row="2" column="0">
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>This is the SDP data that will need to be sent to the other side</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Paste the SDP info from the other side here and press 'process answer'</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QPlainTextEdit" name="m_pOfferText"/>
+      </item>
+      <item row="1" column="1">
+       <widget class="QPlainTextEdit" name="m_pAnswerText"/>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>This is ICE info for the local host, we'll need to send it to the remote end</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QLabel" name="label_5">
+        <property name="text">
+         <string>Paste the ICE info from the remote host here and press 'process ICE candidates'</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0">
+       <widget class="QPlainTextEdit" name="m_pOwnICEText"/>
+      </item>
+      <item row="3" column="1">
+       <widget class="QPlainTextEdit" name="m_pRemoteICEText"/>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>872</width>
+     <height>21</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/widgetstreamer.cpp webrtc_new/trunk/talk/examples/qtwebrtc_textedit/widgetstreamer.cpp
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/widgetstreamer.cpp	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/widgetstreamer.cpp	2014-03-02 20:27:21.456111534 +0100
@@ -0,0 +1,39 @@
+#include "widgetstreamer.h"
+#include <QtWidgets/QTextEdit>
+#include <QtCore/QTimer>
+#include <iostream>
+
+using namespace std;
+
+WidgetStreamer::WidgetStreamer(QWidget *pRenderWidget, TestWidget *pStreamWidget)
+{
+	m_pRenderWidget = pRenderWidget;
+	m_pStreamWidget = pStreamWidget;
+
+	QTimer *pTimer = new QTimer(this);
+	QObject::connect(pTimer, SIGNAL(timeout()), this, SLOT(onTimeout()));
+	pTimer->start(40);
+}
+
+WidgetStreamer::~WidgetStreamer()
+{
+}
+
+void WidgetStreamer::onTimeout()
+{
+	int width = m_pRenderWidget->width();
+	int height = m_pRenderWidget->height();
+
+//	cerr << width << " " << height << endl;
+
+	if (width <= 0 || height <= 0)
+		return;
+
+	QPixmap pixmap(width, height);
+
+	m_pRenderWidget->render(&pixmap);
+	QImage img = pixmap.toImage();
+
+	m_pStreamWidget->setNewFrame(img);
+}
+
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/widgetstreamer.h webrtc_new/trunk/talk/examples/qtwebrtc_textedit/widgetstreamer.h
--- webrtc_orig/trunk/talk/examples/qtwebrtc_textedit/widgetstreamer.h	1970-01-01 01:00:00.000000000 +0100
+++ webrtc_new/trunk/talk/examples/qtwebrtc_textedit/widgetstreamer.h	2014-03-02 20:06:46.463111681 +0100
@@ -0,0 +1,22 @@
+#ifndef WIDGETSTREAMER_H
+
+#define WIDGETSTREAMER_H
+
+#include "testwidget.h"
+
+class WidgetStreamer : public QObject
+{
+	Q_OBJECT
+public:
+	WidgetStreamer(QWidget *pRenderWidget, TestWidget *pStreamWidget);
+	~WidgetStreamer();
+private slots:
+	void onTimeout();
+private:
+	QWidget *m_pRenderWidget;
+	TestWidget *m_pStreamWidget;
+};
+
+#endif // WIDGETSTREAMER_H
+
+
diff -x '*.ninja' -r -u -N webrtc_orig/trunk/talk/libjingle_examples.gyp webrtc_new/trunk/talk/libjingle_examples.gyp
--- webrtc_orig/trunk/talk/libjingle_examples.gyp	2014-03-02 20:02:54.097111709 +0100
+++ webrtc_new/trunk/talk/libjingle_examples.gyp	2014-03-02 20:24:45.145111552 +0100
@@ -218,6 +218,49 @@
       ], # targets
     }],  # OS=="linux" or OS=="win"
 
+    ['OS=="linux"', {
+      'targets': [
+        {
+          'target_name': 'qtwebrtc_textedit',
+          'type': 'executable',
+          'sources': [
+            'examples/qtwebrtc_textedit/moc_testwidget.cpp',
+            'examples/qtwebrtc_textedit/moc_widgetstreamer.cpp',
+            'examples/qtwebrtc_textedit/qtmain.cpp',
+            'examples/qtwebrtc_textedit/testvideocapturer.cpp',
+            'examples/qtwebrtc_textedit/testvideocapturer.h',
+            'examples/qtwebrtc_textedit/testwidget.cpp',
+            'examples/qtwebrtc_textedit/testwidget.h',
+            'examples/qtwebrtc_textedit/testwidget.ui',
+            'examples/qtwebrtc_textedit/ui_testwidget.h',
+            'examples/qtwebrtc_textedit/widgetstreamer.cpp',
+            'examples/qtwebrtc_textedit/widgetstreamer.h',
+          ],
+          'dependencies': [
+            '<(DEPTH)/third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
+            'libjingle.gyp:libjingle_peerconnection',
+          ],
+          'cflags': [
+            '-I /<!@(qmake -v|tail -n 1|cut -f 2- -d /)/../include',
+          ],
+          'link_settings': {
+            'ldflags': [
+	      '-L /<!@(qmake -v|tail -n 1|cut -f 2- -d /)'
+            ],
+            'libraries': [
+              '-lX11',
+              '-lXcomposite',
+              '-lXext',
+              '-lXrender',
+	      '-lQt5Core',
+	      '-lQt5Gui',
+	      '-lQt5Widgets',
+              ],
+	    },
+          },
+       ], # targets
+    }],  # OS=="linux"
+
     ['OS=="ios"', {
       'targets': [
         {
