Fix thread safety in XmlElement.
git-svn-id: http://libjingle.googlecode.com/svn/trunk@76 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/talk/base/basictypes.h b/talk/base/basictypes.h
index a160ee9..d34cb39 100644
--- a/talk/base/basictypes.h
+++ b/talk/base/basictypes.h
@@ -28,6 +28,8 @@
#ifndef TALK_BASE_BASICTYPES_H__
#define TALK_BASE_BASICTYPES_H__
+#include <stddef.h> // for NULL, size_t
+
#ifndef WIN32
#include <stdint.h> // for uintptr_t
#endif
diff --git a/talk/base/criticalsection.h b/talk/base/criticalsection.h
index ee3db1a..07cf5b2 100644
--- a/talk/base/criticalsection.h
+++ b/talk/base/criticalsection.h
@@ -126,6 +126,35 @@
CriticalSection *pcrit_;
};
+// TODO: Replace with platform-specific "atomic" ops.
+// Something like: google3/base/atomicops.h TODO: And, move
+// it to atomicops.h, which can't be done easily because of complex
+// compile rules.
+class AtomicOps {
+ public:
+ static int Increment(int* i) {
+ // Could be faster, and less readable:
+ // static CriticalSection* crit = StaticCrit();
+ // CritScope scope(crit);
+ CritScope scope(StaticCrit());
+ return ++(*i);
+ }
+
+ static int Decrement(int* i) {
+ // Could be faster, and less readable:
+ // static CriticalSection* crit = StaticCrit();
+ // CritScope scope(crit);
+ CritScope scope(StaticCrit());
+ return --(*i);
+ }
+
+ private:
+ static CriticalSection* StaticCrit() {
+ static CriticalSection* crit = new CriticalSection();
+ return crit;
+ }
+};
+
} // namespace talk_base
#endif // TALK_BASE_CRITICALSECTION_H__
diff --git a/talk/base/latebindingsymboltable.h b/talk/base/latebindingsymboltable.h
index 994c26a..3a9544f 100644
--- a/talk/base/latebindingsymboltable.h
+++ b/talk/base/latebindingsymboltable.h
@@ -28,7 +28,6 @@
#ifndef TALK_BASE_LATEBINDINGSYMBOLTABLE_H_
#define TALK_BASE_LATEBINDINGSYMBOLTABLE_H_
-#include <stddef.h> // for NULL
#include <string.h>
#include "talk/base/common.h"
diff --git a/talk/base/macutils.cc b/talk/base/macutils.cc
index fefe2b9..21d31ff 100644
--- a/talk/base/macutils.cc
+++ b/talk/base/macutils.cc
@@ -62,6 +62,7 @@
return (NULL != *str16);
}
+#ifdef OSX
void DecodeFourChar(UInt32 fc, std::string* out) {
std::stringstream ss;
ss << '\'';
@@ -187,7 +188,7 @@
}
err = OSAExecute(component, script_id, kOSANullScript, kOSAModeCanInteract,
- &result_id);
+ &result_id);
if (err == errOSAScriptError) {
LOG(LS_ERROR) << "Error when executing Apple Script: " << script;
@@ -213,7 +214,7 @@
CloseComponent(component);
return true;
}
-
+#endif
///////////////////////////////////////////////////////////////////////////////
diff --git a/talk/base/macutils.h b/talk/base/macutils.h
index 30bb300..be6e728 100644
--- a/talk/base/macutils.h
+++ b/talk/base/macutils.h
@@ -29,16 +29,22 @@
#define TALK_BASE_MACUTILS_H__
#include <CoreFoundation/CoreFoundation.h>
+#ifdef OSX
#include <Carbon/Carbon.h>
+#endif
#include <string>
namespace talk_base {
///////////////////////////////////////////////////////////////////////////////
+// Note that some of these functions work for both iOS and Mac OS X. The ones
+// that are specific to Mac are #ifdef'ed as such.
+
bool ToUtf8(const CFStringRef str16, std::string* str8);
bool ToUtf16(const std::string& str8, CFStringRef* str16);
+#ifdef OSX
void DecodeFourChar(UInt32 fc, std::string* out);
std::string DecodeEvent(EventRef event);
@@ -58,6 +64,7 @@
// Runs the given apple script. Only supports scripts that does not
// require user interaction.
bool RunAppleScript(const std::string& script);
+#endif
///////////////////////////////////////////////////////////////////////////////
diff --git a/talk/base/thread.cc b/talk/base/thread.cc
index 609d965..1603ef6 100644
--- a/talk/base/thread.cc
+++ b/talk/base/thread.cc
@@ -174,7 +174,8 @@
#if defined(WIN32)
thread_(NULL),
#endif
- owned_(true) {
+ owned_(true),
+ delete_self_when_complete_(false) {
g_thmgr.Add(this);
SetName("Thread", this); // default name
}
@@ -367,6 +368,10 @@
} else {
init->thread->Run();
}
+ if (init->thread->delete_self_when_complete_) {
+ init->thread->started_ = false;
+ delete init->thread;
+ }
delete init;
return NULL;
}
diff --git a/talk/base/thread.h b/talk/base/thread.h
index efbdae7..50d8eeb 100644
--- a/talk/base/thread.h
+++ b/talk/base/thread.h
@@ -151,6 +151,12 @@
bool started() const { return started_; }
bool Start(Runnable* runnable = NULL);
+ // Used for fire-and-forget threads. Deletes this thread object when the
+ // Run method returns.
+ void Release() {
+ delete_self_when_complete_ = true;
+ }
+
// Tells the thread to stop and waits until it is joined.
// Never call Stop on the current thread. Instead use the inherited Quit
// function which will exit the base MessageQueue without terminating the
@@ -215,6 +221,7 @@
#endif
bool owned_;
+ bool delete_self_when_complete_;
friend class ThreadManager;
diff --git a/talk/base/unixfilesystem.cc b/talk/base/unixfilesystem.cc
index 2a243ba..096c511 100644
--- a/talk/base/unixfilesystem.cc
+++ b/talk/base/unixfilesystem.cc
@@ -61,36 +61,24 @@
#include "talk/base/stream.h"
#include "talk/base/stringutils.h"
-#ifdef ANDROID
-namespace {
-// Android does not have a concept of a single temp dir shared by all
-// because resource are scarse on a phone. Instead each app gets some
-// space on the sdcard under a path that is given at runtime by the
-// system.
-// The disk allocation feature is still work in progress so currently
-// we return a hardcoded a path on the sdcard. In the future, we
-// should do a JNI call to get that info from the context.
-// TODO: Replace hardcoded path with a query to the Context
-// object to get the equivalents of '/tmp' and '~/.'
-
-// @return the folder for libjingle. Some extra path (typically
-// Google/<app name>) will be added.
-const char* GetAndroidAppDataFolder() {
- return "/sdcard";
-}
-
-// @return the tmp folder to be used. Some extra path will be added to
-// that base folder.
-const char* GetAndroidTempFolder() {
- return "/sdcard";
-}
-
-} // anonymous namespace
-#endif
-
namespace talk_base {
-std::string UnixFilesystem::app_temp_path_;
+#if !defined(ANDROID) && !defined(IOS)
+char* UnixFilesystem::app_temp_path_ = NULL;
+#else
+char* UnixFilesystem::provided_app_data_folder_ = NULL;
+char* UnixFilesystem::provided_app_temp_folder_ = NULL;
+
+void UnixFilesystem::SetAppDataFolder(const std::string& folder) {
+ delete [] provided_app_data_folder_;
+ provided_app_data_folder_ = CopyString(folder);
+}
+
+void UnixFilesystem::SetAppTempFolder(const std::string& folder) {
+ delete [] provided_app_temp_folder_;
+ provided_app_temp_folder_ = CopyString(folder);
+}
+#endif
bool UnixFilesystem::CreateFolder(const Pathname &path) {
std::string pathname(path.pathname());
@@ -179,8 +167,9 @@
if (0 != FSRefMakePath(&fr, buffer, ARRAY_SIZE(buffer)))
return false;
pathname.SetPathname(reinterpret_cast<char*>(buffer), "");
-#elif defined(ANDROID)
- pathname.SetPathname(GetAndroidTempFolder(), "");
+#elif defined(ANDROID) || defined(IOS)
+ ASSERT(provided_app_temp_folder_ != NULL);
+ pathname.SetPathname(provided_app_temp_folder_, "");
#else // !OSX && !ANDROID
if (const char* tmpdir = getenv("TMPDIR")) {
pathname.SetPathname(tmpdir, "");
@@ -288,15 +277,19 @@
}
bool UnixFilesystem::IsTemporaryPath(const Pathname& pathname) {
+#if defined(ANDROID) || defined(IOS)
+ ASSERT(provided_app_temp_folder_ != NULL);
+#endif
+
const char* const kTempPrefixes[] = {
-#ifdef ANDROID
- GetAndroidTempFolder()
+#if defined(ANDROID) || defined(IOS)
+ provided_app_temp_folder_,
#else
"/tmp/", "/var/tmp/",
#ifdef OSX
"/private/tmp/", "/private/var/tmp/", "/private/var/folders/",
#endif // OSX
-#endif // ANDROID
+#endif // ANDROID || IOS
};
for (size_t i = 0; i < ARRAY_SIZE(kTempPrefixes); ++i) {
if (0 == strncmp(pathname.pathname().c_str(), kTempPrefixes[i],
@@ -396,11 +389,10 @@
// TODO
return false;
}
-#elif defined(ANDROID) // && !OSX
- // TODO: Check if the new disk allocation mechanism works
- // per-user and we don't have the per_user distinction.
- path->SetPathname(GetAndroidAppDataFolder(), "");
-#elif defined(LINUX) // && !OSX && !defined(ANDROID)
+#elif defined(ANDROID) || defined(IOS) // && !OSX
+ ASSERT(provided_app_data_folder_ != NULL);
+ path->SetPathname(provided_app_data_folder_, "");
+#elif defined(LINUX) // && !OSX && !defined(ANDROID) && !defined(IOS)
if (per_user) {
// We follow the recommendations in
// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
@@ -434,7 +426,7 @@
#endif // !OSX && !defined(ANDROID) && !defined(LINUX)
// Now add on a sub-path for our app.
-#if defined(OSX) || defined(ANDROID)
+#if defined(OSX) || defined(ANDROID) || defined(IOS)
path->AppendFolder(organization_name_);
path->AppendFolder(application_name_);
#elif defined(LINUX)
@@ -452,9 +444,14 @@
}
bool UnixFilesystem::GetAppTempFolder(Pathname* path) {
+#if defined(ANDROID) || defined(IOS)
+ ASSERT(provided_app_temp_folder_ != NULL);
+ path->SetPathname(provided_app_temp_folder_);
+ return true;
+#else
ASSERT(!application_name_.empty());
// TODO: Consider whether we are worried about thread safety.
- if (!app_temp_path_.empty()) {
+ if (app_temp_path_ != NULL && strlen(app_temp_path_) > 0) {
path->SetPathname(app_temp_path_);
return true;
}
@@ -469,9 +466,11 @@
if (!GetTemporaryFolder(*path, true, &folder))
return false;
- app_temp_path_ = path->pathname();
+ delete [] app_temp_path_;
+ app_temp_path_ = CopyString(path->pathname());
// TODO: atexit(DeleteFolderAndContents(app_temp_path_));
return true;
+#endif
}
bool UnixFilesystem::GetDiskFreeSpace(const Pathname& path, int64 *freebytes) {
@@ -519,4 +518,16 @@
return cwd;
}
+char* UnixFilesystem::CopyString(const std::string& str) {
+ size_t size = str.length() + 1;
+
+ char* buf = new char[size];
+ if (!buf) {
+ return NULL;
+ }
+
+ strcpyn(buf, size, str.c_str());
+ return buf;
+}
+
} // namespace talk_base
diff --git a/talk/base/unixfilesystem.h b/talk/base/unixfilesystem.h
index 71960ac..e443dc8 100644
--- a/talk/base/unixfilesystem.h
+++ b/talk/base/unixfilesystem.h
@@ -34,7 +34,17 @@
class UnixFilesystem : public FilesystemInterface {
public:
-
+
+#if defined(ANDROID) || defined(IOS)
+// Android does not have a native code API to fetch the app data or temp
+// folders. That needs to be passed into this class from Java. Similarly, iOS
+// only supports an Objective-C API for fetching the folder locations, so that
+// needs to be passed in here from Objective-C.
+
+ static void SetAppDataFolder(const std::string& folder);
+ static void SetAppTempFolder(const std::string& folder);
+#endif
+
// Opens a file. Returns an open StreamInterface if function succeeds. Otherwise,
// returns NULL.
virtual FileStream *OpenFile(const Pathname &filename,
@@ -106,7 +116,14 @@
virtual Pathname GetCurrentDirectory();
private:
- static std::string app_temp_path_;
+#if defined(ANDROID) || defined(IOS)
+ static char* provided_app_data_folder_;
+ static char* provided_app_temp_folder_;
+#else
+ static char* app_temp_path_;
+#endif
+
+ static char* CopyString(const std::string& str);
};
} // namespace talk_base
diff --git a/talk/libjingle.scons b/talk/libjingle.scons
index 44259de..10b401a 100644
--- a/talk/libjingle.scons
+++ b/talk/libjingle.scons
@@ -70,6 +70,13 @@
"sound/soundsysteminterface.cc",
"sound/soundsystemproxy.cc",
],
+ dependent_target_settings = {
+ 'lin_libs': [
+ "dl",
+ "pthread",
+ "rt",
+ ],
+ },
mac_srcs = [
"base/macasyncsocket.cc",
"base/macconversion.cc",
@@ -232,44 +239,8 @@
"base/winping.cc",
"session/phone/gdivideorenderer.cc",
],
-)
-talk.App(env, name = "login",
- libs = [
- "libjingle",
- "expat",
- "libxmpphelp",
- ],
- srcs = [
- "examples/login/xmppthread.cc",
- "examples/login/login_main.cc",
- ],
- mac_libs = [
- "crypto",
- "ssl",
- ],
- 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",
+ extra_srcs = [
+ "base/json.cc",
],
)
talk.Library(env, name = "libxmpphelp",
@@ -282,6 +253,32 @@
"examples/login/xmppsocket.cc",
],
)
+talk.Library(env, name = "videorenderer",
+ lin_srcs = [
+ "session/phone/gtkvideorenderer.cc",
+ ],
+ lin_packages = [
+ "gtk+-2.0",
+ ],
+)
+talk.App(env, name = "login",
+ libs = [
+ "libjingle",
+ "expat",
+ "libxmpphelp",
+ ],
+ srcs = [
+ "examples/login/xmppthread.cc",
+ "examples/login/login_main.cc",
+ ],
+ posix_libs = [
+ "crypto",
+ "ssl",
+ ],
+ lin_libs = [
+ "videorenderer",
+ ],
+)
talk.App(env, name = "call",
mac_frameworks = [
"AudioToolbox",
@@ -300,7 +297,7 @@
"strmiids.lib",
"winmm.lib",
],
- mac_libs = [
+ posix_libs = [
"crypto",
"ssl",
],
@@ -308,14 +305,6 @@
"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 = [
@@ -344,9 +333,6 @@
srcs = [
"p2p/base/relayserver_main.cc",
],
- lin_libs = [
- "libpthread",
- ],
)
talk.App(env, name = "stunserver",
libs = [
@@ -355,7 +341,4 @@
srcs = [
"p2p/base/stunserver_main.cc",
],
- lin_libs = [
- "libpthread",
- ],
)
diff --git a/talk/main.scons b/talk/main.scons
index 9289dcf..de1d84b 100644
--- a/talk/main.scons
+++ b/talk/main.scons
@@ -24,6 +24,11 @@
# If the name is the name of a directory then that directory shall contain a
# .scons file with the same name as the directory itself:
# Ex: The directory session/phone contains a file called phone.scons
+# This list must be in order of library dependencies. e.g., if
+# session/phone/phone.scons defines a target that links to a library target
+# defined in sound/sound.scons, then 'sound' must come first.
+# When no particular order is imposed by library dependencies, try to keep in
+# mostly alphabetical order.
#
components = talk.Components("libjingle.scons")
@@ -41,7 +46,7 @@
'component_setup',
'replace_strings',
'talk_noops',
- #'talk_linux',
+ #'talk_utils',
],
BUILD_SCONSCRIPTS = components,
DESTINATION_ROOT = '$MAIN_DIR/build',
@@ -361,8 +366,7 @@
linux_common_env = posix_env.Clone(
tools = [
'target_platform_linux',
- 'talk_libjingle',
- #'talk_linux',
+ 'talk_linux',
],
)
@@ -383,6 +387,8 @@
LINKFLAGS = [
# Enable dead-code removal.
'-Wl,--gc-sections',
+ # Elide dependencies on shared libraries that we're not actually using.
+ '-Wl,--as-needed',
'-Wl,--start-group',
],
_LIBFLAGS = ['-Wl,--end-group'],
diff --git a/talk/p2p/base/port.cc b/talk/p2p/base/port.cc
index 800b9b9..7740336 100644
--- a/talk/p2p/base/port.cc
+++ b/talk/p2p/base/port.cc
@@ -134,6 +134,7 @@
ip_(ip),
min_port_(min_port),
max_port_(max_port),
+ generation_(0),
preference_(-1),
lifetime_(LT_PRESTART),
enable_port_packets_(false) {
diff --git a/talk/p2p/base/pseudotcp.cc b/talk/p2p/base/pseudotcp.cc
index 955584e..685a39f 100644
--- a/talk/p2p/base/pseudotcp.cc
+++ b/talk/p2p/base/pseudotcp.cc
@@ -231,7 +231,7 @@
m_rcv_wnd = sizeof(m_rbuf);
m_snd_nxt = m_slen = 0;
m_snd_wnd = 1;
- m_snd_una = m_rcv_nxt = m_rlen = 0;
+ m_snd_una = m_rcv_nxt = m_rlen = m_rpos = 0;
m_bReadEnable = true;
m_bWriteEnable = false;
m_t_ack = 0;
@@ -400,24 +400,23 @@
return SOCKET_ERROR;
}
- if (m_rlen == 0) {
+ // Make sure read position is correct.
+ ASSERT(m_rpos <= m_rlen);
+ if (m_rlen == m_rpos) {
m_bReadEnable = true;
m_error = EWOULDBLOCK;
return SOCKET_ERROR;
}
- uint32 read = talk_base::_min(uint32(len), m_rlen);
- memcpy(buffer, m_rbuf, read);
- m_rlen -= read;
+ uint32 read = talk_base::_min(uint32(len), m_rlen - m_rpos);
+ memcpy(buffer, m_rbuf + m_rpos, read);
+ m_rpos += read;
- // !?! until we create a circular buffer, we need to move all of the rest of the buffer up!
- memmove(m_rbuf, m_rbuf + read, sizeof(m_rbuf) - read/*m_rlen*/);
-
- if ((sizeof(m_rbuf) - m_rlen - m_rcv_wnd)
- >= talk_base::_min<uint32>(sizeof(m_rbuf) / 2, m_mss)) {
+ if (getReceiveBufferSpace() - m_rcv_wnd >=
+ talk_base::_min<uint32>(sizeof(m_rbuf) / 2, m_mss)) {
bool bWasClosed = (m_rcv_wnd == 0); // !?! Not sure about this was closed business
- m_rcv_wnd = sizeof(m_rbuf) - m_rlen;
+ m_rcv_wnd = getReceiveBufferSpace();
if (bWasClosed) {
attemptSend(sfImmediateAck);
@@ -824,8 +823,8 @@
seg.len = 0;
}
}
- if ((seg.seq + seg.len - m_rcv_nxt) > (sizeof(m_rbuf) - m_rlen)) {
- uint32 nAdjust = seg.seq + seg.len - m_rcv_nxt - (sizeof(m_rbuf) - m_rlen);
+ if ((seg.seq + seg.len - m_rcv_nxt) > getReceiveBufferSpace()) {
+ uint32 nAdjust = seg.seq + seg.len - m_rcv_nxt - getReceiveBufferSpace();
if (nAdjust < seg.len) {
seg.len -= nAdjust;
} else {
@@ -843,6 +842,12 @@
}
} else {
uint32 nOffset = seg.seq - m_rcv_nxt;
+
+ if (getReceiveBufferConsecutiveSpace() < seg.len + nOffset) {
+ consolidateReceiveBufferSpace();
+ ASSERT(getReceiveBufferConsecutiveSpace() >= seg.len + nOffset);
+ }
+
memcpy(m_rbuf + m_rlen + nOffset, seg.data, seg.len);
if (seg.seq == m_rcv_nxt) {
m_rlen += seg.len;
@@ -1082,4 +1087,26 @@
m_cwnd = talk_base::_max(m_cwnd, m_mss);
}
+bool
+PseudoTcp::isReceiveBufferFull() const {
+ return !getReceiveBufferSpace();
+}
+
+uint32
+PseudoTcp::getReceiveBufferSpace() const {
+ return sizeof(m_rbuf) - m_rlen + m_rpos;
+}
+
+uint32
+PseudoTcp::getReceiveBufferConsecutiveSpace() const {
+ return sizeof(m_rbuf) - m_rlen;
+}
+
+void
+PseudoTcp::consolidateReceiveBufferSpace() {
+ memmove(m_rbuf, m_rbuf + m_rpos, sizeof(m_rbuf) - m_rpos);
+ m_rlen -= m_rpos;
+ m_rpos = 0;
+}
+
} // namespace cricket
diff --git a/talk/p2p/base/pseudotcp.h b/talk/p2p/base/pseudotcp.h
index e8e0d3a..fd11c86 100644
--- a/talk/p2p/base/pseudotcp.h
+++ b/talk/p2p/base/pseudotcp.h
@@ -155,7 +155,20 @@
void adjustMTU();
+ protected:
+ // This method is used in test only to query receive buffer state.
+ bool isReceiveBufferFull() const;
+
private:
+ // Get the total number of bytes of free space in m_rbuf, consecutive or not.
+ uint32 getReceiveBufferSpace() const;
+
+ // Get the number of bytes that can be written to m_rbuf.
+ uint32 getReceiveBufferConsecutiveSpace() const;
+
+ // Consolidate free space in m_rbuf so that it is a consecutive segment.
+ void consolidateReceiveBufferSpace();
+
IPseudoTcpNotify* m_notify;
enum Shutdown { SD_NONE, SD_GRACEFUL, SD_FORCEFUL } m_shutdown;
int m_error;
@@ -170,7 +183,7 @@
typedef std::list<RSegment> RList;
RList m_rlist;
char m_rbuf[kRcvBufSize];
- uint32 m_rcv_nxt, m_rcv_wnd, m_rlen, m_lastrecv;
+ uint32 m_rcv_nxt, m_rcv_wnd, m_rpos, m_rlen, m_lastrecv;
// Outgoing data
SList m_slist;
diff --git a/talk/p2p/client/httpportallocator.cc b/talk/p2p/client/httpportallocator.cc
index 066a249..1e5e256 100644
--- a/talk/p2p/client/httpportallocator.cc
+++ b/talk/p2p/client/httpportallocator.cc
@@ -150,6 +150,11 @@
}
void HttpPortAllocatorSession::TryCreateRelaySession() {
+ if (allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY) {
+ LOG(LS_VERBOSE) << "HttpPortAllocator: Relay ports disabled, skipping.";
+ return;
+ }
+
if (attempts_ == HttpPortAllocator::kNumRetries) {
LOG(LS_ERROR) << "HttpPortAllocator: maximum number of requests reached; "
<< "giving up on relay.";
diff --git a/talk/session/phone/channel.cc b/talk/session/phone/channel.cc
index 05366a5..f0b8e79 100644
--- a/talk/session/phone/channel.cc
+++ b/talk/session/phone/channel.cc
@@ -34,7 +34,6 @@
#include "talk/p2p/base/transportchannel.h"
#include "talk/session/phone/channelmanager.h"
#include "talk/session/phone/mediasessionclient.h"
-#include "talk/session/phone/mediasink.h"
#include "talk/session/phone/rtcpmuxfilter.h"
#include "talk/session/phone/rtputils.h"
@@ -81,8 +80,6 @@
media_engine_(media_engine),
session_(session),
media_channel_(media_channel),
- received_media_sink_(NULL),
- sent_media_sink_(NULL),
content_name_(content_name),
transport_channel_(transport_channel),
rtcp_transport_channel_(NULL),
@@ -280,19 +277,6 @@
return false;
}
- // Push the packet down to the media sink.
- // Need to do this before protecting the packet.
- {
- talk_base::CritScope cs(&sink_critical_section_);
- if (sent_media_sink_) {
- if (!rtcp) {
- sent_media_sink_->OnRtpPacket(packet->data(), packet->length());
- } else {
- sent_media_sink_->OnRtcpPacket(packet->data(), packet->length());
- }
- }
- }
-
// Protect if needed.
if (srtp_filter_.IsActive()) {
bool res;
@@ -325,6 +309,13 @@
packet->SetLength(len);
}
+ // Signal to the media sink after protecting the packet. TODO:
+ // Separate APIs to record unprotected media and protected header.
+ {
+ talk_base::CritScope cs(&signal_send_packet_cs_);
+ SignalSendPacket(packet->data(), packet->length(), rtcp);
+ }
+
// Bon voyage.
return (channel->SendPacket(packet->data(), packet->length())
== static_cast<int>(packet->length()));
@@ -339,6 +330,13 @@
return;
}
+ // Signal to the media sink before unprotecting the packet. TODO:
+ // Separate APIs to record unprotected media and protected header.
+ {
+ talk_base::CritScope cs(&signal_recv_packet_cs_);
+ SignalRecvPacket(packet->data(), packet->length(), rtcp);
+ }
+
// Unprotect the packet, if needed.
if (srtp_filter_.IsActive()) {
char* data = packet->data();
@@ -376,18 +374,6 @@
} else {
media_channel_->OnRtcpReceived(packet);
}
-
- // Push it down to the media sink.
- {
- talk_base::CritScope cs(&sink_critical_section_);
- if (received_media_sink_) {
- if (!rtcp) {
- received_media_sink_->OnRtpPacket(packet->data(), packet->length());
- } else {
- received_media_sink_->OnRtcpPacket(packet->data(), packet->length());
- }
- }
- }
}
void BaseChannel::OnSessionState(BaseSession* session,
diff --git a/talk/session/phone/channel.h b/talk/session/phone/channel.h
index 241ca79..baf07a9 100644
--- a/talk/session/phone/channel.h
+++ b/talk/session/phone/channel.h
@@ -47,7 +47,6 @@
namespace cricket {
class MediaContentDescription;
-class MediaSinkInterface;
struct CryptoParams;
enum {
@@ -118,27 +117,46 @@
void StartConnectionMonitor(int cms);
void StopConnectionMonitor();
- // Set and get media sinks for recording media.
- void set_received_media_sink(MediaSinkInterface* sink) {
- talk_base::CritScope cs(&sink_critical_section_);
- received_media_sink_ = sink;
- }
- const MediaSinkInterface* received_media_sink() {
- talk_base::CritScope cs(&sink_critical_section_);
- return received_media_sink_;
- }
- void set_sent_media_sink(MediaSinkInterface* sink) {
- talk_base::CritScope cs(&sink_critical_section_);
- sent_media_sink_ = sink;
- }
- const MediaSinkInterface* sent_media_sink() {
- talk_base::CritScope cs(&sink_critical_section_);
- return sent_media_sink_;
- }
void set_srtp_signal_silent_time(uint32 silent_time) {
srtp_filter_.set_signal_silent_time(silent_time);
}
+ template <class T>
+ void RegisterSendSink(T* sink,
+ void (T::*OnPacket)(const void*, size_t, bool)) {
+ talk_base::CritScope cs(&signal_send_packet_cs_);
+ SignalSendPacket.disconnect(sink);
+ SignalSendPacket.connect(sink, OnPacket);
+ }
+
+ void UnregisterSendSink(sigslot::has_slots<>* sink) {
+ talk_base::CritScope cs(&signal_send_packet_cs_);
+ SignalSendPacket.disconnect(sink);
+ }
+
+ bool HasSendSinks() {
+ talk_base::CritScope cs(&signal_send_packet_cs_);
+ return !SignalSendPacket.is_empty();
+ }
+
+ template <class T>
+ void RegisterRecvSink(T* sink,
+ void (T::*OnPacket)(const void*, size_t, bool)) {
+ talk_base::CritScope cs(&signal_recv_packet_cs_);
+ SignalRecvPacket.disconnect(sink);
+ SignalRecvPacket.connect(sink, OnPacket);
+ }
+
+ void UnregisterRecvSink(sigslot::has_slots<>* sink) {
+ talk_base::CritScope cs(&signal_recv_packet_cs_);
+ SignalRecvPacket.disconnect(sink);
+ }
+
+ bool HasRecvSinks() {
+ talk_base::CritScope cs(&signal_recv_packet_cs_);
+ return !SignalRecvPacket.is_empty();
+ }
+
protected:
MediaEngine* media_engine() const { return media_engine_; }
virtual MediaChannel* media_channel() const { return media_channel_; }
@@ -238,15 +256,15 @@
const std::vector<ConnectionInfo> &infos) = 0;
private:
+ sigslot::signal3<const void*, size_t, bool> SignalSendPacket;
+ sigslot::signal3<const void*, size_t, bool> SignalRecvPacket;
+ talk_base::CriticalSection signal_send_packet_cs_;
+ talk_base::CriticalSection signal_recv_packet_cs_;
+
talk_base::Thread *worker_thread_;
MediaEngine *media_engine_;
BaseSession *session_;
MediaChannel *media_channel_;
- // Media sinks to handle the received or sent RTP/RTCP packets. These are
- // reference to the objects owned by the media recorder.
- MediaSinkInterface* received_media_sink_;
- MediaSinkInterface* sent_media_sink_;
- talk_base::CriticalSection sink_critical_section_;
std::string content_name_;
TransportChannel *transport_channel_;
diff --git a/talk/session/phone/mediaengine.cc b/talk/session/phone/mediaengine.cc
index f483d1b..e6b663d 100644
--- a/talk/session/phone/mediaengine.cc
+++ b/talk/session/phone/mediaengine.cc
@@ -32,37 +32,20 @@
#elif defined(HAVE_WEBRTC)
#include "talk/session/phone/webrtcvoiceengine.h"
#include "talk/session/phone/webrtcvideoengine.h"
-#if defined(PLATFORM_CHROMIUM)
-#include "content/renderer/renderer_webrtc_audio_device_impl.h"
-#else // Other browsers
-#endif // PLATFORM_CHROMIUM
#else
#endif // HAVE_LINPHONE
namespace cricket {
-#if defined(PLATFORM_CHROMIUM)
-class ChromiumWebRtcVoiceEngine : public WebRtcVoiceEngine {
- public:
- // TODO: where should we get the AudioDevice initial configuration
- ChromiumWebRtcVoiceEngine() : WebRtcVoiceEngine(
- new RendererWebRtcAudioDeviceImpl(1440, 1440, 1, 1, 48000, 48000)) {}
-};
-#else // Other browsers
-#endif // PLATFORM_CHROMIUM
-
MediaEngine* MediaEngine::Create() {
#if defined(HAVE_LINPHONE)
return new LinphoneMediaEngine("", "");
-#elif defined(HAVE_WEBRTC) && defined(PLATFORM_CHROMIUM)
- return new CompositeMediaEngine<ChromiumWebRtcVoiceEngine,
- WebRtcVideoEngine>();
#elif defined(HAVE_WEBRTC)
return new CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine>();
#elif defined(ANDROID)
return AndroidMediaEngineFactory::Create();
#else
return new NullMediaEngine();
-#endif // HAVE_LINPHONE HAVE_WEBRTC PLATFORM_CHROMIUM ANDROID
+#endif // HAVE_LINPHONE HAVE_WEBRTC ANDROID
}
}; // namespace cricket
diff --git a/talk/session/phone/mediasink.h b/talk/session/phone/mediasink.h
index 078b534..3bc12bc 100644
--- a/talk/session/phone/mediasink.h
+++ b/talk/session/phone/mediasink.h
@@ -31,8 +31,7 @@
namespace cricket {
// MediaSinkInterface is a sink to handle RTP and RTCP packets that are sent or
-// received by a channel. Each channel needs two MediaSinkInterface, one for
-// the sent packets and the other for the received packets.
+// received by a channel.
class MediaSinkInterface {
public:
virtual ~MediaSinkInterface() {}
@@ -40,8 +39,8 @@
virtual void SetMaxSize(size_t size) = 0;
virtual bool Enable(bool enable) = 0;
virtual bool IsEnabled() const = 0;
- virtual void OnRtpPacket(const void* data, size_t size) = 0;
- virtual void OnRtcpPacket(const void* data, size_t size) = 0;
+ virtual void OnPacket(const void* data, size_t size, bool rtcp) = 0;
+ virtual void set_packet_filter(int filter) = 0;
};
} // namespace cricket
diff --git a/talk/session/phone/rtpdump.cc b/talk/session/phone/rtpdump.cc
index ad0e82d..6358399 100644
--- a/talk/session/phone/rtpdump.cc
+++ b/talk/session/phone/rtpdump.cc
@@ -28,6 +28,7 @@
#include "talk/session/phone/rtpdump.h"
#include <string>
+#include <ctype.h>
#include "talk/base/bytebuffer.h"
#include "talk/base/byteorder.h"
diff --git a/talk/site_scons/site_tools/talk_linux.py b/talk/site_scons/site_tools/talk_linux.py
new file mode 100644
index 0000000..1e204bc
--- /dev/null
+++ b/talk/site_scons/site_tools/talk_linux.py
@@ -0,0 +1,266 @@
+# Copyright 2010 Google Inc.
+# All Rights Reserved.
+# Author: tschmelcher@google.com (Tristan Schmelcher)
+
+"""Tool for helpers used in linux building process."""
+
+import os
+import SCons.Defaults
+import subprocess
+
+
+def _OutputFromShellCommand(command):
+ process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
+ return process.communicate()[0].strip()
+
+
+# This is a pure SCons helper function.
+def _InternalBuildDebianPackage(env, debian_files, package_files,
+ output_dir=None, force_version=None):
+ """Creates build rules to build a Debian package from the specified sources.
+
+ Args:
+ env: SCons Environment.
+ debian_files: Array of the Debian control file sources that should be
+ copied into the package source tree, e.g., changelog, control, rules,
+ etc.
+ package_files: An array of 2-tuples listing the files that should be
+ copied into the package source tree.
+ The first element is the path where the file should be placed for the
+ .install control file to find it, relative to the generated debian
+ package source directory.
+ The second element is the file source.
+ output_dir: An optional directory to place the files in. If omitted, the
+ current output directory is used.
+ force_version: Optional. Forces the version of the package to start with
+ this version string if specified. If the last entry in the changelog
+ is not for a version that starts with this then a dummy entry is
+ generated with this version and a ~prerelease suffix (so that the
+ final version will compare as greater).
+
+ Return:
+ A list of the targets (if any).
+ """
+ if 0 != subprocess.call(['which', 'dpkg-buildpackage']):
+ print ('dpkg-buildpackage not installed on this system; '
+ 'skipping DEB build stage')
+ return []
+ # Read the control file and changelog file to determine the package name,
+ # version, and arch that the Debian build tools will use to name the
+ # generated files.
+ control_file = None
+ changelog_file = None
+ for file in debian_files:
+ if os.path.basename(file) == 'control':
+ control_file = env.File(file).srcnode().abspath
+ elif os.path.basename(file) == 'changelog':
+ changelog_file = env.File(file).srcnode().abspath
+ if not control_file:
+ raise Exception('Need to have a control file')
+ if not changelog_file:
+ raise Exception('Need to have a changelog file')
+ source = _OutputFromShellCommand(
+ "awk '/^Source:/ { print $2; }' " + control_file)
+ packages = _OutputFromShellCommand(
+ "awk '/^Package:/ { print $2; }' " + control_file).split('\n')
+ version = _OutputFromShellCommand(
+ "sed -nr '1 { s/.*\\((.*)\\).*/\\1/; p }' " + changelog_file)
+ arch = _OutputFromShellCommand('dpkg --print-architecture')
+ add_dummy_changelog_entry = False
+ if force_version and not version.startswith(force_version):
+ print ('Warning: no entry in ' + changelog_file + ' for version ' +
+ force_version + ' (last is ' + version +'). A dummy entry will be ' +
+ 'generated. Remember to add the real changelog entry before ' +
+ 'releasing.')
+ version = force_version + '~prerelease'
+ add_dummy_changelog_entry = True
+ source_dir_name = source + '_' + version + '_' + arch
+ target_file_names = [ source_dir_name + '.changes' ]
+ for package in packages:
+ package_file_name = package + '_' + version + '_' + arch + '.deb'
+ target_file_names.append(package_file_name)
+ # The targets
+ if output_dir:
+ targets = [os.path.join(output_dir, s) for s in target_file_names]
+ else:
+ targets = target_file_names
+ # Path to where we will construct the debian build tree.
+ deb_build_tree = os.path.join(source_dir_name, 'deb_build_tree')
+ # First copy the files.
+ for file in package_files:
+ env.Command(os.path.join(deb_build_tree, file[0]), file[1],
+ SCons.Defaults.Copy('$TARGET', '$SOURCE'))
+ env.Depends(targets, os.path.join(deb_build_tree, file[0]))
+ # Now copy the Debian metadata sources. We have to do this all at once so
+ # that we can remove the target directory before copying, because there
+ # can't be any other stale files there or else dpkg-buildpackage may use
+ # them and give incorrect build output.
+ copied_debian_files_paths = []
+ for file in debian_files:
+ copied_debian_files_paths.append(os.path.join(deb_build_tree, 'debian',
+ os.path.basename(file)))
+ copy_commands = [
+ """dir=$$(dirname $TARGET) && \
+ rm -Rf $$dir && \
+ mkdir -p $$dir && \
+ cp $SOURCES $$dir && \
+ chmod -R u+w $$dir"""
+ ]
+ if add_dummy_changelog_entry:
+ copy_commands += [
+ """debchange -c $$(dirname $TARGET)/changelog --newversion %s \
+ --distribution UNRELEASED \
+ 'Developer preview build. (This entry was auto-generated.)'""" %
+ version
+ ]
+ env.Command(copied_debian_files_paths, debian_files, copy_commands)
+ env.Depends(targets, copied_debian_files_paths)
+ # Must explicitly specify -a because otherwise cross-builds won't work.
+ # Must explicitly specify -D because -a disables it.
+ # Must explicitly specify fakeroot because old dpkg tools don't assume that.
+ env.Command(targets, None,
+ """dir=%(dir)s && \
+ cd $$dir && \
+ dpkg-buildpackage -b -uc -a%(arch)s -D -rfakeroot && \
+ cd $$OLDPWD && \
+ for file in %(targets)s; do \
+ mv $$dir/../$$file $$(dirname $TARGET) || exit 1; \
+ done""" %
+ {'dir':env.Dir(deb_build_tree).path,
+ 'arch':arch,
+ 'targets':' '.join(target_file_names)})
+ return targets
+
+
+def BuildDebianPackage(env, debian_files, package_files, force_version=None):
+ """Creates build rules to build a Debian package from the specified sources.
+
+ This is a Hammer-ified version of _InternalBuildDebianPackage that knows to
+ put the packages in the Hammer staging dir.
+
+ Args:
+ env: SCons Environment.
+ debian_files: Array of the Debian control file sources that should be
+ copied into the package source tree, e.g., changelog, control, rules,
+ etc.
+ package_files: An array of 2-tuples listing the files that should be
+ copied into the package source tree.
+ The first element is the path where the file should be placed for the
+ .install control file to find it, relative to the generated debian
+ package source directory.
+ The second element is the file source.
+ force_version: Optional. Forces the version of the package to start with
+ this version string if specified. If the last entry in the changelog
+ is not for a version that starts with this then a dummy entry is
+ generated with this version and a ~prerelease suffix (so that the
+ final version will compare as greater).
+
+ Return:
+ A list of the targets (if any).
+ """
+ if not env.Bit('host_linux'):
+ return []
+ return _InternalBuildDebianPackage(env, debian_files, package_files,
+ output_dir='$STAGING_DIR', force_version=force_version)
+
+
+def _HavePackage(package):
+ """Whether the given pkg-config package name is present on the build system.
+
+ Args:
+ package: The name of the package.
+
+ Returns:
+ True if the package is present, else False
+ """
+ return subprocess.call(['pkg-config', '--exists', package]) == 0
+
+
+def _GetPackageFlags(flag_type, packages):
+ """Get the flags needed to compile/link against the given package(s).
+
+ Returns the flags that are needed to compile/link against the given pkg-config
+ package(s).
+
+ Args:
+ flag_type: The option to pkg-config specifying the type of flags to get.
+ packages: The list of package names as strings.
+
+ Returns:
+ The flags of the requested type.
+ """
+ process = subprocess.Popen(['pkg-config', flag_type] + packages,
+ stdout=subprocess.PIPE)
+ return process.communicate()[0].strip().split(' ')
+
+
+def GetPackageParams(env, packages):
+ """Get the params needed to compile/link against the given package(s).
+
+ Returns the params that are needed to compile/link against the given
+ pkg-config package(s).
+
+ Args:
+ env: The current SCons environment.
+ packages: The name of the package, or a list of names.
+
+ Returns:
+ A dictionary containing the params.
+
+ Raises:
+ Exception: One or more of the packages is not installed.
+ """
+ if not env.Bit('host_linux'):
+ return {}
+ if not SCons.Util.is_List(packages):
+ packages = [packages]
+ for package in packages:
+ if not _HavePackage(package):
+ raise Exception(('Required package \"%s\" was not found. Please install '
+ 'the package that provides the \"%s.pc\" file.') %
+ (package, package))
+ package_ccflags = _GetPackageFlags('--cflags', packages)
+ package_libs = _GetPackageFlags('--libs', packages)
+ # Split package_libs into actual libs and non-lib linker flags.
+ libs = [flag[2:] for flag in package_libs if flag[0:2] == '-l']
+ link_flags = [flag for flag in package_libs if flag[0:2] != '-l']
+ return {
+ 'ccflags': package_ccflags,
+ 'libs': libs,
+ 'link_flags': link_flags,
+ 'dependent_target_settings' : {
+ 'libs': libs[:],
+ 'link_flags': link_flags[:],
+ },
+ }
+
+
+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 generate(env):
+ if env.Bit('linux'):
+ env.AddMethod(EnableFeatureWherePackagePresent)
+ env.AddMethod(GetPackageParams)
+ env.AddMethod(BuildDebianPackage)
+
+
+def exists(env):
+ return 1 # Required by scons
diff --git a/talk/site_scons/talk.py b/talk/site_scons/talk.py
index 94f1b14..e2a2166 100644
--- a/talk/site_scons/talk.py
+++ b/talk/site_scons/talk.py
@@ -5,10 +5,108 @@
# Daniel Petersson (dape@google.com)
#
import os
+import SCons.Util
# Keep a global dictionary of library target params for lookups in
# ExtendComponent().
_all_lib_targets = {}
+# Maintain a set of all prebuilt static libraries.
+_all_prebuilt_libraries = set()
+# Set of libraries not found in the above (used to detect out-of-order build
+# rules).
+_all_system_libraries = set()
+
+def _GetLibParams(lib):
+ """Gets the params for the given library if it is a library target.
+
+ Returns the params that were specified when the given lib target name was
+ created, or None if no such lib target has been defined. In the None case, it
+ additionally records the negative result so as to detect out-of-order
+ dependencies for future targets.
+
+ Args:
+ lib: The library's name as a string.
+
+ Returns:
+ Its dictionary of params, or None.
+ """
+ if lib in _all_lib_targets:
+ return _all_lib_targets[lib]
+ else:
+ if lib not in _all_prebuilt_libraries and lib not in _all_system_libraries:
+ _all_system_libraries.add(lib)
+ return None
+
+
+def _RecordLibParams(lib, params):
+ """Record the params used for a library target.
+
+ Record the params used for a library target while checking for several error
+ conditions.
+
+ Args:
+ lib: The library target's name as a string.
+ params: Its dictionary of params.
+
+ Raises:
+ Exception: The lib target has already been recorded, or the lib was
+ previously declared to be prebuilt, or the lib target is being defined
+ after a reverse library dependency.
+ """
+ if lib in _all_lib_targets:
+ raise Exception('Multiple definitions of ' + lib)
+ if lib in _all_prebuilt_libraries:
+ raise Exception(lib + ' already declared as a prebuilt library')
+ if lib in _all_system_libraries:
+ raise Exception(lib + ' cannot be defined after its reverse library '
+ 'dependencies')
+ _all_lib_targets[lib] = params
+
+
+def _IsPrebuiltLibrary(lib):
+ """Checks whether or not the given library is a prebuilt static library.
+
+ Returns whether or not the given library name has been declared to be a
+ prebuilt static library. In the False case, it additionally records the
+ negative result so as to detect out-of-order dependencies for future targets.
+
+ Args:
+ lib: The library's name as a string.
+
+ Returns:
+ True or False
+ """
+ if lib in _all_prebuilt_libraries:
+ return True
+ else:
+ if lib not in _all_lib_targets and lib not in _all_system_libraries:
+ _all_system_libraries.add(lib)
+ return False
+
+
+def _RecordPrebuiltLibrary(lib):
+ """Record that a library is a prebuilt static library.
+
+ Record that the given library name refers to a prebuilt static library while
+ checking for several error conditions.
+
+ Args:
+ lib: The library's name as a string.
+
+ Raises:
+ Exception: The lib has already been recorded to be prebuilt, or the lib was
+ previously declared as a target, or the lib is being declared as
+ prebuilt after a reverse library dependency.
+ """
+ if lib in _all_prebuilt_libraries:
+ raise Exception('Multiple prebuilt declarations of ' + lib)
+ if lib in _all_lib_targets:
+ raise Exception(lib + ' already defined as a target')
+ if lib in _all_system_libraries:
+ raise Exception(lib + ' cannot be declared as prebuilt after its reverse '
+ 'library dependencies')
+ _all_prebuilt_libraries.add(lib)
+
def _GenericLibrary(env, static, **kwargs):
"""Extends ComponentLibrary to support multiplatform builds
@@ -25,6 +123,22 @@
return ExtendComponent(env, 'ComponentLibrary', **params)
+def DeclarePrebuiltLibraries(libraries):
+ """Informs the build engine about external static libraries.
+
+ Informs the build engine that the given external library name(s) are prebuilt
+ static libraries, as opposed to shared libraries.
+
+ Args:
+ libraries: The library or libraries that are being declared as prebuilt
+ static libraries.
+ """
+ if not SCons.Util.is_List(libraries):
+ libraries = [libraries]
+ for library in libraries:
+ _RecordPrebuiltLibrary(library)
+
+
def Library(env, **kwargs):
"""Extends ComponentLibrary to support multiplatform builds of static
libraries.
@@ -74,7 +188,7 @@
'posix_cppdefines': ['GUNIT_NO_GOOGLE3', 'GTEST_HAS_RTTI=0'],
'libs': ['unittest_main', 'gunit']
}
- if not kwargs.has_key('explicit_libs'):
+ if 'explicit_libs' not in kwargs:
common_test_params['win_libs'] = [
'advapi32',
'crypt32',
@@ -107,7 +221,7 @@
Returns:
See swtoolkit ComponentProgram.
"""
- if not kwargs.has_key('explicit_libs'):
+ if 'explicit_libs' not in kwargs:
common_app_params = {
'win_libs': [
'advapi32',
@@ -184,96 +298,11 @@
return '%s/%s.scons' % (path, os.path.basename(path))
-def AddMediaLibs(env, **kwargs):
- lmi_libdir = '$GOOGLE3/../googleclient/third_party/lmi/files/lib/'
- if env.Bit('windows'):
- if env.get('COVERAGE_ENABLED'):
- lmi_libdir += 'win32/c_only'
- else:
- lmi_libdir += 'win32/Release'
- elif env.Bit('mac'):
- lmi_libdir += 'macos'
- elif env.Bit('linux'):
- lmi_libdir += 'linux/x86'
-
-
- AddToDict(kwargs, 'libdirs', [
- '$MAIN_DIR/third_party/gips/Libraries/',
- lmi_libdir,
- ])
-
- gips_lib = ''
- if env.Bit('windows'):
- if env.Bit('debug'):
- gips_lib = 'gipsvoiceenginelib_mtd'
- else:
- gips_lib = 'gipsvoiceenginelib_mt'
- elif env.Bit('mac'):
- gips_lib = 'VoiceEngine_mac_universal_gcc'
- elif env.Bit('linux'):
- gips_lib = 'VoiceEngine_Linux_gcc'
-
-
- AddToDict(kwargs, 'libs', [
- gips_lib,
- 'LmiAudioCommon',
- 'LmiClient',
- 'LmiCmcp',
- 'LmiDeviceManager',
- 'LmiH263ClientPlugIn',
- 'LmiH263CodecCommon',
- 'LmiH263Decoder',
- 'LmiH263Encoder',
- 'LmiH264ClientPlugIn',
- 'LmiH264CodecCommon',
- 'LmiH264Common',
- 'LmiH264Decoder',
- 'LmiH264Encoder',
- 'LmiIce',
- 'LmiMediaPayload',
- 'LmiOs',
- 'LmiPacketCache',
- 'LmiProtocolStack',
- 'LmiRateShaper',
- 'LmiRtp',
- 'LmiSecurity',
- 'LmiSignaling',
- 'LmiStun',
- 'LmiTransport',
- 'LmiUi',
- 'LmiUtils',
- 'LmiVideoCommon',
- 'LmiXml',
- ])
-
- if env.Bit('windows'):
- AddToDict(kwargs, 'libs', [
- 'dsound',
- 'd3d9',
- 'gdi32',
- 'strmiids',
- ])
-
- if env.Bit('mac'):
- AddToDict(kwargs, 'FRAMEWORKS', [
- 'AudioToolbox',
- 'AudioUnit',
- 'Cocoa',
- 'CoreAudio',
- 'CoreFoundation',
- 'IOKit',
- 'QTKit',
- 'QuickTime',
- 'QuartzCore',
- ])
- return kwargs
-
-
def ReadVersion(filename):
"""Executes the supplied file and pulls out a version definition from it. """
defs = {}
execfile(str(filename), defs)
- if not defs.has_key('version'):
+ if 'version' not in defs:
return '0.0.0.0'
version = defs['version']
parts = version.split(',')
@@ -287,23 +316,22 @@
# Helper methods for translating talk.Foo() declarations in to manipulations of
# environmuent construction variables, including parameter parsing and merging,
#
-def GetEntry(dict, key):
+def PopEntry(dictionary, key):
"""Get the value from a dictionary by key. If the key
isn't in the dictionary then None is returned. If it is in
- the dictionaruy the value is fetched and then is it removed
+ the dictionary the value is fetched and then is it removed
from the dictionary.
Args:
+ dictionary: The dictionary.
key: The key to get the value for.
- kwargs: The keyword argument dictionary.
Returns:
The value or None if the key is missing.
"""
value = None
- if dict.has_key(key):
- value = dict[key]
- dict.pop(key)
-
+ if key in dictionary:
+ value = dictionary[key]
+ dictionary.pop(key)
return value
@@ -355,6 +383,7 @@
return merged
+
# Linux can build both 32 and 64 bit on 64 bit host, but 32 bit host can
# only build 32 bit. For 32 bit debian installer a 32 bit host is required.
# ChromeOS (linux) ebuild don't support 64 bit and requires 32 bit build only
@@ -363,18 +392,21 @@
return (env.Bit('linux') and env.Bit('platform_arch_64bit')
)
+
def MergeSettingsFromLibraryDependencies(env, params):
- if params.has_key('libs'):
+ if 'libs' in params:
for lib in params['libs']:
- if (_all_lib_targets.has_key(lib) and
- _all_lib_targets[lib].has_key('dependent_target_settings')):
- params = CombineDicts(
- params,
- MergeAndFilterByPlatform(
- env,
- _all_lib_targets[lib]['dependent_target_settings']))
+ libparams = _GetLibParams(lib)
+ if libparams:
+ if 'dependent_target_settings' in libparams:
+ params = CombineDicts(
+ params,
+ MergeAndFilterByPlatform(
+ env,
+ libparams['dependent_target_settings']))
return params
+
def ExtendComponent(env, component, **kwargs):
"""A wrapper around a scons builder function that preprocesses and post-
processes its inputs and outputs. For example, it merges and filters
@@ -399,31 +431,32 @@
params = MergeAndFilterByPlatform(env, kwargs)
# get the 'target' field
- name = GetEntry(params, 'name')
+ name = PopEntry(params, 'name')
+
+ # get the 'packages' field and process it if present (only used for Linux).
+ packages = PopEntry(params, 'packages')
+ if packages and len(packages):
+ params = CombineDicts(params, env.GetPackageParams(packages))
# save pristine params of lib targets for future reference
if 'ComponentLibrary' == component:
- _all_lib_targets[name] = dict(params)
+ _RecordLibParams(name, dict(params))
# add any dependent target settings from library dependencies
params = MergeSettingsFromLibraryDependencies(env, params)
# if this is a signed binary we need to make an unsigned version first
- signed = env.Bit('windows') and GetEntry(params, 'signed')
+ signed = env.Bit('windows') and PopEntry(params, 'signed')
if signed:
name = 'unsigned_' + name
- # add default values
- if GetEntry(params, 'include_talk_media_libs'):
- params = AddMediaLibs(env, **params)
-
# potentially exit now
- srcs = GetEntry(params, 'srcs')
+ srcs = PopEntry(params, 'srcs')
if not srcs or not hasattr(env, component):
return None
# apply any explicit dependencies
- dependencies = GetEntry(params, 'depends')
+ dependencies = PopEntry(params, 'depends')
if dependencies is not None:
env.Depends(name, dependencies)
@@ -443,17 +476,17 @@
else:
# ... while GCC compile flags have precedence at the end
appends['ccflags'] = 'CCFLAGS'
- if GetEntry(params, 'prepend_includedirs'):
+ if PopEntry(params, 'prepend_includedirs'):
prepends['includedirs'] = 'CPPPATH'
else:
appends['includedirs'] = 'CPPPATH'
for field, var in appends.items():
- values = GetEntry(params, field)
+ values = PopEntry(params, field)
if values is not None:
env.Append(**{var : values})
for field, var in prepends.items():
- values = GetEntry(params, field)
+ values = PopEntry(params, field)
if values is not None:
env.Prepend(**{var : values})
@@ -468,13 +501,30 @@
for field, value in params.items():
env.Replace(**{field : value})
+ if env.Bit('linux') and 'LIBS' in env:
+ libs = env['LIBS']
+ # When using --as-needed + --start/end-group, shared libraries need to come
+ # after --end-group on the command-line because the pruning decision only
+ # considers the preceding modules and --start/end-group may cause the
+ # effective position of early static libraries on the command-line to be
+ # deferred to the point of --end-group. To effect this, we move shared libs
+ # into _LIBFLAGS, which has the --end-group as its first entry. SCons does
+ # not track dependencies on system shared libraries anyway so we lose
+ # nothing by removing them from LIBS.
+ static_libs = [lib for lib in libs if
+ _GetLibParams(lib) or _IsPrebuiltLibrary(lib)]
+ shared_libs = ['-l' + lib for lib in libs if not
+ (_GetLibParams(lib) or _IsPrebuiltLibrary(lib))]
+ env.Replace(LIBS=static_libs)
+ env.Append(_LIBFLAGS=shared_libs)
+
# invoke the builder function
builder = getattr(env, component)
node = builder(name, srcs)
# make a parallel 64bit version if requested
- if Allow64BitCompile(env) and GetEntry(params, 'also64bit'):
+ if Allow64BitCompile(env) and PopEntry(params, 'also64bit'):
env_64bit = env.Clone()
env_64bit.FilterOut(CCFLAGS = ['-m32'], LINKFLAGS = ['-m32'])
env_64bit.Prepend(CCFLAGS = ['-m64', '-fPIC'], LINKFLAGS = ['-m64'])
@@ -487,8 +537,8 @@
# link 64 bit versions of libraries
libs = []
for lib in env_64bit['LIBS']:
- if (_all_lib_targets.has_key(lib) and
- _all_lib_targets[lib].has_key('also64bit')):
+ libparams = _GetLibParams(lib)
+ if libparams and 'also64bit' in libparams:
libs.append(lib + '64')
else:
libs.append(lib)
@@ -513,7 +563,7 @@
# same name. Setting postsignprefix allows the EXE and its PDB
# to be renamed and copied in a previous step; then the desired
# name of the EXE (but not PDB) is reconstructed after signing.
- postsignprefix = GetEntry(params, 'postsignprefix')
+ postsignprefix = PopEntry(params, 'postsignprefix')
if postsignprefix is not None:
target = postsignprefix + target
signed_node = env.SignedBinary(
@@ -534,7 +584,7 @@
if values is None:
return
- if not dictionary.has_key(key):
+ if key not in dictionary:
dictionary[key] = values
return
@@ -551,12 +601,28 @@
def CombineDicts(a, b):
- """Unions two dictionaries by combining values of keys shared between them.
+ """Unions two dictionaries of arrays/dictionaries.
+
+ Unions two dictionaries of arrays/dictionaries by combining the values of keys
+ shared between them. The original dictionaries should not be used again after
+ this call.
+
+ Args:
+ a: First dict.
+ b: Second dict.
+
+ Returns:
+ The union of a and b.
"""
c = {}
for key in a:
- if b.has_key(key):
- c[key] = a[key] + b.pop(key)
+ if key in b:
+ aval = a[key]
+ bval = b.pop(key)
+ if isinstance(aval, dict) and isinstance(bval, dict):
+ c[key] = CombineDicts(aval, bval)
+ else:
+ c[key] = aval + bval
else:
c[key] = a[key]
@@ -567,4 +633,4 @@
def RenameKey(d, old, new, append=True):
- AddToDict(d, new, GetEntry(d, old), append)
+ AddToDict(d, new, PopEntry(d, old), append)
diff --git a/talk/xmllite/qname.h b/talk/xmllite/qname.h
index 3e64726..172a067 100644
--- a/talk/xmllite/qname.h
+++ b/talk/xmllite/qname.h
@@ -29,6 +29,7 @@
#define _qname_h_
#include <string>
+#include "talk/base/criticalsection.h"
namespace buzz {
@@ -49,7 +50,7 @@
return *this;
}
~QName();
-
+
const std::string & Namespace() const { return data_->namespace_; }
const std::string & LocalPart() const { return data_->localPart_; }
std::string Merged() const;
@@ -57,7 +58,7 @@
bool operator==(const QName & other) const;
bool operator!=(const QName & other) const { return !operator==(other); }
bool operator<(const QName & other) const { return Compare(other) < 0; }
-
+
class Data {
public:
Data(const std::string & ns, const std::string & local) :
@@ -66,11 +67,11 @@
refcount_(1) {}
Data() : refcount_(0) {}
-
+
std::string namespace_;
std::string localPart_;
- void AddRef() { refcount_++; }
- void Release() { if (!--refcount_) { delete this; } }
+ void AddRef() { talk_base::AtomicOps::Increment(&refcount_); }
+ void Release() { if (!talk_base::AtomicOps::Decrement(&refcount_)) { delete this; } }
bool Occupied() { return !!refcount_; }
private: