Update in preparation for libjingle 0.5.7:
- Support for setting MUC display name
- Update STUN support to RFC5389
- Handle description-info message
git-svn-id: http://libjingle.googlecode.com/svn/trunk@67 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/README b/README
index 9867fbf..ccf22ea 100644
--- a/README
+++ b/README
@@ -94,6 +94,7 @@
* Third, go to the talk/ directory and run $path_to_swtoolkit/hammer.sh. Run
$path_to_swtoolkit/hammer.sh --help for information on how to build for
different modes.
+ * On Linux, you need to install libssl-dev, libasound2-dev and gtk+2.0.
2.3 Build Libjingle under Windows
* First, make sure the SCONS_DIR environment variable is set correctly and
@@ -141,6 +142,6 @@
In the "talk.App(env, name = "call",..." section, you need to add:
"mediastreamer",
to the "libs = [".
- * Add the following line into the "srcs = [ ..." section of the
- libjingle.scons file.
+ * In the libjingle.scons file, add the following line into the "srcs = [ ..."
+ section of the "libjingle" Library.
"session/phone/linphonemediaengine.cc",
diff --git a/talk/base/diskcache.cc b/talk/base/diskcache.cc
index 4e70543..afaf9d2 100644
--- a/talk/base/diskcache.cc
+++ b/talk/base/diskcache.cc
@@ -139,7 +139,7 @@
}
scoped_ptr<FileStream> file(new FileStream);
- if (!file->Open(filename, "wb")) {
+ if (!file->Open(filename, "wb", NULL)) {
LOG_F(LS_ERROR) << "Couldn't create cache file";
return NULL;
}
@@ -177,7 +177,7 @@
return NULL;
scoped_ptr<FileStream> file(new FileStream);
- if (!file->Open(IdToFilename(id, index), "rb"))
+ if (!file->Open(IdToFilename(id, index), "rb", NULL))
return NULL;
entry->accessors += 1;
diff --git a/talk/base/fileutils.h b/talk/base/fileutils.h
index 217cd83..644516d 100644
--- a/talk/base/fileutils.h
+++ b/talk/base/fileutils.h
@@ -118,6 +118,8 @@
// Opens a file. Returns an open StreamInterface if function succeeds.
// Otherwise, returns NULL.
+ // TODO: Add an error param to indicate failure reason, similar to
+ // FileStream::Open
virtual FileStream *OpenFile(const Pathname &filename,
const std::string &mode) = 0;
diff --git a/talk/base/helpers.cc b/talk/base/helpers.cc
index f8d8a9f..e2dabde 100644
--- a/talk/base/helpers.cc
+++ b/talk/base/helpers.cc
@@ -224,7 +224,9 @@
return str;
}
-bool CreateRandomString(size_t len, std::string* str) {
+bool CreateRandomString(size_t len,
+ const char* table, int table_size,
+ std::string* str) {
str->clear();
scoped_array<uint8> bytes(new uint8[len]);
if (!g_rng->Generate(bytes.get(), len)) {
@@ -233,11 +235,20 @@
}
str->reserve(len);
for (size_t i = 0; i < len; ++i) {
- str->push_back(BASE64[bytes[i] & 63]);
+ str->push_back(table[bytes[i] % table_size]);
}
return true;
}
+bool CreateRandomString(size_t len, std::string* str) {
+ return CreateRandomString(len, BASE64, 64, str);
+}
+
+bool CreateRandomString(size_t len, const std::string& table,
+ std::string* str) {
+ return CreateRandomString(len, table.c_str(), table.size(), str);
+}
+
uint32 CreateRandomId() {
uint32 id;
if (!g_rng->Generate(&id, sizeof(id))) {
diff --git a/talk/base/helpers.h b/talk/base/helpers.h
index 83a3c7f..74867c0 100644
--- a/talk/base/helpers.h
+++ b/talk/base/helpers.h
@@ -50,6 +50,12 @@
// Return false if the random number generator failed.
bool CreateRandomString(size_t length, std::string* str);
+// Generates a (cryptographically) random string of the given length,
+// with characters from the given table. Return false if the random
+// number generator failed.
+bool CreateRandomString(size_t length, const std::string& table,
+ std::string* str);
+
// Generates a random id.
uint32 CreateRandomId();
diff --git a/talk/base/httpcommon.cc b/talk/base/httpcommon.cc
index f7553b2..229aef9 100644
--- a/talk/base/httpcommon.cc
+++ b/talk/base/httpcommon.cc
@@ -390,7 +390,7 @@
int hours = (zone[1] - '0') * 10 + (zone[2] - '0');
int minutes = (zone[3] - '0') * 10 + (zone[4] - '0');
int offset = (hours * 60 + minutes) * 60;
- gmt = non_gmt + (zone[0] == '+') ? offset : -offset;
+ gmt = non_gmt + ((zone[0] == '+') ? offset : -offset);
} else {
size_t zindex;
if (!find_string(zindex, zone, kTimeZones, ARRAY_SIZE(kTimeZones))) {
diff --git a/talk/base/linux.cc b/talk/base/linux.cc
index 514ab94..ba80ff5 100644
--- a/talk/base/linux.cc
+++ b/talk/base/linux.cc
@@ -176,7 +176,7 @@
bool ConfigParser::Open(const std::string& filename) {
FileStream* fs = new FileStream();
- if (!fs->Open(filename, "r")) {
+ if (!fs->Open(filename, "r", NULL)) {
return false;
}
instream_.reset(fs);
@@ -335,7 +335,7 @@
FileStream fs;
std::string str;
int freq = -1;
- if (!fs.Open(kCpuMaxFreqFile, "r") ||
+ if (!fs.Open(kCpuMaxFreqFile, "r", NULL) ||
SR_SUCCESS != fs.ReadLine(&str) ||
!FromString(str, &freq)) {
return -1;
diff --git a/talk/base/logging.cc b/talk/base/logging.cc
index 654d8c6..b5c588c 100644
--- a/talk/base/logging.cc
+++ b/talk/base/logging.cc
@@ -333,7 +333,7 @@
scoped_ptr<FileStream> stream;
if (NO_LOGGING != file_level) {
stream.reset(new FileStream);
- if (!stream->Open(filename, "wb") || !stream->DisableBuffering()) {
+ if (!stream->Open(filename, "wb", NULL) || !stream->DisableBuffering()) {
stream.reset();
}
}
diff --git a/talk/base/network.cc b/talk/base/network.cc
index 8a56d0a..e5dffc1 100644
--- a/talk/base/network.cc
+++ b/talk/base/network.cc
@@ -208,7 +208,7 @@
// Gets the default gateway for the specified interface.
uint32 GetDefaultGateway(const std::string& name) {
#ifdef OSX
- // TODO: /proc/net/route doesn't exist,
+ // TODO: /proc/net/route doesn't exist,
// Use ioctl to get the routing table
return 0xFFFFFFFF;
#endif
@@ -216,7 +216,7 @@
uint32 gateway_ip = 0;
FileStream fs;
- if (fs.Open("/proc/net/route", "r")) {
+ if (fs.Open("/proc/net/route", "r", NULL)) {
std::string line;
while (fs.ReadLine(&line) == SR_SUCCESS && gateway_ip == 0) {
char iface[16];
diff --git a/talk/base/stream.cc b/talk/base/stream.cc
index 3022d3e..cdd6098 100644
--- a/talk/base/stream.cc
+++ b/talk/base/stream.cc
@@ -349,35 +349,49 @@
FileStream::Close();
}
-bool FileStream::Open(const std::string& filename, const char* mode) {
+bool FileStream::Open(const std::string& filename, const char* mode,
+ int* error) {
Close();
#ifdef WIN32
std::wstring wfilename;
if (Utf8ToWindowsFilename(filename, &wfilename)) {
file_ = _wfopen(wfilename.c_str(), ToUtf16(mode).c_str());
} else {
- file_ = NULL;
+ if (error) {
+ *error = -1;
+ return false;
+ }
}
#else
file_ = fopen(filename.c_str(), mode);
#endif
+ if (!file_ && error) {
+ *error = errno;
+ }
return (file_ != NULL);
}
bool FileStream::OpenShare(const std::string& filename, const char* mode,
- int shflag) {
+ int shflag, int* error) {
Close();
#ifdef WIN32
std::wstring wfilename;
if (Utf8ToWindowsFilename(filename, &wfilename)) {
file_ = _wfsopen(wfilename.c_str(), ToUtf16(mode).c_str(), shflag);
+ if (!file_ && error) {
+ *error = errno;
+ return false;
+ }
+ return file_ != NULL;
} else {
- file_ = NULL;
+ if (error) {
+ *error = -1;
+ }
+ return false;
}
#else
- return Open(filename, mode);
+ return Open(filename, mode, error);
#endif
- return (file_ != NULL);
}
bool FileStream::DisableBuffering() {
diff --git a/talk/base/stream.h b/talk/base/stream.h
index a8d399d..496b4ce 100644
--- a/talk/base/stream.h
+++ b/talk/base/stream.h
@@ -410,9 +410,9 @@
virtual ~FileStream();
// The semantics of filename and mode are the same as stdio's fopen
- virtual bool Open(const std::string& filename, const char* mode);
+ virtual bool Open(const std::string& filename, const char* mode, int* error);
virtual bool OpenShare(const std::string& filename, const char* mode,
- int shflag);
+ int shflag, int* error);
// By default, reads and writes are buffered for efficiency. Disabling
// buffering causes writes to block until the bytes on disk are updated.
diff --git a/talk/base/thread.h b/talk/base/thread.h
index 8eeef42..42656e9 100644
--- a/talk/base/thread.h
+++ b/talk/base/thread.h
@@ -48,7 +48,7 @@
class Thread;
class ThreadManager {
-public:
+ public:
ThreadManager();
~ThreadManager();
@@ -75,7 +75,7 @@
static void StopAllThreads_(); // Experimental
-private:
+ private:
Thread *main_thread_;
std::vector<Thread *> threads_;
CriticalSection crit_;
@@ -112,7 +112,7 @@
};
class Thread : public MessageQueue {
-public:
+ public:
Thread(SocketServer* ss = NULL);
virtual ~Thread();
@@ -184,11 +184,13 @@
}
#endif
-private:
- static void *PreRun(void *pv);
+ protected:
// Blocks the calling thread until this thread has terminated.
void Join();
+ private:
+ static void *PreRun(void *pv);
+
std::list<_SendMessage> sendlist_;
std::string name_;
ThreadPriority priority_;
diff --git a/talk/base/unixfilesystem.cc b/talk/base/unixfilesystem.cc
index 436dc2f..2a243ba 100644
--- a/talk/base/unixfilesystem.cc
+++ b/talk/base/unixfilesystem.cc
@@ -124,7 +124,7 @@
FileStream *UnixFilesystem::OpenFile(const Pathname &filename,
const std::string &mode) {
FileStream *fs = new FileStream();
- if (fs && !fs->Open(filename.pathname().c_str(), mode.c_str())) {
+ if (fs && !fs->Open(filename.pathname().c_str(), mode.c_str(), NULL)) {
delete fs;
fs = NULL;
}
diff --git a/talk/base/win32filesystem.cc b/talk/base/win32filesystem.cc
index ccf4618..42c0388 100644
--- a/talk/base/win32filesystem.cc
+++ b/talk/base/win32filesystem.cc
@@ -80,7 +80,7 @@
FileStream *Win32Filesystem::OpenFile(const Pathname &filename,
const std::string &mode) {
FileStream *fs = new FileStream();
- if (fs && !fs->Open(filename.pathname().c_str(), mode.c_str())) {
+ if (fs && !fs->Open(filename.pathname().c_str(), mode.c_str(), NULL)) {
delete fs;
fs = NULL;
}
diff --git a/talk/examples/call/call_main.cc b/talk/examples/call/call_main.cc
index 9735cfc..8120f2e 100644
--- a/talk/examples/call/call_main.cc
+++ b/talk/examples/call/call_main.cc
@@ -200,6 +200,12 @@
std::vector<cricket::AudioCodec> voice_codecs;
voice_codecs.push_back(
cricket::AudioCodec(9, "G722", 16000, 0, 1, 0));
+ voice_codecs.push_back(
+ cricket::AudioCodec(0, "PCMU", 8000, 0, 1, 0));
+ voice_codecs.push_back(
+ cricket::AudioCodec(13, "CN", 8000, 0, 1, 0));
+ voice_codecs.push_back(
+ cricket::AudioCodec(105, "CN", 16000, 0, 1, 0));
file_media_engine->set_voice_codecs(voice_codecs);
std::vector<cricket::VideoCodec> video_codecs;
video_codecs.push_back(
diff --git a/talk/examples/call/callclient.cc b/talk/examples/call/callclient.cc
index 3192daf..65bca1f 100644
--- a/talk/examples/call/callclient.cc
+++ b/talk/examples/call/callclient.cc
@@ -120,6 +120,7 @@
" ljoin [room_name] Joins a MUC by looking up JID from room name.\n"
" invite user [room] Invites a friend to a multi-user-chat.\n"
" leave [room] Leaves a multi-user-chat.\n"
+" nick [nick] Sets the nick.\n"
" getdevs Prints the available media devices.\n"
" quit Quits the application.\n"
"";
@@ -207,6 +208,8 @@
InviteToMuc(words[1], GetWord(words, 2, ""));
} else if (command == "leave") {
LeaveMuc(GetWord(words, 1, ""));
+ } else if (command == "nick") {
+ SetNick(GetWord(words, 1, ""));
} else if (command == "getdevs") {
GetDevices();
} else if ((words.size() == 2) && (command == "setvol")) {
@@ -638,6 +641,20 @@
talk_base::Thread::Current()->Quit();
}
+void CallClient::SetNick(const std::string& muc_nick) {
+ my_status_.set_nick(muc_nick);
+
+ // TODO: We might want to re-send presence, but right
+ // now, it appears to be ignored by the MUC.
+ //
+ // presence_out_->Send(my_status_); for (MucMap::const_iterator itr
+ // = mucs_.begin(); itr != mucs_.end(); ++itr) {
+ // presence_out_->SendDirected(itr->second->local_jid(),
+ // my_status_); }
+
+ console_->PrintLine("Nick set to '%s'.", muc_nick.c_str());
+}
+
void CallClient::LookupAndJoinMuc(const std::string& room_name) {
// The room_name can't be empty for lookup task.
if (room_name.empty()) {
@@ -810,7 +827,10 @@
mucs_.erase(elem);
}
-void CallClient::InviteToMuc(const std::string& user, const std::string& room) {
+void CallClient::InviteToMuc(const std::string& given_user,
+ const std::string& room) {
+ std::string user = given_user;
+
// First find the room.
const buzz::Muc* found_muc;
if (room.length() == 0) {
@@ -828,19 +848,23 @@
}
found_muc = elem->second;
}
+
+ buzz::Jid invite_to = found_muc->jid();
+
// Now find the user. We invite all of their resources.
bool found_user = false;
buzz::Jid user_jid(user);
for (RosterMap::iterator iter = roster_->begin();
iter != roster_->end(); ++iter) {
if (iter->second.jid.BareEquals(user_jid)) {
- muc_invite_send_->Send(iter->second.jid, *found_muc);
+ buzz::Jid invitee = iter->second.jid;
+ muc_invite_send_->Send(invite_to, invitee);
found_user = true;
}
}
if (!found_user) {
- console_->PrintLine("No such friend as %s.", user.c_str());
- return;
+ buzz::Jid invitee = user_jid;
+ muc_invite_send_->Send(invite_to, invitee);
}
}
diff --git a/talk/examples/call/callclient.h b/talk/examples/call/callclient.h
index 72a9ca9..e39c9d4 100644
--- a/talk/examples/call/callclient.h
+++ b/talk/examples/call/callclient.h
@@ -118,6 +118,7 @@
void LookupAndJoinMuc(const std::string& room_name);
void InviteToMuc(const std::string& user, const std::string& room);
void LeaveMuc(const std::string& room);
+ void SetNick(const std::string& muc_nick);
void SetPortAllocatorFlags(uint32 flags) { portallocator_flags_ = flags; }
void SetAllowLocalIps(bool allow_local_ips) {
allow_local_ips_ = allow_local_ips;
diff --git a/talk/examples/call/mucinvitesendtask.cc b/talk/examples/call/mucinvitesendtask.cc
index efd9a81..d648fef 100644
--- a/talk/examples/call/mucinvitesendtask.cc
+++ b/talk/examples/call/mucinvitesendtask.cc
@@ -32,18 +32,18 @@
namespace buzz {
XmppReturnStatus
-MucInviteSendTask::Send(const Jid& user, const Muc& muc) {
+MucInviteSendTask::Send(const Jid& to, const Jid& invitee) {
if (GetState() != STATE_INIT && GetState() != STATE_START)
return XMPP_RETURN_BADSTATE;
XmlElement* message = new XmlElement(QN_MESSAGE);
- message->AddAttr(QN_TO, muc.jid().Str());
+ message->AddAttr(QN_TO, to.Str());
XmlElement* xstanza = new XmlElement(QN_MUC_USER_X);
XmlElement* invite = new XmlElement(QN_MUC_USER_INVITE);
- invite->AddAttr(QN_TO, user.Str());
+ invite->AddAttr(QN_TO, invitee.Str());
xstanza->AddElement(invite);
message->AddElement(xstanza);
-
+
QueueStanza(message);
return XMPP_RETURN_OK;
}
diff --git a/talk/examples/call/mucinvitesendtask.h b/talk/examples/call/mucinvitesendtask.h
index 18e0f99..8afd361 100644
--- a/talk/examples/call/mucinvitesendtask.h
+++ b/talk/examples/call/mucinvitesendtask.h
@@ -39,7 +39,7 @@
MucInviteSendTask(Task* parent) : XmppTask(parent) {}
virtual ~MucInviteSendTask() {}
- XmppReturnStatus Send(const Jid& user, const Muc& muc);
+ XmppReturnStatus Send(const Jid& to, const Jid& invitee);
virtual int ProcessStart();
};
diff --git a/talk/examples/call/presenceouttask.cc b/talk/examples/call/presenceouttask.cc
index b3e5f37..919a1af 100644
--- a/talk/examples/call/presenceouttask.cc
+++ b/talk/examples/call/presenceouttask.cc
@@ -106,6 +106,11 @@
result->AddElement(new XmlElement(QN_STATUS));
result->AddText(s.status(), 1);
+ if (!s.nick().empty()) {
+ result->AddElement(new XmlElement(QN_NICKNAME));
+ result->AddText(s.nick(), 1);
+ }
+
std::string pri;
talk_base::ToString(s.priority(), &pri);
diff --git a/talk/examples/call/presencepushtask.cc b/talk/examples/call/presencepushtask.cc
index 1e2cc52..320b99c 100644
--- a/talk/examples/call/presencepushtask.cc
+++ b/talk/examples/call/presencepushtask.cc
@@ -208,6 +208,11 @@
std::string stamp = delay->Attr(kQnStamp);
s->set_sent_time(stamp);
}
+
+ const XmlElement* nick = stanza->FirstNamed(QN_NICKNAME);
+ if (nick) {
+ s->set_nick(nick->BodyText());
+ }
}
}
diff --git a/talk/examples/call/status.h b/talk/examples/call/status.h
index 68c333b..c3778e5 100644
--- a/talk/examples/call/status.h
+++ b/talk/examples/call/status.h
@@ -70,6 +70,7 @@
int priority() const { return pri_; }
Show show() const { return show_; }
const std::string & status() const { return status_; }
+ const std::string & nick() const { return nick_; }
bool available() const { return available_ ; }
int error_code() const { return e_code_; }
const std::string & error_string() const { return e_str_; }
@@ -87,6 +88,7 @@
void set_priority(int pri) { pri_ = pri; }
void set_show(Show show) { show_ = show; }
void set_status(const std::string & status) { status_ = status; }
+ void set_nick(const std::string & nick) { nick_ = nick; }
void set_available(bool a) { available_ = a; }
void set_error(int e_code, const std::string e_str)
{ e_code_ = e_code; e_str_ = e_str; }
@@ -206,6 +208,7 @@
int pri_;
Show show_;
std::string status_;
+ std::string nick_;
bool available_;
int e_code_;
std::string e_str_;
diff --git a/talk/main.scons b/talk/main.scons
index f88d1a5..c8b0fd9 100644
--- a/talk/main.scons
+++ b/talk/main.scons
@@ -77,6 +77,14 @@
'Whether the build system has the libpulse package')
+# List all the locales we localize to.
+root_env.AppendUnique(locales = [
+ 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en-GB', 'es', 'es-419',
+ 'et', 'fa', 'fi', 'fil', 'fr', 'gu', 'hi', 'hr', 'hu', 'id', 'is', 'it',
+ 'iw', 'ja', 'kn', 'ko', 'lt', 'lv', 'ml', 'mr', 'ms', 'nl', 'no', 'or',
+ 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv', 'ta', 'te',
+ 'th', 'tl', 'tr', 'uk', 'ur', 'vi', 'zh-CN', 'zh-TW'])
+
#-------------------------------------------------------------------------------
# W I N D O W S
#
diff --git a/talk/p2p/base/relayport.cc b/talk/p2p/base/relayport.cc
index 2d3be61..5348fe5 100644
--- a/talk/p2p/base/relayport.cc
+++ b/talk/p2p/base/relayport.cc
@@ -199,8 +199,10 @@
set_username_fragment(username);
set_password(password);
- if (magic_cookie_.size() == 0)
- magic_cookie_.append(STUN_MAGIC_COOKIE_VALUE, 4);
+ if (magic_cookie_.size() == 0) {
+ magic_cookie_.append(TURN_MAGIC_COOKIE_VALUE,
+ sizeof(TURN_MAGIC_COOKIE_VALUE));
+ }
}
RelayPort::~RelayPort() {
@@ -535,7 +537,8 @@
StunMessage request;
request.SetType(STUN_SEND_REQUEST);
- request.SetTransactionID(talk_base::CreateRandomString(16));
+ request.SetTransactionID(
+ talk_base::CreateRandomString(kStunTransactionIdLength));
StunByteStringAttribute* magic_cookie_attr =
StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
diff --git a/talk/p2p/base/relayserver.cc b/talk/p2p/base/relayserver.cc
index 17d4227..82f382a 100644
--- a/talk/p2p/base/relayserver.cc
+++ b/talk/p2p/base/relayserver.cc
@@ -79,10 +79,12 @@
StunByteStringAttribute* magic_cookie_attr =
StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
- if (magic_cookie.size() == 0)
- magic_cookie_attr->CopyBytes(cricket::STUN_MAGIC_COOKIE_VALUE, 4);
- else
+ if (magic_cookie.size() == 0) {
+ magic_cookie_attr->CopyBytes(cricket::TURN_MAGIC_COOKIE_VALUE,
+ sizeof(cricket::TURN_MAGIC_COOKIE_VALUE));
+ } else {
magic_cookie_attr->CopyBytes(magic_cookie.c_str(), magic_cookie.size());
+ }
err_msg.AddAttribute(magic_cookie_attr);
StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
@@ -610,7 +612,6 @@
StunMessage msg;
msg.SetType(STUN_DATA_INDICATION);
- msg.SetTransactionID("0000000000000000");
StunByteStringAttribute* magic_cookie_attr =
StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
@@ -669,7 +670,8 @@
lifetime_(lifetime) {
// For now, every connection uses the standard magic cookie value.
magic_cookie_.append(
- reinterpret_cast<const char*>(STUN_MAGIC_COOKIE_VALUE), 4);
+ reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE),
+ sizeof(TURN_MAGIC_COOKIE_VALUE));
// Initialize the last-used time to now.
NoteUsed();
diff --git a/talk/p2p/base/session.cc b/talk/p2p/base/session.cc
index e9c5a03..54ae1bc 100644
--- a/talk/p2p/base/session.cc
+++ b/talk/p2p/base/session.cc
@@ -868,8 +868,38 @@
bool Session::OnUpdateMessage(const SessionMessage& msg,
MessageError* error) {
- // TODO: Once someone needs it, parse the message
- // into a data structure and signal out.
+ if (!CheckState(STATE_INPROGRESS, error))
+ return false;
+
+ DescriptionInfo description_info;
+ if (!ParseDescriptionInfo(msg.protocol, msg.action_elem,
+ GetContentParsers(), GetTransportParsers(),
+ &description_info, error)) {
+ return false;
+ }
+
+ ContentInfos updated_contents = description_info.ClearContents();
+ ContentInfos::iterator it;
+
+ // First, ensure all updates are valid before modifying remote_description_.
+ for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
+ if (remote_description_->GetContentByName(it->name) == NULL) {
+ return false;
+ }
+
+ // TODO: We should add a check to ensure that the updated
+ // contents are compatible with the original contents.
+ }
+
+ // Merge the updates into the remote description.
+ for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
+ LOG(LS_INFO) << "Updating content " << it->name;
+ remote_description_->RemoveContentByName(it->name);
+ remote_description_->AddContent(it->name, it->type, it->description);
+ }
+
+ SignalRemoteDescriptionUpdate(this);
+
return true;
}
diff --git a/talk/p2p/base/session.h b/talk/p2p/base/session.h
index c299ac6..bfafe77 100644
--- a/talk/p2p/base/session.h
+++ b/talk/p2p/base/session.h
@@ -233,7 +233,7 @@
return remote_description_;
}
// Takes ownership of SessionDescription*
- bool set_remote_description(const SessionDescription* sdesc) {
+ bool set_remote_description(SessionDescription* sdesc) {
if (sdesc != remote_description_) {
delete remote_description_;
remote_description_ = sdesc;
@@ -273,11 +273,14 @@
const std::string& id() const { return sid_; }
+ // Fired when the remote description is updated.
+ sigslot::signal1<BaseSession *> SignalRemoteDescriptionUpdate;
+
protected:
State state_;
Error error_;
const SessionDescription* local_description_;
- const SessionDescription* remote_description_;
+ SessionDescription* remote_description_;
std::string sid_;
// We don't use buzz::Jid because changing to buzz:Jid here has a
// cascading effect that requires an enormous number places to
diff --git a/talk/p2p/base/sessiondescription.cc b/talk/p2p/base/sessiondescription.cc
index 872358e..6554f5a 100644
--- a/talk/p2p/base/sessiondescription.cc
+++ b/talk/p2p/base/sessiondescription.cc
@@ -69,4 +69,17 @@
contents_.push_back(ContentInfo(name, type, description));
}
+bool SessionDescription::RemoveContentByName(const std::string& name) {
+ for (ContentInfos::iterator content = contents_.begin();
+ content != contents_.end(); ++content) {
+ if (content->name == name) {
+ delete content->description;
+ contents_.erase(content);
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace cricket
diff --git a/talk/p2p/base/sessiondescription.h b/talk/p2p/base/sessiondescription.h
index fe575fa..38c902b 100644
--- a/talk/p2p/base/sessiondescription.h
+++ b/talk/p2p/base/sessiondescription.h
@@ -75,9 +75,7 @@
void AddContent(const std::string& name,
const std::string& type,
const ContentDescription* description);
- // TODO: Implement RemoveContent when it's needed for
- // content-remove Jingle messages.
- // void RemoveContent(const std::string& name);
+ bool RemoveContentByName(const std::string& name);
const ContentInfos& contents() const { return contents_; }
~SessionDescription() {
diff --git a/talk/p2p/base/sessionmessages.cc b/talk/p2p/base/sessionmessages.cc
index 7bc47b4..ae2e656 100644
--- a/talk/p2p/base/sessionmessages.cc
+++ b/talk/p2p/base/sessionmessages.cc
@@ -675,12 +675,13 @@
return true;
}
-bool ParseSessionInitiate(SignalingProtocol protocol,
- const buzz::XmlElement* action_elem,
- const ContentParserMap& content_parsers,
- const TransportParserMap& trans_parsers,
- SessionInitiate* init,
- ParseError* error) {
+static bool ParseContentMessage(
+ SignalingProtocol protocol,
+ const buzz::XmlElement* action_elem,
+ const ContentParserMap& content_parsers,
+ const TransportParserMap& trans_parsers,
+ SessionInitiate* init,
+ ParseError* error) {
init->owns_contents = true;
if (protocol == PROTOCOL_GINGLE) {
if (!ParseGingleContentInfos(action_elem, content_parsers,
@@ -703,14 +704,14 @@
return true;
}
-
-bool WriteSessionInitiate(SignalingProtocol protocol,
- const ContentInfos& contents,
- const TransportInfos& tinfos,
- const ContentParserMap& content_parsers,
- const TransportParserMap& transport_parsers,
- XmlElements* elems,
- WriteError* error) {
+static bool WriteContentMessage(
+ SignalingProtocol protocol,
+ const ContentInfos& contents,
+ const TransportInfos& tinfos,
+ const ContentParserMap& content_parsers,
+ const TransportParserMap& transport_parsers,
+ XmlElements* elems,
+ WriteError* error) {
if (protocol == PROTOCOL_GINGLE) {
if (!WriteGingleContentInfos(contents, content_parsers, elems, error))
return false;
@@ -728,15 +729,39 @@
return true;
}
+bool ParseSessionInitiate(SignalingProtocol protocol,
+ const buzz::XmlElement* action_elem,
+ const ContentParserMap& content_parsers,
+ const TransportParserMap& trans_parsers,
+ SessionInitiate* init,
+ ParseError* error) {
+ return ParseContentMessage(protocol, action_elem,
+ content_parsers, trans_parsers,
+ init, error);
+}
+
+
+bool WriteSessionInitiate(SignalingProtocol protocol,
+ const ContentInfos& contents,
+ const TransportInfos& tinfos,
+ const ContentParserMap& content_parsers,
+ const TransportParserMap& transport_parsers,
+ XmlElements* elems,
+ WriteError* error) {
+ return WriteContentMessage(protocol, contents, tinfos,
+ content_parsers, transport_parsers,
+ elems, error);
+}
+
bool ParseSessionAccept(SignalingProtocol protocol,
const buzz::XmlElement* action_elem,
const ContentParserMap& content_parsers,
const TransportParserMap& transport_parsers,
SessionAccept* accept,
ParseError* error) {
- return ParseSessionInitiate(protocol, action_elem,
- content_parsers, transport_parsers,
- accept, error);
+ return ParseContentMessage(protocol, action_elem,
+ content_parsers, transport_parsers,
+ accept, error);
}
bool WriteSessionAccept(SignalingProtocol protocol,
@@ -746,9 +771,9 @@
const TransportParserMap& transport_parsers,
XmlElements* elems,
WriteError* error) {
- return WriteSessionInitiate(protocol, contents, tinfos,
- content_parsers, transport_parsers,
- elems, error);
+ return WriteContentMessage(protocol, contents, tinfos,
+ content_parsers, transport_parsers,
+ elems, error);
}
bool ParseSessionTerminate(SignalingProtocol protocol,
@@ -794,6 +819,17 @@
}
}
+bool ParseDescriptionInfo(SignalingProtocol protocol,
+ const buzz::XmlElement* action_elem,
+ const ContentParserMap& content_parsers,
+ const TransportParserMap& transport_parsers,
+ DescriptionInfo* description_info,
+ ParseError* error) {
+ return ParseContentMessage(protocol, action_elem,
+ content_parsers, transport_parsers,
+ description_info, error);
+}
+
bool ParseTransportInfos(SignalingProtocol protocol,
const buzz::XmlElement* action_elem,
const ContentInfos& contents,
diff --git a/talk/p2p/base/sessionmessages.h b/talk/p2p/base/sessionmessages.h
index ef7cc69..214fa8c 100644
--- a/talk/p2p/base/sessionmessages.h
+++ b/talk/p2p/base/sessionmessages.h
@@ -114,10 +114,12 @@
typedef std::vector<TransportInfo> TransportInfos;
-struct SessionInitiate {
- SessionInitiate() : owns_contents(false) {}
+// TODO: Break up this class so we don't have to typedef it into
+// different classes.
+struct ContentMessage {
+ ContentMessage() : owns_contents(false) {}
- ~SessionInitiate() {
+ ~ContentMessage() {
if (owns_contents) {
for (ContentInfos::iterator content = contents.begin();
content != contents.end(); content++) {
@@ -139,8 +141,10 @@
TransportInfos transports;
};
-// Right now, a SessionAccept is functionally equivalent to a SessionInitiate.
-typedef SessionInitiate SessionAccept;
+typedef ContentMessage SessionInitiate;
+typedef ContentMessage SessionAccept;
+// Note that a DescriptionInfo does not have TransportInfos.
+typedef ContentMessage DescriptionInfo;
struct SessionTerminate {
SessionTerminate() {}
@@ -202,6 +206,12 @@
void WriteSessionTerminate(SignalingProtocol protocol,
const SessionTerminate& term,
XmlElements* elems);
+bool ParseDescriptionInfo(SignalingProtocol protocol,
+ const buzz::XmlElement* action_elem,
+ const ContentParserMap& content_parsers,
+ const TransportParserMap& transport_parsers,
+ DescriptionInfo* description_info,
+ ParseError* error);
// Since a TransportInfo is not a transport-info message, and a
// transport-info message is just a collection of TransportInfos, we
// say Parse/Write TransportInfos for transport-info messages.
diff --git a/talk/p2p/base/stun.cc b/talk/p2p/base/stun.cc
index ad8b5ce..e324d7e 100644
--- a/talk/p2p/base/stun.cc
+++ b/talk/p2p/base/stun.cc
@@ -40,15 +40,21 @@
const std::string STUN_ERROR_REASON_UNAUTHORIZED = "UNAUTHORIZED";
const std::string STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE = "UNKNOWN ATTRIBUTE";
const std::string STUN_ERROR_REASON_STALE_CREDENTIALS = "STALE CREDENTIALS";
-const std::string STUN_ERROR_REASON_INTEGRITY_CHECK_FAILURE = "INTEGRITY CHECK FAILURE";
+const std::string STUN_ERROR_REASON_INTEGRITY_CHECK_FAILURE =
+ "INTEGRITY CHECK FAILURE";
const std::string STUN_ERROR_REASON_MISSING_USERNAME = "MISSING USERNAME";
const std::string STUN_ERROR_REASON_USE_TLS = "USE TLS";
const std::string STUN_ERROR_REASON_SERVER_ERROR = "SERVER ERROR";
const std::string STUN_ERROR_REASON_GLOBAL_FAILURE = "GLOBAL FAILURE";
-StunMessage::StunMessage() : type_(0), length_(0),
- transaction_id_("0000000000000000") {
- ASSERT(transaction_id_.size() == 16);
+const char kStunMagicCookie[] = { '\x21', '\x12', '\xA4', '\x42' };
+
+const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
+
+StunMessage::StunMessage()
+ : type_(0), length_(0),
+ transaction_id_("000000000000") {
+ ASSERT(IsValidTransactionId(transaction_id_));
attrs_ = new std::vector<StunAttribute*>();
}
@@ -58,8 +64,15 @@
delete attrs_;
}
+bool StunMessage::IsLegacy() const {
+ if (transaction_id_.size() == kStunLegacyTransactionIdLength)
+ return true;
+ ASSERT(transaction_id_.size() == kStunTransactionIdLength);
+ return false;
+}
+
void StunMessage::SetTransactionID(const std::string& str) {
- ASSERT(str.size() == 16);
+ ASSERT(IsValidTransactionId(str));
transaction_id_ = str;
}
@@ -154,10 +167,20 @@
if (!buf->ReadUInt16(&length_))
return false;
- std::string transaction_id;
- if (!buf->ReadString(&transaction_id, 16))
+ std::string magic_cookie;
+ if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
return false;
- ASSERT(transaction_id.size() == 16);
+
+ std::string transaction_id;
+ if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
+ return false;
+ if (magic_cookie != std::string(kStunMagicCookie,
+ kStunMagicCookie + kStunMagicCookieLength)) {
+ // If magic cookie is invalid it means that the peer implements
+ // RFC3489 instead of RFC5389.
+ transaction_id.insert(0, magic_cookie);
+ }
+ ASSERT(IsValidTransactionId(transaction_id));
transaction_id_ = transaction_id;
if (length_ > buf->Length())
@@ -193,6 +216,8 @@
void StunMessage::Write(ByteBuffer* buf) const {
buf->WriteUInt16(type_);
buf->WriteUInt16(length_);
+ if (!IsLegacy())
+ buf->WriteBytes(kStunMagicCookie, kStunMagicCookieLength);
buf->WriteString(transaction_id_);
for (unsigned i = 0; i < attrs_->size(); i++) {
@@ -202,6 +227,11 @@
}
}
+bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
+ return transaction_id.size() == kStunTransactionIdLength ||
+ transaction_id.size() == kStunLegacyTransactionIdLength;
+}
+
StunAttribute::StunAttribute(uint16 type, uint16 length)
: type_(type), length_(length) {
}
diff --git a/talk/p2p/base/stun.h b/talk/p2p/base/stun.h
index 2282fed..cc0e972 100644
--- a/talk/p2p/base/stun.h
+++ b/talk/p2p/base/stun.h
@@ -25,8 +25,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __STUN_H__
-#define __STUN_H__
+#ifndef TALK_P2P_BASE_STUN_H_
+#define TALK_P2P_BASE_STUN_H_
// This file contains classes for dealing with the STUN and TURN protocols.
// Both protocols use the same wire format.
@@ -39,6 +39,9 @@
namespace cricket {
+// TODO: Remove message types and attributes that are no
+// longer suppored in RFC5389 (see section 18.2).
+
// These are the types of STUN & TURN messages as of last check.
enum StunMessageType {
STUN_BINDING_REQUEST = 0x0001,
@@ -103,6 +106,16 @@
extern const std::string STUN_ERROR_REASON_SERVER_ERROR;
extern const std::string STUN_ERROR_REASON_GLOBAL_FAILURE;
+// Following values correspond to RFC5389.
+const size_t kStunTransactionIdOffset = 8;
+const size_t kStunTransactionIdLength = 12;
+extern const char kStunMagicCookie[4];
+const size_t kStunMagicCookieLength = sizeof(kStunMagicCookie);
+
+// Following value corresponds to an earlier version of STUN from
+// RFC3489.
+const size_t kStunLegacyTransactionIdLength = 16;
+
class StunAttribute;
class StunAddressAttribute;
class StunUInt32Attribute;
@@ -119,11 +132,17 @@
public:
StunMessage();
~StunMessage();
-
StunMessageType type() const { return static_cast<StunMessageType>(type_); }
uint16 length() const { return length_; }
const std::string& transaction_id() const { return transaction_id_; }
+ // Returns true if the message confirms to RFC3489 rather than
+ // RFC5389. The main difference between two version of the STUN
+ // protocol is the presence of the magic cookie and different length
+ // of transaction ID. For outgoing packets version of the protocol
+ // is determined by the lengths of the transaction ID.
+ bool IsLegacy() const;
+
void SetType(StunMessageType type) { type_ = type; }
void SetTransactionID(const std::string& str);
@@ -140,7 +159,7 @@
// return value indicates whether this was successful.
bool Read(talk_base::ByteBuffer* buf);
- // Writes this object into a STUN/TURN packet. Return value is true if
+ // Writes this object into a STUN/TURN packet. Return value is true if
// successful.
void Write(talk_base::ByteBuffer* buf) const;
@@ -151,6 +170,7 @@
std::vector<StunAttribute*>* attrs_;
const StunAttribute* GetAttribute(StunAttributeType type) const;
+ static bool IsValidTransactionId(const std::string& transaction_id);
};
// Base class for all STUN/TURN attributes.
@@ -160,7 +180,7 @@
StunAttributeType type() const {
return static_cast<StunAttributeType>(type_);
- }
+ }
uint16 length() const { return length_; }
// Reads the body (not the type or length) for this type of attribute from
@@ -195,7 +215,7 @@
// Implements STUN/TURN attributes that record an Internet address.
class StunAddressAttribute : public StunAttribute {
public:
- StunAddressAttribute(uint16 type);
+ explicit StunAddressAttribute(uint16 type);
#if (_MSC_VER < 1300)
enum { SIZE = 8 };
@@ -223,7 +243,7 @@
// Implements STUN/TURN attributs that record a 32-bit integer.
class StunUInt32Attribute : public StunAttribute {
public:
- StunUInt32Attribute(uint16 type);
+ explicit StunUInt32Attribute(uint16 type);
#if (_MSC_VER < 1300)
enum { SIZE = 4 };
@@ -352,7 +372,9 @@
// The special MAGIC-COOKIE attribute is used to distinguish TURN packets from
// other kinds of traffic.
-const char STUN_MAGIC_COOKIE_VALUE[] = { 0x72, char(0xc6), 0x4b, char(0xc6) };
+// TODO: This value has nothing to do with STUN. Move it to a
+// separate file.
+extern const char TURN_MAGIC_COOKIE_VALUE[4];
// Returns the (successful) response type for the given request type.
StunMessageType GetStunResponseType(StunMessageType request_type);
@@ -362,4 +384,4 @@
} // namespace cricket
-#endif // __STUN_H__
+#endif // TALK_P2P_BASE_STUN_H_
diff --git a/talk/p2p/base/stunrequest.cc b/talk/p2p/base/stunrequest.cc
index 1ad121e..9c1ada7 100644
--- a/talk/p2p/base/stunrequest.cc
+++ b/talk/p2p/base/stunrequest.cc
@@ -110,7 +110,7 @@
return false;
std::string id;
- id.append(data + 4, 16);
+ id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength);
RequestMap::iterator iter = requests_.find(id);
if (iter == requests_.end())
@@ -128,7 +128,8 @@
StunRequest::StunRequest()
: count_(0), timeout_(false), manager_(0),
- id_(talk_base::CreateRandomString(16)), msg_(new StunMessage()),
+ id_(talk_base::CreateRandomString(kStunTransactionIdLength)),
+ msg_(new StunMessage()),
tstamp_(0) {
msg_->SetTransactionID(id_);
}
diff --git a/talk/session/phone/call.cc b/talk/session/phone/call.cc
index 251eafa..08658ff 100644
--- a/talk/session/phone/call.cc
+++ b/talk/session/phone/call.cc
@@ -138,7 +138,7 @@
for (it = view_request.static_video_views.begin();
it != view_request.static_video_views.end(); ++it) {
const NamedSource* found_source =
- media_sources.GetVideoSourceBySsrc(it->ssrc);
+ media_sources_.GetVideoSourceBySsrc(it->ssrc);
if (!found_source) {
LOG(LS_WARNING) <<
"Tried sending view request for bad ssrc: " << it->ssrc;
@@ -547,11 +547,11 @@
for (it = sources.audio.begin(); it != sources.audio.end(); ++it) {
const NamedSource* found;
if (it->ssrc_set) {
- found = media_sources.GetAudioSourceBySsrc(it->ssrc);
+ found = media_sources_.GetAudioSourceBySsrc(it->ssrc);
} else {
// For backwards compatibility, we remove by nick.
// TODO: Remove once all senders use explicit remove by ssrc.
- found = media_sources.GetFirstAudioSourceByNick(it->nick);
+ found = media_sources_.GetFirstAudioSourceByNick(it->nick);
if (found) {
it->SetSsrc(found->ssrc);
it->removed = true;
@@ -561,12 +561,12 @@
}
if (it->removed && found) {
RemoveVoiceStream(session, found->ssrc);
- media_sources.RemoveAudioSourceBySsrc(it->ssrc);
+ media_sources_.RemoveAudioSourceBySsrc(it->ssrc);
updates.audio.push_back(*it);
LOG(LS_INFO) << "Removed voice stream: " << found->ssrc;
} else if (!it->removed && !found) {
AddVoiceStream(session, it->ssrc);
- media_sources.AddAudioSource(*it);
+ media_sources_.AddAudioSource(*it);
updates.audio.push_back(*it);
LOG(LS_INFO) << "Added voice stream: " << it->ssrc;
}
@@ -574,11 +574,11 @@
for (it = sources.video.begin(); it != sources.video.end(); ++it) {
const NamedSource* found;
if (it->ssrc_set) {
- found = media_sources.GetVideoSourceBySsrc(it->ssrc);
+ found = media_sources_.GetVideoSourceBySsrc(it->ssrc);
} else {
// For backwards compatibility, we remove by nick.
// TODO: Remove once all senders use explicit remove by ssrc.
- found = media_sources.GetFirstVideoSourceByNick(it->nick);
+ found = media_sources_.GetFirstVideoSourceByNick(it->nick);
if (found) {
it->SetSsrc(found->ssrc);
it->removed = true;
@@ -588,12 +588,12 @@
}
if (it->removed && found) {
RemoveVideoStream(session, found->ssrc);
- media_sources.RemoveVideoSourceBySsrc(it->ssrc);
+ media_sources_.RemoveVideoSourceBySsrc(it->ssrc);
updates.video.push_back(*it);
LOG(LS_INFO) << "Removed video stream: " << found->ssrc;
} else if (!it->removed && !found) {
AddVideoStream(session, it->ssrc);
- media_sources.AddVideoSource(*it);
+ media_sources_.AddVideoSource(*it);
updates.video.push_back(*it);
LOG(LS_INFO) << "Added video stream: " << it->ssrc;
}
diff --git a/talk/session/phone/call.h b/talk/session/phone/call.h
index 06c3981..38e0684 100644
--- a/talk/session/phone/call.h
+++ b/talk/session/phone/call.h
@@ -131,7 +131,7 @@
uint32 id_;
MediaSessionClient *session_client_;
std::vector<Session *> sessions_;
- MediaSources media_sources;
+ MediaSources media_sources_;
std::map<std::string, VoiceChannel *> voice_channel_map_;
std::map<std::string, VideoChannel *> video_channel_map_;
VideoRenderer* local_renderer_;
diff --git a/talk/session/phone/channel.cc b/talk/session/phone/channel.cc
index bd5ec30..b23d877 100644
--- a/talk/session/phone/channel.cc
+++ b/talk/session/phone/channel.cc
@@ -101,6 +101,8 @@
LOG(LS_INFO) << "Created channel";
session->SignalState.connect(this, &BaseChannel::OnSessionState);
+ session->SignalRemoteDescriptionUpdate.connect(this,
+ &BaseChannel::OnRemoteDescriptionUpdate);
}
BaseChannel::~BaseChannel() {
@@ -425,6 +427,16 @@
}
}
+void BaseChannel::OnRemoteDescriptionUpdate(BaseSession* session) {
+ const MediaContentDescription* content =
+ GetFirstContent(session->remote_description());
+
+ if (content && !SetRemoteContent(content, CA_UPDATE)) {
+ LOG(LS_ERROR) << "Failure in SetRemoteContent with CA_UPDATE";
+ session->SetError(BaseSession::ERROR_CONTENT);
+ }
+}
+
void BaseChannel::EnableMedia_w() {
ASSERT(worker_thread_ == talk_base::Thread::Current());
if (enabled_)
diff --git a/talk/session/phone/channel.h b/talk/session/phone/channel.h
index 9378a0f..7d6577a 100644
--- a/talk/session/phone/channel.h
+++ b/talk/session/phone/channel.h
@@ -176,6 +176,7 @@
// Setting the send codec based on the remote description.
void OnSessionState(BaseSession* session, BaseSession::State state);
+ void OnRemoteDescriptionUpdate(BaseSession* session);
void EnableMedia_w();
void DisableMedia_w();
diff --git a/talk/session/phone/mediaengine.cc b/talk/session/phone/mediaengine.cc
index a3eb227..43d75e1 100644
--- a/talk/session/phone/mediaengine.cc
+++ b/talk/session/phone/mediaengine.cc
@@ -33,15 +33,35 @@
#ifdef 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
#endif
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
MediaEngine* MediaEngine::Create() {
#if defined(HAVE_LINPHONE)
return new LinphoneMediaEngine("", "");
#elif defined(HAVE_WEBRTC)
+#if defined(PLATFORM_CHROMIUM)
+ return new CompositeMediaEngine<ChromiumWebRtcVoiceEngine,
+ WebRtcVideoEngine>();
+#else
return new CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine>();
+#endif
#else
return new NullMediaEngine();
#endif
diff --git a/talk/session/phone/rtpdump.cc b/talk/session/phone/rtpdump.cc
index 2ac83eb..ad0e82d 100644
--- a/talk/session/phone/rtpdump.cc
+++ b/talk/session/phone/rtpdump.cc
@@ -86,6 +86,11 @@
cricket::GetRtpSsrc(&data[0], data.size(), ssrc);
}
+bool RtpDumpPacket::GetRtpHeaderLen(size_t* len) const {
+ return IsValidRtpPacket() &&
+ cricket::GetRtpHeaderLen(&data[0], data.size(), len);
+}
+
bool RtpDumpPacket::GetRtcpType(int* type) const {
return IsValidRtcpPacket() &&
cricket::GetRtcpType(&data[0], data.size(), type);
@@ -287,6 +292,7 @@
RtpDumpWriter::RtpDumpWriter(talk_base::StreamInterface* stream)
: stream_(stream),
+ packet_filter_(PF_ALL),
file_header_written_(false),
start_time_ms_(talk_base::Time()) {
}
@@ -295,6 +301,20 @@
return talk_base::TimeSince(start_time_ms_);
}
+talk_base::StreamResult RtpDumpWriter::WriteFileHeader() {
+ talk_base::StreamResult res = stream_->WriteAll(
+ RtpDumpFileHeader::kFirstLine.c_str(),
+ RtpDumpFileHeader::kFirstLine.size(), NULL, NULL);
+ if (res != talk_base::SR_SUCCESS) {
+ return res;
+ }
+
+ talk_base::ByteBuffer buf;
+ RtpDumpFileHeader file_header(talk_base::Time(), 0, 0);
+ file_header.WriteToByteBuffer(&buf);
+ return stream_->WriteAll(buf.Data(), buf.Length(), NULL, NULL);
+}
+
talk_base::StreamResult RtpDumpWriter::WritePacket(
const void* data, size_t data_len, uint32 elapsed, bool rtcp) {
if (!stream_ || !data || 0 == data_len) return talk_base::SR_ERROR;
@@ -309,9 +329,16 @@
file_header_written_ = true;
}
+ // Figure out what to write.
+ size_t write_len = FilterPacket(data, data_len, rtcp);
+ if (write_len == 0) {
+ return talk_base::SR_SUCCESS;
+ }
+
// Write the dump packet header.
talk_base::ByteBuffer buf;
- buf.WriteUInt16(static_cast<uint16>(RtpDumpPacket::kHeaderLength + data_len));
+ buf.WriteUInt16(static_cast<uint16>(
+ RtpDumpPacket::kHeaderLength + write_len));
buf.WriteUInt16(static_cast<uint16>(rtcp ? 0 : data_len));
buf.WriteUInt32(elapsed);
res = stream_->WriteAll(buf.Data(), buf.Length(), NULL, NULL);
@@ -319,22 +346,32 @@
return res;
}
- // Write the actual RTP or RTCP packet.
- return stream_->WriteAll(data, data_len, NULL, NULL);
+ // Write the header or full packet as indicated by write_len.
+ return stream_->WriteAll(data, write_len, NULL, NULL);
}
-talk_base::StreamResult RtpDumpWriter::WriteFileHeader() {
- talk_base::StreamResult res = stream_->WriteAll(
- RtpDumpFileHeader::kFirstLine.c_str(),
- RtpDumpFileHeader::kFirstLine.size(), NULL, NULL);
- if (res != talk_base::SR_SUCCESS) {
- return res;
+size_t RtpDumpWriter::FilterPacket(const void* data, size_t data_len,
+ bool rtcp) {
+ size_t filtered_len = 0;
+ if (!rtcp) {
+ if ((packet_filter_ & PF_RTPPACKET) == PF_RTPPACKET) {
+ // RTP header + payload
+ filtered_len = data_len;
+ } else if ((packet_filter_ & PF_RTPHEADER) == PF_RTPHEADER) {
+ // RTP header only
+ size_t header_len;
+ if (GetRtpHeaderLen(data, data_len, &header_len)) {
+ filtered_len = header_len;
+ }
+ }
+ } else {
+ if ((packet_filter_ & PF_RTCPPACKET) == PF_RTCPPACKET) {
+ // RTCP header + payload
+ filtered_len = data_len;
+ }
}
- talk_base::ByteBuffer buf;
- RtpDumpFileHeader file_header(talk_base::Time(), 0, 0);
- file_header.WriteToByteBuffer(&buf);
- return stream_->WriteAll(buf.Data(), buf.Length(), NULL, NULL);
+ return filtered_len;
}
} // namespace cricket
diff --git a/talk/session/phone/rtpdump.h b/talk/session/phone/rtpdump.h
index 5cc36a6..6b9f5a0 100644
--- a/talk/session/phone/rtpdump.h
+++ b/talk/session/phone/rtpdump.h
@@ -48,6 +48,15 @@
// For each packet, the file contains a 8 byte dump packet header, followed by
// the actual RTP or RTCP packet.
+enum RtpDumpPacketFilter {
+ PF_NONE = 0x0,
+ PF_RTPHEADER = 0x1,
+ PF_RTPPACKET = 0x3, // includes header
+ // PF_RTCPHEADER = 0x4, // TODO
+ PF_RTCPPACKET = 0xC, // includes header
+ PF_ALL = 0xF
+};
+
struct RtpDumpFileHeader {
RtpDumpFileHeader(uint32 start_ms, uint32 s, uint16 p);
void WriteToByteBuffer(talk_base::ByteBuffer* buf);
@@ -79,6 +88,7 @@
bool GetRtpSeqNum(int* seq_num) const;
bool GetRtpTimestamp(uint32* ts) const;
bool GetRtpSsrc(uint32* ssrc) const;
+ bool GetRtpHeaderLen(size_t* len) const;
// Get the type of the RTCP packet. Return true and set the output parameter
// if successful.
bool GetRtcpType(int* type) const;
@@ -170,6 +180,11 @@
public:
explicit RtpDumpWriter(talk_base::StreamInterface* stream);
+ // Filter to control what packets we actually record.
+ void set_packet_filter(int filter) {
+ packet_filter_ = filter;
+ }
+
// Write a RTP or RTCP packet. The parameters data points to the packet and
// data_len is its length.
talk_base::StreamResult WriteRtpPacket(const void* data, size_t data_len) {
@@ -196,8 +211,10 @@
private:
talk_base::StreamResult WritePacket(const void* data, size_t data_len,
uint32 elapsed, bool rtcp);
+ size_t FilterPacket(const void* data, size_t data_len, bool rtcp);
talk_base::StreamInterface* stream_;
+ int packet_filter_;
bool file_header_written_;
uint32 start_time_ms_; // Time when the record starts.
DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter);
diff --git a/talk/session/phone/rtputils.cc b/talk/session/phone/rtputils.cc
index 5e32c8b..e37c390 100644
--- a/talk/session/phone/rtputils.cc
+++ b/talk/session/phone/rtputils.cc
@@ -54,6 +54,23 @@
return true;
}
+bool GetRtpHeaderLen(const void* data, size_t len, size_t* value) {
+ if (!data || len < kMinRtpPacketLen || !value) return false;
+ const uint8* header = static_cast<const uint8*>(data);
+ // Get base header size + length of CSRCs (not counting extension yet).
+ size_t header_size = kMinRtpPacketLen + (header[0] & 0xF) * sizeof(uint32);
+ if (len < header_size) return false;
+ // If there's an extension, read and add in the extension size.
+ if (header[0] & 0x10) {
+ if (len < header_size + sizeof(uint32)) return false;
+ header_size += ((talk_base::GetBE16(header + header_size + 2) + 1) *
+ sizeof(uint32));
+ if (len < header_size) return false;
+ }
+ *value = header_size;
+ return true;
+}
+
bool GetRtcpType(const void* data, size_t len, int* value) {
if (!data || len < kMinRtcpPacketLen || !value) return false;
*value = static_cast<int>(*(static_cast<const uint8*>(data) + 1));
diff --git a/talk/session/phone/rtputils.h b/talk/session/phone/rtputils.h
index 1ac3214..69daa83 100644
--- a/talk/session/phone/rtputils.h
+++ b/talk/session/phone/rtputils.h
@@ -40,6 +40,7 @@
bool GetRtpSeqNum(const void* data, size_t len, int* value);
bool GetRtpTimestamp(const void* data, size_t len, uint32* value);
bool GetRtpSsrc(const void* data, size_t len, uint32* value);
+bool GetRtpHeaderLen(const void* data, size_t len, size_t* value);
bool GetRtcpType(const void* data, size_t len, int* value);
} // namespace cricket
diff --git a/talk/session/phone/srtpfilter.cc b/talk/session/phone/srtpfilter.cc
index fe91e5c..10ccfea 100644
--- a/talk/session/phone/srtpfilter.cc
+++ b/talk/session/phone/srtpfilter.cc
@@ -172,9 +172,9 @@
return recv_session_->UnprotectRtcp(p, in_len, out_len);
}
-void SrtpFilter::set_signal_silent_time(int signal_silent_time) {
- send_session_->set_signal_silent_time(signal_silent_time);
- recv_session_->set_signal_silent_time(signal_silent_time);
+void SrtpFilter::set_signal_silent_time(uint32 signal_silent_time_in_ms) {
+ send_session_->set_signal_silent_time(signal_silent_time_in_ms);
+ recv_session_->set_signal_silent_time(signal_silent_time_in_ms);
}
bool SrtpFilter::StoreParams(const std::vector<CryptoParams>& params,
@@ -386,8 +386,8 @@
return true;
}
-void SrtpSession::set_signal_silent_time(int signal_silent_time) {
- srtp_stat_->set_signal_silent_time(signal_silent_time);
+void SrtpSession::set_signal_silent_time(uint32 signal_silent_time_in_ms) {
+ srtp_stat_->set_signal_silent_time(signal_silent_time_in_ms);
}
bool SrtpSession::SetKey(int type, const std::string& cs,
@@ -531,7 +531,7 @@
return SrtpNotAvailable(__FUNCTION__);
}
-void SrtpSession::set_signal_silent_time(int signal_silent_time) {
+void SrtpSession::set_signal_silent_time(uint32 signal_silent_time) {
// Do nothing.
}
@@ -585,39 +585,11 @@
}
void SrtpStat::AddProtectRtcpResult(int result) {
- FailureKey key;
- key.mode = SrtpFilter::PROTECT;
- switch (result) {
- case err_status_ok:
- key.error = SrtpFilter::ERROR_NONE;
- break;
- case err_status_auth_fail:
- key.error = SrtpFilter::ERROR_AUTH;
- break;
- default:
- key.error = SrtpFilter::ERROR_FAIL;
- }
- HandleSrtpResult(key);
+ AddProtectRtpResult(0U, result);
}
void SrtpStat::AddUnprotectRtcpResult(int result) {
- FailureKey key;
- key.mode = SrtpFilter::UNPROTECT;
- switch (result) {
- case err_status_ok:
- key.error = SrtpFilter::ERROR_NONE;
- break;
- case err_status_auth_fail:
- key.error = SrtpFilter::ERROR_AUTH;
- break;
- case err_status_replay_fail:
- case err_status_replay_old:
- key.error = SrtpFilter::ERROR_REPLAY;
- break;
- default:
- key.error = SrtpFilter::ERROR_FAIL;
- }
- HandleSrtpResult(key);
+ AddUnprotectRtpResult(0U, result);
}
void SrtpStat::HandleSrtpResult(const SrtpStat::FailureKey& key) {
@@ -630,7 +602,7 @@
uint32 current_time = talk_base::Time();
if (stat->last_signal_time == 0 ||
talk_base::TimeDiff(current_time, stat->last_signal_time) >
- signal_silent_time_) {
+ static_cast<int>(signal_silent_time_)) {
SignalSrtpError(key.ssrc, key.mode, key.error);
stat->last_signal_time = current_time;
}
diff --git a/talk/session/phone/srtpfilter.h b/talk/session/phone/srtpfilter.h
index 9cae3c3..c59ee59 100644
--- a/talk/session/phone/srtpfilter.h
+++ b/talk/session/phone/srtpfilter.h
@@ -107,8 +107,8 @@
bool UnprotectRtp(void* data, int in_len, int* out_len);
bool UnprotectRtcp(void* data, int in_len, int* out_len);
- // Update the silent threshold for signaling errors.
- void set_signal_silent_time(int signal_silent_time);
+ // Update the silent threshold (in ms) for signaling errors.
+ void set_signal_silent_time(uint32 signal_silent_time_in_ms);
sigslot::repeater3<uint32, Mode, Error> SignalSrtpError;
@@ -152,8 +152,8 @@
bool UnprotectRtp(void* data, int in_len, int* out_len);
bool UnprotectRtcp(void* data, int in_len, int* out_len);
- // Update the silent threshold for signaling errors.
- void set_signal_silent_time(int signal_silent_time);
+ // Update the silent threshold (in ms) for signaling errors.
+ void set_signal_silent_time(uint32 signal_silent_time_in_ms);
sigslot::repeater3<uint32, SrtpFilter::Mode, SrtpFilter::Error>
SignalSrtpError;
@@ -171,21 +171,31 @@
static bool inited_;
static std::list<SrtpSession*> sessions_;
int last_send_seq_num_;
+ DISALLOW_COPY_AND_ASSIGN(SrtpSession);
};
// Class that collects failures of SRTP.
class SrtpStat {
public:
SrtpStat();
+
+ // Report RTP protection results to the handler.
void AddProtectRtpResult(uint32 ssrc, int result);
+ // Report RTP unprotection results to the handler.
void AddUnprotectRtpResult(uint32 ssrc, int result);
+ // Report RTCP protection results to the handler.
void AddProtectRtcpResult(int result);
+ // Report RTCP unprotection results to the handler.
void AddUnprotectRtcpResult(int result);
+
+ // Get silent time (in ms) for SRTP statistics handler.
uint32 signal_silent_time() const { return signal_silent_time_; }
+ // Set silent time (in ms) for SRTP statistics handler.
void set_signal_silent_time(uint32 signal_silent_time) {
signal_silent_time_ = signal_silent_time;
}
+ // Sigslot for reporting errors.
sigslot::signal3<uint32, SrtpFilter::Mode, SrtpFilter::Error>
SignalSrtpError;
@@ -226,13 +236,14 @@
uint32 last_signal_time;
};
+ // Inspect SRTP result and signal error if needed.
void HandleSrtpResult(const FailureKey& key);
std::map<FailureKey, FailureStat> failures_;
// Threshold in ms to silent the signaling errors.
- int signal_silent_time_;
+ uint32 signal_silent_time_;
- DISALLOW_EVIL_CONSTRUCTORS(SrtpStat);
+ DISALLOW_COPY_AND_ASSIGN(SrtpStat);
};
} // namespace cricket
diff --git a/talk/xmpp/constants.cc b/talk/xmpp/constants.cc
index 647658a..2d108ac 100644
--- a/talk/xmpp/constants.cc
+++ b/talk/xmpp/constants.cc
@@ -290,9 +290,9 @@
const QName QN_VCARD_AVATAR_HASH(true, NS_AVATAR_HASH, "hash");
const QName QN_VCARD_AVATAR_HASH_MODIFIED(true, NS_AVATAR_HASH, "modified");
-const buzz::QName QN_NAME(true, STR_EMPTY, "name");
-const buzz::QName QN_AFFILIATION(true, STR_EMPTY, "affiliation");
-const buzz::QName QN_ROLE(true, STR_EMPTY, "role");
+const QName QN_NAME(true, STR_EMPTY, "name");
+const QName QN_AFFILIATION(true, STR_EMPTY, "affiliation");
+const QName QN_ROLE(true, STR_EMPTY, "role");
#if defined(FEATURE_ENABLE_PSTN)
const QName QN_VCARD_TEL(true, NS_VCARD, "TEL");
@@ -324,6 +324,7 @@
const QName QN_TITLE1(true, STR_EMPTY, "title1");
const QName QN_TITLE2(true, STR_EMPTY, "title2");
const QName QN_SOURCE(true, STR_EMPTY, "source");
+const QName QN_TIME(true, STR_EMPTY, "time");
const QName QN_XMLNS_CLIENT(true, NS_XMLNS, STR_CLIENT);
const QName QN_XMLNS_SERVER(true, NS_XMLNS, STR_SERVER);
@@ -419,8 +420,8 @@
const QName kQnVCardPhoto(true, kNSVCard, "photo");
// JEP 0172 User Nickname
-const std::string kNSNickname("http://jabber.org/protocol/nick");
-const QName kQnNickname(true, kNSNickname, "nick");
+const std::string NS_NICKNAME("http://jabber.org/protocol/nick");
+const QName QN_NICKNAME(true, NS_NICKNAME, "nick");
// JEP 0085 chat state
diff --git a/talk/xmpp/constants.h b/talk/xmpp/constants.h
index ae3abe4..07e8554 100644
--- a/talk/xmpp/constants.h
+++ b/talk/xmpp/constants.h
@@ -289,6 +289,7 @@
extern const QName QN_TITLE2;
extern const QName QN_AFFILIATION;
extern const QName QN_ROLE;
+extern const QName QN_TIME;
extern const QName QN_XMLNS_CLIENT;
@@ -386,8 +387,8 @@
extern const QName kQnVCardPhoto;
// JEP 0172 User Nickname
-extern const std::string kNSNickname;
-extern const QName kQnNickname;
+extern const std::string NS_NICKNAME;
+extern const QName QN_NICKNAME;
// JEP 0085 chat state
diff --git a/talk/xmpp/xmpptask.h b/talk/xmpp/xmpptask.h
index a821d3c..86fbe27 100644
--- a/talk/xmpp/xmpptask.h
+++ b/talk/xmpp/xmpptask.h
@@ -93,7 +93,6 @@
virtual void Stop();
virtual bool HandleStanza(const XmlElement* stanza) { return false; }
virtual void OnDisconnect();
- virtual int ProcessReponse() { return STATE_DONE; }
virtual void QueueStanza(const XmlElement* stanza);
const XmlElement* NextStanza();