Fix build for Windows and Linux.
git-svn-id: http://libjingle.googlecode.com/svn/trunk@57 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/talk/base/basicpacketsocketfactory.cc b/talk/base/basicpacketsocketfactory.cc
new file mode 100644
index 0000000..42721ba
--- /dev/null
+++ b/talk/base/basicpacketsocketfactory.cc
@@ -0,0 +1,175 @@
+/*
+ * libjingle
+ * Copyright 2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/basicpacketsocketfactory.h"
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/asynctcpsocket.h"
+#include "talk/base/logging.h"
+#include "talk/base/socketadapters.h"
+#include "talk/base/thread.h"
+
+namespace talk_base {
+
+BasicPacketSocketFactory::BasicPacketSocketFactory()
+ : thread_(Thread::Current()),
+ socket_factory_(NULL) {
+}
+
+BasicPacketSocketFactory::BasicPacketSocketFactory(Thread* thread)
+ : thread_(thread),
+ socket_factory_(NULL) {
+}
+
+BasicPacketSocketFactory::BasicPacketSocketFactory(
+ SocketFactory* socket_factory)
+ : thread_(NULL),
+ socket_factory_(socket_factory) {
+}
+
+BasicPacketSocketFactory::~BasicPacketSocketFactory() {
+}
+
+AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket(
+ const SocketAddress& address, int min_port, int max_port) {
+ // UDP sockets are simple.
+ talk_base::AsyncSocket* socket =
+ socket_factory()->CreateAsyncSocket(SOCK_DGRAM);
+ if (!socket) {
+ return NULL;
+ }
+ if (BindSocket(socket, address, min_port, max_port) < 0) {
+ LOG(LS_ERROR) << "UDP bind failed with error "
+ << socket->GetError();
+ delete socket;
+ return NULL;
+ }
+ return new talk_base::AsyncUDPSocket(socket);
+}
+
+AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket(
+ const SocketAddress& local_address, int min_port, int max_port, bool ssl) {
+ talk_base::AsyncSocket* socket =
+ socket_factory()->CreateAsyncSocket(SOCK_STREAM);
+ if (!socket) {
+ return NULL;
+ }
+
+ if (BindSocket(socket, local_address, min_port, max_port) < 0) {
+ LOG(LS_ERROR) << "TCP bind failed with error "
+ << socket->GetError();
+ delete socket;
+ return NULL;
+ }
+
+ // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
+ if (ssl) {
+ socket = new talk_base::AsyncSSLSocket(socket);
+ }
+
+ // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
+ // See http://go/gtalktcpnodelayexperiment
+ socket->SetOption(talk_base::Socket::OPT_NODELAY, 1);
+
+ return new talk_base::AsyncTCPSocket(socket, true);
+}
+
+AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
+ const SocketAddress& local_address, const SocketAddress& remote_address,
+ const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl) {
+ talk_base::AsyncSocket* socket =
+ socket_factory()->CreateAsyncSocket(SOCK_STREAM);
+ if (!socket) {
+ return NULL;
+ }
+
+ if (BindSocket(socket, local_address, 0, 0) < 0) {
+ LOG(LS_ERROR) << "TCP bind failed with error "
+ << socket->GetError();
+ delete socket;
+ return NULL;
+ }
+
+ // If using a proxy, wrap the socket in a proxy socket.
+ if (proxy_info.type == talk_base::PROXY_SOCKS5) {
+ socket = new talk_base::AsyncSocksProxySocket(
+ socket, proxy_info.address, proxy_info.username, proxy_info.password);
+ } else if (proxy_info.type == talk_base::PROXY_HTTPS) {
+ socket = new talk_base::AsyncHttpsProxySocket(
+ socket, user_agent, proxy_info.address,
+ proxy_info.username, proxy_info.password);
+ }
+
+ // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
+ if (ssl) {
+ socket = new talk_base::AsyncSSLSocket(socket);
+ }
+
+ if (socket->Connect(remote_address) < 0) {
+ LOG(LS_ERROR) << "TCP connect failed with error "
+ << socket->GetError();
+ delete socket;
+ return NULL;
+ }
+
+ // Finally, wrap that socket in a TCP packet socket.
+ talk_base::AsyncTCPSocket* tcp_socket =
+ new talk_base::AsyncTCPSocket(socket, false);
+
+ // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
+ // See http://go/gtalktcpnodelayexperiment
+ tcp_socket->SetOption(talk_base::Socket::OPT_NODELAY, 1);
+
+ return tcp_socket;
+}
+
+int BasicPacketSocketFactory::BindSocket(
+ AsyncSocket* socket, const SocketAddress& local_address,
+ int min_port, int max_port) {
+ int ret = -1;
+ if (min_port == 0 && max_port == 0) {
+ // If there's no port range, let the OS pick a port for us.
+ ret = socket->Bind(local_address);
+ } else {
+ // Otherwise, try to find a port in the provided range.
+ for (int port = min_port; ret < 0 && port <= max_port; ++port) {
+ ret = socket->Bind(talk_base::SocketAddress(local_address.ip(), port));
+ }
+ }
+ return ret;
+}
+
+SocketFactory* BasicPacketSocketFactory::socket_factory() {
+ if (thread_) {
+ ASSERT(thread_ == Thread::Current());
+ return thread_->socketserver();
+ } else {
+ return socket_factory_;
+ }
+}
+
+} // namespace talk_base
diff --git a/talk/base/basicpacketsocketfactory.h b/talk/base/basicpacketsocketfactory.h
new file mode 100644
index 0000000..bf66bc8
--- /dev/null
+++ b/talk/base/basicpacketsocketfactory.h
@@ -0,0 +1,66 @@
+/*
+ * libjingle
+ * Copyright 2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_BASE_BASICPACKETSOCKETFACTORY_H_
+#define TALK_BASE_BASICPACKETSOCKETFACTORY_H_
+
+#include "talk/base/packetsocketfactory.h"
+
+namespace talk_base {
+
+class AsyncSocket;
+class SocketFactory;
+class Thread;
+
+class BasicPacketSocketFactory : public PacketSocketFactory {
+ public:
+ BasicPacketSocketFactory();
+ explicit BasicPacketSocketFactory(Thread* thread);
+ explicit BasicPacketSocketFactory(SocketFactory* socket_factory);
+ virtual ~BasicPacketSocketFactory();
+
+ virtual AsyncPacketSocket* CreateUdpSocket(
+ const SocketAddress& local_address, int min_port, int max_port);
+ virtual AsyncPacketSocket* CreateServerTcpSocket(
+ const SocketAddress& local_address, int min_port, int max_port, bool ssl);
+ virtual AsyncPacketSocket* CreateClientTcpSocket(
+ const SocketAddress& local_address, const SocketAddress& remote_address,
+ const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl);
+
+ private:
+ int BindSocket(AsyncSocket* socket, const SocketAddress& local_address,
+ int min_port, int max_port);
+
+ SocketFactory* socket_factory();
+
+ Thread* thread_;
+ SocketFactory* socket_factory_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_BASICPACKETSOCKETFACTORY_H_
diff --git a/talk/base/packetsocketfactory.h b/talk/base/packetsocketfactory.h
new file mode 100644
index 0000000..7c74e86
--- /dev/null
+++ b/talk/base/packetsocketfactory.h
@@ -0,0 +1,60 @@
+/*
+ * libjingle
+ * Copyright 2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_BASE_PACKETSOCKETFACTORY_H_
+#define TALK_BASE_PACKETSOCKETFACTORY_H_
+
+#include "talk/base/proxyinfo.h"
+
+namespace talk_base {
+
+class AsyncPacketSocket;
+
+class PacketSocketFactory {
+ public:
+ PacketSocketFactory() { }
+ virtual ~PacketSocketFactory() { }
+
+ virtual AsyncPacketSocket* CreateUdpSocket(
+ const SocketAddress& address, int min_port, int max_port) = 0;
+ virtual AsyncPacketSocket* CreateServerTcpSocket(
+ const SocketAddress& local_address, int min_port, int max_port,
+ bool ssl) = 0;
+
+ // TODO: |proxy_info| and |user_agent| should be set
+ // per-factory and not when socket is created.
+ virtual AsyncPacketSocket* CreateClientTcpSocket(
+ const SocketAddress& local_address, const SocketAddress& remote_address,
+ const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl) = 0;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(PacketSocketFactory);
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_PACKETSOCKETFACTORY_H_
diff --git a/talk/libjingle.scons b/talk/libjingle.scons
index b48fc65..5d77429 100644
--- a/talk/libjingle.scons
+++ b/talk/libjingle.scons
@@ -46,8 +46,8 @@
"third_party/srtp/srtp/srtp.c",
],
includedirs = [
- "third_party/srtpinclude",
- "third_party/srtpcrypto/include",
+ "third_party/srtp/include",
+ "third_party/srtp/crypto/include",
],
win_ccflags = [
"/wd4701",
@@ -64,6 +64,7 @@
"sound/alsasymboltable.cc",
"sound/linuxsoundsystem.cc",
"sound/pulseaudiosoundsystem.cc",
+ "sound/pulseaudiosymboltable.cc",
"sound/platformsoundsystem.cc",
"sound/platformsoundsystemfactory.cc",
"sound/soundsysteminterface.cc",
@@ -99,6 +100,7 @@
"base/asyncudpsocket.cc",
"base/autodetectproxy.cc",
"base/base64.cc",
+ "base/basicpacketsocketfactory.cc",
"base/bytebuffer.cc",
"base/checks.cc",
"base/common.cc",
@@ -209,8 +211,8 @@
includedirs = [
"third_party/libudev",
"third_party/expat-2.0.1",
- "third_party/srtpinclude",
- "third_party/srtpcrypto/include",
+ "third_party/srtp/include",
+ "third_party/srtp/crypto/include",
],
win_srcs = [
"base/schanneladapter.cc",
@@ -222,6 +224,7 @@
"base/win32window.cc",
"base/winfirewall.cc",
"base/winping.cc",
+ "session/phone/gdivideorenderer.cc",
],
)
talk.App(env, name = "login",
@@ -241,8 +244,28 @@
lin_libs = [
"libpthread",
":libssl.so.0.9.8",
+ "gdk_pixbuf-2.0",
+ "gdk-x11-2.0",
+ "glib-2.0",
+ "gobject-2.0",
+ "gtk-x11-2.0",
+ "videorenderer",
],
)
+talk.Library(env, name = "videorenderer",
+ lin_srcs = [
+ "session/phone/gtkvideorenderer.cc",
+ ],
+ lin_includedirs = [
+ "/usr/include/atk-1.0",
+ "/usr/include/cairo",
+ "/usr/include/glib-2.0",
+ "/usr/include/gtk-2.0",
+ "/usr/include/pango-1.0",
+ "/usr/lib/glib-2.0/include",
+ "/usr/lib/gtk-2.0/include",
+ ],
+)
talk.Library(env, name = "libxmpphelp",
libs = [
"libjingle",
@@ -279,10 +302,15 @@
"FEATURE_ENABLE_VOICEMAIL",
],
lin_libs = [
+ "gdk_pixbuf-2.0",
+ "gdk-x11-2.0",
+ "glib-2.0",
+ "gobject-2.0",
"gtk-x11-2.0",
"libasound",
"libpthread",
":libssl.so.0.9.8",
+ "videorenderer",
],
srcs = [
"examples/call/call_main.cc",
diff --git a/talk/main.scons b/talk/main.scons
index 58c3bae..349c317 100644
--- a/talk/main.scons
+++ b/talk/main.scons
@@ -347,6 +347,7 @@
linux_common_env = posix_env.Clone(
tools = [
'target_platform_linux',
+ 'talk_libjingle',
#'talk_linux',
],
)
diff --git a/talk/session/phone/devicemanager.cc b/talk/session/phone/devicemanager.cc
index 283b84e..87cd8c9 100644
--- a/talk/session/phone/devicemanager.cc
+++ b/talk/session/phone/devicemanager.cc
@@ -113,14 +113,6 @@
DeviceManager* manager_;
void* impl_;
};
-#elif defined(IOS) || defined(ANDROID)
-// We don't use DeviceWatcher on iOS or Android, so just stub out a noop class.
-class DeviceWatcher {
- public:
- explicit DeviceWatcher(DeviceManager* dm) {}
- bool Start() { return true; }
- void Stop() {}
-};
#endif
#if !defined(LINUX) && !defined(IOS)
diff --git a/talk/session/phone/gdivideorenderer.cc b/talk/session/phone/gdivideorenderer.cc
new file mode 100644
index 0000000..6afb764
--- /dev/null
+++ b/talk/session/phone/gdivideorenderer.cc
@@ -0,0 +1,265 @@
+// libjingle
+// Copyright 2004 Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// 3. The name of the author may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Implementation of GdiVideoRenderer on Windows
+
+#ifdef WIN32
+
+#include "talk/session/phone/gdivideorenderer.h"
+
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/thread.h"
+#include "talk/base/win32window.h"
+#include "talk/session/phone/videocommon.h"
+
+namespace cricket {
+
+/////////////////////////////////////////////////////////////////////////////
+// Definition of private class VideoWindow. We use a worker thread to manage
+// the window.
+/////////////////////////////////////////////////////////////////////////////
+class GdiVideoRenderer::VideoWindow : public talk_base::Win32Window {
+ public:
+ VideoWindow(int x, int y, int width, int height);
+ virtual ~VideoWindow();
+
+ // Called when the video size changes. If it is called the first time, we
+ // create and start the thread. Otherwise, we send kSetSizeMsg to the thread.
+ // Context: non-worker thread.
+ bool SetSize(int width, int height);
+
+ // Called when a new frame is available. Upon this call, we send
+ // kRenderFrameMsg to the window thread. Context: non-worker thread. It may be
+ // better to pass RGB bytes to VideoWindow. However, we pass VideoFrame to put
+ // all the thread synchronization within VideoWindow.
+ bool RenderFrame(const VideoFrame* frame);
+
+ protected:
+ // Override virtual method of talk_base::Win32Window. Context: worker Thread.
+ virtual bool OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
+ LRESULT& result);
+
+ private:
+ enum { kSetSizeMsg = WM_USER, kRenderFrameMsg};
+
+ class WindowThread : public talk_base::Thread {
+ public:
+ explicit WindowThread(VideoWindow* window) : window_(window) {}
+
+ // Override virtual method of talk_base::Thread. Context: worker Thread.
+ virtual void Run() {
+ // Initialize the window
+ if (!window_ || !window_->Initialize()) {
+ return;
+ }
+ // Run the message loop
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ private:
+ VideoWindow* window_;
+ };
+
+ // Context: worker Thread.
+ bool Initialize();
+ void OnPaint();
+ void OnSize(int width, int height, bool frame_changed);
+ void OnRenderFrame(const VideoFrame* frame);
+
+ BITMAPINFO bmi_;
+ talk_base::scoped_array<uint8> image_;
+ talk_base::scoped_ptr<WindowThread> window_thread_;
+ // The initial position of the window.
+ int initial_x_;
+ int initial_y_;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// Implementation of class VideoWindow
+/////////////////////////////////////////////////////////////////////////////
+GdiVideoRenderer::VideoWindow::VideoWindow(
+ int x, int y, int width, int height)
+ : initial_x_(x),
+ initial_y_(y) {
+ memset(&bmi_.bmiHeader, 0, sizeof(bmi_.bmiHeader));
+ bmi_.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi_.bmiHeader.biPlanes = 1;
+ bmi_.bmiHeader.biBitCount = 32;
+ bmi_.bmiHeader.biCompression = BI_RGB;
+ bmi_.bmiHeader.biWidth = width;
+ bmi_.bmiHeader.biHeight = -height;
+ bmi_.bmiHeader.biSizeImage = width * height * 4;
+
+ image_.reset(new uint8[bmi_.bmiHeader.biSizeImage]);
+}
+
+GdiVideoRenderer::VideoWindow::~VideoWindow() {
+ // Context: caller Thread. We cannot call Destroy() since the window was
+ // created by another thread. Instead, we send WM_CLOSE message.
+ if (handle()) {
+ SendMessage(handle(), WM_CLOSE, 0, 0);
+ }
+}
+
+bool GdiVideoRenderer::VideoWindow::SetSize(int width, int height) {
+ if (!window_thread_.get()) {
+ // Create and start the window thread.
+ window_thread_.reset(new WindowThread(this));
+ return window_thread_->Start();
+ } else if (width != bmi_.bmiHeader.biWidth ||
+ height != -bmi_.bmiHeader.biHeight) {
+ SendMessage(handle(), kSetSizeMsg, 0, MAKELPARAM(width, height));
+ }
+ return true;
+}
+
+bool GdiVideoRenderer::VideoWindow::RenderFrame(const VideoFrame* frame) {
+ if (!handle()) {
+ return false;
+ }
+
+ SendMessage(handle(), kRenderFrameMsg, reinterpret_cast<WPARAM>(frame), 0);
+ return true;
+}
+
+bool GdiVideoRenderer::VideoWindow::OnMessage(UINT uMsg, WPARAM wParam,
+ LPARAM lParam, LRESULT& result) {
+ switch (uMsg) {
+ case WM_PAINT:
+ OnPaint();
+ return true;
+
+ case WM_DESTROY:
+ PostQuitMessage(0); // post WM_QUIT to end the message loop in Run()
+ return false;
+
+ case WM_SIZE: // The window UI was resized.
+ OnSize(LOWORD(lParam), HIWORD(lParam), false);
+ return true;
+
+ case kSetSizeMsg: // The video resolution changed.
+ OnSize(LOWORD(lParam), HIWORD(lParam), true);
+ return true;
+
+ case kRenderFrameMsg:
+ OnRenderFrame(reinterpret_cast<const VideoFrame*>(wParam));
+ return true;
+ }
+ return false;
+}
+
+bool GdiVideoRenderer::VideoWindow::Initialize() {
+ if (!talk_base::Win32Window::Create(
+ NULL, L"Video Renderer",
+ WS_OVERLAPPEDWINDOW | WS_SIZEBOX,
+ WS_EX_APPWINDOW,
+ initial_x_, initial_y_,
+ bmi_.bmiHeader.biWidth, -bmi_.bmiHeader.biHeight)) {
+ return false;
+ }
+ OnSize(bmi_.bmiHeader.biWidth, -bmi_.bmiHeader.biHeight, false);
+ return true;
+}
+
+void GdiVideoRenderer::VideoWindow::OnPaint() {
+ RECT rcClient;
+ GetClientRect(handle(), &rcClient);
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(handle(), &ps);
+ StretchDIBits(hdc,
+ 0, 0, rcClient.right, rcClient.bottom, // destination rect
+ 0, 0, bmi_.bmiHeader.biWidth, -bmi_.bmiHeader.biHeight, // source rect
+ image_.get(), &bmi_, DIB_RGB_COLORS, SRCCOPY);
+ EndPaint(handle(), &ps);
+}
+
+void GdiVideoRenderer::VideoWindow::OnSize(int width, int height,
+ bool frame_changed) {
+ // Get window and client sizes
+ RECT rcClient, rcWindow;
+ GetClientRect(handle(), &rcClient);
+ GetWindowRect(handle(), &rcWindow);
+
+ // Find offset between window size and client size
+ POINT ptDiff;
+ ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
+ ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
+
+ // Resize client
+ MoveWindow(handle(), rcWindow.left, rcWindow.top,
+ width + ptDiff.x, height + ptDiff.y, false);
+ UpdateWindow(handle());
+ ShowWindow(handle(), SW_SHOW);
+
+ if (frame_changed && (width != bmi_.bmiHeader.biWidth ||
+ height != -bmi_.bmiHeader.biHeight)) {
+ // Update the bmi and image buffer
+ bmi_.bmiHeader.biWidth = width;
+ bmi_.bmiHeader.biHeight = -height;
+ bmi_.bmiHeader.biSizeImage = width * height * 4;
+ image_.reset(new uint8[bmi_.bmiHeader.biSizeImage]);
+ }
+}
+
+void GdiVideoRenderer::VideoWindow::OnRenderFrame(const VideoFrame* frame) {
+ if (!frame) {
+ return;
+ }
+ // Convert frame to ARGB format, which is accepted by GDI
+ frame->ConvertToRgbBuffer(cricket::FOURCC_ARGB, image_.get(),
+ bmi_.bmiHeader.biSizeImage,
+ bmi_.bmiHeader.biWidth * 4);
+ InvalidateRect(handle(), 0, 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Implementation of class GdiVideoRenderer
+/////////////////////////////////////////////////////////////////////////////
+GdiVideoRenderer::GdiVideoRenderer(int x, int y)
+ : initial_x_(x),
+ initial_y_(y) {
+}
+GdiVideoRenderer::~GdiVideoRenderer() {}
+
+bool GdiVideoRenderer::SetSize(int width, int height, int reserved) {
+ if (!window_.get()) { // Create the window for the first frame
+ window_.reset(new VideoWindow(initial_x_, initial_y_, width, height));
+ }
+ return window_->SetSize(width, height);
+}
+
+bool GdiVideoRenderer::RenderFrame(const VideoFrame* frame) {
+ if (!frame || !window_.get()) {
+ return false;
+ }
+ return window_->RenderFrame(frame);
+}
+
+} // namespace cricket
+#endif // WIN32
diff --git a/talk/session/phone/gtkvideorenderer.cc b/talk/session/phone/gtkvideorenderer.cc
new file mode 100644
index 0000000..4e356b3
--- /dev/null
+++ b/talk/session/phone/gtkvideorenderer.cc
@@ -0,0 +1,114 @@
+// libjingle
+// Copyright 2004 Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// 3. The name of the author may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Implementation of GtkVideoRenderer
+
+#include "talk/session/phone/gtkvideorenderer.h"
+
+#include <gtk/gtk.h>
+
+#include "talk/session/phone/videocommon.h"
+
+namespace cricket {
+
+GtkVideoRenderer::~GtkVideoRenderer() {
+ if (window_) {
+ gtk_widget_destroy(window_);
+ // Run the Gtk main loop to tear down the window.
+ Pump();
+ }
+ // Don't need to destroy draw_area_ because it is not top-level, so it is
+ // implicitly destroyed by the above.
+}
+
+bool GtkVideoRenderer::SetSize(int width, int height, int reserved) {
+ // For the first frame, initialize the GTK window
+ if (!window_ && !Initialize(width, height)) {
+ return false;
+ }
+
+ image_.reset(new uint8[width * height * 4]);
+ gtk_window_resize(GTK_WINDOW(window_), width, height);
+ return true;
+}
+
+bool GtkVideoRenderer::RenderFrame(const VideoFrame* frame) {
+ if (!frame) {
+ return false;
+ }
+
+ if (!GTK_IS_WINDOW(window_) || !GTK_IS_DRAWING_AREA(draw_area_)) {
+ // window was closed
+ return false;
+ }
+
+ // convert I420 frame to ABGR format, which is accepted by GTK
+ frame->ConvertToRgbBuffer(cricket::FOURCC_ABGR,
+ image_.get(),
+ frame->GetWidth() * frame->GetHeight() * 4,
+ frame->GetWidth() * 4);
+
+ // draw the ABGR image
+ gdk_draw_rgb_32_image(draw_area_->window,
+ draw_area_->style->fg_gc[GTK_STATE_NORMAL],
+ 0,
+ 0,
+ frame->GetWidth(),
+ frame->GetHeight(),
+ GDK_RGB_DITHER_MAX,
+ image_.get(),
+ frame->GetWidth() * 4);
+
+ // Run the Gtk main loop to refresh the window.
+ Pump();
+ return true;
+}
+
+bool GtkVideoRenderer::Initialize(int width, int height) {
+ gtk_init(NULL, NULL);
+ window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ draw_area_ = gtk_drawing_area_new();
+ if (!window_ || !draw_area_) {
+ return false;
+ }
+
+ gtk_window_set_position(GTK_WINDOW(window_), GTK_WIN_POS_CENTER);
+ gtk_window_set_title(GTK_WINDOW(window_), "Video Renderer");
+ gtk_widget_set_size_request(draw_area_, width, height);
+ gtk_container_add(GTK_CONTAINER(window_), draw_area_);
+ gtk_widget_show_all(window_);
+ gtk_window_move(GTK_WINDOW(window_), initial_x_, initial_y_);
+
+ image_.reset(new uint8[width * height * 4]);
+ return true;
+}
+
+void GtkVideoRenderer::Pump() {
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+}
+
+} // namespace cricket
diff --git a/talk/site_scons/site_tools/talk_libjingle.py b/talk/site_scons/site_tools/talk_libjingle.py
new file mode 100644
index 0000000..3086614
--- /dev/null
+++ b/talk/site_scons/site_tools/talk_libjingle.py
@@ -0,0 +1,45 @@
+# Copyright 2010 Google Inc.
+# All Rights Reserved.
+# Author: thaloun@google.com (Tim Haloun)
+
+"""Tools that we need to include with libjingle."""
+
+import subprocess
+
+# We need this in libjingle because main.scons depends on it and
+# libjingle depends on main.scons.
+def EnableFeatureWherePackagePresent(env, bit, cpp_flag, package):
+ """Enable a feature if a required pkg-config package is present.
+
+ Args:
+ env: The current SCons environment.
+ bit: The name of the Bit to enable when the package is present.
+ cpp_flag: The CPP flag to enable when the package is present.
+ package: The name of the package.
+ """
+ if not env.Bit('host_linux'):
+ return
+ if _HavePackage(package):
+ env.SetBits(bit)
+ env.Append(CPPDEFINES = [cpp_flag])
+ else:
+ print ("Warning: Package \"%s\" not found. Feature \"%s\" will not be "
+ "built. To build with this feature, install the package that "
+ "provides the \"%s.pc\" file.") % (package, bit, package)
+
+def _HavePackage(package):
+ """Whether the given pkg-config package name is present on the build system.
+
+ Args:
+ package: The name of the package.
+
+ Return:
+ True if the package is present, else False
+ """
+ return subprocess.call(["pkg-config", "--exists", package]) == 0
+
+def generate(env):
+ env.AddMethod(EnableFeatureWherePackagePresent)
+
+def exists(env):
+ return 1
diff --git a/talk/sound/pulseaudiosymboltable.cc b/talk/sound/pulseaudiosymboltable.cc
new file mode 100644
index 0000000..008b003
--- /dev/null
+++ b/talk/sound/pulseaudiosymboltable.cc
@@ -0,0 +1,39 @@
+/*
+ * libjingle
+ * Copyright 2004--2010, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/sound/pulseaudiosymboltable.h"
+
+namespace cricket {
+
+LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(PulseAudioSymbolTable, "libpulse.so.0")
+#define X(sym) \
+ LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(PulseAudioSymbolTable, sym)
+PULSE_AUDIO_SYMBOLS_LIST
+#undef X
+LATE_BINDING_SYMBOL_TABLE_DEFINE_END(PulseAudioSymbolTable)
+
+} // namespace cricket
diff --git a/talk/sound/pulseaudiosymboltable.h b/talk/sound/pulseaudiosymboltable.h
new file mode 100644
index 0000000..21be35e
--- /dev/null
+++ b/talk/sound/pulseaudiosymboltable.h
@@ -0,0 +1,99 @@
+/*
+ * libjingle
+ * Copyright 2004--2010, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_SOUND_PULSEAUDIOSYMBOLTABLE_H_
+#define TALK_SOUND_PULSEAUDIOSYMBOLTABLE_H_
+
+#include "talk/base/latebindingsymboltable.h"
+
+namespace cricket {
+
+// The PulseAudio symbols we need, as an X-Macro list.
+// This list must contain precisely every libpulse function that is used in
+// pulseaudiosoundsystem.cc.
+#define PULSE_AUDIO_SYMBOLS_LIST \
+ X(pa_bytes_per_second) \
+ X(pa_context_connect) \
+ X(pa_context_disconnect) \
+ X(pa_context_errno) \
+ X(pa_context_get_protocol_version) \
+ X(pa_context_get_server_info) \
+ X(pa_context_get_sink_info_list) \
+ X(pa_context_get_sink_input_info) \
+ X(pa_context_get_source_info_by_index) \
+ X(pa_context_get_source_info_list) \
+ X(pa_context_get_state) \
+ X(pa_context_new) \
+ X(pa_context_set_sink_input_volume) \
+ X(pa_context_set_source_volume_by_index) \
+ X(pa_context_set_state_callback) \
+ X(pa_context_unref) \
+ X(pa_cvolume_set) \
+ X(pa_operation_get_state) \
+ X(pa_operation_unref) \
+ X(pa_stream_connect_playback) \
+ X(pa_stream_connect_record) \
+ X(pa_stream_disconnect) \
+ X(pa_stream_drop) \
+ X(pa_stream_get_device_index) \
+ X(pa_stream_get_index) \
+ X(pa_stream_get_latency) \
+ X(pa_stream_get_sample_spec) \
+ X(pa_stream_get_state) \
+ X(pa_stream_new) \
+ X(pa_stream_peek) \
+ X(pa_stream_readable_size) \
+ X(pa_stream_set_buffer_attr) \
+ X(pa_stream_set_overflow_callback) \
+ X(pa_stream_set_read_callback) \
+ X(pa_stream_set_state_callback) \
+ X(pa_stream_set_underflow_callback) \
+ X(pa_stream_set_write_callback) \
+ X(pa_stream_unref) \
+ X(pa_stream_writable_size) \
+ X(pa_stream_write) \
+ X(pa_strerror) \
+ X(pa_threaded_mainloop_free) \
+ X(pa_threaded_mainloop_get_api) \
+ X(pa_threaded_mainloop_lock) \
+ X(pa_threaded_mainloop_new) \
+ X(pa_threaded_mainloop_signal) \
+ X(pa_threaded_mainloop_start) \
+ X(pa_threaded_mainloop_stop) \
+ X(pa_threaded_mainloop_unlock) \
+ X(pa_threaded_mainloop_wait)
+
+LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(PulseAudioSymbolTable)
+#define X(sym) \
+ LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(PulseAudioSymbolTable, sym)
+PULSE_AUDIO_SYMBOLS_LIST
+#undef X
+LATE_BINDING_SYMBOL_TABLE_DECLARE_END(PulseAudioSymbolTable)
+
+} // namespace cricket
+
+#endif // TALK_SOUND_PULSEAUDIOSYMBOLTABLE_H_