New snapshot with the latest fixes.
git-svn-id: http://libjingle.googlecode.com/svn/trunk@78 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/talk/base/base64.cc b/talk/base/base64.cc
index 363c378..0c9ee73 100644
--- a/talk/base/base64.cc
+++ b/talk/base/base64.cc
@@ -27,10 +27,10 @@
static const unsigned char sp = 0xFE; // Whitespace
static const unsigned char il = 0xFF; // Illegal base64 character
-const string Base64::Base64Table(
+const char Base64::Base64Table[] =
// 0000000000111111111122222222223333333333444444444455555555556666
// 0123456789012345678901234567890123456789012345678901234567890123
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// Decode Table gives the index of any valid base64 character in the
// Base64 table
diff --git a/talk/base/base64.h b/talk/base/base64.h
index 73904dc..2e37bc3 100644
--- a/talk/base/base64.h
+++ b/talk/base/base64.h
@@ -79,7 +79,7 @@
}
private:
- static const std::string Base64Table;
+ static const char Base64Table[];
static const unsigned char DecodeTable[];
static size_t GetNextQuantum(DecodeFlags parse_flags, bool illegal_pads,
diff --git a/talk/base/bytebuffer.cc b/talk/base/bytebuffer.cc
index 036b34c..12c8bc0 100644
--- a/talk/base/bytebuffer.cc
+++ b/talk/base/bytebuffer.cc
@@ -213,20 +213,22 @@
bytes_ = new_bytes;
}
-void ByteBuffer::Consume(size_t size) {
+bool ByteBuffer::Consume(size_t size) {
if (size > Length())
- return;
+ return false;
start_ += size;
+ return true;
}
-void ByteBuffer::Shift(size_t size) {
+bool ByteBuffer::Shift(size_t size) {
if (size > Length())
- return;
+ return false;
end_ = Length() - size;
memmove(bytes_, bytes_ + start_ + size, end_);
start_ = 0;
+ return true;
}
} // namespace talk_base
diff --git a/talk/base/bytebuffer.h b/talk/base/bytebuffer.h
index f5d2640..1a494cb 100644
--- a/talk/base/bytebuffer.h
+++ b/talk/base/bytebuffer.h
@@ -39,29 +39,40 @@
public:
enum ByteOrder {
- ORDER_NETWORK = 0, // Default, use network byte order (big endian)
- ORDER_HOST, // Use the native order of the host
+ ORDER_NETWORK = 0, // Default, use network byte order (big endian).
+ ORDER_HOST, // Use the native order of the host.
};
+ // |byte_order| defines order of bytes in the buffer.
ByteBuffer();
- ByteBuffer(ByteOrder byte_order); // convert to/from network format
+ explicit ByteBuffer(ByteOrder byte_order);
ByteBuffer(const char* bytes, size_t len);
ByteBuffer(const char* bytes, size_t len, ByteOrder byte_order);
- explicit ByteBuffer(const char* bytes); // uses strlen
+
+ // Initializes buffer from a zero-terminated string.
+ explicit ByteBuffer(const char* bytes);
+
~ByteBuffer();
const char* Data() const { return bytes_ + start_; }
size_t Length() const { return end_ - start_; }
size_t Capacity() const { return size_ - start_; }
+ // Read a next value from the buffer. Return false if there isn't
+ // enough data left for the specified type.
bool ReadUInt8(uint8* val);
bool ReadUInt16(uint16* val);
bool ReadUInt24(uint32* val);
bool ReadUInt32(uint32* val);
bool ReadUInt64(uint64* val);
- bool ReadString(std::string* val, size_t len); // append to val
bool ReadBytes(char* val, size_t len);
+ // Appends next |len| bytes from the buffer to |val|. Returns false
+ // if there is less than |len| bytes left.
+ bool ReadString(std::string* val, size_t len);
+
+ // Write value to the buffer. Resizes the buffer when it is
+ // neccessary.
void WriteUInt8(uint8 val);
void WriteUInt16(uint16 val);
void WriteUInt24(uint32 val);
@@ -70,9 +81,16 @@
void WriteString(const std::string& val);
void WriteBytes(const char* val, size_t len);
+ // Resize the buffer to the specified |size|.
void Resize(size_t size);
- void Consume(size_t size);
- void Shift(size_t size);
+
+ // Moves current position |size| bytes forward. Return false if
+ // there is less than |size| bytes left in the buffer.
+ bool Consume(size_t size);
+
+ // Drops |size| bytes from the front of the buffer. Return false if
+ // there is less than |size| bytes left in the buffer.
+ bool Shift(size_t size);
private:
void Construct(const char* bytes, size_t size, ByteOrder byte_order);
diff --git a/talk/base/criticalsection.h b/talk/base/criticalsection.h
index 07cf5b2..fd0f06c 100644
--- a/talk/base/criticalsection.h
+++ b/talk/base/criticalsection.h
@@ -132,6 +132,15 @@
// compile rules.
class AtomicOps {
public:
+#ifdef WIN32
+ // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
+ static int Increment(int* i) {
+ return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
+ }
+ static int Decrement(int* i) {
+ return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
+ }
+#else
static int Increment(int* i) {
// Could be faster, and less readable:
// static CriticalSection* crit = StaticCrit();
@@ -153,6 +162,7 @@
static CriticalSection* crit = new CriticalSection();
return crit;
}
+#endif
};
} // namespace talk_base
diff --git a/talk/base/helpers.cc b/talk/base/helpers.cc
index e2dabde..5b0e447 100644
--- a/talk/base/helpers.cc
+++ b/talk/base/helpers.cc
@@ -27,6 +27,8 @@
#include "talk/base/helpers.h"
+#include <limits>
+
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@@ -42,6 +44,9 @@
#include "talk/base/scoped_ptr.h"
#include "talk/base/time.h"
+// Protect against max macro inclusion.
+#undef max
+
namespace talk_base {
// Base class for RNG implementations.
@@ -196,13 +201,26 @@
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
-static scoped_ptr<RandomGenerator> g_rng(new SecureRandomGenerator());
+namespace {
+
+// This round about way of creating a global RNG is to safe-guard against
+// indeterminant static initialization order.
+scoped_ptr<RandomGenerator>& GetGlobalRng() {
+ static scoped_ptr<RandomGenerator> g_rng(new SecureRandomGenerator());
+ return g_rng;
+}
+
+RandomGenerator& Rng() {
+ return *GetGlobalRng();
+}
+
+} // namespace
void SetRandomTestMode(bool test) {
if (!test) {
- g_rng.reset(new SecureRandomGenerator());
+ GetGlobalRng().reset(new SecureRandomGenerator());
} else {
- g_rng.reset(new TestRandomGenerator());
+ GetGlobalRng().reset(new TestRandomGenerator());
}
}
@@ -211,7 +229,7 @@
}
bool InitRandom(const char* seed, size_t len) {
- if (!g_rng->Init(seed, len)) {
+ if (!Rng().Init(seed, len)) {
LOG(LS_ERROR) << "Failed to init random generator!";
return false;
}
@@ -229,7 +247,7 @@
std::string* str) {
str->clear();
scoped_array<uint8> bytes(new uint8[len]);
- if (!g_rng->Generate(bytes.get(), len)) {
+ if (!Rng().Generate(bytes.get(), len)) {
LOG(LS_ERROR) << "Failed to generate random string!";
return false;
}
@@ -251,7 +269,7 @@
uint32 CreateRandomId() {
uint32 id;
- if (!g_rng->Generate(&id, sizeof(id))) {
+ if (!Rng().Generate(&id, sizeof(id))) {
LOG(LS_ERROR) << "Failed to generate random id!";
}
return id;
@@ -265,4 +283,9 @@
return id;
}
+double CreateRandomDouble() {
+ return CreateRandomId() / (std::numeric_limits<uint32>::max() +
+ std::numeric_limits<double>::epsilon());
+}
+
} // namespace talk_base
diff --git a/talk/base/helpers.h b/talk/base/helpers.h
index 74867c0..3e3eea7 100644
--- a/talk/base/helpers.h
+++ b/talk/base/helpers.h
@@ -62,6 +62,9 @@
// Generates a random id > 0.
uint32 CreateRandomNonZeroId();
+// Generates a random double between 0.0 (inclusive) and 1.0 (exclusive).
+double CreateRandomDouble();
+
} // namespace talk_base
#endif // TALK_BASE_HELPERS_H_
diff --git a/talk/base/json.cc b/talk/base/json.cc
index 1c84b26..721fb94 100644
--- a/talk/base/json.cc
+++ b/talk/base/json.cc
@@ -115,6 +115,25 @@
return ret;
}
+bool GetDoubleFromJson(const Json::Value& in, double* out) {
+ bool ret;
+ if (!in.isString()) {
+ ret = in.isConvertibleTo(Json::realValue);
+ if (ret) {
+ *out = in.asDouble();
+ }
+ } else {
+ double val;
+ const char* c_str = in.asCString();
+ char* end_ptr;
+ errno = 0;
+ val = strtod(c_str, &end_ptr);
+ ret = (end_ptr != c_str && *end_ptr == '\0' && !errno);
+ *out = val;
+ }
+ return ret;
+}
+
bool GetValueFromJsonArray(const Json::Value& in, size_t n,
Json::Value* out) {
if (!in.isArray() || !in.isValidIndex(n)) {
@@ -149,6 +168,12 @@
return GetValueFromJsonArray(in, n, &x) && GetBoolFromJson(x, out);
}
+bool GetDoubleFromJsonArray(const Json::Value& in, size_t n,
+ double* out) {
+ Json::Value x;
+ return GetValueFromJsonArray(in, n, &x) && GetDoubleFromJson(x, out);
+}
+
bool GetValueFromJsonObject(const Json::Value& in, const std::string& k,
Json::Value* out) {
if (!in.isObject() || !in.isMember(k)) {
@@ -159,7 +184,6 @@
return true;
}
-
bool GetIntFromJsonObject(const Json::Value& in, const std::string& k,
int* out) {
Json::Value x;
@@ -184,6 +208,12 @@
return GetValueFromJsonObject(in, k, &x) && GetBoolFromJson(x, out);
}
+bool GetDoubleFromJsonObject(const Json::Value& in, const std::string& k,
+ double* out) {
+ Json::Value x;
+ return GetValueFromJsonObject(in, k, &x) && GetDoubleFromJson(x, out);
+}
+
Json::Value StringVectorToJsonValue(const std::vector<std::string>& strings) {
Json::Value result(Json::arrayValue);
for (size_t i = 0; i < strings.size(); ++i) {
diff --git a/talk/base/json.h b/talk/base/json.h
index 73d0f69..5685503 100644
--- a/talk/base/json.h
+++ b/talk/base/json.h
@@ -44,6 +44,7 @@
bool GetUIntFromJson(const Json::Value& in, unsigned int* out);
bool GetStringFromJson(const Json::Value& in, std::string* out);
bool GetBoolFromJson(const Json::Value& in, bool* out);
+bool GetDoubleFromJson(const Json::Value& in, double* out);
// Pull values out of a JSON array.
bool GetValueFromJsonArray(const Json::Value& in, size_t n,
@@ -56,6 +57,8 @@
std::string* out);
bool GetBoolFromJsonArray(const Json::Value& in, size_t n,
bool* out);
+bool GetDoubleFromJsonArray(const Json::Value& in, size_t n,
+ double* out);
// Pull values out of a JSON object.
bool GetValueFromJsonObject(const Json::Value& in, const std::string& k,
@@ -68,6 +71,8 @@
std::string* out);
bool GetBoolFromJsonObject(const Json::Value& in, const std::string& k,
bool* out);
+bool GetDoubleFromJsonObject(const Json::Value& in, const std::string& k,
+ double* out);
// Converts vectors of strings to/from JSON arrays.
Json::Value StringVectorToJsonValue(const std::vector<std::string>& strings);
diff --git a/talk/base/md5c.c b/talk/base/md5c.c
index eb2c034..ef9f862 100644
--- a/talk/base/md5c.c
+++ b/talk/base/md5c.c
@@ -148,7 +148,7 @@
MD5Transform(ctx->buf, (uint32 *)ctx->in);
byteReverse((unsigned char *)ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
- memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
#ifndef ASM_MD5
diff --git a/talk/base/pathutils.cc b/talk/base/pathutils.cc
index d56373b..02aba7f 100644
--- a/talk/base/pathutils.cc
+++ b/talk/base/pathutils.cc
@@ -41,7 +41,7 @@
namespace talk_base {
-std::string const EMPTY_STR = "";
+static const char EMPTY_STR[] = "";
// EXT_DELIM separates a file basename from extension
const char EXT_DELIM = '.';
@@ -224,7 +224,7 @@
extension_.insert(extension_.begin(), EXT_DELIM);
}
return true;
-}
+}
std::string Pathname::filename() const {
std::string filename(basename_);
@@ -246,16 +246,16 @@
return GetDrive(drive, bytes, folder_);
}
-// static
+// static
bool Pathname::GetDrive(char *drive, uint32 bytes,
const std::string& pathname) {
// need at lease 4 bytes to save c:
if (bytes < 4 || pathname.size() < 3) {
return false;
}
-
+
memcpy(drive, pathname.c_str(), 3);
- drive[3] = 0;
+ drive[3] = 0;
// sanity checking
return (isalpha(drive[0]) &&
drive[1] == ':' &&
diff --git a/talk/base/stringutils.cc b/talk/base/stringutils.cc
index 8d8b7e0..c4c2b2f 100644
--- a/talk/base/stringutils.cc
+++ b/talk/base/stringutils.cc
@@ -119,17 +119,22 @@
}
bool starts_with(const char *s1, const char *s2) {
- while (*s2 != '\0') {
- if (*s1 != *s2) {
- return false;
- }
- s1++;
- s2++;
- }
- return true;
+ return strncmp(s1, s2, strlen(s2)) == 0;
}
-static const std::string kWhitespace(" \n\r\t");
+bool ends_with(const char *s1, const char *s2) {
+ size_t s1_length = strlen(s1);
+ size_t s2_length = strlen(s2);
+
+ if (s2_length > s1_length) {
+ return false;
+ }
+
+ const char* start = s1 + (s1_length - s2_length);
+ return strncmp(start, s2, s2_length) == 0;
+}
+
+static const char kWhitespace[] = " \n\r\t";
std::string string_trim(const std::string& s) {
std::string::size_type first = s.find_first_not_of(kWhitespace);
diff --git a/talk/base/stringutils.h b/talk/base/stringutils.h
index 6aa9b18..661a343 100644
--- a/talk/base/stringutils.h
+++ b/talk/base/stringutils.h
@@ -332,6 +332,9 @@
// True iff s1 starts with s2.
bool starts_with(const char *s1, const char *s2);
+// True iff s1 ends with s2.
+bool ends_with(const char *s1, const char *s2);
+
// Remove leading and trailing whitespaces.
std::string string_trim(const std::string& s);
diff --git a/talk/base/taskparent.h b/talk/base/taskparent.h
index a6c5795..e2093d6 100644
--- a/talk/base/taskparent.h
+++ b/talk/base/taskparent.h
@@ -47,16 +47,6 @@
TaskParent *GetParent() { return parent_; }
TaskRunner *GetRunner() { return runner_; }
- // Retrieves a parent that corresponds to the given "code". The code
- // should be defined in a unique manner for the given subtree. This
- // method will crash (when the parent_ is NULL) if there is no corresponding
- // parent.
- //
- // Example use:
- // XmppClient* client =
- // static_cast<XmppClient*>(parent->GetParent(XMPP_CLIENT_TASK_CODE));
- virtual TaskParent *GetParent(int code) { return parent_->GetParent(code); }
-
bool AllChildrenDone();
bool AnyChildError();
#ifdef _DEBUG
diff --git a/talk/base/thread.cc b/talk/base/thread.cc
index 1603ef6..5e0eec4 100644
--- a/talk/base/thread.cc
+++ b/talk/base/thread.cc
@@ -109,20 +109,8 @@
Thread* result = CurrentThread();
if (NULL == result) {
result = new Thread();
-#if defined(WIN32)
- // We explicitly ask for no rights other than synchronization.
- // This gives us the best chance of succeeding.
- result->thread_ = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId());
- if (!result->thread_)
- LOG_GLE(LS_ERROR) << "Unable to get handle to thread.";
-#elif defined(POSIX)
- result->thread_ = pthread_self();
-#endif
- result->owned_ = false;
- result->started_ = true;
- SetCurrent(result);
+ result->WrapCurrent();
}
-
return result;
}
@@ -130,14 +118,7 @@
void ThreadManager::UnwrapCurrentThread() {
Thread* t = CurrentThread();
if (t && !(t->IsOwned())) {
- // Clears the platform-specific thread-specific storage.
- SetCurrent(NULL);
-#ifdef WIN32
- if (!CloseHandle(t->thread_)) {
- LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle.";
- }
-#endif
- t->started_ = false;
+ t->UnwrapCurrent();
delete t;
}
}
@@ -527,6 +508,38 @@
}
}
+bool Thread::WrapCurrent() {
+ if (started_)
+ return false;
+#if defined(WIN32)
+ // We explicitly ask for no rights other than synchronization.
+ // This gives us the best chance of succeeding.
+ thread_ = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId());
+ if (!thread_) {
+ LOG_GLE(LS_ERROR) << "Unable to get handle to thread.";
+ return false;
+ }
+#elif defined(POSIX)
+ thread_ = pthread_self();
+#endif
+ owned_ = false;
+ started_ = true;
+ ThreadManager::SetCurrent(this);
+ return true;
+}
+
+void Thread::UnwrapCurrent() {
+ // Clears the platform-specific thread-specific storage.
+ ThreadManager::SetCurrent(NULL);
+#ifdef WIN32
+ if (!CloseHandle(thread_)) {
+ LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle.";
+ }
+#endif
+ started_ = false;
+}
+
+
AutoThread::AutoThread(SocketServer* ss) : Thread(ss) {
if (!ThreadManager::CurrentThread()) {
ThreadManager::SetCurrent(this);
diff --git a/talk/base/thread.h b/talk/base/thread.h
index 50d8eeb..04ceeef 100644
--- a/talk/base/thread.h
+++ b/talk/base/thread.h
@@ -199,6 +199,15 @@
}
#endif
+ // This method should be called when thread is created using non standard
+ // method, like derived implementation of talk_base::Thread and it can not be
+ // started by calling Start(). This will set started flag to true and
+ // owned to false. This must be called from the current thread.
+ // NOTE: These methods should be used by the derived classes only, added here
+ // only for testing.
+ bool WrapCurrent();
+ void UnwrapCurrent();
+
protected:
// Blocks the calling thread until this thread has terminated.
void Join();
diff --git a/talk/examples/call/call_main.cc b/talk/examples/call/call_main.cc
index f8d66bc..5af5474 100644
--- a/talk/examples/call/call_main.cc
+++ b/talk/examples/call/call_main.cc
@@ -27,6 +27,7 @@
#include <time.h>
#include <iomanip>
+#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
@@ -177,10 +178,10 @@
static const int DEFAULT_PORT = 5222;
-cricket::MediaEngine* CreateFileMediaEngine(const char* voice_in,
- const char* voice_out,
- const char* video_in,
- const char* video_out) {
+cricket::MediaEngineInterface* CreateFileMediaEngine(const char* voice_in,
+ const char* voice_out,
+ const char* video_in,
+ const char* video_out) {
cricket::FileMediaEngine* file_media_engine = new cricket::FileMediaEngine;
// Set the RTP dump file names.
if (voice_in) {
@@ -250,6 +251,7 @@
DEFINE_string(videoinput, NULL, "RTP dump file for video input.");
DEFINE_string(yuvvideoinput, NULL, "YUV file for video input.");
DEFINE_string(videooutput, NULL, "RTP dump file for video output.");
+ DEFINE_bool(render, true, "Renders the video.");
DEFINE_bool(debugsrtp, false, "Enable debugging for srtp.");
DEFINE_bool(help, false, "Prints this message");
@@ -270,6 +272,7 @@
std::string server = FLAG_s;
std::string secure = FLAG_secure;
bool debugsrtp = FLAG_debugsrtp;
+ bool render = FLAG_render;
if (debugsrtp) {
cricket::EnableSrtpDebugging();
@@ -384,10 +387,8 @@
if (FLAG_voiceinput || FLAG_voiceoutput ||
FLAG_videoinput || FLAG_videooutput) {
// If any dump file is specified, we use FileMediaEngine.
- cricket::MediaEngine* engine = CreateFileMediaEngine(FLAG_voiceinput,
- FLAG_voiceoutput,
- FLAG_videoinput,
- FLAG_videooutput);
+ cricket::MediaEngineInterface* engine = CreateFileMediaEngine(
+ FLAG_voiceinput, FLAG_voiceoutput, FLAG_videoinput, FLAG_videooutput);
// The engine will be released by the client later.
client->SetMediaEngine(engine);
}
@@ -399,6 +400,7 @@
client->SetAllowLocalIps(true);
client->SetInitialProtocol(initial_protocol);
client->SetSecurePolicy(secure_policy);
+ client->SetRender(render);
console->Start();
if (debug) {
diff --git a/talk/examples/call/callclient.cc b/talk/examples/call/callclient.cc
index 943ccb5..8b9a834 100644
--- a/talk/examples/call/callclient.cc
+++ b/talk/examples/call/callclient.cc
@@ -48,6 +48,7 @@
#include "talk/p2p/client/basicportallocator.h"
#include "talk/p2p/client/sessionmanagertask.h"
#include "talk/session/phone/devicemanager.h"
+#include "talk/session/phone/mediacommon.h"
#include "talk/session/phone/mediaengine.h"
#include "talk/session/phone/mediamessages.h"
#include "talk/session/phone/mediasessionclient.h"
@@ -225,12 +226,14 @@
CallClient::CallClient(buzz::XmppClient* xmpp_client)
: xmpp_client_(xmpp_client),
+ worker_thread_(NULL),
media_engine_(NULL),
media_client_(NULL),
call_(NULL),
incoming_call_(false),
auto_accept_(false),
pmuc_domain_("groupchat.google.com"),
+ render_(true),
local_renderer_(NULL),
remote_renderer_(NULL),
static_views_accumulated_count_(0),
@@ -245,6 +248,7 @@
CallClient::~CallClient() {
delete media_client_;
delete roster_;
+ delete worker_thread_;
}
const std::string CallClient::strerror(buzz::XmppEngine::Error err) {
@@ -354,7 +358,7 @@
session_manager_task_->Start();
if (!media_engine_) {
- media_engine_ = cricket::MediaEngine::Create();
+ media_engine_ = cricket::MediaEngineFactory::Create();
}
media_client_ = new cricket::MediaSessionClient(
@@ -385,15 +389,15 @@
}
void CallClient::OnSessionState(cricket::Call* call,
- cricket::BaseSession* session,
- cricket::BaseSession::State state) {
+ cricket::Session* session,
+ cricket::Session::State state) {
if (state == cricket::Session::STATE_RECEIVEDINITIATE) {
buzz::Jid jid(session->remote_name());
console_->PrintLine("Incoming call from '%s'", jid.Str().c_str());
call_ = call;
session_ = session;
incoming_call_ = true;
- if (call->video()) {
+ if (call->video() && render_) {
local_renderer_ =
cricket::VideoRendererFactory::CreateGuiVideoRenderer(160, 100);
remote_renderer_ =
@@ -404,7 +408,7 @@
Accept(options);
}
} else if (state == cricket::Session::STATE_SENTINITIATE) {
- if (call->video()) {
+ if (call->video() && render_) {
local_renderer_ =
cricket::VideoRendererFactory::CreateGuiVideoRenderer(160, 100);
remote_renderer_ =
@@ -425,7 +429,7 @@
}
void CallClient::OnSpeakerChanged(cricket::Call* call,
- cricket::BaseSession* session,
+ cricket::Session* session,
const cricket::NamedSource& speaker) {
if (speaker.ssrc == 0) {
console_->PrintLine("Session %s has no current speaker.",
@@ -475,11 +479,11 @@
my_status_.set_know_capabilities(true);
my_status_.set_pmuc_capability(true);
my_status_.set_voice_capability(
- (media_caps & cricket::MediaEngine::AUDIO_RECV) != 0);
+ (media_caps & cricket::AUDIO_RECV) != 0);
my_status_.set_video_capability(
- (media_caps & cricket::MediaEngine::VIDEO_RECV) != 0);
+ (media_caps & cricket::VIDEO_RECV) != 0);
my_status_.set_camera_capability(
- (media_caps & cricket::MediaEngine::VIDEO_SEND) != 0);
+ (media_caps & cricket::VIDEO_SEND) != 0);
my_status_.set_is_google_client(true);
my_status_.set_version("1.0.0.67");
presence_out_->Send(my_status_);
@@ -604,7 +608,7 @@
session_ = call_->InitiateSession(jid, options);
}
media_client_->SetFocus(call_);
- if (call_->video()) {
+ if (call_->video() && render_) {
if (!options.is_muc) {
call_->SetLocalRenderer(local_renderer_);
call_->SetVideoRenderer(session_, 0, remote_renderer_);
@@ -642,7 +646,7 @@
ASSERT(call_->sessions().size() == 1);
call_->AcceptSession(call_->sessions()[0], options);
media_client_->SetFocus(call_);
- if (call_->video()) {
+ if (call_->video() && render_) {
call_->SetLocalRenderer(local_renderer_);
// The client never does an accept for multiway, so this must be 1:1,
// so there's no SSRC.
@@ -740,8 +744,11 @@
}
void CallClient::OnRoomLookupError(const buzz::XmlElement* stanza) {
- console_->PrintLine("Failed to look up the room_jid. %s",
- stanza->Str().c_str());
+ if (stanza == NULL) {
+ console_->PrintLine("Room lookup failed.");
+ } else {
+ console_->PrintLine("Room lookup error: ", stanza->Str().c_str());
+ }
}
void CallClient::OnMucInviteReceived(const buzz::Jid& inviter,
@@ -924,10 +931,12 @@
if (it->removed) {
RemoveStaticRenderedView(it->ssrc);
} else {
- // TODO: Make dimensions and positions more configurable.
- int offset = (50 * static_views_accumulated_count_) % 300;
- AddStaticRenderedView(session, it->ssrc, 640, 400, 30,
- offset, offset);
+ if (render_) {
+ // TODO: Make dimensions and positions more configurable.
+ int offset = (50 * static_views_accumulated_count_) % 300;
+ AddStaticRenderedView(session, it->ssrc, 640, 400, 30,
+ offset, offset);
+ }
}
}
diff --git a/talk/examples/call/callclient.h b/talk/examples/call/callclient.h
index 3af2b39..fb7878e 100644
--- a/talk/examples/call/callclient.h
+++ b/talk/examples/call/callclient.h
@@ -64,7 +64,7 @@
namespace cricket {
class PortAllocator;
-class MediaEngine;
+class MediaEngineInterface;
class MediaSessionClient;
class Receiver;
class Call;
@@ -98,7 +98,7 @@
~CallClient();
cricket::MediaSessionClient* media_client() const { return media_client_; }
- void SetMediaEngine(cricket::MediaEngine* media_engine) {
+ void SetMediaEngine(cricket::MediaEngineInterface* media_engine) {
media_engine_ = media_engine;
}
void SetAutoAccept(bool auto_accept) {
@@ -107,6 +107,9 @@
void SetPmucDomain(const std::string &pmuc_domain) {
pmuc_domain_ = pmuc_domain;
}
+ void SetRender(bool render) {
+ render_ = render;
+ }
void SetConsole(Console *console) {
console_ = console;
}
@@ -154,8 +157,8 @@
void OnCallCreate(cricket::Call* call);
void OnCallDestroy(cricket::Call* call);
void OnSessionState(cricket::Call* call,
- cricket::BaseSession* session,
- cricket::BaseSession::State state);
+ cricket::Session* session,
+ cricket::Session::State state);
void OnStatusUpdate(const buzz::Status& status);
void OnMucInviteReceived(const buzz::Jid& inviter, const buzz::Jid& room,
const std::vector<buzz::AvailableMediaEntry>& avail);
@@ -169,7 +172,7 @@
cricket::Session* session,
const cricket::MediaSources& sources);
void OnSpeakerChanged(cricket::Call* call,
- cricket::BaseSession* session,
+ cricket::Session* session,
const cricket::NamedSource& speaker_source);
void OnRoomLookupResponse(const buzz::MucRoomInfo& room_info);
void OnRoomLookupError(const buzz::XmlElement* stanza);
@@ -208,15 +211,16 @@
cricket::PortAllocator* port_allocator_;
cricket::SessionManager* session_manager_;
cricket::SessionManagerTask* session_manager_task_;
- cricket::MediaEngine* media_engine_;
+ cricket::MediaEngineInterface* media_engine_;
cricket::MediaSessionClient* media_client_;
MucMap mucs_;
cricket::Call* call_;
- cricket::BaseSession *session_;
+ cricket::Session *session_;
bool incoming_call_;
bool auto_accept_;
std::string pmuc_domain_;
+ bool render_;
cricket::VideoRenderer* local_renderer_;
cricket::VideoRenderer* remote_renderer_;
StaticRenderedViews static_rendered_views_;
diff --git a/talk/examples/call/discoitemsquerytask.cc b/talk/examples/call/discoitemsquerytask.cc
index df6d96d..6bbfb1d 100644
--- a/talk/examples/call/discoitemsquerytask.cc
+++ b/talk/examples/call/discoitemsquerytask.cc
@@ -36,8 +36,8 @@
const int kDiscoItemsTimeout = 60;
} // namespace
-DiscoItemsQueryTask::DiscoItemsQueryTask(Task* parent,
- const std::string node,
+DiscoItemsQueryTask::DiscoItemsQueryTask(XmppTaskParentInterface* parent,
+ const std::string& node,
const Jid& to)
: XmppTask(parent, XmppEngine::HL_SINGLE), node_(node) {
set_timeout_seconds(kDiscoItemsTimeout);
diff --git a/talk/examples/call/discoitemsquerytask.h b/talk/examples/call/discoitemsquerytask.h
index 6be8c35..27912bc 100644
--- a/talk/examples/call/discoitemsquerytask.h
+++ b/talk/examples/call/discoitemsquerytask.h
@@ -59,7 +59,8 @@
public:
// TODO: Currently, this only supports one query stanza - we may eventually
// need it to support multiple
- DiscoItemsQueryTask(Task* parent, const std::string node, const Jid& to);
+ DiscoItemsQueryTask(XmppTaskParentInterface* parent,
+ const std::string& node, const Jid& to);
virtual int ProcessStart();
virtual int ProcessResponse();
diff --git a/talk/examples/call/friendinvitesendtask.h b/talk/examples/call/friendinvitesendtask.h
index 3f776bb..625f077 100644
--- a/talk/examples/call/friendinvitesendtask.h
+++ b/talk/examples/call/friendinvitesendtask.h
@@ -35,7 +35,8 @@
class FriendInviteSendTask : public XmppTask {
public:
- FriendInviteSendTask(Task* parent) : XmppTask(parent) {}
+ explicit FriendInviteSendTask(XmppTaskParentInterface* parent)
+ : XmppTask(parent) {}
virtual ~FriendInviteSendTask() {}
XmppReturnStatus Send(const Jid& user);
diff --git a/talk/examples/call/mucinviterecvtask.h b/talk/examples/call/mucinviterecvtask.h
index 892b484..24f05e0 100644
--- a/talk/examples/call/mucinviterecvtask.h
+++ b/talk/examples/call/mucinviterecvtask.h
@@ -65,15 +65,16 @@
class MucInviteRecvTask : public XmppTask {
public:
- MucInviteRecvTask(Task* parent) : XmppTask(parent, XmppEngine::HL_TYPE) {}
+ explicit MucInviteRecvTask(XmppTaskParentInterface* parent)
+ : XmppTask(parent, XmppEngine::HL_TYPE) {}
virtual int ProcessStart();
-
+
// First arg is inviter's JID; second is MUC's JID.
sigslot::signal3<const Jid&, const Jid&, const std::vector<AvailableMediaEntry>& > SignalInviteReceived;
protected:
virtual bool HandleStanza(const XmlElement* stanza);
-
+
};
}
diff --git a/talk/examples/call/mucinvitesendtask.h b/talk/examples/call/mucinvitesendtask.h
index 8afd361..2429b31 100644
--- a/talk/examples/call/mucinvitesendtask.h
+++ b/talk/examples/call/mucinvitesendtask.h
@@ -36,7 +36,8 @@
class MucInviteSendTask : public XmppTask {
public:
- MucInviteSendTask(Task* parent) : XmppTask(parent) {}
+ explicit MucInviteSendTask(XmppTaskParentInterface* parent)
+ : XmppTask(parent) {}
virtual ~MucInviteSendTask() {}
XmppReturnStatus Send(const Jid& to, const Jid& invitee);
diff --git a/talk/examples/call/presenceouttask.h b/talk/examples/call/presenceouttask.h
index 36e7f15..5735ce2 100644
--- a/talk/examples/call/presenceouttask.h
+++ b/talk/examples/call/presenceouttask.h
@@ -36,7 +36,8 @@
class PresenceOutTask : public XmppTask {
public:
- PresenceOutTask(Task * parent) : XmppTask(parent) {}
+ explicit PresenceOutTask(XmppTaskParentInterface* parent)
+ : XmppTask(parent) {}
virtual ~PresenceOutTask() {}
XmppReturnStatus Send(const Status & s);
diff --git a/talk/examples/call/presencepushtask.h b/talk/examples/call/presencepushtask.h
index 998a98e..dccc827 100644
--- a/talk/examples/call/presencepushtask.h
+++ b/talk/examples/call/presencepushtask.h
@@ -40,7 +40,7 @@
class PresencePushTask : public XmppTask {
public:
- PresencePushTask(Task * parent, CallClient* client)
+ PresencePushTask(XmppTaskParentInterface* parent, CallClient* client)
: XmppTask(parent, XmppEngine::HL_TYPE),
client_(client) {}
virtual int ProcessStart();
diff --git a/talk/examples/call/voicemailjidrequester.cc b/talk/examples/call/voicemailjidrequester.cc
index 81f3dbc..7287700 100644
--- a/talk/examples/call/voicemailjidrequester.cc
+++ b/talk/examples/call/voicemailjidrequester.cc
@@ -25,20 +25,21 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "talk/base/scoped_ptr.h"
#include "talk/examples/call/discoitemsquerytask.h"
#include "talk/examples/call/voicemailjidrequester.h"
-#include "talk/base/scoped_ptr.h"
#include "talk/xmpp/constants.h"
+#include "talk/xmpp/xmpptask.h"
namespace buzz {
-VoicemailJidRequester::VoicemailJidRequester(talk_base::Task* parent,
+VoicemailJidRequester::VoicemailJidRequester(XmppTaskParentInterface* parent,
const Jid& their_jid,
- const Jid& my_jid) : Task(parent),
- their_jid_(their_jid),
- my_jid_(my_jid),
- done_with_query_(false) {
- parent_ = parent;
+ const Jid& my_jid) :
+ XmppTaskBase(parent),
+ their_jid_(their_jid),
+ my_jid_(my_jid),
+ done_with_query_(false) {
}
int VoicemailJidRequester::ProcessStart() {
diff --git a/talk/examples/call/voicemailjidrequester.h b/talk/examples/call/voicemailjidrequester.h
index 34b3c4b..686f763 100644
--- a/talk/examples/call/voicemailjidrequester.h
+++ b/talk/examples/call/voicemailjidrequester.h
@@ -73,9 +73,10 @@
class Task;
class VoicemailJidRequester : public sigslot::has_slots<>,
- public talk_base::Task {
+ public XmppTaskBase {
public:
- VoicemailJidRequester(talk_base::Task* parent, const Jid& their_jid, const Jid& my_jid);
+ VoicemailJidRequester(XmppTaskParentInterface* parent,
+ const Jid& their_jid, const Jid& my_jid);
// Provides the target jid and the voicemail to reach it
sigslot::signal2<const Jid&, const Jid&> SignalGotVoicemailJid;
@@ -110,8 +111,6 @@
// the first query fails.
void StartSecondQuery();
- talk_base::Task* parent_;
-
Jid their_jid_;
// Your own jid (not the other user's)
diff --git a/talk/examples/login/xmppthread.h b/talk/examples/login/xmppthread.h
index 247b7bd..bfed5e0 100644
--- a/talk/examples/login/xmppthread.h
+++ b/talk/examples/login/xmppthread.h
@@ -32,7 +32,6 @@
#include "talk/base/thread.h"
#include "talk/examples/login/xmpppump.h"
#include "talk/examples/login/xmppsocket.h"
-#include <iostream>
class XmppThread:
public talk_base::Thread, XmppPumpNotify, talk_base::MessageHandler {
diff --git a/talk/libjingle.scons b/talk/libjingle.scons
index 10b401a..03239d4 100644
--- a/talk/libjingle.scons
+++ b/talk/libjingle.scons
@@ -20,7 +20,7 @@
"HAVE_EXPAT_CONFIG_H",
],
)
-talk.Library(env, name = "libsrtp",
+talk.Library(env, name = "srtp",
srcs = [
"third_party/srtp/crypto/cipher/aes.c",
"third_party/srtp/crypto/cipher/aes_cbc.c",
@@ -54,7 +54,7 @@
"/wd4702",
],
)
-talk.Library(env, name = "libjingle",
+talk.Library(env, name = "jingle",
lin_srcs = [
"base/latebindingsymboltable.cc",
"base/linux.cc",
@@ -195,6 +195,7 @@
"session/phone/mediaengine.cc",
"session/phone/mediamessages.cc",
"session/phone/mediamonitor.cc",
+ "session/phone/mediasession.cc",
"session/phone/mediasessionclient.cc",
"session/phone/rtpdump.cc",
"session/phone/rtputils.cc",
@@ -243,9 +244,9 @@
"base/json.cc",
],
)
-talk.Library(env, name = "libxmpphelp",
+talk.Library(env, name = "xmpphelp",
libs = [
- "libjingle",
+ "jingle",
],
srcs = [
"examples/login/xmppauth.cc",
@@ -263,9 +264,9 @@
)
talk.App(env, name = "login",
libs = [
- "libjingle",
+ "jingle",
"expat",
- "libxmpphelp",
+ "xmpphelp",
],
srcs = [
"examples/login/xmppthread.cc",
@@ -320,15 +321,15 @@
"examples/call/voicemailjidrequester.cc",
],
libs = [
- "libjingle",
+ "jingle",
"expat",
- "libsrtp",
- "libxmpphelp",
+ "srtp",
+ "xmpphelp",
],
)
talk.App(env, name = "relayserver",
libs = [
- "libjingle",
+ "jingle",
],
srcs = [
"p2p/base/relayserver_main.cc",
@@ -336,7 +337,7 @@
)
talk.App(env, name = "stunserver",
libs = [
- "libjingle",
+ "jingle",
],
srcs = [
"p2p/base/stunserver_main.cc",
diff --git a/talk/main.scons b/talk/main.scons
index 0464252..ae71b1d 100644
--- a/talk/main.scons
+++ b/talk/main.scons
@@ -175,7 +175,6 @@
'$PLATFORM_SDK_VISTA_6_0_DIR/Lib'
],
LINKFLAGS = [
- '-opt:ref', # Remove unused references (functions/data).
'-manifest' # TODO: Why do we need this?
],
MIDLFLAGS = [
@@ -248,7 +247,8 @@
'/GS', # enable security checks
],
LINKFLAGS = [
- '/safeseh',
+ '/safeseh', # protect against attacks against exception handlers
+ '/opt:ref', # Remove unused references (functions/data).
],
)
@@ -302,7 +302,7 @@
CCFLAGS = [
'-m32',
'-arch', 'i386',
- '-isysroot', '/Developer/SDKs/MacOSX10.5.sdk',
+ '-isysroot', '/Developer/SDKs/MacOSX10.6.sdk',
'-fasm-blocks',
],
LINKFLAGS = [
@@ -313,9 +313,10 @@
# TODO: consider only defining for libs that actually have objc.
'-ObjC',
'-arch', 'i386',
+ '-mmacosx-version-min=10.5',
+ '-isysroot', '/Developer/SDKs/MacOSX10.6.sdk',
'-m32',
- # Enable dead-code removal.
- '-dead_strip',
+ '-dead-strip'
],
FRAMEWORKS = [
'CoreServices',
diff --git a/talk/p2p/base/constants.cc b/talk/p2p/base/constants.cc
index e7025a0..178bd59 100644
--- a/talk/p2p/base/constants.cc
+++ b/talk/p2p/base/constants.cc
@@ -106,6 +106,7 @@
true, NS_JINGLE_RTP, LN_PAYLOADTYPE);
const buzz::QName QN_JINGLE_RTP_BANDWIDTH(
true, NS_JINGLE_RTP, LN_BANDWIDTH);
+const buzz::QName QN_JINGLE_RTCP_MUX(true, NS_JINGLE_RTP, "rtcp-mux");
const buzz::QName QN_PARAMETER(true, NS_JINGLE_RTP, "parameter");
const std::string NS_GINGLE_AUDIO("http://www.google.com/session/phone");
diff --git a/talk/p2p/base/constants.h b/talk/p2p/base/constants.h
index 5ffeca8..ab0ed2c 100644
--- a/talk/p2p/base/constants.h
+++ b/talk/p2p/base/constants.h
@@ -125,6 +125,7 @@
extern const buzz::QName QN_JINGLE_SSRC;
extern const buzz::QName QN_JINGLE_RTP_PAYLOADTYPE;
extern const buzz::QName QN_JINGLE_RTP_BANDWIDTH;
+extern const buzz::QName QN_JINGLE_RTCP_MUX;
extern const std::string NS_GINGLE_AUDIO;
extern const buzz::QName QN_GINGLE_AUDIO_CONTENT;
diff --git a/talk/p2p/base/parsing.cc b/talk/p2p/base/parsing.cc
index 70e00d7..a54d379 100644
--- a/talk/p2p/base/parsing.cc
+++ b/talk/p2p/base/parsing.cc
@@ -32,8 +32,8 @@
#include "talk/base/stringutils.h"
namespace {
-std::string kTrue = "true";
-std::string kOne = "1";
+static const char kTrue[] = "true";
+static const char kOne[] = "1";
}
namespace cricket {
diff --git a/talk/p2p/base/port.cc b/talk/p2p/base/port.cc
index 7740336..bb4ab26 100644
--- a/talk/p2p/base/port.cc
+++ b/talk/p2p/base/port.cc
@@ -350,7 +350,6 @@
StunAddressAttribute* addr_attr =
StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
- addr_attr->SetFamily(1);
addr_attr->SetPort(addr.port());
addr_attr->SetIP(addr.ip());
response.AddAttribute(addr_attr);
diff --git a/talk/p2p/base/pseudotcp.cc b/talk/p2p/base/pseudotcp.cc
index 2e8cea3..fc903e0 100644
--- a/talk/p2p/base/pseudotcp.cc
+++ b/talk/p2p/base/pseudotcp.cc
@@ -537,6 +537,7 @@
len,
offset,
&bytes_read);
+ UNUSED(result);
ASSERT(result == talk_base::SR_SUCCESS);
ASSERT(static_cast<uint32>(bytes_read) == len);
}
@@ -897,6 +898,7 @@
talk_base::StreamResult result = m_rbuf.WriteOffset(seg.data, seg.len,
nOffset, NULL);
ASSERT(result == talk_base::SR_SUCCESS);
+ UNUSED(result);
if (seg.seq == m_rcv_nxt) {
m_rbuf.ConsumeWriteBuffer(seg.len);
@@ -1188,7 +1190,8 @@
}
// Length of this option.
- ASSERT(len);
+ ASSERT(len != 0);
+ UNUSED(len);
uint8 opt_len = 0;
buf.ReadUInt8(&opt_len);
@@ -1262,6 +1265,7 @@
// before connection is established or when peers are exchanging connect
// messages.
ASSERT(result);
+ UNUSED(result);
m_rbuf_len = new_size;
m_rwnd_scale = scale_factor;
m_ssthresh = new_size;
diff --git a/talk/p2p/base/relayport.cc b/talk/p2p/base/relayport.cc
index 5348fe5..76bd5ff 100644
--- a/talk/p2p/base/relayport.cc
+++ b/talk/p2p/base/relayport.cc
@@ -183,7 +183,7 @@
uint32 start_time_;
};
-const std::string RELAY_PORT_TYPE("relay");
+const char RELAY_PORT_TYPE[] = "relay";
RelayPort::RelayPort(
talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
@@ -554,7 +554,6 @@
StunAddressAttribute* addr_attr =
StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
- addr_attr->SetFamily(1);
addr_attr->SetIP(addr.ip());
addr_attr->SetPort(addr.port());
request.AddAttribute(addr_attr);
diff --git a/talk/p2p/base/relayport.h b/talk/p2p/base/relayport.h
index 025668a..62bb758 100644
--- a/talk/p2p/base/relayport.h
+++ b/talk/p2p/base/relayport.h
@@ -38,7 +38,7 @@
namespace cricket {
-extern const std::string RELAY_PORT_TYPE;
+extern const char RELAY_PORT_TYPE[];
class RelayEntry;
class RelayConnection;
diff --git a/talk/p2p/base/relayserver.cc b/talk/p2p/base/relayserver.cc
index 82f382a..554337f 100644
--- a/talk/p2p/base/relayserver.cc
+++ b/talk/p2p/base/relayserver.cc
@@ -444,7 +444,6 @@
StunAddressAttribute* addr_attr =
StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
- addr_attr->SetFamily(1);
addr_attr->SetIP(ext_addr.ip());
addr_attr->SetPort(ext_addr.port());
response.AddAttribute(addr_attr);
@@ -621,7 +620,6 @@
StunAddressAttribute* addr_attr =
StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
- addr_attr->SetFamily(1);
addr_attr->SetIP(from_addr.ip());
addr_attr->SetPort(from_addr.port());
msg.AddAttribute(addr_attr);
diff --git a/talk/p2p/base/session.cc b/talk/p2p/base/session.cc
index 54ae1bc..ef6737a 100644
--- a/talk/p2p/base/session.cc
+++ b/talk/p2p/base/session.cc
@@ -159,20 +159,138 @@
proxy->SetImplementation(impl);
}
-
-
-
-BaseSession::BaseSession(talk_base::Thread *signaling_thread)
- : state_(STATE_INIT), error_(ERROR_NONE),
- local_description_(NULL), remote_description_(NULL),
- signaling_thread_(signaling_thread) {
+BaseSession::BaseSession(talk_base::Thread* signaling_thread,
+ talk_base::Thread* worker_thread,
+ PortAllocator* port_allocator,
+ const std::string& sid,
+ const std::string& content_type,
+ bool initiator)
+ : state_(STATE_INIT),
+ error_(ERROR_NONE),
+ signaling_thread_(signaling_thread),
+ worker_thread_(worker_thread),
+ port_allocator_(port_allocator),
+ sid_(sid),
+ content_type_(content_type),
+ transport_type_(NS_GINGLE_P2P),
+ initiator_(initiator),
+ local_description_(NULL),
+ remote_description_(NULL) {
+ ASSERT(signaling_thread->IsCurrent());
}
BaseSession::~BaseSession() {
+ ASSERT(signaling_thread()->IsCurrent());
+
+ ASSERT(state_ != STATE_DEINIT);
+ state_ = STATE_DEINIT;
+ SignalState(this, state_);
+
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ delete iter->second;
+ }
+
delete remote_description_;
delete local_description_;
}
+void BaseSession::set_allow_local_ips(bool allow) {
+ allow_local_ips_ = allow;
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ iter->second->impl()->set_allow_local_ips(allow);
+ }
+}
+
+TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
+ const std::string& channel_name) {
+ // We create the proxy "on demand" here because we need to support
+ // creating channels at any time, even before we send or receive
+ // initiate messages, which is before we create the transports.
+ TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
+ return transproxy->CreateChannel(channel_name, content_type_);
+}
+
+TransportChannel* BaseSession::GetChannel(const std::string& content_name,
+ const std::string& channel_name) {
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ if (transproxy == NULL)
+ return NULL;
+ else
+ return transproxy->GetChannel(channel_name);
+}
+
+void BaseSession::DestroyChannel(const std::string& content_name,
+ const std::string& channel_name) {
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ ASSERT(transproxy != NULL);
+ transproxy->DestroyChannel(channel_name);
+}
+
+TransportProxy* BaseSession::GetOrCreateTransportProxy(
+ const std::string& content_name) {
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ if (transproxy)
+ return transproxy;
+
+ Transport* transport = CreateTransport();
+ transport->set_allow_local_ips(allow_local_ips_);
+ transport->SignalConnecting.connect(
+ this, &BaseSession::OnTransportConnecting);
+ transport->SignalWritableState.connect(
+ this, &BaseSession::OnTransportWritable);
+ transport->SignalRequestSignaling.connect(
+ this, &BaseSession::OnTransportRequestSignaling);
+ transport->SignalCandidatesReady.connect(
+ this, &BaseSession::OnTransportCandidatesReady);
+ transport->SignalTransportError.connect(
+ this, &BaseSession::OnTransportSendError);
+ transport->SignalChannelGone.connect(
+ this, &BaseSession::OnTransportChannelGone);
+
+ transproxy = new TransportProxy(content_name, transport);
+ transports_[content_name] = transproxy;
+
+ return transproxy;
+}
+
+Transport* BaseSession::GetTransport(const std::string& content_name) {
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ if (transproxy == NULL)
+ return NULL;
+ return transproxy->impl();
+}
+
+TransportProxy* BaseSession::GetTransportProxy(
+ const std::string& content_name) {
+ TransportMap::iterator iter = transports_.find(content_name);
+ return (iter != transports_.end()) ? iter->second : NULL;
+}
+
+TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) {
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ TransportProxy* transproxy = iter->second;
+ if (transproxy->impl() == transport) {
+ return transproxy;
+ }
+ }
+ return NULL;
+}
+
+TransportProxy* BaseSession::GetFirstTransportProxy() {
+ if (transports_.empty())
+ return NULL;
+ return transports_.begin()->second;
+}
+
+cricket::Transport* BaseSession::CreateTransport() {
+ ASSERT(transport_type_ == NS_GINGLE_P2P);
+ return new cricket::P2PTransport(
+ signaling_thread(), worker_thread(), port_allocator());
+}
+
void BaseSession::SetState(State state) {
ASSERT(signaling_thread_->IsCurrent());
if (state != state_) {
@@ -190,6 +308,21 @@
}
}
+void BaseSession::OnSignalingReady() {
+ ASSERT(signaling_thread()->IsCurrent());
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ iter->second->impl()->OnSignalingReady();
+ }
+}
+
+void BaseSession::SpeculativelyConnectAllTransportChannels() {
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ iter->second->SpeculativelyConnectChannels();
+ }
+}
+
void BaseSession::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
case MSG_TIMEOUT:
@@ -197,10 +330,6 @@
SetError(ERROR_TIME);
break;
- case MSG_ERROR:
- TerminateWithReason(STR_TERMINATE_ERROR);
- break;
-
case MSG_STATE:
switch (state_) {
case STATE_SENTACCEPT:
@@ -208,12 +337,6 @@
SetState(STATE_INPROGRESS);
break;
- case STATE_SENTREJECT:
- case STATE_RECEIVEDREJECT:
- // Assume clean termination.
- Terminate();
- break;
-
default:
// Explicitly ignoring some states here.
break;
@@ -222,74 +345,41 @@
}
}
-
-Session::Session(SessionManager *session_manager,
+Session::Session(SessionManager* session_manager,
const std::string& local_name,
const std::string& initiator_name,
- const std::string& sid, const std::string& content_type,
- SessionClient* client) :
- BaseSession(session_manager->signaling_thread()) {
- ASSERT(session_manager->signaling_thread()->IsCurrent());
+ const std::string& sid,
+ const std::string& content_type,
+ SessionClient* client)
+ : BaseSession(session_manager->signaling_thread(),
+ session_manager->worker_thread(),
+ session_manager->port_allocator(),
+ sid, content_type, initiator_name == local_name) {
ASSERT(client != NULL);
session_manager_ = session_manager;
local_name_ = local_name;
- sid_ = sid;
initiator_name_ = initiator_name;
- content_type_ = content_type;
- // TODO: Once we support different transport types,
- // don't hard code this here.
- transport_type_ = NS_GINGLE_P2P;
transport_parser_ = new P2PTransportParser();
client_ = client;
- error_ = ERROR_NONE;
- state_ = STATE_INIT;
- initiator_ = false;
initiate_acked_ = false;
current_protocol_ = PROTOCOL_HYBRID;
}
Session::~Session() {
- ASSERT(signaling_thread_->IsCurrent());
-
- ASSERT(state_ != STATE_DEINIT);
- state_ = STATE_DEINIT;
- SignalState(this, state_);
-
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
- delete iter->second;
- }
-
delete transport_parser_;
}
-Transport* Session::GetTransport(const std::string& content_name) {
- TransportProxy* transproxy = GetTransportProxy(content_name);
- if (transproxy == NULL)
- return NULL;
- return transproxy->impl();
-}
-
-void Session::set_allow_local_ips(bool allow) {
- allow_local_ips_ = allow;
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
- iter->second->impl()->set_allow_local_ips(allow);
- }
-}
-
bool Session::Initiate(const std::string &to,
const SessionDescription* sdesc) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
SessionError error;
// Only from STATE_INIT
- if (state_ != STATE_INIT)
+ if (state() != STATE_INIT)
return false;
// Setup for signaling.
- remote_name_ = to;
- initiator_ = true;
+ set_remote_name(to);
set_local_description(sdesc);
if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()),
&error)) {
@@ -309,14 +399,13 @@
}
bool Session::Accept(const SessionDescription* sdesc) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
// Only if just received initiate
- if (state_ != STATE_RECEIVEDINITIATE)
+ if (state() != STATE_RECEIVEDINITIATE)
return false;
// Setup for signaling.
- initiator_ = false;
set_local_description(sdesc);
SessionError error;
@@ -330,16 +419,13 @@
}
bool Session::Reject(const std::string& reason) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
// Reject is sent in response to an initiate or modify, to reject the
// request
- if (state_ != STATE_RECEIVEDINITIATE && state_ != STATE_RECEIVEDMODIFY)
+ if (state() != STATE_RECEIVEDINITIATE && state() != STATE_RECEIVEDMODIFY)
return false;
- // Setup for signaling.
- initiator_ = false;
-
SessionError error;
if (!SendRejectMessage(reason, &error)) {
LOG(LS_ERROR) << "Could not send reject message: " << error.text;
@@ -351,10 +437,10 @@
}
bool Session::TerminateWithReason(const std::string& reason) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
// Either side can terminate, at any time.
- switch (state_) {
+ switch (state()) {
case STATE_SENTTERMINATE:
case STATE_RECEIVEDTERMINATE:
return false;
@@ -379,7 +465,7 @@
}
bool Session::SendInfoMessage(const XmlElements& elems) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
SessionError error;
if (!SendMessage(ACTION_SESSION_INFO, elems, &error)) {
LOG(LS_ERROR) << "Could not send info message " << error.text;
@@ -388,41 +474,17 @@
return true;
}
-
-TransportProxy* Session::GetTransportProxy(const Transport* transport) {
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
- TransportProxy* transproxy = iter->second;
- if (transproxy->impl() == transport) {
- return transproxy;
- }
- }
- return NULL;
-}
-
-TransportProxy* Session::GetTransportProxy(const std::string& content_name) {
- TransportMap::iterator iter = transports_.find(content_name);
- return (iter != transports_.end()) ? iter->second : NULL;
-}
-
-TransportProxy* Session::GetFirstTransportProxy() {
- if (transports_.empty())
- return NULL;
- return transports_.begin()->second;
-}
-
TransportInfos Session::GetEmptyTransportInfos(
const ContentInfos& contents) const {
TransportInfos tinfos;
for (ContentInfos::const_iterator content = contents.begin();
content != contents.end(); ++content) {
tinfos.push_back(
- TransportInfo(content->name, transport_type_, Candidates()));
+ TransportInfo(content->name, transport_type(), Candidates()));
}
return tinfos;
}
-
bool Session::OnRemoteCandidates(
const TransportInfos& tinfos, ParseError* error) {
for (TransportInfos::const_iterator tinfo = tinfos.begin();
@@ -457,42 +519,11 @@
return true;
}
-
-TransportProxy* Session::GetOrCreateTransportProxy(
- const std::string& content_name) {
- TransportProxy* transproxy = GetTransportProxy(content_name);
- if (transproxy)
- return transproxy;
-
- Transport* transport =
- new P2PTransport(signaling_thread_,
- session_manager_->worker_thread(),
- session_manager_->port_allocator());
- transport->set_allow_local_ips(allow_local_ips_);
- transport->SignalConnecting.connect(
- this, &Session::OnTransportConnecting);
- transport->SignalWritableState.connect(
- this, &Session::OnTransportWritable);
- transport->SignalRequestSignaling.connect(
- this, &Session::OnTransportRequestSignaling);
- transport->SignalCandidatesReady.connect(
- this, &Session::OnTransportCandidatesReady);
- transport->SignalTransportError.connect(
- this, &Session::OnTransportSendError);
- transport->SignalChannelGone.connect(
- this, &Session::OnTransportChannelGone);
-
- transproxy = new TransportProxy(content_name, transport);
- transports_[content_name] = transproxy;
-
- return transproxy;
-}
-
bool Session::CreateTransportProxies(const TransportInfos& tinfos,
SessionError* error) {
for (TransportInfos::const_iterator tinfo = tinfos.begin();
tinfo != tinfos.end(); ++tinfo) {
- if (tinfo->transport_type != transport_type_) {
+ if (tinfo->transport_type != transport_type()) {
error->SetText("No supported transport in offer.");
return false;
}
@@ -502,56 +533,21 @@
return true;
}
-void Session::SpeculativelyConnectAllTransportChannels() {
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
- iter->second->SpeculativelyConnectChannels();
- }
-}
-
TransportParserMap Session::GetTransportParsers() {
TransportParserMap parsers;
- parsers[transport_type_] = transport_parser_;
+ parsers[transport_type()] = transport_parser_;
return parsers;
}
ContentParserMap Session::GetContentParsers() {
ContentParserMap parsers;
- parsers[content_type_] = client_;
+ parsers[content_type()] = client_;
return parsers;
}
-TransportChannel* Session::CreateChannel(const std::string& content_name,
- const std::string& channel_name) {
- // We create the proxy "on demand" here because we need to support
- // creating channels at any time, even before we send or receive
- // initiate messages, which is before we create the transports.
- TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
- return transproxy->CreateChannel(channel_name, content_type_);
-}
-
-TransportChannel* Session::GetChannel(const std::string& content_name,
- const std::string& channel_name) {
- TransportProxy* transproxy = GetTransportProxy(content_name);
- if (transproxy == NULL)
- return NULL;
- else
- return transproxy->GetChannel(channel_name);
-}
-
-void Session::DestroyChannel(const std::string& content_name,
- const std::string& channel_name) {
- TransportProxy* transproxy = GetTransportProxy(content_name);
- ASSERT(transproxy != NULL);
- transproxy->DestroyChannel(channel_name);
-}
-
-void Session::OnSignalingReady() {
- ASSERT(signaling_thread_->IsCurrent());
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
- iter->second->impl()->OnSignalingReady();
- }
+void Session::OnTransportRequestSignaling(Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ SignalRequestSignaling(this);
}
void Session::OnTransportConnecting(Transport* transport) {
@@ -561,31 +557,26 @@
}
void Session::OnTransportWritable(Transport* transport) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
// If the transport is not writable, start a timer to make sure that it
// becomes writable within a reasonable amount of time. If it does not, we
// terminate since we can't actually send data. If the transport is writable,
// cancel the timer. Note that writability transitions may occur repeatedly
// during the lifetime of the session.
- signaling_thread_->Clear(this, MSG_TIMEOUT);
+ signaling_thread()->Clear(this, MSG_TIMEOUT);
if (transport->HasChannels() && !transport->writable()) {
- signaling_thread_->PostDelayed(
+ signaling_thread()->PostDelayed(
session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
}
}
-void Session::OnTransportRequestSignaling(Transport* transport) {
- ASSERT(signaling_thread_->IsCurrent());
- SignalRequestSignaling(this);
-}
-
void Session::OnTransportCandidatesReady(Transport* transport,
const Candidates& candidates) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
TransportProxy* transproxy = GetTransportProxy(transport);
if (transproxy != NULL) {
- if (initiator_ && !initiate_acked_) {
+ if (initiator() && !initiate_acked_) {
// TODO: This is to work around server re-ordering
// messages. We send the candidates once the session-initiate
// is acked. Once we have fixed the server to guarantee message
@@ -611,19 +602,19 @@
const std::string& type,
const std::string& text,
const buzz::XmlElement* extra_info) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
SignalErrorMessage(this, stanza, name, type, text, extra_info);
}
void Session::OnTransportChannelGone(Transport* transport,
const std::string& name) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
SignalChannelGone(this, name);
}
void Session::OnIncomingMessage(const SessionMessage& msg) {
- ASSERT(signaling_thread_->IsCurrent());
- ASSERT(state_ == STATE_INIT || msg.from == remote_name_);
+ ASSERT(signaling_thread()->IsCurrent());
+ ASSERT(state() == STATE_INIT || msg.from == remote_name());
if (current_protocol_== PROTOCOL_HYBRID) {
if (msg.protocol == PROTOCOL_GINGLE) {
@@ -677,7 +668,7 @@
void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
const buzz::XmlElement* response_stanza,
const SessionMessage& msg) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
if (msg.type == ACTION_SESSION_INITIATE) {
OnInitiateAcked();
@@ -698,7 +689,7 @@
void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
const buzz::XmlElement* error_stanza) {
- ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(signaling_thread()->IsCurrent());
SessionMessage msg;
ParseError parse_error;
@@ -744,7 +735,7 @@
// which we pass on to the respective transport.
// TODO: This is only used for unknown channel name.
- // For Jingle, find a stanard-compliant way of doing this. For
+ // For Jingle, find a standard-compliant way of doing this. For
// Gingle, guess the content name based on the channel name.
for (const buzz::XmlElement* elem = error->FirstElement();
NULL != elem; elem = elem->NextElement()) {
@@ -777,13 +768,12 @@
session_error.text, error);
}
- initiator_ = false;
- remote_name_ = msg.from;
+ set_remote_name(msg.from);
set_remote_description(new SessionDescription(init.ClearContents()));
SetState(STATE_RECEIVEDINITIATE);
// Users of Session may listen to state change and call Reject().
- if (state_ != STATE_SENTREJECT) {
+ if (state() != STATE_SENTREJECT) {
if (!OnRemoteCandidates(init.transports, error))
return false;
}
@@ -809,7 +799,7 @@
SetState(STATE_RECEIVEDACCEPT);
// Users of Session may listen to state change and call Reject().
- if (state_ != STATE_SENTREJECT) {
+ if (state() != STATE_SENTREJECT) {
if (!OnRemoteCandidates(accept.transports, error))
return false;
}
@@ -883,7 +873,7 @@
// 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) {
+ if (remote_description()->GetContentByName(it->name) == NULL) {
return false;
}
@@ -894,8 +884,8 @@
// 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);
+ remote_description()->RemoveContentByName(it->name);
+ remote_description()->AddContent(it->name, it->type, it->description);
}
SignalRemoteDescriptionUpdate(this);
@@ -918,20 +908,20 @@
return BadWrite(message_error.text, error);
}
- if (!BareJidsEqual(remote_name_, redirect.target))
+ if (!BareJidsEqual(remote_name(), redirect.target))
return BadWrite("Redirection not allowed: must be the same bare jid.",
error);
// When we receive a redirect, we point the session at the new JID
// and resend the candidates.
- remote_name_ = redirect.target;
+ set_remote_name(redirect.target);
return (SendInitiateMessage(local_description(), error) &&
ResendAllTransportInfoMessages(error));
}
-bool Session::CheckState(State state, MessageError* error) {
- ASSERT(state_ == state);
- if (state_ != state) {
+bool Session::CheckState(State expected, MessageError* error) {
+ ASSERT(state() == expected);
+ if (state() != expected) {
return BadMessage(buzz::QN_STANZA_NOT_ALLOWED,
"message not allowed in current state",
error);
@@ -941,19 +931,29 @@
void Session::SetError(Error error) {
BaseSession::SetError(error);
- if (error_ != ERROR_NONE)
- signaling_thread_->Post(this, MSG_ERROR);
+ if (error != ERROR_NONE)
+ signaling_thread()->Post(this, MSG_ERROR);
}
void Session::OnMessage(talk_base::Message *pmsg) {
// preserve this because BaseSession::OnMessage may modify it
- BaseSession::State orig_state = state_;
+ State orig_state = state();
BaseSession::OnMessage(pmsg);
switch (pmsg->message_id) {
+ case MSG_ERROR:
+ TerminateWithReason(STR_TERMINATE_ERROR);
+ break;
+
case MSG_STATE:
switch (orig_state) {
+ case STATE_SENTREJECT:
+ case STATE_RECEIVEDREJECT:
+ // Assume clean termination.
+ Terminate();
+ break;
+
case STATE_SENTTERMINATE:
case STATE_RECEIVEDTERMINATE:
session_manager_->DestroySession(this);
@@ -1045,8 +1045,8 @@
}
bool Session::ResendAllTransportInfoMessages(SessionError* error) {
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
+ for (TransportMap::const_iterator iter = transport_proxies().begin();
+ iter != transport_proxies().end(); ++iter) {
TransportProxy* transproxy = iter->second;
if (transproxy->sent_candidates().size() > 0) {
if (!SendTransportInfoMessage(
@@ -1062,8 +1062,8 @@
}
bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) {
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
+ for (TransportMap::const_iterator iter = transport_proxies().begin();
+ iter != transport_proxies().end(); ++iter) {
TransportProxy* transproxy = iter->second;
if (transproxy->unsent_candidates().size() > 0) {
if (!SendTransportInfoMessage(
@@ -1083,8 +1083,8 @@
talk_base::scoped_ptr<buzz::XmlElement> stanza(
new buzz::XmlElement(buzz::QN_IQ));
- SessionMessage msg(current_protocol_, type, sid_, initiator_name_);
- msg.to = remote_name_;
+ SessionMessage msg(current_protocol_, type, id(), initiator_name());
+ msg.to = remote_name();
WriteSessionMessage(msg, action_elems, stanza.get());
SignalOutgoingMessage(this, stanza.get());
@@ -1127,8 +1127,8 @@
if (!WriteSessionAction(protocol, action, &action_elems, error))
return false;
- SessionMessage msg(protocol, type, sid_, initiator_name_);
- msg.to = remote_name_;
+ SessionMessage msg(protocol, type, id(), initiator_name());
+ msg.to = remote_name();
WriteSessionMessage(msg, action_elems, stanza);
return true;
@@ -1137,7 +1137,7 @@
void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) {
talk_base::scoped_ptr<buzz::XmlElement> ack(
new buzz::XmlElement(buzz::QN_IQ));
- ack->SetAttr(buzz::QN_TO, remote_name_);
+ ack->SetAttr(buzz::QN_TO, remote_name());
ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
ack->SetAttr(buzz::QN_TYPE, "result");
diff --git a/talk/p2p/base/session.h b/talk/p2p/base/session.h
index bfafe77..cb3c1fc 100644
--- a/talk/p2p/base/session.h
+++ b/talk/p2p/base/session.h
@@ -127,12 +127,6 @@
typedef std::map<std::string, TransportProxy*> TransportMap;
-// TODO: Consider simplifying the dependency from Voice/VideoChannel
-// on Session. Right now the Channel class requires a BaseSession, but it only
-// uses CreateChannel/DestroyChannel. Perhaps something like a
-// TransportChannelFactory could be hoisted up out of BaseSession, or maybe
-// the transports could be passed in directly.
-
// A BaseSession manages general session state. This includes negotiation
// of both the application-level and network-level protocols: the former
// defines what will be sent and the latter defines how it will be sent. Each
@@ -168,17 +162,71 @@
ERROR_CONTENT = 4, // channel errors in SetLocalContent/SetRemoteContent
};
- explicit BaseSession(talk_base::Thread *signaling_thread);
+ BaseSession(talk_base::Thread* signaling_thread,
+ talk_base::Thread* worker_thread,
+ PortAllocator* port_allocator,
+ const std::string& sid,
+ const std::string& content_type,
+ bool initiator);
virtual ~BaseSession();
- // Updates the state, signaling if necessary.
- void SetState(State state);
+ talk_base::Thread* signaling_thread() { return signaling_thread_; }
+ talk_base::Thread* worker_thread() { return worker_thread_; }
+ PortAllocator* port_allocator() { return port_allocator_; }
- // Updates the error state, signaling if necessary.
- virtual void SetError(Error error);
+ // The ID of this session.
+ const std::string& id() const { return sid_; }
- // Handles messages posted to us.
- virtual void OnMessage(talk_base::Message *pmsg);
+ // Returns the XML namespace identifying the type of this session.
+ const std::string& content_type() const { return content_type_; }
+
+ // Returns the XML namespace identifying the transport used for this session.
+ const std::string& transport_type() const { return transport_type_; }
+
+ // Indicates whether we initiated this session.
+ bool initiator() const { return initiator_; }
+
+ // Returns the application-level description given by our client.
+ // If we are the recipient, this will be NULL until we send an accept.
+ const SessionDescription* local_description() const {
+ return local_description_;
+ }
+ // Returns the application-level description given by the other client.
+ // If we are the initiator, this will be NULL until we receive an accept.
+ const SessionDescription* remote_description() const {
+ return remote_description_;
+ }
+ SessionDescription* remote_description() {
+ return remote_description_;
+ }
+
+ // Takes ownership of SessionDescription*
+ bool set_local_description(const SessionDescription* sdesc) {
+ if (sdesc != local_description_) {
+ delete local_description_;
+ local_description_ = sdesc;
+ }
+ return true;
+ }
+
+ // Takes ownership of SessionDescription*
+ bool set_remote_description(SessionDescription* sdesc) {
+ if (sdesc != remote_description_) {
+ delete remote_description_;
+ remote_description_ = sdesc;
+ }
+ return true;
+ }
+
+ const SessionDescription* initiator_description() const {
+ if (initiator_) {
+ return local_description_;
+ } else {
+ return remote_description_;
+ }
+ }
+
+ void set_allow_local_ips(bool allow);
// Returns the current state of the session. See the enum above for details.
// Each time the state changes, we will fire this signal.
@@ -190,6 +238,19 @@
Error error() const { return error_; }
sigslot::signal2<BaseSession *, Error> SignalError;
+ // Updates the state, signaling if necessary.
+ virtual void SetState(State state);
+
+ // Updates the error state, signaling if necessary.
+ virtual void SetError(Error error);
+
+ // Fired when the remote description is updated.
+ sigslot::signal1<BaseSession *> SignalRemoteDescriptionUpdate;
+
+ // Returns the transport that has been negotiated or NULL if
+ // negotiation is still in progress.
+ Transport* GetTransport(const std::string& content_name);
+
// Creates a new channel with the given names. This method may be called
// immediately after creating the session. However, the actual
// implementation may not be fixed until transport negotiation completes.
@@ -197,68 +258,102 @@
// shouldn't be an issue since the main thread will be blocked in
// Send when doing so.
virtual TransportChannel* CreateChannel(const std::string& content_name,
- const std::string& channel_name) = 0;
+ const std::string& channel_name);
// Returns the channel with the given names.
virtual TransportChannel* GetChannel(const std::string& content_name,
- const std::string& channel_name) = 0;
+ const std::string& channel_name);
// Destroys the channel with the given names.
// This will usually be called from the worker thread, but that
// shouldn't be an issue since the main thread will be blocked in
// Send when doing so.
virtual void DestroyChannel(const std::string& content_name,
- const std::string& channel_name) = 0;
+ const std::string& channel_name);
+ protected:
+ const TransportMap& transport_proxies() const { return transports_; }
+ // Get a TransportProxy by content_name or transport. NULL if not found.
+ TransportProxy* GetTransportProxy(const std::string& content_name);
+ TransportProxy* GetTransportProxy(const Transport* transport);
+ TransportProxy* GetFirstTransportProxy();
+ // TransportProxy is owned by session. Return proxy just for convenience.
+ TransportProxy* GetOrCreateTransportProxy(const std::string& content_name);
+ // Creates the actual transport object. Overridable for testing.
+ virtual Transport* CreateTransport();
- // Invoked when we notice that there is no matching channel on our peer.
- sigslot::signal2<Session*, const std::string&> SignalChannelGone;
+ void OnSignalingReady();
+ void SpeculativelyConnectAllTransportChannels();
- // Returns the application-level description given by our client.
- // If we are the recipient, this will be NULL until we send an accept.
- const SessionDescription* local_description() const {
- return local_description_;
- }
- // Takes ownership of SessionDescription*
- bool set_local_description(const SessionDescription* sdesc) {
- if (sdesc != local_description_) {
- delete local_description_;
- local_description_ = sdesc;
- }
- return true;
+ // Called when a transport requests signaling.
+ virtual void OnTransportRequestSignaling(Transport* transport) {
}
- // Returns the application-level description given by the other client.
- // If we are the initiator, this will be NULL until we receive an accept.
- const SessionDescription* remote_description() const {
- return remote_description_;
- }
- // Takes ownership of SessionDescription*
- bool set_remote_description(SessionDescription* sdesc) {
- if (sdesc != remote_description_) {
- delete remote_description_;
- remote_description_ = sdesc;
- }
- return true;
+ // Called when the first channel of a transport begins connecting. We use
+ // this to start a timer, to make sure that the connection completes in a
+ // reasonable amount of time.
+ virtual void OnTransportConnecting(Transport* transport) {
}
- // When we receive an initiate, we create a session in the
- // RECEIVEDINITIATE state and respond by accepting or rejecting.
- // Takes ownership of session description.
- virtual bool Accept(const SessionDescription* sdesc) = 0;
- virtual bool Reject(const std::string& reason) = 0;
- bool Terminate() {
- return TerminateWithReason(STR_TERMINATE_SUCCESS);
- }
- virtual bool TerminateWithReason(const std::string& reason) = 0;
-
- // The worker thread used by the session manager
- virtual talk_base::Thread *worker_thread() = 0;
-
- talk_base::Thread *signaling_thread() {
- return signaling_thread_;
+ // Called when a transport changes its writable state. We track this to make
+ // sure that the transport becomes writable within a reasonable amount of
+ // time. If this does not occur, we signal an error.
+ virtual void OnTransportWritable(Transport* transport) {
}
- // Returns the JID of this client.
+ // Called when a transport signals that it has new candidates.
+ virtual void OnTransportCandidatesReady(Transport* transport,
+ const Candidates& candidates) {
+ }
+
+ // Called when a transport signals that it found an error in an incoming
+ // message.
+ virtual void OnTransportSendError(Transport* transport,
+ const buzz::XmlElement* stanza,
+ const buzz::QName& name,
+ const std::string& type,
+ const std::string& text,
+ const buzz::XmlElement* extra_info) {
+ }
+
+ // Called when we notice that one of our local channels has no peer, so it
+ // should be destroyed.
+ virtual void OnTransportChannelGone(Transport* transport,
+ const std::string& name) {
+ }
+
+ // Handles messages posted to us.
+ virtual void OnMessage(talk_base::Message *pmsg);
+
+ protected:
+// private:
+ State state_;
+ Error error_;
+ private:
+ talk_base::Thread* signaling_thread_;
+ talk_base::Thread* worker_thread_;
+ PortAllocator* port_allocator_;
+ std::string sid_;
+ std::string content_type_;
+ std::string transport_type_;
+ bool initiator_;
+ const SessionDescription* local_description_;
+ SessionDescription* remote_description_;
+ // This is transport-specific but required so much by unit tests
+ // that it's much easier to put it here.
+ bool allow_local_ips_;
+ TransportMap transports_;
+};
+
+// A specific Session created by the SessionManager, using XMPP for protocol.
+class Session : public BaseSession {
+ public:
+ // Returns the manager that created and owns this session.
+ SessionManager* session_manager() const { return session_manager_; }
+
+ // Returns the client that is handling the application data of this session.
+ SessionClient* client() const { return client_; }
+
+ // Returns the JID of this client.
const std::string& local_name() const { return local_name_; }
// Returns the JID of the other peer in this session.
@@ -271,41 +366,9 @@
// explicitly.
void set_remote_name(const std::string& name) { remote_name_ = name; }
- 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_;
- 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
- // change to buzz::Jid as well.
- std::string local_name_;
- std::string remote_name_;
- talk_base::Thread *signaling_thread_;
-};
-
-// A specific Session created by the SessionManager, using XMPP for protocol.
-class Session : public BaseSession {
- public:
- // Returns the manager that created and owns this session.
- SessionManager* session_manager() const { return session_manager_; }
-
- // the worker thread used by the session manager
- talk_base::Thread *worker_thread() {
- return session_manager_->worker_thread();
- }
-
- // Returns the XML namespace identifying the type of this session.
- const std::string& content_type() const { return content_type_; }
-
- // Returns the client that is handling the application data of this session.
- SessionClient* client() const { return client_; }
+ // Indicates the JID of the entity who initiated this session.
+ // In special cases, may be different than both local_name and remote_name.
+ const std::string& initiator_name() const { return initiator_name_; }
SignalingProtocol current_protocol() const { return current_protocol_; }
@@ -313,25 +376,18 @@
current_protocol_ = protocol;
}
- // Indicates whether we initiated this session.
- bool initiator() const { return initiator_; }
+ // Updates the error state, signaling if necessary.
+ virtual void SetError(Error error);
- const SessionDescription* initiator_description() const {
- if (initiator_) {
- return local_description_;
- } else {
- return remote_description_;
- }
- }
+ // When the session needs to send signaling messages, it beings by requesting
+ // signaling. The client should handle this by calling OnSignalingReady once
+ // it is ready to send the messages.
+ // (These are called only by SessionManager.)
+ sigslot::signal1<Session*> SignalRequestSignaling;
+ void OnSignalingReady() { BaseSession::OnSignalingReady(); }
- // Fired whenever we receive a terminate message along with a reason
- sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason;
-
- void set_allow_local_ips(bool allow);
-
- // Returns the transport that has been negotiated or NULL if
- // negotiation is still in progress.
- Transport* GetTransport(const std::string& content_name);
+ // Invoked when we notice that there is no matching channel on our peer.
+ sigslot::signal2<Session*, const std::string&> SignalChannelGone;
// Takes ownership of session description.
// TODO: Add an error argument to pass back to the caller.
@@ -342,9 +398,14 @@
// RECEIVEDINITIATE state and respond by accepting or rejecting.
// Takes ownership of session description.
// TODO: Add an error argument to pass back to the caller.
- virtual bool Accept(const SessionDescription* sdesc);
- virtual bool Reject(const std::string& reason);
- virtual bool TerminateWithReason(const std::string& reason);
+ bool Accept(const SessionDescription* sdesc);
+ bool Reject(const std::string& reason);
+ bool Terminate() {
+ return TerminateWithReason(STR_TERMINATE_SUCCESS);
+ }
+ bool TerminateWithReason(const std::string& reason);
+ // Fired whenever we receive a terminate message along with a reason
+ sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason;
// The two clients in the session may also send one another
// arbitrary XML messages, which are called "info" messages. Sending
@@ -353,30 +414,6 @@
bool SendInfoMessage(const XmlElements& elems);
sigslot::signal2<Session*, const buzz::XmlElement*> SignalInfoMessage;
- // Maps passed to serialization functions.
- TransportParserMap GetTransportParsers();
- ContentParserMap GetContentParsers();
-
- // Creates a new channel with the given names. This method may be called
- // immediately after creating the session. However, the actual
- // implementation may not be fixed until transport negotiation completes.
- virtual TransportChannel* CreateChannel(const std::string& content_name,
- const std::string& channel_name);
-
- // Returns the channel with the given names.
- virtual TransportChannel* GetChannel(const std::string& content_name,
- const std::string& channel_name);
-
- // Destroys the channel with the given names.
- virtual void DestroyChannel(const std::string& content_name,
- const std::string& channel_name);
-
- // Updates the error state, signaling if necessary.
- virtual void SetError(Error error);
-
- // Handles messages posted to us.
- virtual void OnMessage(talk_base::Message *pmsg);
-
private:
// Creates or destroys a session. (These are called only SessionManager.)
Session(SessionManager *session_manager,
@@ -384,62 +421,35 @@
const std::string& sid, const std::string& content_type,
SessionClient* client);
~Session();
-
- // Get a TransportProxy by content_name or transport. NULL if not found.
- TransportProxy* GetTransportProxy(const std::string& content_name);
- TransportProxy* GetTransportProxy(const Transport* transport);
- TransportProxy* GetFirstTransportProxy();
- // TransportProxy is owned by session. Return proxy just for convenience.
- TransportProxy* GetOrCreateTransportProxy(const std::string& content_name);
// For each transport info, create a transport proxy. Can fail for
// incompatible transport types.
bool CreateTransportProxies(const TransportInfos& tinfos,
SessionError* error);
- void SpeculativelyConnectAllTransportChannels();
bool OnRemoteCandidates(const TransportInfos& tinfos,
ParseError* error);
// Returns a TransportInfo without candidates for each content name.
// Uses the transport_type_ of the session.
TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const;
- // Called when the first channel of a transport begins connecting. We use
- // this to start a timer, to make sure that the connection completes in a
- // reasonable amount of time.
- void OnTransportConnecting(Transport* transport);
+ // Maps passed to serialization functions.
+ TransportParserMap GetTransportParsers();
+ ContentParserMap GetContentParsers();
- // Called when a transport changes its writable state. We track this to make
- // sure that the transport becomes writable within a reasonable amount of
- // time. If this does not occur, we signal an error.
- void OnTransportWritable(Transport* transport);
+ virtual void OnTransportRequestSignaling(Transport* transport);
+ virtual void OnTransportConnecting(Transport* transport);
+ virtual void OnTransportWritable(Transport* transport);
+ virtual void OnTransportCandidatesReady(Transport* transport,
+ const Candidates& candidates);
+ virtual void OnTransportSendError(Transport* transport,
+ const buzz::XmlElement* stanza,
+ const buzz::QName& name,
+ const std::string& type,
+ const std::string& text,
+ const buzz::XmlElement* extra_info);
+ virtual void OnTransportChannelGone(Transport* transport,
+ const std::string& name);
- // Called when a transport requests signaling.
- void OnTransportRequestSignaling(Transport* transport);
-
- // Called when a transport signals that it has a message to send. Note that
- // these messages are just the transport part of the stanza; they need to be
- // wrapped in the appropriate session tags.
- void OnTransportCandidatesReady(Transport* transport,
- const Candidates& candidates);
-
- // Called when a transport signals that it found an error in an incoming
- // message.
- void OnTransportSendError(Transport* transport,
- const buzz::XmlElement* stanza,
- const buzz::QName& name,
- const std::string& type,
- const std::string& text,
- const buzz::XmlElement* extra_info);
-
- // Called when we notice that one of our local channels has no peer, so it
- // should be destroyed.
- void OnTransportChannelGone(Transport* transport, const std::string& name);
-
- // When the session needs to send signaling messages, it beings by requesting
- // signaling. The client should handle this by calling OnSignalingReady once
- // it is ready to send the messages.
- // (These are called only by SessionManager.)
- sigslot::signal1<Session*> SignalRequestSignaling;
- void OnSignalingReady();
+ virtual void OnMessage(talk_base::Message *pmsg);
// Send various kinds of session messages.
bool SendInitiateMessage(const SessionDescription* sdesc,
@@ -535,18 +545,13 @@
// Verifies that we are in the appropriate state to receive this message.
bool CheckState(State state, MessageError* error);
- SessionManager *session_manager_;
- bool initiator_;
+ SessionManager* session_manager_;
bool initiate_acked_;
+ std::string local_name_;
std::string initiator_name_;
- std::string content_type_;
+ std::string remote_name_;
SessionClient* client_;
- std::string transport_type_;
TransportParser* transport_parser_;
- // This is transport-specific but required so much by unit tests
- // that it's much easier to put it here.
- bool allow_local_ips_;
- TransportMap transports_;
// Keeps track of what protocol we are speaking.
SignalingProtocol current_protocol_;
diff --git a/talk/p2p/base/stun.cc b/talk/p2p/base/stun.cc
index e324d7e..fab14af 100644
--- a/talk/p2p/base/stun.cc
+++ b/talk/p2p/base/stun.cc
@@ -29,6 +29,7 @@
#include <cstring>
+#include "talk/base/byteorder.h"
#include "talk/base/common.h"
#include "talk/base/logging.h"
@@ -36,18 +37,9 @@
namespace cricket {
-const std::string STUN_ERROR_REASON_BAD_REQUEST = "BAD REQUEST";
-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_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";
-
-const char kStunMagicCookie[] = { '\x21', '\x12', '\xA4', '\x42' };
+const char STUN_ERROR_REASON_BAD_REQUEST[] = "BAD REQUEST";
+const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "STALE CREDENTIALS";
+const char STUN_ERROR_REASON_SERVER_ERROR[] = "SERVER ERROR";
const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
@@ -84,50 +76,54 @@
const StunAddressAttribute*
StunMessage::GetAddress(StunAttributeType type) const {
switch (type) {
- case STUN_ATTR_MAPPED_ADDRESS:
- case STUN_ATTR_RESPONSE_ADDRESS:
- case STUN_ATTR_SOURCE_ADDRESS:
- case STUN_ATTR_CHANGED_ADDRESS:
- case STUN_ATTR_REFLECTED_FROM:
- case STUN_ATTR_ALTERNATE_SERVER:
- case STUN_ATTR_DESTINATION_ADDRESS:
- case STUN_ATTR_SOURCE_ADDRESS2:
- return reinterpret_cast<const StunAddressAttribute*>(GetAttribute(type));
+ case STUN_ATTR_MAPPED_ADDRESS: {
+ // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
+ // missing.
+ const StunAttribute* mapped_address =
+ GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
+ if (!mapped_address)
+ mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
+ }
- default:
- ASSERT(0);
- return 0;
+ case STUN_ATTR_DESTINATION_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS2:
+ case STUN_ATTR_XOR_MAPPED_ADDRESS:
+ return reinterpret_cast<const StunAddressAttribute*>(GetAttribute(type));
+
+ default:
+ ASSERT(0);
+ return NULL;
}
}
const StunUInt32Attribute*
StunMessage::GetUInt32(StunAttributeType type) const {
switch (type) {
- case STUN_ATTR_CHANGE_REQUEST:
- case STUN_ATTR_LIFETIME:
- case STUN_ATTR_BANDWIDTH:
- case STUN_ATTR_OPTIONS:
- return reinterpret_cast<const StunUInt32Attribute*>(GetAttribute(type));
+ case STUN_ATTR_LIFETIME:
+ case STUN_ATTR_BANDWIDTH:
+ case STUN_ATTR_OPTIONS:
+ return reinterpret_cast<const StunUInt32Attribute*>(GetAttribute(type));
- default:
- ASSERT(0);
- return 0;
+ default:
+ ASSERT(0);
+ return NULL;
}
}
const StunByteStringAttribute*
StunMessage::GetByteString(StunAttributeType type) const {
switch (type) {
- case STUN_ATTR_USERNAME:
- case STUN_ATTR_PASSWORD:
- case STUN_ATTR_MESSAGE_INTEGRITY:
- case STUN_ATTR_DATA:
- case STUN_ATTR_MAGIC_COOKIE:
- return reinterpret_cast<const StunByteStringAttribute*>(GetAttribute(type));
+ case STUN_ATTR_USERNAME:
+ case STUN_ATTR_MESSAGE_INTEGRITY:
+ case STUN_ATTR_DATA:
+ case STUN_ATTR_MAGIC_COOKIE:
+ return reinterpret_cast<const StunByteStringAttribute*>(
+ GetAttribute(type));
- default:
- ASSERT(0);
- return 0;
+ default:
+ ASSERT(0);
+ return NULL;
}
}
@@ -141,17 +137,12 @@
GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
}
-const StunTransportPrefsAttribute* StunMessage::GetTransportPrefs() const {
- return reinterpret_cast<const StunTransportPrefsAttribute*>(
- GetAttribute(STUN_ATTR_TRANSPORT_PREFERENCES));
-}
-
const StunAttribute* StunMessage::GetAttribute(StunAttributeType type) const {
for (unsigned i = 0; i < attrs_->size(); i++) {
if ((*attrs_)[i]->type() == type)
return (*attrs_)[i];
}
- return 0;
+ return NULL;
}
bool StunMessage::Read(ByteBuffer* buf) {
@@ -174,8 +165,10 @@
std::string transaction_id;
if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
return false;
- if (magic_cookie != std::string(kStunMagicCookie,
- kStunMagicCookie + kStunMagicCookieLength)) {
+
+ uint32 magic_cookie_int =
+ *reinterpret_cast<const uint32*>(magic_cookie.data());
+ if (talk_base::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
// If magic cookie is invalid it means that the peer implements
// RFC3489 instead of RFC5389.
transaction_id.insert(0, magic_cookie);
@@ -197,18 +190,18 @@
return false;
StunAttribute* attr = StunAttribute::Create(attr_type, attr_length);
- if (!attr || !attr->Read(buf))
- return false;
-
- attrs_->push_back(attr);
+ if (!attr) {
+ // Skip an unknown attribute.
+ if (!buf->Consume(attr_length))
+ return false;
+ } else {
+ if (!attr->Read(buf))
+ return false;
+ attrs_->push_back(attr);
+ }
}
- if (buf->Length() != rest) {
- // fixme: shouldn't be doing this
- LOG(LERROR) << "wrong message length (" << rest << " != " << buf->Length()
- << ")";
- return false;
- }
+ ASSERT(buf->Length() == rest);
return true;
}
@@ -217,7 +210,7 @@
buf->WriteUInt16(type_);
buf->WriteUInt16(length_);
if (!IsLegacy())
- buf->WriteBytes(kStunMagicCookie, kStunMagicCookieLength);
+ buf->WriteUInt32(kStunMagicCookie);
buf->WriteString(transaction_id_);
for (unsigned i = 0; i < attrs_->size(); i++) {
@@ -238,77 +231,72 @@
StunAttribute* StunAttribute::Create(uint16 type, uint16 length) {
switch (type) {
- case STUN_ATTR_MAPPED_ADDRESS:
- case STUN_ATTR_RESPONSE_ADDRESS:
- case STUN_ATTR_SOURCE_ADDRESS:
- case STUN_ATTR_CHANGED_ADDRESS:
- case STUN_ATTR_REFLECTED_FROM:
- case STUN_ATTR_ALTERNATE_SERVER:
- case STUN_ATTR_DESTINATION_ADDRESS:
- case STUN_ATTR_SOURCE_ADDRESS2:
- if (length != StunAddressAttribute::SIZE)
- return 0;
- return new StunAddressAttribute(type);
+ case STUN_ATTR_MAPPED_ADDRESS:
+ case STUN_ATTR_DESTINATION_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS2:
+ // TODO: Addresses may be different size for IPv6
+ // addresses, but we don't support IPv6 yet. Fix address parsing
+ // when IPv6 support is implemented.
+ if (length != StunAddressAttribute::SIZE)
+ return NULL;
+ return new StunAddressAttribute(type);
- case STUN_ATTR_CHANGE_REQUEST:
- case STUN_ATTR_LIFETIME:
- case STUN_ATTR_BANDWIDTH:
- case STUN_ATTR_OPTIONS:
- if (length != StunUInt32Attribute::SIZE)
- return 0;
- return new StunUInt32Attribute(type);
+ case STUN_ATTR_LIFETIME:
+ case STUN_ATTR_BANDWIDTH:
+ case STUN_ATTR_OPTIONS:
+ if (length != StunUInt32Attribute::SIZE)
+ return NULL;
+ return new StunUInt32Attribute(type);
- case STUN_ATTR_USERNAME:
- case STUN_ATTR_PASSWORD:
- case STUN_ATTR_MAGIC_COOKIE:
- return (length % 4 == 0) ? new StunByteStringAttribute(type, length) : 0;
+ case STUN_ATTR_USERNAME:
+ case STUN_ATTR_MAGIC_COOKIE:
+ return (length % 4 == 0) ? new StunByteStringAttribute(type, length) : 0;
- case STUN_ATTR_MESSAGE_INTEGRITY:
- return (length == 20) ? new StunByteStringAttribute(type, length) : 0;
+ case STUN_ATTR_MESSAGE_INTEGRITY:
+ return (length == 20) ? new StunByteStringAttribute(type, length) : 0;
- case STUN_ATTR_DATA:
- return new StunByteStringAttribute(type, length);
+ case STUN_ATTR_DATA:
+ return new StunByteStringAttribute(type, length);
- case STUN_ATTR_ERROR_CODE:
- if (length < StunErrorCodeAttribute::MIN_SIZE)
- return 0;
- return new StunErrorCodeAttribute(type, length);
+ case STUN_ATTR_ERROR_CODE:
+ if (length < StunErrorCodeAttribute::MIN_SIZE)
+ return NULL;
+ return new StunErrorCodeAttribute(type, length);
- case STUN_ATTR_UNKNOWN_ATTRIBUTES:
- return (length % 2 == 0) ? new StunUInt16ListAttribute(type, length) : 0;
+ case STUN_ATTR_UNKNOWN_ATTRIBUTES:
+ return (length % 2 == 0) ? new StunUInt16ListAttribute(type, length) : 0;
- case STUN_ATTR_TRANSPORT_PREFERENCES:
- if ((length != StunTransportPrefsAttribute::SIZE1) &&
- (length != StunTransportPrefsAttribute::SIZE2))
- return 0;
- return new StunTransportPrefsAttribute(type, length);
+ case STUN_ATTR_XOR_MAPPED_ADDRESS:
+ // TODO: Addresses may be different size for IPv6
+ // addresses, but we don't support IPv6 yet. Fix address parsing
+ // when IPv6 support is implemented.
+ if (length != StunAddressAttribute::SIZE)
+ return NULL;
+ return new StunXorAddressAttribute(type);
- default:
- return 0;
+ default:
+ return NULL;
}
}
StunAddressAttribute* StunAttribute::CreateAddress(uint16 type) {
switch (type) {
- case STUN_ATTR_MAPPED_ADDRESS:
- case STUN_ATTR_RESPONSE_ADDRESS:
- case STUN_ATTR_SOURCE_ADDRESS:
- case STUN_ATTR_CHANGED_ADDRESS:
- case STUN_ATTR_REFLECTED_FROM:
- case STUN_ATTR_ALTERNATE_SERVER:
- case STUN_ATTR_DESTINATION_ADDRESS:
- case STUN_ATTR_SOURCE_ADDRESS2:
- return new StunAddressAttribute(type);
+ case STUN_ATTR_MAPPED_ADDRESS:
+ case STUN_ATTR_DESTINATION_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS2:
+ return new StunAddressAttribute(type);
+
+ case STUN_ATTR_XOR_MAPPED_ADDRESS:
+ return new StunXorAddressAttribute(type);
default:
ASSERT(false);
- return 0;
+ return NULL;
}
}
StunUInt32Attribute* StunAttribute::CreateUInt32(uint16 type) {
switch (type) {
- case STUN_ATTR_CHANGE_REQUEST:
case STUN_ATTR_LIFETIME:
case STUN_ATTR_BANDWIDTH:
case STUN_ATTR_OPTIONS:
@@ -316,22 +304,21 @@
default:
ASSERT(false);
- return 0;
+ return NULL;
}
}
StunByteStringAttribute* StunAttribute::CreateByteString(uint16 type) {
switch (type) {
- case STUN_ATTR_USERNAME:
- case STUN_ATTR_PASSWORD:
- case STUN_ATTR_MESSAGE_INTEGRITY:
- case STUN_ATTR_DATA:
- case STUN_ATTR_MAGIC_COOKIE:
- return new StunByteStringAttribute(type, 0);
+ case STUN_ATTR_USERNAME:
+ case STUN_ATTR_MESSAGE_INTEGRITY:
+ case STUN_ATTR_DATA:
+ case STUN_ATTR_MAGIC_COOKIE:
+ return new StunByteStringAttribute(type, 0);
- default:
- ASSERT(false);
- return 0;
+ default:
+ ASSERT(false);
+ return NULL;
}
}
@@ -344,35 +331,70 @@
return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
}
-StunTransportPrefsAttribute* StunAttribute::CreateTransportPrefs() {
- return new StunTransportPrefsAttribute(
- STUN_ATTR_TRANSPORT_PREFERENCES, StunTransportPrefsAttribute::SIZE1);
+StunAddressAttribute::StunAddressAttribute(uint16 type)
+ : StunAttribute(type, SIZE), family_(STUN_ADDRESS_IPV4), port_(0), ip_(0) {
}
-StunAddressAttribute::StunAddressAttribute(uint16 type)
- : StunAttribute(type, SIZE), family_(0), port_(0), ip_(0) {
+void StunAddressAttribute::SetFamily(StunAddressFamily family) {
+ family_ = family;
}
bool StunAddressAttribute::Read(ByteBuffer* buf) {
uint8 dummy;
if (!buf->ReadUInt8(&dummy))
return false;
- if (!buf->ReadUInt8(&family_))
+
+ uint8 family;
+ // We don't expect IPv6 address here because IPv6 addresses would
+ // not pass the attribute size check in StunAttribute::Create().
+ if (!buf->ReadUInt8(&family) || family != STUN_ADDRESS_IPV4) {
return false;
+ }
+ family_ = static_cast<StunAddressFamily>(family);
+
if (!buf->ReadUInt16(&port_))
return false;
+
if (!buf->ReadUInt32(&ip_))
return false;
+
return true;
}
void StunAddressAttribute::Write(ByteBuffer* buf) const {
+ // Only IPv4 address family is currently supported.
+ ASSERT(family_ == STUN_ADDRESS_IPV4);
+
buf->WriteUInt8(0);
buf->WriteUInt8(family_);
buf->WriteUInt16(port_);
buf->WriteUInt32(ip_);
}
+StunXorAddressAttribute::StunXorAddressAttribute(uint16 type)
+ : StunAddressAttribute(type) {
+}
+
+bool StunXorAddressAttribute::Read(ByteBuffer* buf) {
+ if (!StunAddressAttribute::Read(buf))
+ return false;
+
+ SetPort(port() ^ (kStunMagicCookie >> 16));
+ SetIP(ip() ^ kStunMagicCookie);
+
+ return true;
+}
+
+void StunXorAddressAttribute::Write(ByteBuffer* buf) const {
+ // Only IPv4 address family is currently supported.
+ ASSERT(family() == STUN_ADDRESS_IPV4);
+
+ buf->WriteUInt8(0);
+ buf->WriteUInt8(family());
+ buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
+ buf->WriteUInt32(ip() ^ kStunMagicCookie);
+}
+
StunUInt32Attribute::StunUInt32Attribute(uint16 type)
: StunAttribute(type, SIZE), bits_(0) {
}
@@ -524,86 +546,29 @@
buf->WriteUInt16((*attr_types_)[i]);
}
-StunTransportPrefsAttribute::StunTransportPrefsAttribute(
- uint16 type, uint16 length)
- : StunAttribute(type, length), preallocate_(false), prefs_(0), addr_(0) {
-}
-
-StunTransportPrefsAttribute::~StunTransportPrefsAttribute() {
- delete addr_;
-}
-
-void StunTransportPrefsAttribute::SetPreallocateAddress(
- StunAddressAttribute* addr) {
- if (!addr) {
- preallocate_ = false;
- addr_ = 0;
- SetLength(SIZE1);
- } else {
- preallocate_ = true;
- addr_ = addr;
- SetLength(SIZE2);
- }
-}
-
-bool StunTransportPrefsAttribute::Read(ByteBuffer* buf) {
- uint32 val;
- if (!buf->ReadUInt32(&val))
- return false;
-
- if ((val >> 3) != 0)
- LOG(LERROR) << "transport-preferences bits not zero";
-
- preallocate_ = static_cast<bool>((val >> 2) & 0x1);
- prefs_ = (uint8)(val & 0x3);
-
- if (preallocate_ && (prefs_ == 3))
- LOG(LERROR) << "transport-preferences imcompatible P and Typ";
-
- if (!preallocate_) {
- if (length() != StunUInt32Attribute::SIZE)
- return false;
- } else {
- if (length() != StunUInt32Attribute::SIZE + StunAddressAttribute::SIZE)
- return false;
-
- addr_ = new StunAddressAttribute(STUN_ATTR_SOURCE_ADDRESS);
- addr_->Read(buf);
- }
-
- return true;
-}
-
-void StunTransportPrefsAttribute::Write(ByteBuffer* buf) const {
- buf->WriteUInt32((preallocate_ ? 4 : 0) | prefs_);
-
- if (preallocate_)
- addr_->Write(buf);
-}
-
StunMessageType GetStunResponseType(StunMessageType request_type) {
switch (request_type) {
- case STUN_SHARED_SECRET_REQUEST:
- return STUN_SHARED_SECRET_RESPONSE;
- case STUN_ALLOCATE_REQUEST:
- return STUN_ALLOCATE_RESPONSE;
- case STUN_SEND_REQUEST:
- return STUN_SEND_RESPONSE;
- default:
- return STUN_BINDING_RESPONSE;
+ case STUN_SHARED_SECRET_REQUEST:
+ return STUN_SHARED_SECRET_RESPONSE;
+ case STUN_ALLOCATE_REQUEST:
+ return STUN_ALLOCATE_RESPONSE;
+ case STUN_SEND_REQUEST:
+ return STUN_SEND_RESPONSE;
+ default:
+ return STUN_BINDING_RESPONSE;
}
}
StunMessageType GetStunErrorResponseType(StunMessageType request_type) {
switch (request_type) {
- case STUN_SHARED_SECRET_REQUEST:
- return STUN_SHARED_SECRET_ERROR_RESPONSE;
- case STUN_ALLOCATE_REQUEST:
- return STUN_ALLOCATE_ERROR_RESPONSE;
- case STUN_SEND_REQUEST:
- return STUN_SEND_ERROR_RESPONSE;
- default:
- return STUN_BINDING_ERROR_RESPONSE;
+ case STUN_SHARED_SECRET_REQUEST:
+ return STUN_SHARED_SECRET_ERROR_RESPONSE;
+ case STUN_ALLOCATE_REQUEST:
+ return STUN_ALLOCATE_ERROR_RESPONSE;
+ case STUN_SEND_REQUEST:
+ return STUN_SEND_ERROR_RESPONSE;
+ default:
+ return STUN_BINDING_ERROR_RESPONSE;
}
}
diff --git a/talk/p2p/base/stun.h b/talk/p2p/base/stun.h
index cc0e972..efc5f2c 100644
--- a/talk/p2p/base/stun.h
+++ b/talk/p2p/base/stun.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -39,9 +39,6 @@
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,
@@ -61,26 +58,23 @@
// These are the types of attributes defined in STUN & TURN. Next to each is
// the name of the class (T is StunTAttribute) that implements that type.
+//
+// TODO: Some attributes defined in RFC5389 are not
+// implemented yet, particularly REALM, NONCE, SOFTWARE,
+// ALTERNATE-SERVE and FINGEPRINT. Implement them.
enum StunAttributeType {
STUN_ATTR_MAPPED_ADDRESS = 0x0001, // Address
- STUN_ATTR_RESPONSE_ADDRESS = 0x0002, // Address
- STUN_ATTR_CHANGE_REQUEST = 0x0003, // UInt32
- STUN_ATTR_SOURCE_ADDRESS = 0x0004, // Address
- STUN_ATTR_CHANGED_ADDRESS = 0x0005, // Address
STUN_ATTR_USERNAME = 0x0006, // ByteString, multiple of 4 bytes
- STUN_ATTR_PASSWORD = 0x0007, // ByteString, multiple of 4 bytes
STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, // ByteString, 20 bytes
STUN_ATTR_ERROR_CODE = 0x0009, // ErrorCode
STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000a, // UInt16List
- STUN_ATTR_REFLECTED_FROM = 0x000b, // Address
- STUN_ATTR_TRANSPORT_PREFERENCES = 0x000c, // TransportPrefs
STUN_ATTR_LIFETIME = 0x000d, // UInt32
- STUN_ATTR_ALTERNATE_SERVER = 0x000e, // Address
STUN_ATTR_MAGIC_COOKIE = 0x000f, // ByteString, 4 bytes
STUN_ATTR_BANDWIDTH = 0x0010, // UInt32
STUN_ATTR_DESTINATION_ADDRESS = 0x0011, // Address
STUN_ATTR_SOURCE_ADDRESS2 = 0x0012, // Address
STUN_ATTR_DATA = 0x0013, // ByteString
+ STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020, // XorAddress
STUN_ATTR_OPTIONS = 0x8001 // UInt32
};
@@ -96,20 +90,19 @@
STUN_ERROR_GLOBAL_FAILURE = 600
};
-extern const std::string STUN_ERROR_REASON_BAD_REQUEST;
-extern const std::string STUN_ERROR_REASON_UNAUTHORIZED;
-extern const std::string STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE;
-extern const std::string STUN_ERROR_REASON_STALE_CREDENTIALS;
-extern const std::string STUN_ERROR_REASON_INTEGRITY_CHECK_FAILURE;
-extern const std::string STUN_ERROR_REASON_MISSING_USERNAME;
-extern const std::string STUN_ERROR_REASON_USE_TLS;
-extern const std::string STUN_ERROR_REASON_SERVER_ERROR;
-extern const std::string STUN_ERROR_REASON_GLOBAL_FAILURE;
+enum StunAddressFamily {
+ STUN_ADDRESS_IPV4 = 1,
+ STUN_ADDRESS_IPV6 = 2
+};
+
+extern const char STUN_ERROR_REASON_BAD_REQUEST[];
+extern const char STUN_ERROR_REASON_STALE_CREDENTIALS[];
+extern const char STUN_ERROR_REASON_SERVER_ERROR[];
// Following values correspond to RFC5389.
const size_t kStunTransactionIdOffset = 8;
const size_t kStunTransactionIdLength = 12;
-extern const char kStunMagicCookie[4];
+const uint32 kStunMagicCookie = 0x2112A442;
const size_t kStunMagicCookieLength = sizeof(kStunMagicCookie);
// Following value corresponds to an earlier version of STUN from
@@ -217,39 +210,40 @@
public:
explicit StunAddressAttribute(uint16 type);
-#if (_MSC_VER < 1300)
- enum { SIZE = 8 };
-#else
static const uint16 SIZE = 8;
-#endif
- uint8 family() const { return family_; }
+ StunAddressFamily family() const { return family_; }
uint16 port() const { return port_; }
uint32 ip() const { return ip_; }
- void SetFamily(uint8 family) { family_ = family; }
+ void SetFamily(StunAddressFamily family);
void SetIP(uint32 ip) { ip_ = ip; }
void SetPort(uint16 port) { port_ = port; }
- bool Read(talk_base::ByteBuffer* buf);
- void Write(talk_base::ByteBuffer* buf) const;
+ virtual bool Read(talk_base::ByteBuffer* buf);
+ virtual void Write(talk_base::ByteBuffer* buf) const;
private:
- uint8 family_;
+ StunAddressFamily family_;
uint16 port_;
uint32 ip_;
};
+// Implements STUN/TURN attributes that record an Internet address.
+class StunXorAddressAttribute : public StunAddressAttribute {
+public:
+ explicit StunXorAddressAttribute(uint16 type);
+
+ virtual bool Read(talk_base::ByteBuffer* buf);
+ virtual void Write(talk_base::ByteBuffer* buf) const;
+};
+
// Implements STUN/TURN attributs that record a 32-bit integer.
class StunUInt32Attribute : public StunAttribute {
public:
explicit StunUInt32Attribute(uint16 type);
-#if (_MSC_VER < 1300)
- enum { SIZE = 4 };
-#else
static const uint16 SIZE = 4;
-#endif
uint32 value() const { return bits_; }
@@ -294,11 +288,7 @@
StunErrorCodeAttribute(uint16 type, uint16 length);
~StunErrorCodeAttribute();
-#if (_MSC_VER < 1300)
- enum { MIN_SIZE = 4 };
-#else
static const uint16 MIN_SIZE = 4;
-#endif
uint32 error_code() const { return (class_ << 8) | number_; }
uint8 error_class() const { return class_; }
@@ -337,39 +327,6 @@
std::vector<uint16>* attr_types_;
};
-// Implements the TURN TRANSPORT-PREFS attribute, which provides information
-// about the ports to allocate.
-class StunTransportPrefsAttribute : public StunAttribute {
-public:
- StunTransportPrefsAttribute(uint16 type, uint16 length);
- ~StunTransportPrefsAttribute();
-
-#if (_MSC_VER < 1300)
- enum { SIZE1 = 4, SIZE2 = 12 };
-#else
- static const uint16 SIZE1 = 4;
- static const uint16 SIZE2 = 12;
-#endif
-
- bool preallocate() const { return preallocate_; }
- uint8 preference_type() const { return prefs_; }
- const StunAddressAttribute* address() const { return addr_; }
-
- void SetPreferenceType(uint8 prefs) { prefs_ = prefs; }
-
- // Sets the preallocate address to the given value, or if 0 is given, it sets
- // to not preallocate.
- void SetPreallocateAddress(StunAddressAttribute* addr);
-
- bool Read(talk_base::ByteBuffer* buf);
- void Write(talk_base::ByteBuffer* buf) const;
-
-private:
- bool preallocate_;
- uint8 prefs_;
- StunAddressAttribute* addr_;
-};
-
// The special MAGIC-COOKIE attribute is used to distinguish TURN packets from
// other kinds of traffic.
// TODO: This value has nothing to do with STUN. Move it to a
diff --git a/talk/p2p/base/stunport.cc b/talk/p2p/base/stunport.cc
index 2b81fee..ba797ff 100644
--- a/talk/p2p/base/stunport.cc
+++ b/talk/p2p/base/stunport.cc
@@ -122,7 +122,7 @@
uint32 start_time_;
};
-const std::string STUN_PORT_TYPE("stun");
+const char STUN_PORT_TYPE[] = "stun";
StunPort::StunPort(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
diff --git a/talk/p2p/base/stunport.h b/talk/p2p/base/stunport.h
index 7db3b04..26f46a5 100644
--- a/talk/p2p/base/stunport.h
+++ b/talk/p2p/base/stunport.h
@@ -41,7 +41,7 @@
namespace cricket {
-extern const std::string STUN_PORT_TYPE;
+extern const char STUN_PORT_TYPE[];
// Communicates using the address on the outside of a NAT.
class StunPort : public Port {
diff --git a/talk/p2p/base/stunrequest.cc b/talk/p2p/base/stunrequest.cc
index 9c1ada7..f1fd2ac 100644
--- a/talk/p2p/base/stunrequest.cc
+++ b/talk/p2p/base/stunrequest.cc
@@ -78,8 +78,11 @@
for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i)
requests.push_back(i->second);
- for (uint32 i = 0; i < requests.size(); ++i)
- Remove(requests[i]);
+ for (uint32 i = 0; i < requests.size(); ++i) {
+ // StunRequest destructor calls Remove() which deletes requests
+ // from |requests_|.
+ delete requests[i];
+ }
}
bool StunRequestManager::CheckResponse(StunMessage* msg) {
diff --git a/talk/p2p/base/stunserver.cc b/talk/p2p/base/stunserver.cc
index a3c4bde..f34fd2d 100644
--- a/talk/p2p/base/stunserver.cc
+++ b/talk/p2p/base/stunserver.cc
@@ -89,26 +89,18 @@
response.SetTransactionID(msg->transaction_id());
// Tell the user the address that we received their request from.
- StunAddressAttribute* mapped_addr =
- StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
- mapped_addr->SetFamily(1);
+ StunAddressAttribute* mapped_addr;
+ if (!msg->IsLegacy()) {
+ mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ } else {
+ mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ }
mapped_addr->SetPort(remote_addr.port());
mapped_addr->SetIP(remote_addr.ip());
response.AddAttribute(mapped_addr);
- // Tell the user the address that we are sending the response from.
- talk_base::SocketAddress local_addr = socket_->GetLocalAddress();
- StunAddressAttribute* source_addr =
- StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS);
- source_addr->SetFamily(1);
- source_addr->SetPort(local_addr.port());
- source_addr->SetIP(local_addr.ip());
- response.AddAttribute(source_addr);
-
// TODO: Add username and message-integrity.
- // TODO: Add changed-address. (Keep information about three other servers.)
-
SendResponse(response, remote_addr);
}
diff --git a/talk/p2p/base/tcpport.h b/talk/p2p/base/tcpport.h
index fcc4aa2..8345b12 100644
--- a/talk/p2p/base/tcpport.h
+++ b/talk/p2p/base/tcpport.h
@@ -37,7 +37,7 @@
class TCPConnection;
-extern const std::string LOCAL_PORT_TYPE; // type of TCP ports
+extern const char LOCAL_PORT_TYPE[]; // type of TCP ports
// Communicates using a local TCP port.
//
diff --git a/talk/p2p/base/udpport.cc b/talk/p2p/base/udpport.cc
index e7644f4..8355b00 100644
--- a/talk/p2p/base/udpport.cc
+++ b/talk/p2p/base/udpport.cc
@@ -33,7 +33,7 @@
namespace cricket {
-const std::string LOCAL_PORT_TYPE("local");
+const char LOCAL_PORT_TYPE[] = "local";
UDPPort::UDPPort(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
diff --git a/talk/p2p/base/udpport.h b/talk/p2p/base/udpport.h
index 6663dc6..d74d4a3 100644
--- a/talk/p2p/base/udpport.h
+++ b/talk/p2p/base/udpport.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -40,7 +40,7 @@
namespace cricket {
-extern const std::string LOCAL_PORT_TYPE; // type of UDP ports
+extern const char LOCAL_PORT_TYPE[]; // type of UDP ports
// Communicates using a local UDP port.
class UDPPort : public Port {
diff --git a/talk/p2p/client/httpportallocator.cc b/talk/p2p/client/httpportallocator.cc
index 1e5e256..1a25287 100644
--- a/talk/p2p/client/httpportallocator.cc
+++ b/talk/p2p/client/httpportallocator.cc
@@ -94,7 +94,7 @@
const int HttpPortAllocator::kHostPort = 80;
const int HttpPortAllocator::kNumRetries = 5;
-const std::string HttpPortAllocator::kCreateSessionURL = "/create_session";
+const char HttpPortAllocator::kCreateSessionURL[] = "/create_session";
HttpPortAllocator::HttpPortAllocator(
talk_base::NetworkManager* network_manager,
diff --git a/talk/p2p/client/httpportallocator.h b/talk/p2p/client/httpportallocator.h
index 82e9110..e7211c5 100644
--- a/talk/p2p/client/httpportallocator.h
+++ b/talk/p2p/client/httpportallocator.h
@@ -47,7 +47,7 @@
static const int kNumRetries;
// Records the URL that we will GET in order to create a session.
- static const std::string kCreateSessionURL;
+ static const char kCreateSessionURL[];
HttpPortAllocator(talk_base::NetworkManager* network_manager,
const std::string& user_agent);
diff --git a/talk/p2p/client/sessionmanagertask.h b/talk/p2p/client/sessionmanagertask.h
index 2026bf6..d7d9733 100644
--- a/talk/p2p/client/sessionmanagertask.h
+++ b/talk/p2p/client/sessionmanagertask.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -40,9 +40,10 @@
class SessionManagerTask : public buzz::XmppTask {
public:
- SessionManagerTask(TaskParent *parent, SessionManager *session_manager)
- : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE) {
- session_manager_ = session_manager;
+ SessionManagerTask(buzz::XmppTaskParentInterface* parent,
+ SessionManager* session_manager)
+ : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
+ session_manager_(session_manager) {
}
~SessionManagerTask() {
@@ -76,15 +77,15 @@
}
private:
- SessionManager* session_manager_;
-
void OnOutgoingMessage(SessionManager* manager,
const buzz::XmlElement* stanza) {
cricket::SessionSendTask* sender =
- new cricket::SessionSendTask(GetParent(), session_manager_);
+ new cricket::SessionSendTask(parent_, session_manager_);
sender->Send(stanza);
sender->Start();
}
+
+ SessionManager* session_manager_;
};
} // namespace cricket
diff --git a/talk/p2p/client/sessionsendtask.h b/talk/p2p/client/sessionsendtask.h
index 5466e47..ea1e4f0 100644
--- a/talk/p2p/client/sessionsendtask.h
+++ b/talk/p2p/client/sessionsendtask.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -45,7 +45,8 @@
class SessionSendTask : public buzz::XmppTask {
public:
- SessionSendTask(TaskParent *parent, SessionManager *session_manager)
+ SessionSendTask(buzz::XmppTaskParentInterface* parent,
+ SessionManager* session_manager)
: buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
session_manager_(session_manager) {
set_timeout_seconds(15);
@@ -107,7 +108,7 @@
}
virtual int ProcessResponse() {
- if (GetClient()->GetState() != buzz::XmppEngine::STATE_OPEN) {
+ if (parent_->GetState() != buzz::XmppEngine::STATE_OPEN) {
return STATE_DONE;
}
diff --git a/talk/session/phone/call.cc b/talk/session/phone/call.cc
index 5925e30..e01e937 100644
--- a/talk/session/phone/call.cc
+++ b/talk/session/phone/call.cc
@@ -54,6 +54,7 @@
local_renderer_(NULL),
video_(false),
muted_(false),
+ video_muted_(false),
send_to_voicemail_(true),
playing_dtmf_(false) {
}
@@ -94,7 +95,7 @@
SignalSessionState(this, session, Session::STATE_RECEIVEDINITIATE);
}
-void Call::AcceptSession(BaseSession* session,
+void Call::AcceptSession(Session* session,
const cricket::CallOptions& options) {
std::vector<Session *>::iterator it;
it = std::find(sessions_.begin(), sessions_.end(), session);
@@ -105,7 +106,7 @@
}
}
-void Call::RejectSession(BaseSession *session) {
+void Call::RejectSession(Session *session) {
std::vector<Session *>::iterator it;
it = std::find(sessions_.begin(), sessions_.end(), session);
ASSERT(it != sessions_.end());
@@ -114,7 +115,7 @@
session->Reject(STR_TERMINATE_DECLINE);
}
-void Call::TerminateSession(BaseSession *session) {
+void Call::TerminateSession(Session *session) {
ASSERT(std::find(sessions_.begin(), sessions_.end(), session)
!= sessions_.end());
std::vector<Session *>::iterator it;
@@ -165,7 +166,7 @@
}
}
-void Call::SetVideoRenderer(BaseSession *session, uint32 ssrc,
+void Call::SetVideoRenderer(Session *session, uint32 ssrc,
VideoRenderer* renderer) {
VideoChannel *video_channel = GetVideoChannel(session);
if (video_channel) {
@@ -177,14 +178,14 @@
}
}
-void Call::AddVoiceStream(BaseSession *session, uint32 voice_ssrc) {
+void Call::AddVoiceStream(Session *session, uint32 voice_ssrc) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel && voice_ssrc) {
voice_channel->AddStream(voice_ssrc);
}
}
-void Call::AddVideoStream(BaseSession *session, uint32 video_ssrc) {
+void Call::AddVideoStream(Session *session, uint32 video_ssrc) {
VideoChannel *video_channel = GetVideoChannel(session);
if (video_channel && video_ssrc) {
// TODO: Do we need the audio_ssrc here?
@@ -193,14 +194,14 @@
}
}
-void Call::RemoveVoiceStream(BaseSession *session, uint32 voice_ssrc) {
+void Call::RemoveVoiceStream(Session *session, uint32 voice_ssrc) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel && voice_ssrc) {
voice_channel->RemoveStream(voice_ssrc);
}
}
-void Call::RemoveVideoStream(BaseSession *session, uint32 video_ssrc) {
+void Call::RemoveVideoStream(Session *session, uint32 video_ssrc) {
VideoChannel *video_channel = GetVideoChannel(session);
if (video_channel && video_ssrc) {
video_channel->RemoveStream(video_ssrc);
@@ -238,32 +239,39 @@
VoiceChannel *voice_channel = NULL;
VideoChannel *video_channel = NULL;
+ // Generate a random string for the RTCP CNAME, as stated in RFC 6222.
+ // This string is only used for synchronization, and therefore is opaque.
+ std::string rtcp_cname;
+ if (!talk_base::CreateRandomString(16, &rtcp_cname)) {
+ return false;
+ }
+
const ContentInfo* audio_offer = GetFirstAudioContent(offer);
const ContentInfo* video_offer = GetFirstVideoContent(offer);
video_ = (video_offer != NULL);
ASSERT(audio_offer != NULL);
- // Create voice channel and start a media monitor
+ // Create voice channel and start a media monitor.
voice_channel = session_client_->channel_manager()->CreateVoiceChannel(
session, audio_offer->name, video_);
// voice_channel can be NULL in case of NullVoiceEngine.
if (voice_channel) {
voice_channel_map_[session->id()] = voice_channel;
-
+ voice_channel->SetRtcpCName(rtcp_cname);
voice_channel->SignalMediaMonitor.connect(this, &Call::OnMediaMonitor);
voice_channel->StartMediaMonitor(kMediaMonitorInterval);
} else {
succeeded = false;
}
- // If desired, create video channel and start a media monitor
+ // If desired, create video channel and start a media monitor.
if (video_ && succeeded) {
video_channel = session_client_->channel_manager()->CreateVideoChannel(
session, video_offer->name, true, voice_channel);
// video_channel can be NULL in case of NullVideoEngine.
if (video_channel) {
video_channel_map_[session->id()] = video_channel;
-
+ video_channel->SetRtcpCName(rtcp_cname);
video_channel->SignalMediaMonitor.connect(this, &Call::OnMediaMonitor);
video_channel->StartMediaMonitor(kMediaMonitorInterval);
} else {
@@ -272,7 +280,7 @@
}
if (succeeded) {
- // Add session to list, create channels for this session
+ // Add session to list, create channels for this session.
sessions_.push_back(session);
session->SignalState.connect(this, &Call::OnSessionState);
session->SignalError.connect(this, &Call::OnSessionError);
@@ -280,7 +288,7 @@
session->SignalReceivedTerminateReason
.connect(this, &Call::OnReceivedTerminateReason);
- // If this call has the focus, enable this channel
+ // If this call has the focus, enable this channel.
if (session_client_->GetFocus() == this) {
voice_channel->Enable(true);
if (video_channel) {
@@ -288,7 +296,7 @@
}
}
- // Signal client
+ // Signal client.
SignalAddSession(this, session);
}
@@ -331,13 +339,13 @@
talk_base::Thread::Current()->Post(this, MSG_CHECKAUTODESTROY);
}
-VoiceChannel* Call::GetVoiceChannel(BaseSession* session) {
+VoiceChannel* Call::GetVoiceChannel(Session* session) {
std::map<std::string, VoiceChannel *>::iterator it
= voice_channel_map_.find(session->id());
return (it != voice_channel_map_.end()) ? it->second : NULL;
}
-VideoChannel* Call::GetVideoChannel(BaseSession* session) {
+VideoChannel* Call::GetVideoChannel(Session* session) {
std::map<std::string, VideoChannel *>::iterator it
= video_channel_map_.find(session->id());
return (it != video_channel_map_.end()) ? it->second : NULL;
@@ -367,6 +375,16 @@
}
}
+void Call::MuteVideo(bool mute) {
+ video_muted_ = mute;
+ std::vector<Session *>::iterator it;
+ for (it = sessions_.begin(); it != sessions_.end(); it++) {
+ VideoChannel *video_channel = video_channel_map_[(*it)->id()];
+ if (video_channel != NULL)
+ video_channel->Mute(mute);
+ }
+}
+
void Call::PressDTMF(int event) {
// Queue up this digit
if (queued_dtmf_.size() < kMaxDTMFDigits) {
@@ -438,7 +456,7 @@
}
}
-void Call::StartConnectionMonitor(BaseSession *session, int cms) {
+void Call::StartConnectionMonitor(Session *session, int cms) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel) {
voice_channel->SignalConnectionMonitor.connect(this,
@@ -454,7 +472,7 @@
}
}
-void Call::StopConnectionMonitor(BaseSession *session) {
+void Call::StopConnectionMonitor(Session *session) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel) {
voice_channel->StopConnectionMonitor();
@@ -468,7 +486,7 @@
}
}
-void Call::StartAudioMonitor(BaseSession *session, int cms) {
+void Call::StartAudioMonitor(Session *session, int cms) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel) {
voice_channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor);
@@ -476,7 +494,7 @@
}
}
-void Call::StopAudioMonitor(BaseSession *session) {
+void Call::StopAudioMonitor(Session *session) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel) {
voice_channel->StopAudioMonitor();
@@ -484,7 +502,7 @@
}
}
-bool Call::IsAudioMonitorRunning(BaseSession *session) {
+bool Call::IsAudioMonitorRunning(Session *session) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel) {
return voice_channel->IsAudioMonitorRunning();
@@ -493,7 +511,7 @@
}
}
-void Call::StartSpeakerMonitor(BaseSession *session) {
+void Call::StartSpeakerMonitor(Session *session) {
if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) {
if (!IsAudioMonitorRunning(session)) {
StartAudioMonitor(session, kAudioMonitorPollPeriodMillis);
@@ -509,7 +527,7 @@
}
}
-void Call::StopSpeakerMonitor(BaseSession *session) {
+void Call::StopSpeakerMonitor(Session *session) {
if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) {
LOG(LS_WARNING) << "Speaker monitor for session "
<< session->id() << " already stopped.";
@@ -538,7 +556,8 @@
NamedSource source;
source.ssrc = ssrc;
media_sources_.GetAudioSourceBySsrc(ssrc, &source);
- SignalSpeakerMonitor(this, monitor->session(), source);
+ SignalSpeakerMonitor(this, static_cast<Session *>(monitor->session()),
+ source);
}
void Call::OnConnectionMonitor(VideoChannel *channel,
@@ -565,13 +584,13 @@
default:
break;
}
- SignalSessionState(this, session, state);
+ SignalSessionState(this, static_cast<Session *>(session), state);
}
void Call::OnSessionError(BaseSession *session, Session::Error error) {
session_client_->session_manager()->signaling_thread()->Clear(this,
MSG_TERMINATECALL);
- SignalSessionError(this, session, error);
+ SignalSessionError(this, static_cast<Session *>(session), error);
}
void Call::OnSessionInfo(Session *session,
diff --git a/talk/session/phone/call.h b/talk/session/phone/call.h
index 19dc59a..357f884 100644
--- a/talk/session/phone/call.h
+++ b/talk/session/phone/call.h
@@ -39,42 +39,49 @@
#include "talk/session/phone/audiomonitor.h"
#include "talk/session/phone/currentspeakermonitor.h"
#include "talk/session/phone/mediamessages.h"
-#include "talk/session/phone/voicechannel.h"
+#include "talk/session/phone/mediasession.h"
namespace cricket {
class MediaSessionClient;
-struct CallOptions;
+class VoiceChannel;
+class VideoChannel;
+
+// Can't typedef this easily since it's forward declared as struct elsewhere.
+struct CallOptions : public MediaSessionOptions {
+};
class Call : public talk_base::MessageHandler, public sigslot::has_slots<> {
public:
- Call(MediaSessionClient* session_client);
+ explicit Call(MediaSessionClient* session_client);
~Call();
Session *InitiateSession(const buzz::Jid &jid, const CallOptions& options);
- void AcceptSession(BaseSession *session, const CallOptions& options);
- void RejectSession(BaseSession *session);
- void TerminateSession(BaseSession *session);
+ void AcceptSession(Session *session, const CallOptions& options);
+ void RejectSession(Session *session);
+ void TerminateSession(Session *session);
void Terminate();
bool SendViewRequest(Session* session,
const ViewRequest& view_request);
void SetLocalRenderer(VideoRenderer* renderer);
- void SetVideoRenderer(BaseSession *session, uint32 ssrc,
+ void SetVideoRenderer(Session *session, uint32 ssrc,
VideoRenderer* renderer);
- void StartConnectionMonitor(BaseSession *session, int cms);
- void StopConnectionMonitor(BaseSession *session);
- void StartAudioMonitor(BaseSession *session, int cms);
- void StopAudioMonitor(BaseSession *session);
- bool IsAudioMonitorRunning(BaseSession *session);
- void StartSpeakerMonitor(BaseSession *session);
- void StopSpeakerMonitor(BaseSession *session);
+ void StartConnectionMonitor(Session *session, int cms);
+ void StopConnectionMonitor(Session *session);
+ void StartAudioMonitor(Session *session, int cms);
+ void StopAudioMonitor(Session *session);
+ bool IsAudioMonitorRunning(Session *session);
+ void StartSpeakerMonitor(Session *session);
+ void StopSpeakerMonitor(Session *session);
void Mute(bool mute);
+ void MuteVideo(bool mute);
void PressDTMF(int event);
const std::vector<Session *> &sessions();
uint32 id();
bool video() const { return video_; }
bool muted() const { return muted_; }
+ bool video_muted() const { return video_muted_; }
// Setting this to false will cause the call to have a longer timeout and
// for the SignalSetupToCallVoicemail to never fire.
@@ -88,9 +95,9 @@
sigslot::signal0<> SignalSetupToCallVoicemail;
sigslot::signal2<Call *, Session *> SignalAddSession;
sigslot::signal2<Call *, Session *> SignalRemoveSession;
- sigslot::signal3<Call *, BaseSession *, BaseSession::State>
+ sigslot::signal3<Call *, Session *, Session::State>
SignalSessionState;
- sigslot::signal3<Call *, BaseSession *, Session::Error>
+ sigslot::signal3<Call *, Session *, Session::Error>
SignalSessionError;
sigslot::signal3<Call *, Session *, const std::string &>
SignalReceivedTerminateReason;
@@ -101,7 +108,7 @@
// Empty nick on NamedSource means "unknown".
// Ssrc of 0 on NamedSource means "no current speaker".
sigslot::signal3<Call *,
- BaseSession *,
+ Session *,
const NamedSource&> SignalSpeakerMonitor;
sigslot::signal2<Call *, const std::vector<ConnectionInfo> &>
SignalVideoConnectionMonitor;
@@ -130,12 +137,12 @@
void OnConnectionMonitor(VideoChannel *channel,
const std::vector<ConnectionInfo> &infos);
void OnMediaMonitor(VideoChannel *channel, const VideoMediaInfo& info);
- VoiceChannel* GetVoiceChannel(BaseSession* session);
- VideoChannel* GetVideoChannel(BaseSession* session);
- void AddVoiceStream(BaseSession *session, uint32 voice_ssrc);
- void AddVideoStream(BaseSession *session, uint32 video_ssrc);
- void RemoveVoiceStream(BaseSession *session, uint32 voice_ssrc);
- void RemoveVideoStream(BaseSession *session, uint32 video_ssrc);
+ VoiceChannel* GetVoiceChannel(Session* session);
+ VideoChannel* GetVideoChannel(Session* session);
+ void AddVoiceStream(Session *session, uint32 voice_ssrc);
+ void AddVideoStream(Session *session, uint32 video_ssrc);
+ void RemoveVoiceStream(Session *session, uint32 voice_ssrc);
+ void RemoveVideoStream(Session *session, uint32 video_ssrc);
void ContinuePlayDTMF();
uint32 id_;
@@ -148,6 +155,7 @@
VideoRenderer* local_renderer_;
bool video_;
bool muted_;
+ bool video_muted_;
bool send_to_voicemail_;
// DTMF tones have to be queued up so that we don't flood the call. We
diff --git a/talk/session/phone/carbonvideorenderer.cc b/talk/session/phone/carbonvideorenderer.cc
index 9b9a01c..f34fce5 100644
--- a/talk/session/phone/carbonvideorenderer.cc
+++ b/talk/session/phone/carbonvideorenderer.cc
@@ -29,6 +29,7 @@
#include "talk/base/logging.h"
#include "talk/session/phone/videocommon.h"
+#include "talk/session/phone/videoframe.h"
namespace cricket {
diff --git a/talk/session/phone/carbonvideorenderer.h b/talk/session/phone/carbonvideorenderer.h
index 8865349..20cf328 100644
--- a/talk/session/phone/carbonvideorenderer.h
+++ b/talk/session/phone/carbonvideorenderer.h
@@ -33,7 +33,7 @@
#include "talk/base/criticalsection.h"
#include "talk/base/scoped_ptr.h"
-#include "talk/session/phone/mediachannel.h"
+#include "talk/session/phone/videorenderer.h"
namespace cricket {
diff --git a/talk/session/phone/channel.cc b/talk/session/phone/channel.cc
index f0b8e79..32ff5c1 100644
--- a/talk/session/phone/channel.cc
+++ b/talk/session/phone/channel.cc
@@ -72,7 +72,8 @@
packet->length() <= kMaxRtpPacketLen);
}
-BaseChannel::BaseChannel(talk_base::Thread* thread, MediaEngine* media_engine,
+BaseChannel::BaseChannel(talk_base::Thread* thread,
+ MediaEngineInterface* media_engine,
MediaChannel* media_channel, BaseSession* session,
const std::string& content_name,
TransportChannel* transport_channel)
@@ -618,7 +619,7 @@
}
VoiceChannel::VoiceChannel(talk_base::Thread* thread,
- MediaEngine* media_engine,
+ MediaEngineInterface* media_engine,
VoiceMediaChannel* media_channel,
BaseSession* session,
const std::string& content_name,
@@ -685,6 +686,12 @@
return data.result;
}
+bool VoiceChannel::SetOutputScaling(uint32 ssrc, double left, double right) {
+ ScaleVolumeMessageData data(ssrc, left, right);
+ Send(MSG_SCALEVOLUME, &data);
+ return data.result;
+}
+
void VoiceChannel::StartMediaMonitor(int cms) {
media_monitor_.reset(new VoiceMediaMonitor(media_channel(), worker_thread(),
talk_base::Thread::Current()));
@@ -886,6 +893,10 @@
return media_channel()->PressDTMF(digit, playout);
}
+bool VoiceChannel::SetOutputScaling_w(uint32 ssrc, double left, double right) {
+ return media_channel()->SetOutputScaling(ssrc, left, right);
+}
+
void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
case MSG_ADDSTREAM: {
@@ -913,6 +924,12 @@
data->result = PressDTMF_w(data->digit, data->playout);
break;
}
+ case MSG_SCALEVOLUME: {
+ ScaleVolumeMessageData* data =
+ static_cast<ScaleVolumeMessageData*>(pmsg->pdata);
+ data->result = SetOutputScaling_w(data->ssrc, data->left, data->right);
+ break;
+ }
case MSG_CHANNEL_ERROR: {
VoiceChannelErrorMessageData* data =
static_cast<VoiceChannelErrorMessageData*>(pmsg->pdata);
@@ -974,7 +991,7 @@
}
VideoChannel::VideoChannel(talk_base::Thread* thread,
- MediaEngine* media_engine,
+ MediaEngineInterface* media_engine,
VideoMediaChannel* media_channel,
BaseSession* session,
const std::string& content_name,
diff --git a/talk/session/phone/channel.h b/talk/session/phone/channel.h
index baf07a9..157999d 100644
--- a/talk/session/phone/channel.h
+++ b/talk/session/phone/channel.h
@@ -38,8 +38,8 @@
#include "talk/p2p/client/socketmonitor.h"
#include "talk/p2p/base/session.h"
#include "talk/session/phone/audiomonitor.h"
-#include "talk/session/phone/mediaengine.h"
#include "talk/session/phone/mediachannel.h"
+#include "talk/session/phone/mediaengine.h"
#include "talk/session/phone/mediamonitor.h"
#include "talk/session/phone/rtcpmuxfilter.h"
#include "talk/session/phone/srtpfilter.h"
@@ -71,7 +71,8 @@
MSG_RTCPPACKET = 23,
MSG_CHANNEL_ERROR = 24,
MSG_ENABLECPUADAPTATION = 25,
- MSG_DISABLECPUADAPTATION = 26
+ MSG_DISABLECPUADAPTATION = 26,
+ MSG_SCALEVOLUME = 27
};
// BaseChannel contains logic common to voice and video, including
@@ -81,7 +82,7 @@
: public talk_base::MessageHandler, public sigslot::has_slots<>,
public MediaChannel::NetworkInterface {
public:
- BaseChannel(talk_base::Thread* thread, MediaEngine* media_engine,
+ BaseChannel(talk_base::Thread* thread, MediaEngineInterface* media_engine,
MediaChannel* channel, BaseSession* session,
const std::string& content_name,
TransportChannel* transport_channel);
@@ -158,7 +159,7 @@
}
protected:
- MediaEngine* media_engine() const { return media_engine_; }
+ MediaEngineInterface* media_engine() const { return media_engine_; }
virtual MediaChannel* media_channel() const { return media_channel_; }
void set_rtcp_transport_channel(TransportChannel* transport);
bool writable() const { return writable_; }
@@ -262,7 +263,7 @@
talk_base::CriticalSection signal_recv_packet_cs_;
talk_base::Thread *worker_thread_;
- MediaEngine *media_engine_;
+ MediaEngineInterface *media_engine_;
BaseSession *session_;
MediaChannel *media_channel_;
@@ -283,7 +284,7 @@
// and input/output level monitoring.
class VoiceChannel : public BaseChannel {
public:
- VoiceChannel(talk_base::Thread *thread, MediaEngine *media_engine,
+ VoiceChannel(talk_base::Thread *thread, MediaEngineInterface *media_engine,
VoiceMediaChannel *channel, BaseSession *session,
const std::string& content_name, bool rtcp);
~VoiceChannel();
@@ -305,6 +306,7 @@
bool PlayRingbackTone(uint32 ssrc, bool play, bool loop);
bool PressDTMF(int digit, bool playout);
+ bool SetOutputScaling(uint32 ssrc, double left, double right);
// Monitoring functions
sigslot::signal2<VoiceChannel*, const std::vector<ConnectionInfo> &>
@@ -361,6 +363,18 @@
bool playout;
bool result;
};
+ struct ScaleVolumeMessageData : public talk_base::MessageData {
+ ScaleVolumeMessageData(uint32 s, double l, double r)
+ : ssrc(s),
+ left(l),
+ right(r),
+ result(false) {
+ }
+ uint32 ssrc;
+ double left;
+ double right;
+ bool result;
+ };
// overrides from BaseChannel
virtual void OnChannelRead(TransportChannel* channel,
@@ -380,6 +394,7 @@
bool PlayRingbackTone_w(uint32 ssrc, bool play, bool loop);
void HandleEarlyMediaTimeout();
bool PressDTMF_w(int digit, bool playout);
+ bool SetOutputScaling_w(uint32 ssrc, double left, double right);
virtual void OnMessage(talk_base::Message *pmsg);
virtual void OnConnectionMonitorUpdate(
@@ -400,7 +415,7 @@
// VideoChannel is a specialization for video.
class VideoChannel : public BaseChannel {
public:
- VideoChannel(talk_base::Thread *thread, MediaEngine *media_engine,
+ VideoChannel(talk_base::Thread *thread, MediaEngineInterface *media_engine,
VideoMediaChannel *channel, BaseSession *session,
const std::string& content_name, bool rtcp,
VoiceChannel *voice_channel);
diff --git a/talk/session/phone/channelmanager.cc b/talk/session/phone/channelmanager.cc
index 6ff76ce..97419cb 100644
--- a/talk/session/phone/channelmanager.cc
+++ b/talk/session/phone/channelmanager.cc
@@ -37,7 +37,6 @@
#include "talk/base/logging.h"
#include "talk/base/sigslotrepeater.h"
#include "talk/base/stringencode.h"
-#include "talk/session/phone/mediaengine.h"
#include "talk/session/phone/soundclip.h"
namespace cricket {
@@ -132,21 +131,21 @@
};
ChannelManager::ChannelManager(talk_base::Thread* worker_thread)
- : media_engine_(MediaEngine::Create()),
+ : media_engine_(MediaEngineFactory::Create()),
device_manager_(new DeviceManager()),
initialized_(false),
main_thread_(talk_base::Thread::Current()),
worker_thread_(worker_thread),
audio_in_device_(DeviceManager::kDefaultDeviceName),
audio_out_device_(DeviceManager::kDefaultDeviceName),
- audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+ audio_options_(MediaEngineInterface::DEFAULT_AUDIO_OPTIONS),
local_renderer_(NULL),
capturing_(false),
monitoring_(false) {
Construct();
}
-ChannelManager::ChannelManager(MediaEngine* me, DeviceManager* dm,
+ChannelManager::ChannelManager(MediaEngineInterface* me, DeviceManager* dm,
talk_base::Thread* worker_thread)
: media_engine_(me),
device_manager_(dm),
@@ -155,7 +154,7 @@
worker_thread_(worker_thread),
audio_in_device_(DeviceManager::kDefaultDeviceName),
audio_out_device_(DeviceManager::kDefaultDeviceName),
- audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+ audio_options_(MediaEngineInterface::DEFAULT_AUDIO_OPTIONS),
local_renderer_(NULL),
capturing_(false),
monitoring_(false) {
@@ -653,7 +652,10 @@
return true;
}
-void ChannelManager::OnVideoCaptureResult(CaptureResult result) {
+void ChannelManager::OnVideoCaptureResult(VideoCapturer* capturer,
+ CaptureResult result) {
+ // TODO: Check capturer and signal failure only for camera video, not
+ // screencast.
capturing_ = result == CR_SUCCESS;
main_thread_->Post(this, MSG_CAMERASTARTED,
new talk_base::TypedMessageData<CaptureResult>(result));
diff --git a/talk/session/phone/channelmanager.h b/talk/session/phone/channelmanager.h
index 3b34e62..cada408 100644
--- a/talk/session/phone/channelmanager.h
+++ b/talk/session/phone/channelmanager.h
@@ -37,7 +37,6 @@
#include "talk/p2p/base/session.h"
#include "talk/session/phone/voicechannel.h"
#include "talk/session/phone/mediaengine.h"
-#include "talk/session/phone/devicemanager.h"
namespace cricket {
@@ -59,7 +58,8 @@
explicit ChannelManager(talk_base::Thread* worker);
// For testing purposes. Allows the media engine and dev manager to be mocks.
// The ChannelManager takes ownership of these objects.
- ChannelManager(MediaEngine* me, DeviceManager* dm, talk_base::Thread* worker);
+ ChannelManager(MediaEngineInterface* me, DeviceManager* dm,
+ talk_base::Thread* worker);
~ChannelManager();
// Accessors for the worker thread, allowing it to be set after construction,
@@ -175,11 +175,12 @@
CaptureResult SetVideoCapture_w(bool capture);
void SetMediaLogging(bool video, int level, const char* filter);
void SetMediaLogging_w(bool video, int level, const char* filter);
- void OnVideoCaptureResult(CaptureResult result);
+ void OnVideoCaptureResult(VideoCapturer* capturer,
+ CaptureResult result);
void OnMessage(talk_base::Message *message);
talk_base::CriticalSection crit_;
- talk_base::scoped_ptr<MediaEngine> media_engine_;
+ talk_base::scoped_ptr<MediaEngineInterface> media_engine_;
talk_base::scoped_ptr<DeviceManager> device_manager_;
bool initialized_;
talk_base::Thread* main_thread_;
diff --git a/talk/session/phone/devicemanager.cc b/talk/session/phone/devicemanager.cc
index 98aaf42..376b0e9 100644
--- a/talk/session/phone/devicemanager.cc
+++ b/talk/session/phone/devicemanager.cc
@@ -60,11 +60,12 @@
#include "talk/base/logging.h"
#include "talk/base/stringutils.h"
-#include "talk/session/phone/mediaengine.h"
+#include "talk/base/thread.h"
+#include "talk/session/phone/mediacommon.h"
namespace cricket {
// Initialize to empty string.
-const std::string DeviceManager::kDefaultDeviceName;
+const char DeviceManager::kDefaultDeviceName[] = "";
#ifdef WIN32
class DeviceWatcher : public talk_base::Win32Window {
@@ -196,15 +197,15 @@
int DeviceManager::GetCapabilities() {
std::vector<Device> devices;
- int caps = MediaEngine::VIDEO_RECV;
+ int caps = VIDEO_RECV;
if (GetAudioInputDevices(&devices) && !devices.empty()) {
- caps |= MediaEngine::AUDIO_SEND;
+ caps |= AUDIO_SEND;
}
if (GetAudioOutputDevices(&devices) && !devices.empty()) {
- caps |= MediaEngine::AUDIO_RECV;
+ caps |= AUDIO_RECV;
}
if (GetVideoCaptureDevices(&devices) && !devices.empty()) {
- caps |= MediaEngine::VIDEO_SEND;
+ caps |= VIDEO_SEND;
}
return caps;
}
diff --git a/talk/session/phone/devicemanager.h b/talk/session/phone/devicemanager.h
index cd41f6f..04e494e 100644
--- a/talk/session/phone/devicemanager.h
+++ b/talk/session/phone/devicemanager.h
@@ -84,7 +84,7 @@
void OnDevicesChange() { SignalDevicesChange(); }
- static const std::string kDefaultDeviceName;
+ static const char kDefaultDeviceName[];
protected:
virtual bool GetAudioDevice(bool is_input, const std::string& name,
diff --git a/talk/session/phone/filemediaengine.cc b/talk/session/phone/filemediaengine.cc
index 3e7e517..f7a0461 100644
--- a/talk/session/phone/filemediaengine.cc
+++ b/talk/session/phone/filemediaengine.cc
@@ -43,16 +43,16 @@
int FileMediaEngine::GetCapabilities() {
int capabilities = 0;
if (!voice_input_filename_.empty()) {
- capabilities |= MediaEngine::AUDIO_SEND;
+ capabilities |= AUDIO_SEND;
}
if (!voice_output_filename_.empty()) {
- capabilities |= MediaEngine::AUDIO_RECV;
+ capabilities |= AUDIO_RECV;
}
if (!video_input_filename_.empty()) {
- capabilities |= MediaEngine::VIDEO_SEND;
+ capabilities |= VIDEO_SEND;
}
if (!video_output_filename_.empty()) {
- capabilities |= MediaEngine::VIDEO_RECV;
+ capabilities |= VIDEO_RECV;
}
return capabilities;
}
diff --git a/talk/session/phone/filemediaengine.h b/talk/session/phone/filemediaengine.h
index 62e28f9..18f62ca 100644
--- a/talk/session/phone/filemediaengine.h
+++ b/talk/session/phone/filemediaengine.h
@@ -48,7 +48,7 @@
// stream. Depending on the parameters of the constructor, FileMediaEngine can
// act as file voice engine, file video engine, or both. Currently, we use
// only the RTP dump packets. TODO: Enable RTCP packets.
-class FileMediaEngine : public MediaEngine {
+class FileMediaEngine : public MediaEngineInterface {
public:
FileMediaEngine() {}
virtual ~FileMediaEngine() {}
@@ -149,6 +149,12 @@
virtual bool RemoveStream(uint32 ssrc) { return true; }
virtual bool GetActiveStreams(AudioInfo::StreamList* actives) { return true; }
virtual int GetOutputLevel() { return 0; }
+ virtual bool SetOutputScaling(uint32 ssrc, double left, double right) {
+ return false;
+ }
+ virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right) {
+ return false;
+ }
virtual bool SetRingbackTone(const char* buf, int len) { return true; }
virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop) {
return true;
diff --git a/talk/session/phone/gdivideorenderer.cc b/talk/session/phone/gdivideorenderer.cc
index 6afb764..0ee75ab 100644
--- a/talk/session/phone/gdivideorenderer.cc
+++ b/talk/session/phone/gdivideorenderer.cc
@@ -33,6 +33,7 @@
#include "talk/base/thread.h"
#include "talk/base/win32window.h"
#include "talk/session/phone/videocommon.h"
+#include "talk/session/phone/videoframe.h"
namespace cricket {
diff --git a/talk/session/phone/gdivideorenderer.h b/talk/session/phone/gdivideorenderer.h
index d2e363e..7be1cca 100644
--- a/talk/session/phone/gdivideorenderer.h
+++ b/talk/session/phone/gdivideorenderer.h
@@ -30,7 +30,8 @@
#define TALK_SESSION_PHONE_GDIVIDEORENDERER_H_
#ifdef WIN32
-#include "talk/session/phone/mediachannel.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/session/phone/videorenderer.h"
namespace cricket {
diff --git a/talk/session/phone/gtkvideorenderer.cc b/talk/session/phone/gtkvideorenderer.cc
index 059c688..9b17c78 100644
--- a/talk/session/phone/gtkvideorenderer.cc
+++ b/talk/session/phone/gtkvideorenderer.cc
@@ -30,9 +30,21 @@
#include <gtk/gtk.h>
#include "talk/session/phone/videocommon.h"
+#include "talk/session/phone/videoframe.h"
namespace cricket {
+class ScopedGdkLock {
+ public:
+ ScopedGdkLock() {
+ gdk_threads_enter();
+ }
+
+ ~ScopedGdkLock() {
+ gdk_threads_leave();
+ }
+};
+
GtkVideoRenderer::GtkVideoRenderer(int x, int y)
: window_(NULL),
draw_area_(NULL),
@@ -44,28 +56,25 @@
GtkVideoRenderer::~GtkVideoRenderer() {
if (window_) {
- gdk_threads_enter();
+ ScopedGdkLock lock;
gtk_widget_destroy(window_);
// Run the Gtk main loop to tear down the window.
Pump();
- gdk_threads_leave();
}
// Don't need to destroy draw_area_ because it is not top-level, so it is
// implicitly destroyed by the above.
}
bool GtkVideoRenderer::SetSize(int width, int height, int reserved) {
- gdk_threads_enter();
+ ScopedGdkLock lock;
// For the first frame, initialize the GTK window
- if (!window_ && !Initialize(width, height)) {
- gdk_threads_leave();
+ if ((!window_ && !Initialize(width, height)) || IsClosed()) {
return false;
}
image_.reset(new uint8[width * height * 4]);
- gtk_window_resize(GTK_WINDOW(window_), width, height);
- gdk_threads_leave();
+ gtk_widget_set_size_request(draw_area_, width, height);
return true;
}
@@ -74,18 +83,18 @@
return false;
}
- if (!GTK_IS_WINDOW(window_) || !GTK_IS_DRAWING_AREA(draw_area_)) {
- // window was closed
- return false;
- }
-
// convert I420 frame to ABGR format, which is accepted by GTK
frame->ConvertToRgbBuffer(cricket::FOURCC_ABGR,
image_.get(),
frame->GetWidth() * frame->GetHeight() * 4,
frame->GetWidth() * 4);
- gdk_threads_enter();
+ ScopedGdkLock lock;
+
+ if (IsClosed()) {
+ return false;
+ }
+
// draw the ABGR image
gdk_draw_rgb_32_image(draw_area_->window,
draw_area_->style->fg_gc[GTK_STATE_NORMAL],
@@ -99,7 +108,6 @@
// Run the Gtk main loop to refresh the window.
Pump();
- gdk_threads_leave();
return true;
}
@@ -113,6 +121,7 @@
gtk_window_set_position(GTK_WINDOW(window_), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(window_), "Video Renderer");
+ gtk_window_set_resizable(GTK_WINDOW(window_), FALSE);
gtk_widget_set_size_request(draw_area_, width, height);
gtk_container_add(GTK_CONTAINER(window_), draw_area_);
gtk_widget_show_all(window_);
@@ -128,4 +137,17 @@
}
}
+bool GtkVideoRenderer::IsClosed() const {
+ if (!window_) {
+ // Not initialized yet, so hasn't been closed.
+ return false;
+ }
+
+ if (!GTK_IS_WINDOW(window_) || !GTK_IS_DRAWING_AREA(draw_area_)) {
+ return true;
+ }
+
+ return false;
+}
+
} // namespace cricket
diff --git a/talk/session/phone/gtkvideorenderer.h b/talk/session/phone/gtkvideorenderer.h
index 6bdc606..8c36a79 100644
--- a/talk/session/phone/gtkvideorenderer.h
+++ b/talk/session/phone/gtkvideorenderer.h
@@ -29,8 +29,9 @@
#ifndef TALK_SESSION_PHONE_GTKVIDEORENDERER_H_
#define TALK_SESSION_PHONE_GTKVIDEORENDERER_H_
+#include "talk/base/basictypes.h"
#include "talk/base/scoped_ptr.h"
-#include "talk/session/phone/mediachannel.h"
+#include "talk/session/phone/videorenderer.h"
typedef struct _GtkWidget GtkWidget; // forward declaration, defined in gtk.h
@@ -52,6 +53,8 @@
bool Initialize(int width, int height);
// Pump the Gtk event loop until there are no events left.
void Pump();
+ // Check if the window has been closed.
+ bool IsClosed() const;
talk_base::scoped_array<uint8> image_;
GtkWidget* window_;
diff --git a/talk/session/phone/linphonemediaengine.cc b/talk/session/phone/linphonemediaengine.cc
index 161f05b..3188efa 100644
--- a/talk/session/phone/linphonemediaengine.cc
+++ b/talk/session/phone/linphonemediaengine.cc
@@ -96,8 +96,8 @@
int LinphoneMediaEngine::GetCapabilities() {
int capabilities = 0;
- capabilities |= MediaEngine::AUDIO_SEND;
- capabilities |= MediaEngine::AUDIO_RECV;
+ capabilities |= AUDIO_SEND;
+ capabilities |= AUDIO_RECV;
return capabilities;
}
diff --git a/talk/session/phone/linphonemediaengine.h b/talk/session/phone/linphonemediaengine.h
index 81df92b..883580c 100644
--- a/talk/session/phone/linphonemediaengine.h
+++ b/talk/session/phone/linphonemediaengine.h
@@ -48,7 +48,7 @@
namespace cricket {
-class LinphoneMediaEngine : public MediaEngine {
+class LinphoneMediaEngine : public MediaEngineInterface {
public:
LinphoneMediaEngine(const std::string& ringWav, const std::string& callWav);
virtual ~LinphoneMediaEngine() {}
@@ -128,6 +128,12 @@
virtual bool RemoveStream(uint32 ssrc) { return true; }
virtual bool GetActiveStreams(AudioInfo::StreamList* actives) { return true; }
virtual int GetOutputLevel() { return 0; }
+ virtual bool SetOutputScaling(uint32 ssrc, double left, double right) {
+ return false;
+ }
+ virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right) {
+ return false;
+ }
virtual void SetRingbackTone(const char* buf, int len) {}
virtual bool PlayRingbackTone(bool play, bool loop) { return true; }
virtual bool PressDTMF(int event, bool playout) { return true; }
diff --git a/talk/session/phone/mediachannel.h b/talk/session/phone/mediachannel.h
index 7c22b70..aa32671 100644
--- a/talk/session/phone/mediachannel.h
+++ b/talk/session/phone/mediachannel.h
@@ -42,15 +42,29 @@
class Buffer;
}
-namespace flute {
-class MagicCamVideoRenderer;
-}
-
namespace cricket {
+class VideoRenderer;
+
const int kMinRtpHeaderExtensionId = 1;
const int kMaxRtpHeaderExtensionId = 255;
+// A class for playing out soundclips.
+class SoundclipMedia {
+ public:
+ enum SoundclipFlags {
+ SF_LOOP = 1,
+ };
+
+ virtual ~SoundclipMedia() {}
+
+ // Plays a sound out to the speakers with the given audio stream. The stream
+ // must be 16-bit little-endian 16 kHz PCM. If a stream is already playing
+ // on this SoundclipMedia, it is stopped. If clip is NULL, nothing is played.
+ // Returns whether it was successful.
+ virtual bool PlaySound(const char *clip, int len, int flags) = 0;
+};
+
struct RtpHeaderExtension {
RtpHeaderExtension(const std::string& u, int i) : uri(u), id(i) {}
std::string uri;
@@ -253,8 +267,12 @@
virtual bool RemoveStream(uint32 ssrc) = 0;
// Gets current energy levels for all incoming streams.
virtual bool GetActiveStreams(AudioInfo::StreamList* actives) = 0;
- // Get the current energy level for the outgoing stream.
+ // Get the current energy level of the stream sent to the speaker.
virtual int GetOutputLevel() = 0;
+ // Set left and right scale for speaker output volume of the specified ssrc.
+ virtual bool SetOutputScaling(uint32 ssrc, double left, double right) = 0;
+ // Get left and right scale for speaker output volume of the specified ssrc.
+ virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right) = 0;
// Specifies a ringback tone to be played during call setup.
virtual bool SetRingbackTone(const char *buf, int len) = 0;
// Plays or stops the aforementioned ringback tone
@@ -275,179 +293,6 @@
sigslot::signal2<uint32, VoiceMediaChannel::Error> SignalMediaError;
};
-// Represents a YUV420 (a.k.a. I420) video frame.
-class VideoFrame {
- friend class flute::MagicCamVideoRenderer;
-
- public:
- VideoFrame() : rendered_(false) {}
-
- virtual ~VideoFrame() {}
-
- virtual size_t GetWidth() const = 0;
- virtual size_t GetHeight() const = 0;
- virtual const uint8 *GetYPlane() const = 0;
- virtual const uint8 *GetUPlane() const = 0;
- virtual const uint8 *GetVPlane() const = 0;
- virtual uint8 *GetYPlane() = 0;
- virtual uint8 *GetUPlane() = 0;
- virtual uint8 *GetVPlane() = 0;
- virtual int32 GetYPitch() const = 0;
- virtual int32 GetUPitch() const = 0;
- virtual int32 GetVPitch() const = 0;
-
- // For retrieving the aspect ratio of each pixel. Usually this is 1x1, but
- // the aspect_ratio_idc parameter of H.264 can specify non-square pixels.
- virtual size_t GetPixelWidth() const = 0;
- virtual size_t GetPixelHeight() const = 0;
-
- // TODO: Add a fourcc format here and probably combine VideoFrame
- // with CapturedFrame.
- virtual int64 GetElapsedTime() const = 0;
- virtual int64 GetTimeStamp() const = 0;
- virtual void SetElapsedTime(int64 elapsed_time) = 0;
- virtual void SetTimeStamp(int64 time_stamp) = 0;
-
- // Make a copy of the frame. The frame buffer itself may not be copied,
- // in which case both the current and new VideoFrame will share a single
- // reference-counted frame buffer.
- virtual VideoFrame *Copy() const = 0;
-
- // Writes the frame into the given frame buffer, provided that it is of
- // sufficient size. Returns the frame's actual size, regardless of whether
- // it was written or not (like snprintf). If there is insufficient space,
- // nothing is written.
- virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const = 0;
-
- // Converts the I420 data to RGB of a certain type such as ARGB and ABGR.
- // Returns the frame's actual size, regardless of whether it was written or
- // not (like snprintf). Parameters size and pitch_rgb are in units of bytes.
- // If there is insufficient space, nothing is written.
- virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer,
- size_t size, size_t pitch_rgb) const = 0;
-
- // Writes the frame into the given planes, stretched to the given width and
- // height. The parameter "interpolate" controls whether to interpolate or just
- // take the nearest-point. The parameter "crop" controls whether to crop this
- // frame to the aspect ratio of the given dimensions before stretching.
- virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v,
- int32 pitchY, int32 pitchU, int32 pitchV,
- size_t width, size_t height,
- bool interpolate, bool crop) const = 0;
-
- // Writes the frame into the given frame buffer, stretched to the given width
- // and height, provided that it is of sufficient size. Returns the frame's
- // actual size, regardless of whether it was written or not (like snprintf).
- // If there is insufficient space, nothing is written. The parameter
- // "interpolate" controls whether to interpolate or just take the
- // nearest-point. The parameter "crop" controls whether to crop this frame to
- // the aspect ratio of the given dimensions before stretching.
- virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size,
- bool interpolate, bool crop) const = 0;
-
- // Writes the frame into the target VideoFrame, stretched to the size of that
- // frame. The parameter "interpolate" controls whether to interpolate or just
- // take the nearest-point. The parameter "crop" controls whether to crop this
- // frame to the aspect ratio of the target frame before stretching.
- virtual void StretchToFrame(VideoFrame *target, bool interpolate,
- bool crop) const = 0;
-
- // Stretches the frame to the given size, creating a new VideoFrame object to
- // hold it. The parameter "interpolate" controls whether to interpolate or
- // just take the nearest-point. The parameter "crop" controls whether to crop
- // this frame to the aspect ratio of the given dimensions before stretching.
- virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate,
- bool crop) const = 0;
-
- // Size of an I420 image of given dimensions when stored as a frame buffer.
- static size_t SizeOf(size_t w, size_t h) {
- return w * h + ((w + 1) / 2) * ((h + 1) / 2) * 2;
- }
-
- protected:
- // The frame needs to be rendered to magiccam only once.
- // TODO: Remove this flag once magiccam rendering is fully replaced
- // by client3d rendering.
- mutable bool rendered_;
-};
-
-// Simple subclass for use in mocks.
-class NullVideoFrame : public VideoFrame {
- public:
- virtual size_t GetWidth() const { return 0; }
- virtual size_t GetHeight() const { return 0; }
- virtual const uint8 *GetYPlane() const { return NULL; }
- virtual const uint8 *GetUPlane() const { return NULL; }
- virtual const uint8 *GetVPlane() const { return NULL; }
- virtual uint8 *GetYPlane() { return NULL; }
- virtual uint8 *GetUPlane() { return NULL; }
- virtual uint8 *GetVPlane() { return NULL; }
- virtual int32 GetYPitch() const { return 0; }
- virtual int32 GetUPitch() const { return 0; }
- virtual int32 GetVPitch() const { return 0; }
-
- virtual size_t GetPixelWidth() const { return 1; }
- virtual size_t GetPixelHeight() const { return 1; }
- virtual int64 GetElapsedTime() const { return 0; }
- virtual int64 GetTimeStamp() const { return 0; }
- virtual void SetElapsedTime(int64 elapsed_time) {}
- virtual void SetTimeStamp(int64 time_stamp) {}
-
- virtual VideoFrame *Copy() const {
- return NULL;
- }
-
- virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const {
- return 0;
- }
-
- virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer,
- size_t size, size_t pitch_rgb) const {
- return 0;
- }
-
- virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v,
- int32 pitchY, int32 pitchU, int32 pitchV,
- size_t width, size_t height,
- bool interpolate, bool crop) const {
- }
-
- virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size,
- bool interpolate, bool crop) const {
- return 0;
- }
-
- virtual void StretchToFrame(VideoFrame *target, bool interpolate,
- bool crop) const {
- }
-
- virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate,
- bool crop) const {
- return NULL;
- }
-};
-
-// Abstract interface for rendering VideoFrames.
-class VideoRenderer {
- public:
- virtual ~VideoRenderer() {}
- // Called when the video has changed size.
- virtual bool SetSize(int width, int height, int reserved) = 0;
- // Called when a new frame is available for display.
- virtual bool RenderFrame(const VideoFrame *frame) = 0;
-};
-
-// Simple implementation for use in tests.
-class NullVideoRenderer : public VideoRenderer {
- virtual bool SetSize(int width, int height, int reserved) {
- return true;
- }
- // Called when a new frame is available for display.
- virtual bool RenderFrame(const VideoFrame *frame) {
- return true;
- }
-};
-
class VideoMediaChannel : public MediaChannel {
public:
enum Error {
diff --git a/talk/session/phone/mediaengine.cc b/talk/session/phone/mediaengine.cc
index e6b663d..5190232 100644
--- a/talk/session/phone/mediaengine.cc
+++ b/talk/session/phone/mediaengine.cc
@@ -29,23 +29,19 @@
#if defined(HAVE_LINPHONE)
#include "talk/session/phone/linphonemediaengine.h"
-#elif defined(HAVE_WEBRTC)
-#include "talk/session/phone/webrtcvoiceengine.h"
-#include "talk/session/phone/webrtcvideoengine.h"
#else
#endif // HAVE_LINPHONE
namespace cricket {
-MediaEngine* MediaEngine::Create() {
+
+MediaEngineInterface* MediaEngineFactory::Create() {
#if defined(HAVE_LINPHONE)
return new LinphoneMediaEngine("", "");
-#elif defined(HAVE_WEBRTC)
- return new CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine>();
#elif defined(ANDROID)
return AndroidMediaEngineFactory::Create();
#else
return new NullMediaEngine();
-#endif // HAVE_LINPHONE HAVE_WEBRTC ANDROID
+#endif // HAVE_LINPHONE ANDROID HAVE_LMI HAVE_GIPS HAVE_WEBRTC_VOICE/VIDEO
}
}; // namespace cricket
diff --git a/talk/session/phone/mediaengine.h b/talk/session/phone/mediaengine.h
index 4383408..9ea808d 100644
--- a/talk/session/phone/mediaengine.h
+++ b/talk/session/phone/mediaengine.h
@@ -39,53 +39,32 @@
#include "talk/session/phone/codec.h"
#include "talk/session/phone/devicemanager.h"
#include "talk/session/phone/mediachannel.h"
+#include "talk/session/phone/mediacommon.h"
#include "talk/session/phone/videocommon.h"
namespace cricket {
-// A class for playing out soundclips.
-class SoundclipMedia {
+class VideoCapturer;
+
+// MediaEngineInterface is an abstraction of a media engine which can be
+// subclassed to support different media componentry backends.
+// It supports voice and video operations in the same class to facilitate
+// proper synchronization between both media types.
+class MediaEngineInterface {
public:
- enum SoundclipFlags {
- SF_LOOP = 1,
- };
-
- virtual ~SoundclipMedia() {}
-
- // Plays a sound out to the speakers with the given audio stream. The stream
- // must be 16-bit little-endian 16 kHz PCM. If a stream is already playing
- // on this SoundclipMedia, it is stopped. If clip is NULL, nothing is played.
- // Returns whether it was successful.
- virtual bool PlaySound(const char *clip, int len, int flags) = 0;
-};
-
-// MediaEngine is an abstraction of a media engine which can be subclassed
-// to support different media componentry backends. It supports voice and
-// video operations in the same class to facilitate proper synchronization
-// between both media types.
-class MediaEngine {
- public:
- // TODO: Move this to a global location (also used in DeviceManager)
- // Capabilities of the media engine.
- enum Capabilities {
- AUDIO_RECV = 1 << 0,
- AUDIO_SEND = 1 << 1,
- VIDEO_RECV = 1 << 2,
- VIDEO_SEND = 1 << 3,
- };
-
// Bitmask flags for options that may be supported by the media engine
// implementation
enum AudioOptions {
ECHO_CANCELLATION = 1 << 0,
AUTO_GAIN_CONTROL = 1 << 1,
+ NOISE_SUPPRESSION = 1 << 2,
+ TYPING_DETECTION = 1 << 3,
DEFAULT_AUDIO_OPTIONS = ECHO_CANCELLATION | AUTO_GAIN_CONTROL
};
enum VideoOptions {
};
- virtual ~MediaEngine() {}
- static MediaEngine* Create();
+ virtual ~MediaEngineInterface() {}
// Initialization
// Starts the engine.
@@ -147,13 +126,21 @@
virtual void SetVoiceLogging(int min_sev, const char* filter) = 0;
virtual void SetVideoLogging(int min_sev, const char* filter) = 0;
- sigslot::repeater1<CaptureResult> SignalVideoCaptureResult;
+ sigslot::repeater2<VideoCapturer*, CaptureResult>
+ SignalVideoCaptureResult;
};
+
+class MediaEngineFactory {
+ public:
+ static MediaEngineInterface* Create();
+};
+
+
// CompositeMediaEngine constructs a MediaEngine from separate
// voice and video engine classes.
template<class VOICE, class VIDEO>
-class CompositeMediaEngine : public MediaEngine {
+class CompositeMediaEngine : public MediaEngineInterface {
public:
CompositeMediaEngine() {}
virtual ~CompositeMediaEngine() {}
@@ -260,12 +247,16 @@
bool SetDevices(const Device* in_device, const Device* out_device) {
return true;
}
- bool GetOutputVolume(int* level) { *level = 0; return true; }
+ bool GetOutputVolume(int* level) {
+ *level = 0;
+ return true;
+ }
bool SetOutputVolume(int level) { return true; }
int GetInputLevel() { return 0; }
bool SetLocalMonitor(bool enable) { return true; }
const std::vector<AudioCodec>& codecs() { return codecs_; }
void SetLogging(int min_sev, const char* filter) {}
+
private:
std::vector<AudioCodec> codecs_;
};
@@ -291,7 +282,7 @@
CaptureResult SetCapture(bool capture) { return CR_SUCCESS; }
const std::vector<VideoCodec>& codecs() { return codecs_; }
void SetLogging(int min_sev, const char* filter) {}
- sigslot::signal1<CaptureResult> SignalCaptureResult;
+ sigslot::signal2<VideoCapturer*, CaptureResult> SignalCaptureResult;
private:
std::vector<VideoCodec> codecs_;
};
diff --git a/talk/session/phone/mediamonitor.cc b/talk/session/phone/mediamonitor.cc
index 909b536..0160077 100644
--- a/talk/session/phone/mediamonitor.cc
+++ b/talk/session/phone/mediamonitor.cc
@@ -28,7 +28,6 @@
#include "talk/base/common.h"
#include "talk/session/phone/mediamonitor.h"
#include "talk/session/phone/channelmanager.h"
-#include "talk/session/phone/mediaengine.h"
namespace cricket {
diff --git a/talk/session/phone/mediasession.cc b/talk/session/phone/mediasession.cc
new file mode 100644
index 0000000..d70ab16
--- /dev/null
+++ b/talk/session/phone/mediasession.cc
@@ -0,0 +1,307 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/session/phone/mediasession.h"
+
+#include "talk/base/helpers.h"
+#include "talk/base/logging.h"
+#include "talk/p2p/base/constants.h"
+#include "talk/session/phone/channelmanager.h"
+#include "talk/session/phone/cryptoparams.h"
+#include "talk/session/phone/srtpfilter.h"
+#include "talk/xmpp/constants.h"
+
+namespace {
+const char kInline[] = "inline:";
+}
+
+namespace cricket {
+
+static bool CreateCryptoParams(int tag, const std::string& cipher,
+ CryptoParams *out) {
+ std::string key;
+ key.reserve(SRTP_MASTER_KEY_BASE64_LEN);
+
+ if (!talk_base::CreateRandomString(SRTP_MASTER_KEY_BASE64_LEN, &key)) {
+ return false;
+ }
+ out->tag = tag;
+ out->cipher_suite = cipher;
+ out->key_params = kInline;
+ out->key_params += key;
+ return true;
+}
+
+static bool AddCryptoParams(const std::string& cipher_suite,
+ CryptoParamsVec *out) {
+ int size = out->size();
+
+ out->resize(size + 1);
+ return CreateCryptoParams(size, cipher_suite, &out->at(size));
+}
+
+// For audio, HMAC 32 is prefered because of the low overhead.
+static bool GetSupportedAudioCryptos(CryptoParamsVec* cryptos) {
+#ifdef HAVE_SRTP
+ return AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_32, cryptos) &&
+ AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_80, cryptos);
+#else
+ return false;
+#endif
+}
+
+static bool GetSupportedVideoCryptos(CryptoParamsVec* cryptos) {
+#ifdef HAVE_SRTP
+ return AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_80, cryptos);
+#else
+ return false;
+#endif
+}
+
+// For video support only 80-bit SHA1 HMAC. For audio 32-bit HMAC is
+// tolerated because it is low overhead. Pick the crypto in the list
+// that is supported.
+static bool SelectCrypto(const MediaContentDescription* offer,
+ CryptoParams *crypto) {
+ bool audio = offer->type() == MEDIA_TYPE_AUDIO;
+ const CryptoParamsVec& cryptos = offer->cryptos();
+
+ for (CryptoParamsVec::const_iterator i = cryptos.begin();
+ i != cryptos.end(); ++i) {
+ if (CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
+ (CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio)) {
+ return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
+ }
+ }
+ return false;
+}
+
+MediaSessionDescriptionFactory::MediaSessionDescriptionFactory()
+ : secure_(SEC_DISABLED) {
+}
+
+MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
+ ChannelManager* channel_manager)
+ : secure_(SEC_DISABLED) {
+ channel_manager->GetSupportedAudioCodecs(&audio_codecs_);
+ channel_manager->GetSupportedVideoCodecs(&video_codecs_);
+}
+
+SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
+ const MediaSessionOptions& options) {
+ SessionDescription* offer = new SessionDescription();
+
+ if (true) { // TODO: Allow audio to be optional
+ AudioContentDescription* audio = new AudioContentDescription();
+ for (AudioCodecs::const_iterator codec = audio_codecs_.begin();
+ codec != audio_codecs_.end(); ++codec) {
+ audio->AddCodec(*codec);
+ }
+ audio->SortCodecs();
+ audio->set_ssrc(talk_base::CreateRandomNonZeroId());
+ audio->set_rtcp_mux(true);
+ audio->set_lang(lang_);
+
+ if (secure() != SEC_DISABLED) {
+ CryptoParamsVec audio_cryptos;
+ if (GetSupportedAudioCryptos(&audio_cryptos)) {
+ for (CryptoParamsVec::const_iterator crypto = audio_cryptos.begin();
+ crypto != audio_cryptos.end(); ++crypto) {
+ audio->AddCrypto(*crypto);
+ }
+ }
+ if (secure() == SEC_REQUIRED) {
+ if (audio->cryptos().empty()) {
+ return NULL; // Abort, crypto required but none found.
+ }
+ audio->set_crypto_required(true);
+ }
+ }
+
+ offer->AddContent(CN_AUDIO, NS_JINGLE_RTP, audio);
+ }
+
+ // add video codecs, if this is a video call
+ if (options.is_video) {
+ VideoContentDescription* video = new VideoContentDescription();
+ for (VideoCodecs::const_iterator codec = video_codecs_.begin();
+ codec != video_codecs_.end(); ++codec) {
+ video->AddCodec(*codec);
+ }
+
+ video->SortCodecs();
+ video->set_ssrc(talk_base::CreateRandomNonZeroId());
+ video->set_bandwidth(options.video_bandwidth);
+ video->set_rtcp_mux(true);
+
+ if (secure() != SEC_DISABLED) {
+ CryptoParamsVec video_cryptos;
+ if (GetSupportedVideoCryptos(&video_cryptos)) {
+ for (CryptoParamsVec::const_iterator crypto = video_cryptos.begin();
+ crypto != video_cryptos.end(); ++crypto) {
+ video->AddCrypto(*crypto);
+ }
+ }
+ if (secure() == SEC_REQUIRED) {
+ if (video->cryptos().empty()) {
+ return NULL; // Abort, crypto required but none found.
+ }
+ video->set_crypto_required(true);
+ }
+ }
+
+ offer->AddContent(CN_VIDEO, NS_JINGLE_RTP, video);
+ }
+
+ return offer;
+}
+
+SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
+ const SessionDescription* offer, const MediaSessionOptions& options) {
+ // The answer contains the intersection of the codecs in the offer with the
+ // codecs we support, ordered by our local preference. As indicated by
+ // XEP-0167, we retain the same payload ids from the offer in the answer.
+ SessionDescription* accept = new SessionDescription();
+
+ const ContentInfo* audio_content = GetFirstAudioContent(offer);
+ if (audio_content) {
+ const AudioContentDescription* audio_offer =
+ static_cast<const AudioContentDescription*>(audio_content->description);
+ AudioContentDescription* audio_accept = new AudioContentDescription();
+ for (AudioCodecs::const_iterator ours = audio_codecs_.begin();
+ ours != audio_codecs_.end(); ++ours) {
+ for (AudioCodecs::const_iterator theirs = audio_offer->codecs().begin();
+ theirs != audio_offer->codecs().end(); ++theirs) {
+ if (ours->Matches(*theirs)) {
+ AudioCodec negotiated(*ours);
+ negotiated.id = theirs->id;
+ audio_accept->AddCodec(negotiated);
+ }
+ }
+ }
+
+ audio_accept->SortCodecs();
+ audio_accept->set_ssrc(talk_base::CreateRandomNonZeroId());
+ audio_accept->set_rtcp_mux(audio_offer->rtcp_mux());
+
+ if (secure() != SEC_DISABLED) {
+ CryptoParams crypto;
+
+ if (SelectCrypto(audio_offer, &crypto)) {
+ audio_accept->AddCrypto(crypto);
+ }
+ }
+
+ if (audio_accept->cryptos().empty() &&
+ (audio_offer->crypto_required() || secure() == SEC_REQUIRED)) {
+ return NULL; // Fails the session setup.
+ }
+ accept->AddContent(audio_content->name, audio_content->type, audio_accept);
+ }
+
+ const ContentInfo* video_content = GetFirstVideoContent(offer);
+ if (video_content && options.is_video) {
+ const VideoContentDescription* video_offer =
+ static_cast<const VideoContentDescription*>(video_content->description);
+ VideoContentDescription* video_accept = new VideoContentDescription();
+ for (VideoCodecs::const_iterator ours = video_codecs_.begin();
+ ours != video_codecs_.end(); ++ours) {
+ for (VideoCodecs::const_iterator theirs = video_offer->codecs().begin();
+ theirs != video_offer->codecs().end(); ++theirs) {
+ if (ours->Matches(*theirs)) {
+ VideoCodec negotiated(*ours);
+ negotiated.id = theirs->id;
+ video_accept->AddCodec(negotiated);
+ }
+ }
+ }
+
+ video_accept->set_ssrc(talk_base::CreateRandomNonZeroId());
+ video_accept->set_bandwidth(options.video_bandwidth);
+ video_accept->set_rtcp_mux(video_offer->rtcp_mux());
+ video_accept->SortCodecs();
+
+ if (secure() != SEC_DISABLED) {
+ CryptoParams crypto;
+
+ if (SelectCrypto(video_offer, &crypto)) {
+ video_accept->AddCrypto(crypto);
+ }
+ }
+
+ if (video_accept->cryptos().empty() &&
+ (video_offer->crypto_required() || secure() == SEC_REQUIRED)) {
+ return NULL; // Fails the session setup.
+ }
+ accept->AddContent(video_content->name, video_content->type, video_accept);
+ }
+
+ return accept;
+}
+
+static bool IsMediaContent(const ContentInfo* content, MediaType media_type) {
+ if (content == NULL || content->type != NS_JINGLE_RTP) {
+ return false;
+ }
+
+ const MediaContentDescription* media =
+ static_cast<const MediaContentDescription*>(content->description);
+ return media->type() == media_type;
+}
+
+bool IsAudioContent(const ContentInfo* content) {
+ return IsMediaContent(content, MEDIA_TYPE_AUDIO);
+}
+
+bool IsVideoContent(const ContentInfo* content) {
+ return IsMediaContent(content, MEDIA_TYPE_VIDEO);
+}
+
+static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
+ MediaType media_type) {
+ if (sdesc == NULL)
+ return NULL;
+
+ const ContentInfos& contents = sdesc->contents();
+ for (ContentInfos::const_iterator content = contents.begin();
+ content != contents.end(); content++) {
+ if (IsMediaContent(&*content, media_type)) {
+ return &*content;
+ }
+ }
+ return NULL;
+}
+
+const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
+ return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
+}
+
+const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
+ return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
+}
+
+} // namespace cricket
diff --git a/talk/session/phone/mediasession.h b/talk/session/phone/mediasession.h
new file mode 100644
index 0000000..9bfd84f
--- /dev/null
+++ b/talk/session/phone/mediasession.h
@@ -0,0 +1,236 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Types and classes used in media session descriptions.
+
+#ifndef TALK_SESSION_PHONE_MEDIASESSION_H_
+#define TALK_SESSION_PHONE_MEDIASESSION_H_
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include "talk/session/phone/codec.h"
+#include "talk/session/phone/cryptoparams.h"
+#include "talk/session/phone/mediachannel.h"
+#include "talk/p2p/base/sessiondescription.h"
+
+namespace cricket {
+
+class ChannelManager;
+typedef std::vector<AudioCodec> AudioCodecs;
+typedef std::vector<VideoCodec> VideoCodecs;
+typedef std::vector<CryptoParams> CryptoParamsVec;
+
+// SEC_ENABLED and SEC_REQUIRED should only be used if the session
+// was negotiated over TLS, to protect the inline crypto material
+// exchange.
+// SEC_DISABLED: No crypto in outgoing offer and answer. Fail any
+// offer with crypto required.
+// SEC_ENABLED: Crypto in outgoing offer and answer. Fail any offer
+// with unsupported required crypto. Crypto set but not
+// required in outgoing offer.
+// SEC_REQUIRED: Crypto in outgoing offer and answer with
+// required='true'. Fail any offer with no or
+// unsupported crypto (implicit crypto required='true'
+// in the offer.)
+enum SecureMediaPolicy {
+ SEC_DISABLED,
+ SEC_ENABLED,
+ SEC_REQUIRED
+};
+
+// Options to control how session descriptions are generated.
+const int kAutoBandwidth = -1;
+struct MediaSessionOptions {
+ MediaSessionOptions() :
+ is_video(false),
+ is_muc(false),
+ video_bandwidth(kAutoBandwidth) {
+ }
+
+ bool is_video;
+ bool is_muc;
+ // bps. -1 == auto.
+ int video_bandwidth;
+};
+
+enum MediaType {
+ MEDIA_TYPE_AUDIO,
+ MEDIA_TYPE_VIDEO
+};
+
+// "content" (as used in XEP-0166) descriptions for voice and video.
+class MediaContentDescription : public ContentDescription {
+ public:
+ MediaContentDescription()
+ : ssrc_(0),
+ ssrc_set_(false),
+ rtcp_mux_(false),
+ bandwidth_(kAutoBandwidth),
+ crypto_required_(false),
+ rtp_header_extensions_set_(false) {
+ }
+
+ virtual MediaType type() const = 0;
+
+ uint32 ssrc() const { return ssrc_; }
+ bool ssrc_set() const { return ssrc_set_; }
+ void set_ssrc(uint32 ssrc) {
+ ssrc_ = ssrc;
+ ssrc_set_ = true;
+ }
+
+ bool rtcp_mux() const { return rtcp_mux_; }
+ void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; }
+
+ int bandwidth() const { return bandwidth_; }
+ void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; }
+
+ const std::vector<CryptoParams>& cryptos() const { return cryptos_; }
+ void AddCrypto(const CryptoParams& params) {
+ cryptos_.push_back(params);
+ }
+ bool crypto_required() const { return crypto_required_; }
+ void set_crypto_required(bool crypto) {
+ crypto_required_ = crypto;
+ }
+
+ const std::vector<RtpHeaderExtension>& rtp_header_extensions() const {
+ return rtp_header_extensions_;
+ }
+ void AddRtpHeaderExtension(const RtpHeaderExtension& ext) {
+ rtp_header_extensions_.push_back(ext);
+ rtp_header_extensions_set_ = true;
+ }
+ void ClearRtpHeaderExtensions() {
+ rtp_header_extensions_.clear();
+ rtp_header_extensions_set_ = true;
+ }
+ // We can't always tell if an empty list of header extensions is
+ // because the other side doesn't support them, or just isn't hooked up to
+ // signal them. For now we assume an empty list means no signaling, but
+ // provide the ClearRtpHeaderExtensions method to allow "no support" to be
+ // clearly indicated (i.e. when derived from other information).
+ bool rtp_header_extensions_set() const {
+ return rtp_header_extensions_set_;
+ }
+
+ protected:
+ uint32 ssrc_;
+ bool ssrc_set_;
+ bool rtcp_mux_;
+ int bandwidth_;
+ std::vector<CryptoParams> cryptos_;
+ bool crypto_required_;
+ std::vector<RtpHeaderExtension> rtp_header_extensions_;
+ bool rtp_header_extensions_set_;
+};
+
+template <class C>
+class MediaContentDescriptionImpl : public MediaContentDescription {
+ public:
+ struct PreferenceSort {
+ bool operator()(C a, C b) { return a.preference > b.preference; }
+ };
+
+ const std::vector<C>& codecs() const { return codecs_; }
+ void AddCodec(const C& codec) {
+ codecs_.push_back(codec);
+ }
+ void SortCodecs() {
+ std::sort(codecs_.begin(), codecs_.end(), PreferenceSort());
+ }
+
+ private:
+ std::vector<C> codecs_;
+};
+
+class AudioContentDescription : public MediaContentDescriptionImpl<AudioCodec> {
+ public:
+ AudioContentDescription() :
+ conference_mode_(false) {}
+
+ virtual MediaType type() const { return MEDIA_TYPE_AUDIO; }
+
+ bool conference_mode() const { return conference_mode_; }
+ void set_conference_mode(bool enable) {
+ conference_mode_ = enable;
+ }
+
+ const std::string &lang() const { return lang_; }
+ void set_lang(const std::string &lang) { lang_ = lang; }
+
+
+ private:
+ bool conference_mode_;
+ std::string lang_;
+};
+
+class VideoContentDescription : public MediaContentDescriptionImpl<VideoCodec> {
+ public:
+ virtual MediaType type() const { return MEDIA_TYPE_VIDEO; }
+};
+
+// Creates media session descriptions according to the supplied codecs and
+// other fields, as well as the supplied per-call options.
+// When creating answers, performs the appropriate negotiation
+// of the various fields to determine the proper result.
+class MediaSessionDescriptionFactory {
+ public:
+ // Default ctor; use methods below to set configuration.
+ MediaSessionDescriptionFactory();
+ // Helper, to allow configuration to be loaded from a ChannelManager.
+ explicit MediaSessionDescriptionFactory(ChannelManager* manager);
+
+ const AudioCodecs& audio_codecs() const { return audio_codecs_; }
+ void set_audio_codecs(const AudioCodecs& codecs) { audio_codecs_ = codecs; }
+ const VideoCodecs& video_codecs() const { return video_codecs_; }
+ void set_video_codecs(const VideoCodecs& codecs) { video_codecs_ = codecs; }
+ SecureMediaPolicy secure() const { return secure_; }
+ void set_secure(SecureMediaPolicy s) { secure_ = s; }
+
+ SessionDescription* CreateOffer(const MediaSessionOptions& options);
+ SessionDescription* CreateAnswer(const SessionDescription* offer,
+ const MediaSessionOptions& options);
+
+ private:
+ AudioCodecs audio_codecs_;
+ VideoCodecs video_codecs_;
+ SecureMediaPolicy secure_;
+ std::string lang_;
+};
+
+// Convenience functions.
+bool IsAudioContent(const ContentInfo* content);
+bool IsVideoContent(const ContentInfo* content);
+const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc);
+const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc);
+
+} // namespace cricket
+
+#endif // TALK_SESSION_PHONE_MEDIASESSION_H_
diff --git a/talk/session/phone/mediasessionclient.cc b/talk/session/phone/mediasessionclient.cc
index b4d440c..e709479 100644
--- a/talk/session/phone/mediasessionclient.cc
+++ b/talk/session/phone/mediasessionclient.cc
@@ -41,35 +41,30 @@
#include "talk/xmllite/qname.h"
#include "talk/xmllite/xmlconstants.h"
-using namespace talk_base;
-
-namespace {
-const std::string kInline = "inline:";
-}
-
namespace cricket {
-typedef std::vector<CryptoParams> CryptoParamsVec;
-
MediaSessionClient::MediaSessionClient(
const buzz::Jid& jid, SessionManager *manager)
- : jid_(jid), session_manager_(manager), focus_call_(NULL),
+ : jid_(jid),
+ session_manager_(manager),
+ focus_call_(NULL),
channel_manager_(new ChannelManager(session_manager_->worker_thread())),
- secure_(SEC_DISABLED) {
+ desc_factory_(channel_manager_) {
Construct();
}
MediaSessionClient::MediaSessionClient(
const buzz::Jid& jid, SessionManager *manager,
- MediaEngine* media_engine, DeviceManager* device_manager)
- : jid_(jid), session_manager_(manager), focus_call_(NULL),
+ MediaEngineInterface* media_engine, DeviceManager* device_manager)
+ : jid_(jid),
+ session_manager_(manager),
+ focus_call_(NULL),
channel_manager_(new ChannelManager(
media_engine, device_manager, session_manager_->worker_thread())),
- secure_(SEC_DISABLED) {
+ desc_factory_(channel_manager_) {
Construct();
}
-
void MediaSessionClient::Construct() {
// Register ourselves as the handler of audio and video sessions.
session_manager_->AddClient(NS_JINGLE_RTP, this);
@@ -96,257 +91,6 @@
session_manager_->RemoveClient(NS_JINGLE_RTP);
}
-bool CreateCryptoParams(int tag, const std::string& cipher, CryptoParams *out) {
- std::string key;
- key.reserve(SRTP_MASTER_KEY_BASE64_LEN);
-
- if (!CreateRandomString(SRTP_MASTER_KEY_BASE64_LEN, &key)) {
- return false;
- }
- out->tag = tag;
- out->cipher_suite = cipher;
- out->key_params = kInline + key;
- return true;
-}
-
-bool AddCryptoParams(const std::string& cipher_suite, CryptoParamsVec *out) {
- int size = out->size();
-
- out->resize(size + 1);
- return CreateCryptoParams(size, cipher_suite, &out->at(size));
-}
-
-// For audio, HMAC 32 is prefered because of the low overhead.
-bool GetSupportedAudioCryptos(CryptoParamsVec* cryptos) {
-#ifdef HAVE_SRTP
- return AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_32, cryptos) &&
- AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_80, cryptos);
-#else
- return false;
-#endif
-}
-
-bool GetSupportedVideoCryptos(CryptoParamsVec* cryptos) {
-#ifdef HAVE_SRTP
- return AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_80, cryptos);
-#else
- return false;
-#endif
-}
-
-SessionDescription* MediaSessionClient::CreateOffer(
- const CallOptions& options) {
- SessionDescription* offer = new SessionDescription();
- AudioContentDescription* audio = new AudioContentDescription();
-
-
- AudioCodecs audio_codecs;
- channel_manager_->GetSupportedAudioCodecs(&audio_codecs);
- for (AudioCodecs::const_iterator codec = audio_codecs.begin();
- codec != audio_codecs.end(); ++codec) {
- audio->AddCodec(*codec);
- }
- if (options.is_muc) {
- audio->set_ssrc(talk_base::CreateRandomNonZeroId());
- }
- audio->SortCodecs();
-
- if (secure() != SEC_DISABLED) {
- CryptoParamsVec audio_cryptos;
- if (GetSupportedAudioCryptos(&audio_cryptos)) {
- for (CryptoParamsVec::const_iterator crypto = audio_cryptos.begin();
- crypto != audio_cryptos.end(); ++crypto) {
- audio->AddCrypto(*crypto);
- }
- }
- if (secure() == SEC_REQUIRED) {
- if (audio->cryptos().empty()) {
- return NULL; // Abort, crypto required but none found.
- }
- audio->set_crypto_required(true);
- }
- }
-
- offer->AddContent(CN_AUDIO, NS_JINGLE_RTP, audio);
-
- // add video codecs, if this is a video call
- if (options.is_video) {
- VideoContentDescription* video = new VideoContentDescription();
- VideoCodecs video_codecs;
- channel_manager_->GetSupportedVideoCodecs(&video_codecs);
- for (VideoCodecs::const_iterator codec = video_codecs.begin();
- codec != video_codecs.end(); ++codec) {
- video->AddCodec(*codec);
- }
- if (options.is_muc) {
- video->set_ssrc(talk_base::CreateRandomNonZeroId());
- }
- video->set_bandwidth(options.video_bandwidth);
- video->SortCodecs();
-
- if (secure() != SEC_DISABLED) {
- CryptoParamsVec video_cryptos;
- if (GetSupportedVideoCryptos(&video_cryptos)) {
- for (CryptoParamsVec::const_iterator crypto = video_cryptos.begin();
- crypto != video_cryptos.end(); ++crypto) {
- video->AddCrypto(*crypto);
- }
- }
- if (secure() == SEC_REQUIRED) {
- if (video->cryptos().empty()) {
- return NULL; // Abort, crypto required but none found.
- }
- video->set_crypto_required(true);
- }
- }
-
- offer->AddContent(CN_VIDEO, NS_JINGLE_RTP, video);
- }
-
- return offer;
-}
-
-bool IsMediaContent(const ContentInfo* content, MediaType media_type) {
- if (content == NULL || content->type != NS_JINGLE_RTP) {
- return false;
- }
-
- const MediaContentDescription* media =
- static_cast<const MediaContentDescription*>(content->description);
- return media->type() == media_type;
-}
-
-bool IsAudioContent(const ContentInfo* content) {
- return IsMediaContent(content, MEDIA_TYPE_AUDIO);
-}
-
-bool IsVideoContent(const ContentInfo* content) {
- return IsMediaContent(content, MEDIA_TYPE_VIDEO);
-}
-
-const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
- MediaType media_type) {
- if (sdesc == NULL)
- return NULL;
-
- const ContentInfos& contents = sdesc->contents();
- for (ContentInfos::const_iterator content = contents.begin();
- content != contents.end(); content++) {
- if (IsMediaContent(&*content, media_type)) {
- return &*content;
- }
- }
- return NULL;
-}
-
-const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
- return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
-}
-
-const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
- return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
-}
-
-// For video support only 80-bit SHA1 HMAC. For audio 32-bit HMAC is
-// tolerated because it is low overhead. Pick the crypto in the list
-// that is supported.
-bool SelectCrypto(const MediaContentDescription* offer, CryptoParams *crypto) {
- bool audio = offer->type() == MEDIA_TYPE_AUDIO;
- const CryptoParamsVec& cryptos = offer->cryptos();
-
- for (CryptoParamsVec::const_iterator i = cryptos.begin();
- i != cryptos.end(); ++i) {
- if (CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
- (CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio)) {
- return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
- }
- }
- return false;
-}
-
-SessionDescription* MediaSessionClient::CreateAnswer(
- const SessionDescription* offer, const CallOptions& options) {
- // The answer contains the intersection of the codecs in the offer with the
- // codecs we support, ordered by our local preference. As indicated by
- // XEP-0167, we retain the same payload ids from the offer in the answer.
- SessionDescription* accept = new SessionDescription();
-
- const ContentInfo* audio_content = GetFirstAudioContent(offer);
- if (audio_content) {
- const AudioContentDescription* audio_offer =
- static_cast<const AudioContentDescription*>(audio_content->description);
- AudioContentDescription* audio_accept = new AudioContentDescription();
- AudioCodecs audio_codecs;
- channel_manager_->GetSupportedAudioCodecs(&audio_codecs);
- for (AudioCodecs::const_iterator ours = audio_codecs.begin();
- ours != audio_codecs.end(); ++ours) {
- for (AudioCodecs::const_iterator theirs = audio_offer->codecs().begin();
- theirs != audio_offer->codecs().end(); ++theirs) {
- if (ours->Matches(*theirs)) {
- AudioCodec negotiated(*ours);
- negotiated.id = theirs->id;
- audio_accept->AddCodec(negotiated);
- }
- }
- }
-
- audio_accept->SortCodecs();
-
- if (secure() != SEC_DISABLED) {
- CryptoParams crypto;
-
- if (SelectCrypto(audio_offer, &crypto)) {
- audio_accept->AddCrypto(crypto);
- }
- }
-
- if (audio_accept->cryptos().empty() &&
- (audio_offer->crypto_required() || secure() == SEC_REQUIRED)) {
- return NULL; // Fails the session setup.
- }
- accept->AddContent(audio_content->name, audio_content->type, audio_accept);
- }
-
- const ContentInfo* video_content = GetFirstVideoContent(offer);
- if (video_content) {
- const VideoContentDescription* video_offer =
- static_cast<const VideoContentDescription*>(video_content->description);
- VideoContentDescription* video_accept = new VideoContentDescription();
- VideoCodecs video_codecs;
- channel_manager_->GetSupportedVideoCodecs(&video_codecs);
- for (VideoCodecs::const_iterator ours = video_codecs.begin();
- ours != video_codecs.end(); ++ours) {
- for (VideoCodecs::const_iterator theirs = video_offer->codecs().begin();
- theirs != video_offer->codecs().end(); ++theirs) {
- if (ours->Matches(*theirs)) {
- VideoCodec negotiated(*ours);
- negotiated.id = theirs->id;
- video_accept->AddCodec(negotiated);
- }
- }
- }
-
- video_accept->set_bandwidth(options.video_bandwidth);
- video_accept->SortCodecs();
-
- if (secure() != SEC_DISABLED) {
- CryptoParams crypto;
-
- if (SelectCrypto(video_offer, &crypto)) {
- video_accept->AddCrypto(crypto);
- }
- }
-
- if (video_accept->cryptos().empty() &&
- (video_offer->crypto_required() || secure() == SEC_REQUIRED)) {
- return NULL; // Fails the session setup.
- }
- accept->AddContent(video_content->name, video_content->type, video_accept);
- }
-
- return accept;
-}
-
Call *MediaSessionClient::CreateCall() {
Call *call = new Call(this);
calls_[call->id()] = call;
@@ -484,7 +228,7 @@
uint32 parse_ssrc(const std::string& ssrc) {
// TODO: Return an error rather than defaulting to 0.
uint32 default_ssrc = 0U;
- return FromString(default_ssrc, ssrc);
+ return talk_base::FromString(default_ssrc, ssrc);
}
void ParseGingleSsrc(const buzz::XmlElement* parent_elem,
@@ -561,7 +305,7 @@
MediaContentDescription* media) {
const buzz::XmlElement* bw_elem = GetXmlChild(parent_elem, LN_BANDWIDTH);
int bandwidth_kbps;
- if (bw_elem && FromString(bw_elem->BodyText(), &bandwidth_kbps)) {
+ if (bw_elem && talk_base::FromString(bw_elem->BodyText(), &bandwidth_kbps)) {
if (bandwidth_kbps >= 0) {
media->set_bandwidth(bandwidth_kbps * 1000);
}
@@ -1000,7 +744,10 @@
elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
}
- // TODO: Figure out how to integrate SSRC into Jingle.
+ if (audio->rtcp_mux()) {
+ elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX));
+ }
+
return elem;
}
@@ -1022,12 +769,15 @@
elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
}
+ if (video->rtcp_mux()) {
+ elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX));
+ }
+
if (video->bandwidth() != kAutoBandwidth) {
elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH,
video->bandwidth()));
}
- // TODO: Figure out how to integrate SSRC into Jingle.
return elem;
}
diff --git a/talk/session/phone/mediasessionclient.h b/talk/session/phone/mediasessionclient.h
index 07fc258..4616589 100644
--- a/talk/session/phone/mediasessionclient.h
+++ b/talk/session/phone/mediasessionclient.h
@@ -35,6 +35,7 @@
#include "talk/session/phone/call.h"
#include "talk/session/phone/channelmanager.h"
#include "talk/session/phone/cryptoparams.h"
+#include "talk/session/phone/mediasession.h"
#include "talk/base/sigslot.h"
#include "talk/base/sigslotrepeater.h"
#include "talk/base/messagequeue.h"
@@ -47,53 +48,24 @@
namespace cricket {
class Call;
-class SessionDescription;
-typedef std::vector<AudioCodec> AudioCodecs;
-typedef std::vector<VideoCodec> VideoCodecs;
-// SEC_ENABLED and SEC_REQUIRED should only be used if the session
-// was negotiated over TLS, to protect the inline crypto material
-// exchange.
-// SEC_DISABLED: No crypto in outgoing offer and answer. Fail any
-// offer with crypto required.
-// SEC_ENABLED: Crypto in outgoing offer and answer. Fail any offer
-// with unsupported required crypto. Crypto set but not
-// required in outgoing offer.
-// SEC_REQUIRED: Crypto in outgoing offer and answer with
-// required='true'. Fail any offer with no or
-// unsupported crypto (implicit crypto required='true'
-// in the offer.)
-enum SecureMediaPolicy {SEC_DISABLED, SEC_ENABLED, SEC_REQUIRED};
-
-const int kAutoBandwidth = -1;
-
-struct CallOptions {
- CallOptions() :
- is_video(false),
- is_muc(false),
- video_bandwidth(kAutoBandwidth) {
- }
-
- bool is_video;
- bool is_muc;
- // bps. -1 == auto.
- int video_bandwidth;
-};
-
-class MediaSessionClient: public SessionClient, public sigslot::has_slots<> {
+class MediaSessionClient : public SessionClient, public sigslot::has_slots<> {
public:
-
MediaSessionClient(const buzz::Jid& jid, SessionManager *manager);
// Alternative constructor, allowing injection of media_engine
// and device_manager.
MediaSessionClient(const buzz::Jid& jid, SessionManager *manager,
- MediaEngine* media_engine, DeviceManager* device_manager);
+ MediaEngineInterface* media_engine,
+ DeviceManager* device_manager);
~MediaSessionClient();
const buzz::Jid &jid() const { return jid_; }
SessionManager* session_manager() const { return session_manager_; }
ChannelManager* channel_manager() const { return channel_manager_; }
+ SecureMediaPolicy secure() const { return desc_factory_.secure(); }
+ void set_secure(SecureMediaPolicy s) { desc_factory_.set_secure(s); }
+
int GetCapabilities() { return channel_manager_->GetCapabilities(); }
Call *CreateCall();
@@ -125,18 +97,19 @@
return channel_manager_->SetVideoOptions(cam_device);
}
+ SessionDescription* CreateOffer(const CallOptions& options) {
+ return desc_factory_.CreateOffer(options);
+ }
+ SessionDescription* CreateAnswer(const SessionDescription* offer,
+ const CallOptions& options) {
+ return desc_factory_.CreateAnswer(offer, options);
+ }
+
sigslot::signal2<Call *, Call *> SignalFocus;
sigslot::signal1<Call *> SignalCallCreate;
sigslot::signal1<Call *> SignalCallDestroy;
sigslot::repeater0<> SignalDevicesChange;
- SessionDescription* CreateOffer(const CallOptions& options);
- SessionDescription* CreateAnswer(const SessionDescription* offer,
- const CallOptions& options);
-
- SecureMediaPolicy secure() const { return secure_; }
- void set_secure(SecureMediaPolicy s) { secure_ = s; }
-
private:
void Construct();
void OnSessionCreate(Session *session, bool received_initiate);
@@ -156,134 +129,12 @@
SessionManager* session_manager_;
Call *focus_call_;
ChannelManager *channel_manager_;
+ MediaSessionDescriptionFactory desc_factory_;
std::map<uint32, Call *> calls_;
std::map<std::string, Call *> session_map_;
- SecureMediaPolicy secure_;
friend class Call;
};
-enum MediaType {
- MEDIA_TYPE_AUDIO,
- MEDIA_TYPE_VIDEO
-};
-
-class MediaContentDescription : public ContentDescription {
- public:
- MediaContentDescription()
- : ssrc_(0),
- ssrc_set_(false),
- rtcp_mux_(false),
- bandwidth_(kAutoBandwidth),
- crypto_required_(false),
- rtp_header_extensions_set_(false) {
- }
-
- virtual MediaType type() const = 0;
-
- uint32 ssrc() const { return ssrc_; }
- bool ssrc_set() const { return ssrc_set_; }
- void set_ssrc(uint32 ssrc) {
- ssrc_ = ssrc;
- ssrc_set_ = true;
- }
-
- bool rtcp_mux() const { return rtcp_mux_; }
- void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; }
-
- int bandwidth() const { return bandwidth_; }
- void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; }
-
- const std::vector<CryptoParams>& cryptos() const { return cryptos_; }
- void AddCrypto(const CryptoParams& params) {
- cryptos_.push_back(params);
- }
- bool crypto_required() const { return crypto_required_; }
- void set_crypto_required(bool crypto) {
- crypto_required_ = crypto;
- }
-
- const std::vector<RtpHeaderExtension>& rtp_header_extensions() const {
- return rtp_header_extensions_;
- }
- void AddRtpHeaderExtension(const RtpHeaderExtension& ext) {
- rtp_header_extensions_.push_back(ext);
- rtp_header_extensions_set_ = true;
- }
- void ClearRtpHeaderExtensions() {
- rtp_header_extensions_.clear();
- rtp_header_extensions_set_ = true;
- }
- // We can't always tell if an empty list of header extensions is
- // because the other side doesn't support them, or just isn't hooked up to
- // signal them. For now we assume an empty list means no signaling, but
- // provide the ClearRtpHeaderExtensions method to allow "no support" to be
- // clearly indicated (i.e. when derived from other information).
- bool rtp_header_extensions_set() const {
- return rtp_header_extensions_set_;
- }
-
- protected:
- uint32 ssrc_;
- bool ssrc_set_;
- bool rtcp_mux_;
- int bandwidth_;
- std::vector<CryptoParams> cryptos_;
- bool crypto_required_;
- std::vector<RtpHeaderExtension> rtp_header_extensions_;
- bool rtp_header_extensions_set_;
-};
-
-template <class C>
-class MediaContentDescriptionImpl : public MediaContentDescription {
- public:
- struct PreferenceSort {
- bool operator()(C a, C b) { return a.preference > b.preference; }
- };
-
- const std::vector<C>& codecs() const { return codecs_; }
- void AddCodec(const C& codec) {
- codecs_.push_back(codec);
- }
- void SortCodecs() {
- std::sort(codecs_.begin(), codecs_.end(), PreferenceSort());
- }
-
- private:
- std::vector<C> codecs_;
-};
-
-class AudioContentDescription : public MediaContentDescriptionImpl<AudioCodec> {
- public:
- AudioContentDescription() :
- conference_mode_(false) {}
-
- virtual MediaType type() const { return MEDIA_TYPE_AUDIO; }
-
- bool conference_mode() const { return conference_mode_; }
- void set_conference_mode(bool enable) {
- conference_mode_ = enable;
- }
-
- const std::string &lang() const { return lang_; }
- void set_lang(const std::string &lang) { lang_ = lang; }
-
-
- private:
- bool conference_mode_;
- std::string lang_;
-};
-
-class VideoContentDescription : public MediaContentDescriptionImpl<VideoCodec> {
- public:
- virtual MediaType type() const { return MEDIA_TYPE_VIDEO; }
-};
-
-// Convenience functions.
-bool IsAudioContent(const ContentInfo* content);
-bool IsVideoContent(const ContentInfo* content);
-const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc);
-const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc);
-
} // namespace cricket
#endif // TALK_SESSION_PHONE_MEDIASESSIONCLIENT_H_
diff --git a/talk/session/phone/rtpdump.cc b/talk/session/phone/rtpdump.cc
index 6358399..65381fd 100644
--- a/talk/session/phone/rtpdump.cc
+++ b/talk/session/phone/rtpdump.cc
@@ -38,8 +38,7 @@
namespace cricket {
-const std::string RtpDumpFileHeader::kFirstLine =
- "#!rtpplay1.0 0.0.0.0/0\n";
+const char RtpDumpFileHeader::kFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n";
RtpDumpFileHeader::RtpDumpFileHeader(uint32 start_ms, uint32 s, uint16 p)
: start_sec(start_ms / 1000),
@@ -296,7 +295,12 @@
packet_filter_(PF_ALL),
file_header_written_(false),
start_time_ms_(talk_base::Time()) {
- }
+}
+
+void RtpDumpWriter::set_packet_filter(int filter) {
+ packet_filter_ = filter;
+ LOG(LS_INFO) << "RtpDumpWriter set_packet_filter to " << packet_filter_;
+}
uint32 RtpDumpWriter::GetElapsedTime() const {
return talk_base::TimeSince(start_time_ms_);
@@ -304,8 +308,8 @@
talk_base::StreamResult RtpDumpWriter::WriteFileHeader() {
talk_base::StreamResult res = stream_->WriteAll(
- RtpDumpFileHeader::kFirstLine.c_str(),
- RtpDumpFileHeader::kFirstLine.size(), NULL, NULL);
+ RtpDumpFileHeader::kFirstLine,
+ strlen(RtpDumpFileHeader::kFirstLine), NULL, NULL);
if (res != talk_base::SR_SUCCESS) {
return res;
}
diff --git a/talk/session/phone/rtpdump.h b/talk/session/phone/rtpdump.h
index 6b9f5a0..57138b8 100644
--- a/talk/session/phone/rtpdump.h
+++ b/talk/session/phone/rtpdump.h
@@ -61,7 +61,7 @@
RtpDumpFileHeader(uint32 start_ms, uint32 s, uint16 p);
void WriteToByteBuffer(talk_base::ByteBuffer* buf);
- static const std::string kFirstLine;
+ static const char kFirstLine[];
static const size_t kHeaderLength = 16;
uint32 start_sec; // start of recording, the seconds part.
uint32 start_usec; // start of recording, the microseconds part.
@@ -181,10 +181,7 @@
explicit RtpDumpWriter(talk_base::StreamInterface* stream);
// Filter to control what packets we actually record.
- void set_packet_filter(int filter) {
- packet_filter_ = filter;
- }
-
+ void set_packet_filter(int 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) {
diff --git a/talk/session/phone/srtpfilter.cc b/talk/session/phone/srtpfilter.cc
index 3b46e57..b3578e1 100644
--- a/talk/session/phone/srtpfilter.cc
+++ b/talk/session/phone/srtpfilter.cc
@@ -76,9 +76,8 @@
namespace cricket {
-const std::string& CS_DEFAULT = CS_AES_CM_128_HMAC_SHA1_80;
-const std::string CS_AES_CM_128_HMAC_SHA1_80 = "AES_CM_128_HMAC_SHA1_80";
-const std::string CS_AES_CM_128_HMAC_SHA1_32 = "AES_CM_128_HMAC_SHA1_32";
+const char CS_AES_CM_128_HMAC_SHA1_80[] = "AES_CM_128_HMAC_SHA1_80";
+const char CS_AES_CM_128_HMAC_SHA1_32[] = "AES_CM_128_HMAC_SHA1_32";
const int SRTP_MASTER_KEY_BASE64_LEN = SRTP_MASTER_KEY_LEN * 4 / 3;
#ifndef HAVE_SRTP
@@ -95,6 +94,7 @@
#endif // !HAVE_SRTP
void EnableSrtpDebugging() {
+#ifdef HAVE_SRTP
#ifdef _DEBUG
debug_on(mod_srtp);
debug_on(mod_auth);
@@ -105,6 +105,7 @@
// debug_on(mod_aes_cbc);
// debug_on(mod_hmac);
#endif
+#endif // HAVE_SRTP
}
SrtpFilter::SrtpFilter()
diff --git a/talk/session/phone/srtpfilter.h b/talk/session/phone/srtpfilter.h
index a03b50f..409a3a9 100644
--- a/talk/session/phone/srtpfilter.h
+++ b/talk/session/phone/srtpfilter.h
@@ -50,11 +50,10 @@
// Cipher suite to use for SRTP. Typically a 80-bit HMAC will be used, except
// in applications (voice) where the additional bandwidth may be significant.
// A 80-bit HMAC is always used for SRTCP.
-extern const std::string& CS_DEFAULT;
// 128-bit AES with 80-bit SHA-1 HMAC.
-extern const std::string CS_AES_CM_128_HMAC_SHA1_80;
+extern const char CS_AES_CM_128_HMAC_SHA1_80[];
// 128-bit AES with 32-bit SHA-1 HMAC.
-extern const std::string CS_AES_CM_128_HMAC_SHA1_32;
+extern const char CS_AES_CM_128_HMAC_SHA1_32[];
// Key is 128 bits and salt is 112 bits == 30 bytes. B64 bloat => 40 bytes.
extern const int SRTP_MASTER_KEY_BASE64_LEN;
diff --git a/talk/session/phone/videocommon.h b/talk/session/phone/videocommon.h
index ff8e8de..27a2e90 100644
--- a/talk/session/phone/videocommon.h
+++ b/talk/session/phone/videocommon.h
@@ -89,6 +89,7 @@
FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'), // Alias for UYVY
FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'), // Alias for UYVY
FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'), // Alias for MJPG
+ FOURCC_DMB1 = FOURCC('d', 'm', 'b', '1'), // Alias for MJPG on Mac
FOURCC_BA81 = FOURCC('B', 'A', '8', '1'), // Alias for BGGR
FOURCC_RGB3 = FOURCC('R', 'G', 'B', '3'), // Alias for RAW
FOURCC_BGR3 = FOURCC('B', 'G', 'R', '3'), // Alias for 24BG
diff --git a/talk/session/phone/videoframe.h b/talk/session/phone/videoframe.h
new file mode 100644
index 0000000..3fa533e
--- /dev/null
+++ b/talk/session/phone/videoframe.h
@@ -0,0 +1,149 @@
+/*
+ * libjingle
+ * Copyright 2004, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_SESSION_PHONE_VIDEOFRAME_H_
+#define TALK_SESSION_PHONE_VIDEOFRAME_H_
+
+#include "talk/base/basictypes.h"
+
+namespace flute {
+class MagicCamVideoRenderer;
+}
+
+namespace cricket {
+
+// Represents a YUV420 (a.k.a. I420) video frame.
+class VideoFrame {
+ friend class flute::MagicCamVideoRenderer;
+
+ public:
+ VideoFrame() : rendered_(false) {}
+
+ virtual ~VideoFrame() {}
+
+ virtual size_t GetWidth() const = 0;
+ virtual size_t GetHeight() const = 0;
+ size_t GetChromaWidth() const { return (GetWidth() + 1) / 2; }
+ size_t GetChromaHeight() const { return (GetHeight() + 1) / 2; }
+ virtual const uint8 *GetYPlane() const = 0;
+ virtual const uint8 *GetUPlane() const = 0;
+ virtual const uint8 *GetVPlane() const = 0;
+ virtual uint8 *GetYPlane() = 0;
+ virtual uint8 *GetUPlane() = 0;
+ virtual uint8 *GetVPlane() = 0;
+ virtual int32 GetYPitch() const = 0;
+ virtual int32 GetUPitch() const = 0;
+ virtual int32 GetVPitch() const = 0;
+
+ // For retrieving the aspect ratio of each pixel. Usually this is 1x1, but
+ // the aspect_ratio_idc parameter of H.264 can specify non-square pixels.
+ virtual size_t GetPixelWidth() const = 0;
+ virtual size_t GetPixelHeight() const = 0;
+
+ // TODO: Add a fourcc format here and probably combine VideoFrame
+ // with CapturedFrame.
+ virtual int64 GetElapsedTime() const = 0;
+ virtual int64 GetTimeStamp() const = 0;
+ virtual void SetElapsedTime(int64 elapsed_time) = 0;
+ virtual void SetTimeStamp(int64 time_stamp) = 0;
+
+ // Make a shallow copy of the frame. The frame buffer itself is not copied.
+ // Both the current and new VideoFrame will share a single reference-counted
+ // frame buffer.
+ virtual VideoFrame *Copy() const = 0;
+
+ // Since VideoFrame supports shallow copy and the internal frame buffer might
+ // be shared, in case VideoFrame needs exclusive access of the frame buffer,
+ // user can call MakeExclusive() to make sure the frame buffer is exclusive
+ // accessable to the current object. This might mean a deep copy of the frame
+ // buffer if it is currently shared by other objects.
+ virtual bool MakeExclusive() = 0;
+
+ // Writes the frame into the given frame buffer, provided that it is of
+ // sufficient size. Returns the frame's actual size, regardless of whether
+ // it was written or not (like snprintf). If there is insufficient space,
+ // nothing is written.
+ virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const = 0;
+
+ // Converts the I420 data to RGB of a certain type such as ARGB and ABGR.
+ // Returns the frame's actual size, regardless of whether it was written or
+ // not (like snprintf). Parameters size and pitch_rgb are in units of bytes.
+ // If there is insufficient space, nothing is written.
+ virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer,
+ size_t size, size_t pitch_rgb) const = 0;
+
+ // Writes the frame into the given planes, stretched to the given width and
+ // height. The parameter "interpolate" controls whether to interpolate or just
+ // take the nearest-point. The parameter "crop" controls whether to crop this
+ // frame to the aspect ratio of the given dimensions before stretching.
+ virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v,
+ int32 pitchY, int32 pitchU, int32 pitchV,
+ size_t width, size_t height,
+ bool interpolate, bool crop) const = 0;
+
+ // Writes the frame into the given frame buffer, stretched to the given width
+ // and height, provided that it is of sufficient size. Returns the frame's
+ // actual size, regardless of whether it was written or not (like snprintf).
+ // If there is insufficient space, nothing is written. The parameter
+ // "interpolate" controls whether to interpolate or just take the
+ // nearest-point. The parameter "crop" controls whether to crop this frame to
+ // the aspect ratio of the given dimensions before stretching.
+ virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size,
+ bool interpolate, bool crop) const = 0;
+
+ // Writes the frame into the target VideoFrame, stretched to the size of that
+ // frame. The parameter "interpolate" controls whether to interpolate or just
+ // take the nearest-point. The parameter "crop" controls whether to crop this
+ // frame to the aspect ratio of the target frame before stretching.
+ virtual void StretchToFrame(VideoFrame *target, bool interpolate,
+ bool crop) const = 0;
+
+ // Stretches the frame to the given size, creating a new VideoFrame object to
+ // hold it. The parameter "interpolate" controls whether to interpolate or
+ // just take the nearest-point. The parameter "crop" controls whether to crop
+ // this frame to the aspect ratio of the given dimensions before stretching.
+ virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate,
+ bool crop) const = 0;
+
+ // Set the video frame to black.
+ bool SetToBlack();
+
+ // Size of an I420 image of given dimensions when stored as a frame buffer.
+ static size_t SizeOf(size_t w, size_t h) {
+ return w * h + ((w + 1) / 2) * ((h + 1) / 2) * 2;
+ }
+
+ protected:
+ // The frame needs to be rendered to magiccam only once.
+ // TODO: Remove this flag once magiccam rendering is fully replaced
+ // by client3d rendering.
+ mutable bool rendered_;
+};
+
+} // namespace cricket
+
+#endif // TALK_SESSION_PHONE_VIDEOFRAME_H_
diff --git a/talk/session/phone/videorenderer.h b/talk/session/phone/videorenderer.h
new file mode 100644
index 0000000..f1fe547
--- /dev/null
+++ b/talk/session/phone/videorenderer.h
@@ -0,0 +1,47 @@
+/*
+ * libjingle
+ * Copyright 2004, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_SESSION_PHONE_VIDEORENDERER_H_
+#define TALK_SESSION_PHONE_VIDEORENDERER_H_
+
+namespace cricket {
+
+class VideoFrame;
+
+// Abstract interface for rendering VideoFrames.
+class VideoRenderer {
+ public:
+ virtual ~VideoRenderer() {}
+ // Called when the video has changed size.
+ virtual bool SetSize(int width, int height, int reserved) = 0;
+ // Called when a new frame is available for display.
+ virtual bool RenderFrame(const VideoFrame *frame) = 0;
+};
+
+} // namespace cricket
+
+#endif // TALK_SESSION_PHONE_VIDEORENDERER_H_
diff --git a/talk/site_scons/site_tools/talk_linux.py b/talk/site_scons/site_tools/talk_linux.py
index 1e204bc..67214c0 100644
--- a/talk/site_scons/site_tools/talk_linux.py
+++ b/talk/site_scons/site_tools/talk_linux.py
@@ -221,15 +221,20 @@
(package, package))
package_ccflags = _GetPackageFlags('--cflags', packages)
package_libs = _GetPackageFlags('--libs', packages)
- # Split package_libs into actual libs and non-lib linker flags.
+ # Split package_libs into libs, libdirs, and misc. linker flags. (In a perfect
+ # world we could just leave libdirs in link_flags, but some linkers are
+ # somehow confused by the different argument order.)
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']
+ libdirs = [flag[2:] for flag in package_libs if flag[0:2] == '-L']
+ link_flags = [flag for flag in package_libs if flag[0:2] not in ['-l', '-L']]
return {
'ccflags': package_ccflags,
'libs': libs,
+ 'libdirs': libdirs,
'link_flags': link_flags,
'dependent_target_settings' : {
'libs': libs[:],
+ 'libdirs': libdirs[:],
'link_flags': link_flags[:],
},
}
diff --git a/talk/site_scons/talk.py b/talk/site_scons/talk.py
index e2a2166..e2ac143 100644
--- a/talk/site_scons/talk.py
+++ b/talk/site_scons/talk.py
@@ -7,16 +7,40 @@
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()
+class LibraryInfo:
+ """Records information on the libraries defined in a build configuration.
-def _GetLibParams(lib):
+ Attributes:
+ lib_targets: Dictionary of library target params for lookups in
+ ExtendComponent().
+ prebuilt_libraries: Set of all prebuilt static libraries.
+ system_libraries: Set of libraries not found in the above (used to detect
+ out-of-order build rules).
+ """
+
+ # Dictionary of LibraryInfo objects keyed by BUILD_TYPE value.
+ __library_info = {}
+
+ @staticmethod
+ def get(env):
+ """Gets the LibraryInfo object for the current build type.
+
+ Args:
+ env: The environment object.
+
+ Returns:
+ The LibraryInfo object.
+ """
+ return LibraryInfo.__library_info.setdefault(env['BUILD_TYPE'],
+ LibraryInfo())
+
+ def __init__(self):
+ self.lib_targets = {}
+ self.prebuilt_libraries = set()
+ self.system_libraries = set()
+
+
+def _GetLibParams(env, 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
@@ -25,26 +49,29 @@
dependencies for future targets.
Args:
+ env: The environment object.
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]
+ info = LibraryInfo.get(env)
+ if lib in info.lib_targets:
+ return info.lib_targets[lib]
else:
- if lib not in _all_prebuilt_libraries and lib not in _all_system_libraries:
- _all_system_libraries.add(lib)
+ if lib not in info.prebuilt_libraries and lib not in info.system_libraries:
+ info.system_libraries.add(lib)
return None
-def _RecordLibParams(lib, params):
+def _RecordLibParams(env, 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:
+ env: The environment object.
lib: The library target's name as a string.
params: Its dictionary of params.
@@ -53,17 +80,18 @@
previously declared to be prebuilt, or the lib target is being defined
after a reverse library dependency.
"""
- if lib in _all_lib_targets:
+ info = LibraryInfo.get(env)
+ if lib in info.lib_targets:
raise Exception('Multiple definitions of ' + lib)
- if lib in _all_prebuilt_libraries:
+ if lib in info.prebuilt_libraries:
raise Exception(lib + ' already declared as a prebuilt library')
- if lib in _all_system_libraries:
+ if lib in info.system_libraries:
raise Exception(lib + ' cannot be defined after its reverse library '
'dependencies')
- _all_lib_targets[lib] = params
+ info.lib_targets[lib] = params
-def _IsPrebuiltLibrary(lib):
+def _IsPrebuiltLibrary(env, 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
@@ -71,26 +99,29 @@
negative result so as to detect out-of-order dependencies for future targets.
Args:
+ env: The environment object.
lib: The library's name as a string.
Returns:
True or False
"""
- if lib in _all_prebuilt_libraries:
+ info = LibraryInfo.get(env)
+ if lib in info.prebuilt_libraries:
return True
else:
- if lib not in _all_lib_targets and lib not in _all_system_libraries:
- _all_system_libraries.add(lib)
+ if lib not in info.lib_targets and lib not in info.system_libraries:
+ info.system_libraries.add(lib)
return False
-def _RecordPrebuiltLibrary(lib):
+def _RecordPrebuiltLibrary(env, 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:
+ env: The environment object.
lib: The library's name as a string.
Raises:
@@ -98,14 +129,15 @@
previously declared as a target, or the lib is being declared as
prebuilt after a reverse library dependency.
"""
- if lib in _all_prebuilt_libraries:
+ info = LibraryInfo.get(env)
+ if lib in info.prebuilt_libraries:
raise Exception('Multiple prebuilt declarations of ' + lib)
- if lib in _all_lib_targets:
+ if lib in info.lib_targets:
raise Exception(lib + ' already defined as a target')
- if lib in _all_system_libraries:
+ if lib in info.system_libraries:
raise Exception(lib + ' cannot be declared as prebuilt after its reverse '
'library dependencies')
- _all_prebuilt_libraries.add(lib)
+ info.prebuilt_libraries.add(lib)
def _GenericLibrary(env, static, **kwargs):
@@ -123,20 +155,21 @@
return ExtendComponent(env, 'ComponentLibrary', **params)
-def DeclarePrebuiltLibraries(libraries):
+def DeclarePrebuiltLibraries(env, 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:
+ env: The environment object.
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)
+ _RecordPrebuiltLibrary(env, library)
def Library(env, **kwargs):
@@ -396,7 +429,7 @@
def MergeSettingsFromLibraryDependencies(env, params):
if 'libs' in params:
for lib in params['libs']:
- libparams = _GetLibParams(lib)
+ libparams = _GetLibParams(env, lib)
if libparams:
if 'dependent_target_settings' in libparams:
params = CombineDicts(
@@ -440,7 +473,7 @@
# save pristine params of lib targets for future reference
if 'ComponentLibrary' == component:
- _RecordLibParams(name, dict(params))
+ _RecordLibParams(env, name, dict(params))
# add any dependent target settings from library dependencies
params = MergeSettingsFromLibraryDependencies(env, params)
@@ -512,9 +545,9 @@
# 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)]
+ _GetLibParams(env, lib) or _IsPrebuiltLibrary(env, lib)]
shared_libs = ['-l' + lib for lib in libs if not
- (_GetLibParams(lib) or _IsPrebuiltLibrary(lib))]
+ (_GetLibParams(env, lib) or _IsPrebuiltLibrary(env, lib))]
env.Replace(LIBS=static_libs)
env.Append(_LIBFLAGS=shared_libs)
@@ -537,7 +570,7 @@
# link 64 bit versions of libraries
libs = []
for lib in env_64bit['LIBS']:
- libparams = _GetLibParams(lib)
+ libparams = _GetLibParams(env, lib)
if libparams and 'also64bit' in libparams:
libs.append(lib + '64')
else:
diff --git a/talk/xmllite/xmlelement.cc b/talk/xmllite/xmlelement.cc
index 3ec085c..bf436fb 100644
--- a/talk/xmllite/xmlelement.cc
+++ b/talk/xmllite/xmlelement.cc
@@ -26,7 +26,6 @@
*/
#include <string>
-#include <iostream>
#include <vector>
#include <sstream>
diff --git a/talk/xmllite/xmlnsstack.cc b/talk/xmllite/xmlnsstack.cc
index 18e1607..b2bf370 100644
--- a/talk/xmllite/xmlnsstack.cc
+++ b/talk/xmllite/xmlnsstack.cc
@@ -2,31 +2,30 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string>
-#include <iostream>
#include <vector>
#include <sstream>
#include "talk/xmllite/xmlelement.h"
@@ -56,9 +55,6 @@
pxmlnsStack_->end());
}
}
-const std::pair<std::string, bool> NS_NOT_FOUND(STR_EMPTY, false);
-const std::pair<std::string, bool> EMPTY_NS_FOUND(STR_EMPTY, true);
-const std::pair<std::string, bool> XMLNS_DEFINITION_FOUND(NS_XMLNS, true);
const std::string *
XmlnsStack::NsForPrefix(const std::string & prefix) {
diff --git a/talk/xmllite/xmlparser.cc b/talk/xmllite/xmlparser.cc
index 5f6f7d5..b267414 100644
--- a/talk/xmllite/xmlparser.cc
+++ b/talk/xmllite/xmlparser.cc
@@ -29,7 +29,6 @@
#include <string>
#include <vector>
-#include <iostream>
#include "talk/base/common.h"
#include "talk/xmllite/xmlconstants.h"
#include "talk/xmllite/xmlelement.h"
diff --git a/talk/xmllite/xmlprinter.cc b/talk/xmllite/xmlprinter.cc
index b05898f..db6704b 100644
--- a/talk/xmllite/xmlprinter.cc
+++ b/talk/xmllite/xmlprinter.cc
@@ -2,33 +2,33 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <string>
-#include <iostream>
-#include <vector>
+#include <ostream>
#include <sstream>
+#include <string>
+#include <vector>
#include "talk/xmllite/xmlelement.h"
#include "talk/xmllite/xmlprinter.h"
#include "talk/xmllite/xmlnsstack.h"
diff --git a/talk/xmpp/constants.cc b/talk/xmpp/constants.cc
index 2d108ac..a1aaa63 100644
--- a/talk/xmpp/constants.cc
+++ b/talk/xmpp/constants.cc
@@ -477,6 +477,9 @@
const QName QN_CALLPERF_REMOTEUSER(true, STR_EMPTY, "remoteUser");
const QName QN_CALLPERF_STARTTIME(true, STR_EMPTY, "startTime");
const QName QN_CALLPERF_CALL_LENGTH(true, STR_EMPTY, "callLength");
+const QName QN_CALLPERF_CALL_ACCEPTED(STR_EMPTY, "callAccepted");
+const QName QN_CALLPERF_CALL_ERROR_CODE(STR_EMPTY, "callErrorCode");
+const QName QN_CALLPERF_TERMINATE_CODE(STR_EMPTY, "terminateCode");
const QName QN_CALLPERF_DATAPOINT(true, NS_GOOGLE_CALLPERF_STATS, "dataPoint");
const QName QN_CALLPERF_DATAPOINT_TIME(true, STR_EMPTY, "timeStamp");
const QName QN_CALLPERF_DATAPOINT_FRACTION_LOST(true, STR_EMPTY, "fraction_lost");
@@ -488,9 +491,41 @@
const QName QN_CALLPERF_DATAPOINT_PACKETS_R(true, STR_EMPTY, "packetsReceived");
const QName QN_CALLPERF_DATAPOINT_BYTES_S(true, STR_EMPTY, "bytesSent");
const QName QN_CALLPERF_DATAPOINT_PACKETS_S(true, STR_EMPTY, "packetsSent");
+const QName QN_CALLPERF_DATAPOINT_PROCESS_CPU(STR_EMPTY, "processCpu");
+const QName QN_CALLPERF_DATAPOINT_SYSTEM_CPU(STR_EMPTY, "systemCpu");
+const QName QN_CALLPERF_DATAPOINT_CPUS(STR_EMPTY, "cpus");
const QName QN_CALLPERF_CONNECTION(true, NS_GOOGLE_CALLPERF_STATS, "connection");
const QName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS(true, STR_EMPTY, "localAddress");
const QName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS(true, STR_EMPTY, "remoteAddress");
+const QName QN_CALLPERF_CONNECTION_FLAGS(STR_EMPTY, "flags");
+const QName QN_CALLPERF_CONNECTION_RTT(STR_EMPTY, "rtt");
+const QName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S(
+ STR_EMPTY, "totalBytesSent");
+const QName QN_CALLPERF_CONNECTION_BYTES_SECOND_S(
+ STR_EMPTY, "bytesSecondSent");
+const QName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R(
+ STR_EMPTY, "totalBytesRecv");
+const QName QN_CALLPERF_CONNECTION_BYTES_SECOND_R(
+ STR_EMPTY, "bytesSecondRecv");
+const QName QN_CALLPERF_CANDIDATE(NS_GOOGLE_CALLPERF_STATS, "candidate");
+const QName QN_CALLPERF_CANDIDATE_ENDPOINT(STR_EMPTY, "endpoint");
+const QName QN_CALLPERF_CANDIDATE_PROTOCOL(STR_EMPTY, "protocol");
+const QName QN_CALLPERF_CANDIDATE_ADDRESS(STR_EMPTY, "address");
+const QName QN_CALLPERF_MEDIA(NS_GOOGLE_CALLPERF_STATS, "media");
+const QName QN_CALLPERF_MEDIA_DIRECTION(STR_EMPTY, "direction");
+const QName QN_CALLPERF_MEDIA_SSRC(STR_EMPTY, "SSRC");
+const QName QN_CALLPERF_MEDIA_ENERGY(STR_EMPTY, "energy");
+const QName QN_CALLPERF_MEDIA_FIR(STR_EMPTY, "fir");
+const QName QN_CALLPERF_MEDIA_NACK(STR_EMPTY, "nack");
+const QName QN_CALLPERF_MEDIA_FPS(STR_EMPTY, "fps");
+const QName QN_CALLPERF_MEDIA_FPS_NETWORK(STR_EMPTY, "fpsNetwork");
+const QName QN_CALLPERF_MEDIA_FPS_DECODED(STR_EMPTY, "fpsDecoded");
+const QName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE(
+ STR_EMPTY, "jitterBufferSize");
+const QName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE(
+ STR_EMPTY, "preferredJitterBufferSize");
+const QName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY(
+ STR_EMPTY, "totalPlayoutDelay");
// Muc invites.
const QName QN_MUC_USER_INVITE(true, NS_MUC_USER, "invite");
diff --git a/talk/xmpp/constants.h b/talk/xmpp/constants.h
index 07e8554..ecc8e00 100644
--- a/talk/xmpp/constants.h
+++ b/talk/xmpp/constants.h
@@ -428,6 +428,9 @@
extern const QName QN_CALLPERF_REMOTEUSER;
extern const QName QN_CALLPERF_STARTTIME;
extern const QName QN_CALLPERF_CALL_LENGTH;
+extern const QName QN_CALLPERF_CALL_ACCEPTED;
+extern const QName QN_CALLPERF_CALL_ERROR_CODE;
+extern const QName QN_CALLPERF_TERMINATE_CODE;
extern const QName QN_CALLPERF_DATAPOINT;
extern const QName QN_CALLPERF_DATAPOINT_TIME;
extern const QName QN_CALLPERF_DATAPOINT_FRACTION_LOST;
@@ -439,9 +442,34 @@
extern const QName QN_CALLPERF_DATAPOINT_PACKETS_R;
extern const QName QN_CALLPERF_DATAPOINT_BYTES_S;
extern const QName QN_CALLPERF_DATAPOINT_PACKETS_S;
+extern const QName QN_CALLPERF_DATAPOINT_PROCESS_CPU;
+extern const QName QN_CALLPERF_DATAPOINT_SYSTEM_CPU;
+extern const QName QN_CALLPERF_DATAPOINT_CPUS;
extern const QName QN_CALLPERF_CONNECTION;
extern const QName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS;
extern const QName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS;
+extern const QName QN_CALLPERF_CONNECTION_FLAGS;
+extern const QName QN_CALLPERF_CONNECTION_RTT;
+extern const QName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S;
+extern const QName QN_CALLPERF_CONNECTION_BYTES_SECOND_S;
+extern const QName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R;
+extern const QName QN_CALLPERF_CONNECTION_BYTES_SECOND_R;
+extern const QName QN_CALLPERF_CANDIDATE;
+extern const QName QN_CALLPERF_CANDIDATE_ENDPOINT;
+extern const QName QN_CALLPERF_CANDIDATE_PROTOCOL;
+extern const QName QN_CALLPERF_CANDIDATE_ADDRESS;
+extern const QName QN_CALLPERF_MEDIA;
+extern const QName QN_CALLPERF_MEDIA_DIRECTION;
+extern const QName QN_CALLPERF_MEDIA_SSRC;
+extern const QName QN_CALLPERF_MEDIA_ENERGY;
+extern const QName QN_CALLPERF_MEDIA_FIR;
+extern const QName QN_CALLPERF_MEDIA_NACK;
+extern const QName QN_CALLPERF_MEDIA_FPS;
+extern const QName QN_CALLPERF_MEDIA_FPS_NETWORK;
+extern const QName QN_CALLPERF_MEDIA_FPS_DECODED;
+extern const QName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE;
+extern const QName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE;
+extern const QName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY;
// Muc invites.
extern const QName QN_MUC_USER_INVITE;
diff --git a/talk/xmpp/iqtask.cc b/talk/xmpp/iqtask.cc
index d73aada..f319990 100644
--- a/talk/xmpp/iqtask.cc
+++ b/talk/xmpp/iqtask.cc
@@ -34,8 +34,10 @@
static const int kDefaultIqTimeoutSecs = 15;
-IqTask::IqTask(talk_base::Task* parent, const std::string& verb,
- const buzz::Jid& to, buzz::XmlElement* el)
+IqTask::IqTask(XmppTaskParentInterface* parent,
+ const std::string& verb,
+ const buzz::Jid& to,
+ buzz::XmlElement* el)
: buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
to_(to),
stanza_(MakeIq(verb, to_, task_id())) {
diff --git a/talk/xmpp/iqtask.h b/talk/xmpp/iqtask.h
index 22e658d..7d9d621 100644
--- a/talk/xmpp/iqtask.h
+++ b/talk/xmpp/iqtask.h
@@ -37,7 +37,8 @@
class IqTask : public buzz::XmppTask {
public:
- IqTask(talk_base::Task* parent, const std::string& verb, const buzz::Jid& to,
+ IqTask(XmppTaskParentInterface* parent,
+ const std::string& verb, const buzz::Jid& to,
buzz::XmlElement* el);
virtual ~IqTask() {}
diff --git a/talk/xmpp/mucroomlookuptask.cc b/talk/xmpp/mucroomlookuptask.cc
index 2cc5285..e6a204a 100644
--- a/talk/xmpp/mucroomlookuptask.cc
+++ b/talk/xmpp/mucroomlookuptask.cc
@@ -34,14 +34,14 @@
namespace buzz {
-MucRoomLookupTask::MucRoomLookupTask(Task* parent,
+MucRoomLookupTask::MucRoomLookupTask(XmppTaskParentInterface* parent,
const std::string& room_name,
const std::string& organizer_domain)
: IqTask(parent, STR_SET, Jid(STR_MUC_LOOKUP_DOMAIN),
MakeRoomQuery(room_name, organizer_domain)) {
}
-MucRoomLookupTask::MucRoomLookupTask(Task* parent,
+MucRoomLookupTask::MucRoomLookupTask(XmppTaskParentInterface* parent,
const Jid& room_jid)
: IqTask(parent, STR_SET, Jid(STR_MUC_LOOKUP_DOMAIN),
MakeJidQuery(room_jid)) {
diff --git a/talk/xmpp/mucroomlookuptask.h b/talk/xmpp/mucroomlookuptask.h
index 9ade9fa..e8e6c76 100644
--- a/talk/xmpp/mucroomlookuptask.h
+++ b/talk/xmpp/mucroomlookuptask.h
@@ -41,9 +41,11 @@
class MucRoomLookupTask : public IqTask {
public:
- MucRoomLookupTask(Task* parent, const std::string& room_name,
- const std::string& organizer_domain);
- MucRoomLookupTask(Task* parent, const Jid& room_jid);
+ MucRoomLookupTask(XmppTaskParentInterface* parent,
+ const std::string& room_name,
+ const std::string& organizer_domain);
+ MucRoomLookupTask(XmppTaskParentInterface* parent,
+ const Jid& room_jid);
sigslot::signal1<const MucRoomInfo&> SignalResult;
diff --git a/talk/xmpp/xmppclient.cc b/talk/xmpp/xmppclient.cc
index ba32908..578884a 100644
--- a/talk/xmpp/xmppclient.cc
+++ b/talk/xmpp/xmppclient.cc
@@ -36,13 +36,6 @@
namespace buzz {
-talk_base::TaskParent* XmppClient::GetParent(int code) {
- if (code == XMPP_CLIENT_TASK_CODE)
- return this;
- else
- return talk_base::Task::GetParent(code);
-}
-
class XmppClient::Private :
public sigslot::has_slots<>,
public XmppSessionHandler,
@@ -279,7 +272,7 @@
}
XmppClient::XmppClient(TaskParent * parent)
- : Task(parent),
+ : XmppTaskParentInterface(parent),
delivering_signal_(false),
valid_(false) {
d_.reset(new Private(this));
diff --git a/talk/xmpp/xmppclient.h b/talk/xmpp/xmppclient.h
index 9983794..b8f854e 100644
--- a/talk/xmpp/xmppclient.h
+++ b/talk/xmpp/xmppclient.h
@@ -31,14 +31,14 @@
#include <string>
#include "talk/base/basicdefs.h"
#include "talk/base/sigslot.h"
-#include "talk/xmpp/xmppengine.h"
+#include "talk/base/task.h"
#include "talk/xmpp/asyncsocket.h"
#include "talk/xmpp/xmppclientsettings.h"
-#include "talk/base/task.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmpptask.h"
namespace buzz {
-class XmppTask;
class PreXmppAuth;
class CaptchaChallenge;
@@ -68,22 +68,22 @@
//
/////////////////////////////////////////////////////////////////////
-class XmppClient : public talk_base::Task, public sigslot::has_slots<>
+class XmppClient : public XmppTaskParentInterface,
+ public XmppClientInterface,
+ public sigslot::has_slots<>
{
public:
explicit XmppClient(talk_base::TaskParent * parent);
- ~XmppClient();
+ virtual ~XmppClient();
XmppReturnStatus Connect(const XmppClientSettings & settings,
const std::string & lang,
AsyncSocket * socket,
PreXmppAuth * preauth);
- virtual talk_base::TaskParent* GetParent(int code);
virtual int ProcessStart();
virtual int ProcessResponse();
XmppReturnStatus Disconnect();
- const Jid & jid();
sigslot::signal1<XmppEngine::State> SignalStateChange;
XmppEngine::State GetState();
@@ -101,30 +101,31 @@
// (if we used GAIA authentication)
std::string GetAuthCookie();
- std::string NextId();
- XmppReturnStatus SendStanza(const XmlElement *stanza);
XmppReturnStatus SendRaw(const std::string & text);
- XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
- XmppStanzaError code,
- const std::string & text);
XmppEngine* engine();
sigslot::signal2<const char *, int> SignalLogInput;
sigslot::signal2<const char *, int> SignalLogOutput;
-private:
+ // As XmppTaskParentIntreface
+ virtual XmppClientInterface* GetClient() { return this; }
+
+ // As XmppClientInterface
+ virtual const Jid& jid();
+ virtual std::string NextId();
+ virtual XmppReturnStatus SendStanza(const XmlElement *stanza);
+ virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+ XmppStanzaError code,
+ const std::string & text);
+ virtual void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel);
+ virtual void RemoveXmppTask(XmppTask *);
+
+ private:
friend class XmppTask;
void OnAuthDone();
- // managed tasks and dispatching
- void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel);
- void RemoveXmppTask(XmppTask *);
-
- sigslot::signal0<> SignalDisconnected;
-
-private:
// Internal state management
enum {
STATE_PRE_XMPP_LOGIN = STATE_NEXT,
diff --git a/talk/xmpp/xmpplogintask.cc b/talk/xmpp/xmpplogintask.cc
index 537818c..340d95d 100644
--- a/talk/xmpp/xmpplogintask.cc
+++ b/talk/xmpp/xmpplogintask.cc
@@ -25,7 +25,6 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <iostream>
#include <string>
#include <vector>
#include "talk/base/base64.h"
diff --git a/talk/xmpp/xmpptask.cc b/talk/xmpp/xmpptask.cc
index 5c4c653..60841d4 100644
--- a/talk/xmpp/xmpptask.cc
+++ b/talk/xmpp/xmpptask.cc
@@ -35,18 +35,22 @@
RateLimitManager task_rate_manager;
-XmppTask::XmppTask(TaskParent* parent, XmppEngine::HandlerLevel level)
- : Task(parent), client_(NULL) {
+XmppClientInterface::XmppClientInterface() {
+}
+
+XmppClientInterface::~XmppClientInterface() {
+}
+
+XmppTask::XmppTask(XmppTaskParentInterface* parent,
+ XmppEngine::HandlerLevel level)
+ : XmppTaskBase(parent), stopped_(false) {
#ifdef _DEBUG
debug_force_timeout_ = false;
#endif
- XmppClient* client =
- static_cast<XmppClient*>(parent->GetParent(XMPP_CLIENT_TASK_CODE));
- client_ = client;
- id_ = client->NextId();
- client->AddXmppTask(this, level);
- client->SignalDisconnected.connect(this, &XmppTask::OnDisconnect);
+ id_ = GetClient()->NextId();
+ GetClient()->AddXmppTask(this, level);
+ GetClient()->SignalDisconnected.connect(this, &XmppTask::OnDisconnect);
}
XmppTask::~XmppTask() {
@@ -55,25 +59,25 @@
void XmppTask::StopImpl() {
while (NextStanza() != NULL) {}
- if (client_) {
- client_->RemoveXmppTask(this);
- client_->SignalDisconnected.disconnect(this);
- client_ = NULL;
+ if (!stopped_) {
+ GetClient()->RemoveXmppTask(this);
+ GetClient()->SignalDisconnected.disconnect(this);
+ stopped_ = true;
}
}
XmppReturnStatus XmppTask::SendStanza(const XmlElement* stanza) {
- if (client_ == NULL)
+ if (stopped_)
return XMPP_RETURN_BADSTATE;
- return client_->SendStanza(stanza);
+ return GetClient()->SendStanza(stanza);
}
XmppReturnStatus XmppTask::SendStanzaError(const XmlElement* element_original,
XmppStanzaError code,
const std::string& text) {
- if (client_ == NULL)
+ if (stopped_)
return XMPP_RETURN_BADSTATE;
- return client_->SendStanzaError(element_original, code, text);
+ return GetClient()->SendStanzaError(element_original, code, text);
}
void XmppTask::Stop() {
@@ -152,7 +156,7 @@
// It is legal for the server to identify itself with "domain" or
// "myself@domain"
- Jid me = client_->jid();
+ Jid me = GetClient()->jid();
return (from == Jid(me.domain())) || (from == me.BareJid());
}
diff --git a/talk/xmpp/xmpptask.h b/talk/xmpp/xmpptask.h
index 86fbe27..fd82c79 100644
--- a/talk/xmpp/xmpptask.h
+++ b/talk/xmpp/xmpptask.h
@@ -31,8 +31,9 @@
#include <string>
#include <deque>
#include "talk/base/sigslot.h"
-#include "talk/xmpp/xmppengine.h"
#include "talk/base/task.h"
+#include "talk/base/taskparent.h"
+#include "talk/xmpp/xmppengine.h"
namespace buzz {
@@ -61,19 +62,76 @@
//
/////////////////////////////////////////////////////////////////////
-class XmppClient;
+class XmppTask;
-class XmppTask :
- public talk_base::Task,
- public XmppStanzaHandler,
- public sigslot::has_slots<>
+// XmppClientInterface is an abstract interface for sending and
+// handling stanzas. It can be implemented for unit tests or
+// different network environments. It will usually be implemented by
+// XmppClient.
+class XmppClientInterface {
+ public:
+ XmppClientInterface();
+ virtual ~XmppClientInterface();
+
+ virtual const Jid& jid() = 0;
+ virtual std::string NextId() = 0;
+ virtual XmppReturnStatus SendStanza(const XmlElement* stanza) = 0;
+ virtual XmppReturnStatus SendStanzaError(const XmlElement* original_stanza,
+ XmppStanzaError error_code,
+ const std::string& message) = 0;
+ virtual void AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) = 0;
+ virtual void RemoveXmppTask(XmppTask* task) = 0;
+ sigslot::signal0<> SignalDisconnected;
+
+ DISALLOW_EVIL_CONSTRUCTORS(XmppClientInterface);
+};
+
+// XmppTaskParentInterface is the interface require for any parent of
+// an XmppTask. It needs, for example, a way to get an
+// XmppClientInterface.
+
+// We really ought to inherit from a TaskParentInterface, but we tried
+// that and it's way too complicated to change
+// Task/TaskParent/TaskRunner. For now, this works.
+class XmppTaskParentInterface : public talk_base::Task {
+ public:
+ explicit XmppTaskParentInterface(talk_base::TaskParent* parent)
+ : Task(parent) {
+ }
+ virtual ~XmppTaskParentInterface() {}
+
+ virtual XmppClientInterface* GetClient() = 0;
+
+ DISALLOW_EVIL_CONSTRUCTORS(XmppTaskParentInterface);
+};
+
+class XmppTaskBase : public XmppTaskParentInterface {
+ public:
+ explicit XmppTaskBase(XmppTaskParentInterface* parent)
+ : XmppTaskParentInterface(parent),
+ parent_(parent) {
+ }
+ virtual ~XmppTaskBase() {}
+
+ virtual XmppClientInterface* GetClient() {
+ return parent_->GetClient();
+ }
+
+ protected:
+ XmppTaskParentInterface* parent_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(XmppTaskBase);
+};
+
+class XmppTask : public XmppTaskBase,
+ public XmppStanzaHandler,
+ public sigslot::has_slots<>
{
public:
- XmppTask(talk_base::TaskParent* parent,
+ XmppTask(XmppTaskParentInterface* parent,
XmppEngine::HandlerLevel level = XmppEngine::HL_NONE);
virtual ~XmppTask();
- virtual XmppClient* GetClient() const { return client_; }
std::string task_id() const { return id_; }
void set_task_id(std::string id) { id_ = id; }
@@ -81,9 +139,9 @@
void set_debug_force_timeout(const bool f) { debug_force_timeout_ = f; }
#endif
- protected:
- friend class XmppClient;
+ virtual bool HandleStanza(const XmlElement* stanza) { return false; }
+ protected:
XmppReturnStatus SendStanza(const XmlElement* stanza);
XmppReturnStatus SetResult(const std::string& code);
XmppReturnStatus SendStanzaError(const XmlElement* element_original,
@@ -91,7 +149,6 @@
const std::string& text);
virtual void Stop();
- virtual bool HandleStanza(const XmlElement* stanza) { return false; }
virtual void OnDisconnect();
virtual void QueueStanza(const XmlElement* stanza);
@@ -116,7 +173,7 @@
private:
void StopImpl();
- XmppClient* client_;
+ bool stopped_;
std::deque<XmlElement*> stanza_queue_;
talk_base::scoped_ptr<XmlElement> next_stanza_;
std::string id_;